explicit

关键字,作为返回值时加上不调用拷贝构造函数。作为类关键字防止被拷贝。

多态

父类指针指向子类对象

父类提供virtual 虚函数,子类对象实现

析构函数加virtual,可以调用子类的析构函数

构造函数前不能加virtual,因为构造函数执行后,虚表才出现

运算符重载

image-20230315211914313

类中,++i比i++效率高,因为后者还要调用构造函数

工厂模式

用父类指针作为返回值,在返回值创建子类对象

image-20230315201712599

单体模式

sizeof、_countof

_tscanf_s( _T(“%d”), v1, _countof(v1));

image-20230315203513264

sizeof 数据类型大小与数据大小相乘,实际的数据大小

countof 数据大小,实际上的数据数量

结构体对齐

大小为4,1,8,按最大的对齐

image-20230315204035697

如上,实际上为16。double占8,另外两个加起来用8

重载

函数名一样,参数类型不同,参数数量不同

与返回值类型无关

使用const,发生重载。

image-20230315204445450

const是常对象调用的。

菱形继承

一个派生类D是由多继承产生的,它的多个基类B、C继承了同一个基类A。造成派生类D中具有多份A类的属性,属于一种不合理的现象

img

会让高层的基类在底层的派生类中拥有多份成员,造成二义性。

解决方法:使用作用域、利用虚继承

在使用时加上作用域

image-20230319195155868

但是不能解决多次拷贝的问题

虚继承

image-20230319195311020

给所有函数都加上virtual 继承时使用虚继承

image-20230319195704646

使用虚继承时,第一成员是一个指针,指向一个结构体,里面第二成员是一个十六进制偏移。偏移值是父类到子类的偏移。

虚继承中,父类指针只能访问子类对象被继承的部分。因为在定义的时候,有一个偏移指向对应的数据。

image-20230319200336941

虚表

将父类中函数定义为虚函数后,会出现一个虚表指针(4或8)在上述结构体的第一成员(第二成员是到子类的偏移),指向一个数组。数组中存放的都是函数,如果孩子实现了这个函数,就会放入孩子的。如果孩子的没实现,就会放入自己的。

img

类A是基类,类B继承类A,类C又继承类B。类A,类B,类C,假设在子类有实现,其对象模型如下图所示。

img

若菱形继承,两个父类均有对虚函数的实现,而子类没有对虚函数的实现,就会出现二义性问题。一般来说,子类都会进行实现,不会出现这种问题。

经常在父类的析构函数前加virtual,是为了在释放内存时使用子类的析构函数。

纯虚类

父类使用纯虚函数virtual void show() = 0;它不会实例化一个对象,在子类继承的时候也会把纯虚函数继承,它强制性要求,派生类必须实现某个接口,不然无法实例化对象

在这里插入图片描述