我们都知道构造函数不能为虚函数,而基类的析构函数一般都要定义为虚函数。今天重新复习了一下,特在此记载,以便查找。
构造函数不能为虚函数主要有以下两点
1、必要性分析:
当定义派生类对象时,它会主动依次调用构造函数,顺序为基类的构造函数->一级派生类构造函数->二级派生类构造函数….直到当前派生类的构造函数调用完毕为止,到此派生类对象生成。
而虚函数存在的意义为动态绑定,从上一段话可知,它会从基类开始依次自动调用相应的构造函数,根本就不存在动态绑定的必要。
2、内存角度分析:
构造函数的作用是生成相应的类对象。虚函数的动态绑定是依据一张虚函数表来确认的最终绑定到哪一个虚函数版本。
而调用构造函数之前,我们对类对象所做的操作仅限于分配内存,还没有对内存进行初始化。此时,内存空间上也不存在虚函数表,因此,按照这样的执行顺序,虚函数的动态绑定是实现不了的。
基类析构函数与虚函数的关系
如果类的数据成员中不存在成员(指针)与动态分配的内存相关联,我们一般不用自己定义析构函数,而是采用默认的析构函数析构类对象。一旦与动态分配的内存相关联,为了防止内存泄露,我们需要自己定义析构函数,手动释放动态分配的内存。
三法则:如果一个类需要析构函数,几乎也需要定义赋值构造函数和重载赋值操作符。
在分析基类析构函数为什么要定义为虚析构函数之前,我们要先明白虚函数存在的意义就是为了动态绑定,实现面向对象的特性之一 :多态。
我们知道通过基类的指针或者引用可以实现对虚函数的动态绑定,那么当我们通过一个基类指针或者引用来析构一个对象时,我们是无法判断基类现在绑定的对象是基类还是派生类,如果析构函数不是虚函数,那么基类指针只会调用基类的析构函数,如此就发生了一些不该发生的事。只有将析构函数定义为虚函数,才能通过动态绑定,调用对应的析构函数版本,正确的析构类对象。
可以这么说:任何class只要有virtual函数都几乎确定也要有一个virtual析构函数(引用自Effective C++ 条款7)