面向对象
explicit
关键字,作为返回值时加上不调用拷贝构造函数。作为类关键字防止被拷贝。
多态
父类指针指向子类对象
父类提供virtual 虚函数,子类对象实现
析构函数加virtual,可以调用子类的析构函数
构造函数前不能加virtual,因为构造函数执行后,虚表才出现
运算符重载
类中,++i比i++效率高,因为后者还要调用构造函数
工厂模式
用父类指针作为返回值,在返回值创建子类对象
单体模式
sizeof、_countof
_tscanf_s( _T(“%d”), v1, _countof(v1));
sizeof 数据类型大小与数据大小相乘,实际的数据大小
countof 数据大小,实际上的数据数量
结构体对齐
大小为4,1,8,按最大的对齐
如上,实际上为16。double占8,另外两个加起来用8
重载
函数名一样,参数类型不同,参数数量不同
与返回值类型无关
使用const,发生重载。
const是常对象调用的。
菱形继承
一个派生类D是由多继承产生的,它的多个基类B、C继承了同一个基类A。造成派生类D中具有多份A类的属性,属于一种不合理的现象
会让高层的基类在底层的派生类中拥有多份成员,造成二义性。
解决方法:使用作用域、利用虚继承
在使用时加上作用域
但是不能解决多次拷贝的问题
虚继承
给所有函数都加上virtual 继承时使用虚继承
使用虚继承时,第一成员是一个指针,指向一个结构体,里面第二成员是一个十六进制偏移。偏移值是父类到子类的偏移。
虚继承中,父类指针只能访问子类对象被继承的部分。因为在定义的时候,有一个偏移指向对应的数据。
虚表
将父类中函数定义为虚函数后,会出现一个虚表指针(4或8)在上述结构体的第一成员(第二成员是到子类的偏移),指向一个数组。数组中存放的都是函数,如果孩子实现了这个函数,就会放入孩子的。如果孩子的没实现,就会放入自己的。
类A是基类,类B继承类A,类C又继承类B。类A,类B,类C,假设在子类有实现,其对象模型如下图所示。
若菱形继承,两个父类均有对虚函数的实现,而子类没有对虚函数的实现,就会出现二义性问题。一般来说,子类都会进行实现,不会出现这种问题。
经常在父类的析构函数前加virtual,是为了在释放内存时使用子类的析构函数。
纯虚类
父类使用纯虚函数virtual void show() = 0;
它不会实例化一个对象,在子类继承的时候也会把纯虚函数继承,它强制性要求,派生类必须实现某个接口,不然无法实例化对象