C++ 构造函数不能是虚函数,基类析构函数应该为虚函数

Posted 森明帮大于黑虎帮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ 构造函数不能是虚函数,基类析构函数应该为虚函数相关的知识,希望对你有一定的参考价值。


简单总结就是: 构造函数不可以是虚函数,而析构函数可以且常常是虚函数。

1.构造函数不能是虚函数

  1. 从vptr角度解释
      虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还没有初始化!
      
    虚函数对应一个虚函数表vtbl,可是这个vtbl其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚函数,就需要通过 vtbl来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtbl。所以构造函数不能是虚函数。
      
    vtbl是在编译期就建立了,各个虚函数这时被组织成了一个虚函数的入口地址的数组.而对象的隐藏成员–vptr是在运行期–也就是构造函数被调用时进行初始化的,这是实现多态的关键。

  2. 从多态角度解释
      虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型来调用函数,例如通过父类的指针或者引用来调用它的时候可以变成调用子类的那个成员函数。而构造函数是在创建对象时自己主动调用的,不可能通过父类的指针或者引用去调用。那使用虚函数也没有实际意义。
      在调用构造函数时还不能确定对象的真实类型(由于子类会调父类的构造函数);并且构造函数的作用是提供初始化,在对象生命期仅仅运行一次,不是对象的动态行为,没有必要成为虚函数。

二、析构函数可以且常常是虚函数

如果我们以这种方式创建对象: 继承中的派生类先调用析构函数清理空间,在调用基类的析构。

SubClass* pObj = new SubClass();
delete pObj;

不管析构函数是否是虚函数(即是否加virtual关键词),delete时基类和子类都会被释放。

如果我们以这种方式创建对象:

BaseClass* pObj = new SubClass();
delete pObj;

  • 若析构函数是虚函数(即加上virtual关键词),delete时基类和子类都会被释放。
  • 若析构函数不是虚函数(即不加virtual关键词),delete时只释放基类,不释放子类。

基类的析构函数不是虚函数的话,删除指针时,只有基类的内存被释放,派生类的没有。这样就内存泄漏了。

析构函数不是虚函数的话,直接按指针类型调用该类型的析构函数代码,因为指针类型是基类,所以直接调用基类析构函数代码。 不满足多态的条件:跟类型有关,调用的类型是谁,调用的就是谁的虚函数。

养成习惯:基类的析构一定virtual。满足多态的条件:跟对象有关,调用的对象是谁,调用的就是谁的虚函数。

以上是关于C++ 构造函数不能是虚函数,基类析构函数应该为虚函数的主要内容,如果未能解决你的问题,请参考以下文章

浅谈多态基类析构函数声明为虚函数

基类析构函数为虚函数

基类析构函数必须为虚函数否则会造成内存泄漏

C++父类中声明了一个虚函数以后 是否在子类 以及子类的子类中 都要声明并重写这个函数?

构造函数和析构函数可以是虚函数吗

构造函数和析构函数可以是虚函数吗