构造函数不能是虚函数,析构函数可以且常常是虚函数。
构造函数不能是虚函数
- 存储空间角度
虚函数的调用需要 vptr 指针,而该指针存放在对象的内容空间中,需要调用构造函数才可以创建它的值,否则即使开辟了空间,该 vptr 指针为随机值;若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有 vptr 地址用来调用虚函数之一的构造函数了。 - 多态角度
虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型来调用函数,例如通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用。那使用虚函数也没有实际意义。
在调用构造函数时还不能确定对象的真实类型(由于子类会调父类的构造函数);并且构造函数的作用是提供初始化,在对象生命期仅仅运行一次,不是对象的动态行为,没有必要成为虚函数。
析构函数常常是虚函数
创建一个对象时我们总是要明白指定对象的类型。虽然我们可能通过基类的指针或引用去訪问它但析构却不一定,我们往往通过基类的指针来销毁对象。这时候假设析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。
写通用函数时,运行根据传入对象的类型确定函数的地址,然后调用该函数。但析构却不一定,上面已经提到过了,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。