1、在类的继承机制中,父类的析构函数要设置成虚析构函数
父类指针绑定子类对象,若父类中析构函数不是虚函数,则静态编译,只会调用父类的析构函数不会调用子类的析构函数,所以会造成内存泄露!
若父类析构函数为虚函数,则指针会动态编译,调用子类的析构函数,调用子类的析构函数后会自动调用父类的析构函数。(子类对象创建会自动调用父类的构造函数,先调用父类的构造函数!子类析构函数调用完成后会自动调用父类的析构函数)。
2、父类指针和子类指针几种情况分析
(1)父类指针绑定父类对象,完全正常使用。
(2)子类指针绑定子类对象,完全正常使用。
(3)父类指针引用子类对象,只能引用父类中的函数(除了虚函数)。父类指针肯定不能调用子类函数(静态属性就不能)。
(4)子类指针引用父类对象,子类中不涉及子类内部数据成员的函数可以通过该指针调用,父类函数均可调用,涉及内部数据的会调用成功但执行失败。
(5)一个空指针也可以调用函数!指针为空,指向一个类(用dynamic_ cast,父类项子类的转换没有虚函数,转换失败,返回空指针),可以直接调用没有数据成员的函数(因为代码段是共有的,也就是函数是共有的)。但是涉及数据成员的函数会调用成功但是执行失败。
(6)父类指针指向子类对象(没有虚析构函数),销毁父类指针会造成内存泄漏。原因如1.
(7)内存越界:子类指针指向父类对象,销毁子类指针会造成内存越界!
fu *pfu = new fu;
zi *pzi = static_cast<zi*>(pfu);
delete pzi; //有时出错,有时无错
所以c++不允许子类指针绑定到父类对象!
3、静态联编和动态联编
静态联编:是程序匹配连接在编译阶段实现,例如:重载函数。
动态联编:程序匹配实在运行时进行,例如:switch,if。
4、虚函数
(1)虚函数的本质:本质是一个函数指针(32位系统占用4字节)。
(2)存在虚函数的类都有一个一维的虚函数表,表中存放虚函数地址,类内必须保存这个虚表的起始地址,所以类存在一个指向虚表的指针,但不管类中有几个虚函数,类内部只保存虚表的起始地址,虚函数地址可由偏移算法得到。
(3)虚函数作用:基类指针指向不同的派生类对象,实现不同的功能。基类指针提供一个接口作用。
一个接口实现多个功能,可以实现需求扩展。
(4)构造函数不能为虚函数。因为违背继承。若构造函数为虚函数基类指针指向子类对象只会调用子类的构造函数不会调用父类构造函数。
(5)虚析构函数:适配器模式,让父类指针正确释放子类对象的内存。防止内存泄漏。
(6)虚函数必须要定义。
(7)虚函数实现运行时多态。父类指针绑定到子类对象。
5、纯虚函数和抽象类
(1)形式:virtual 类型名 函数名(参数表) = 0;
(2)一个具有纯虚函数的基类称为抽象类,不能创建对象,实例化,不能作为返回值类型,参数类型。抽象类存在就是为了提供接口。可以创建指针!
(3)纯虚函数在基类中没有定义,任何派生类中都提供自己的定义,否则变成抽象类(只要有一个纯虚函数没有定义)。
6、类所占内存