构造函数不能是虚函数 基类析构函数必须为虚函数

1,从存储空间角度

   虚函数对应一个虚表vtbl,可是这个vtbl其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtbl来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtbl。所以构造函数不能是虚函数。

  vtbl是在编译期就建立了,各个虚函数这时被组织成了一个虚函数的入口地址的数组.而对象的隐藏成员--vptr是在运行期--也就是构造函数被调用时进行初始化的,这是实现多态的关键。

2,从使用角度

  虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。

虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数

3、构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它。但析构却不一定,我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。

4、从实现上看,vtbl在构造函数调用后才建立,因而构造函数不可能成为虚函数  

  从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数

5、当一个构造函数被调用时,它做的首要的事情之一是初始化它的vptr。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。 当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码- -既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。

  所以它使用的vptr必须是对于这个类的vtbl。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内,vptr将 保持被初始化为指向这个vtbl, 但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置vptr指向它的vtbl,等.直到最后的构造函数结束。vptr的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到更加派生类顺序的另一个理由。

  但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置vptr指向它自己的vtbl。如果函数调用使用虚机制,它将只产生通过它自己的vtbl的调用,而不是最后的vtbl(所有构造函数被调用后才会有最后的vtbl)。


基类析构函数只能是虚函数:

派生类对象构造的时候先调用基类的构造函数再调用派生类的构造函数,析构的时候先调用派生类析构函数再调用基类析构函数。

其实这个很好理解,派生类的成员由两部分组成,一部分是从基类那里继承而来,一部分是自己定义的。那么在实例化对象的时候,首先利用基类构造函数去初始化从基类继承而来的成员,再用派生类构造函数初始化自己定义的部分。

同时,不止构造函数派生类只负责自己的那部分,析构函数也是,所以派生类的析构函数会只析构自己的那部分,这时候如果基类的析构函数不是虚函数,则只能调用基类的析构函数析构从基类继承来的那部分成员,而派生类自己的成员没有被析构,所以就会出现只删一半的现象,造成内存泄漏。

所以析构函数要定义成虚函数。

用基类指针指向派生类时

在基类析构函数声明为virtual的时候,delete基类指针,会先调用派生类的析构函数,由于继承关系再调用基类的析构函数。

在基类析构函数没有声明为virtual的时候,delete基类指针,只会调用基类的析构函数,而不会调用派生类的析构函数,这样会造成销毁对象的不完全。

个人举例:Base *p=new Drived;

//new 过程,会先调用operator new分配空间,再调用Dirived的constructor,在调用Dirived的constructor时,会先调用Bass的constructor再调用Dirived的constructor,故delete p时,(在Bass的destructor是virtual时)会先调用Dirived的destructor再调用Bass的destructor


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值