不要在构造函数和析构函数中调用虚函数

读Effective C++ 条歀09:绝不在构造和析构过程中调用虚函数(Never call virtual functions during construction or destruction)

首先,我们用一句在程序员中比较流行的话作为本文的开篇:如果你在基类的构造函数中调用虚函数,那么在基类构造期间,虚函数的行为像一个“实”函数。

在派生类对象的基类部分构造期间,对象的类型是base class,而不是derived class。这时,不只是虚函数会被编译器解析至基类型,就连RTTI中的typeid和dynamic_cast也会把对象视为基类型。C++标准和编译器这样做的原因其实很简单:在派生类对象的基类部分构造期间,派生类的专属成分尚未被初始化,所以面对它们,最安全的做法就是视它们不存在。派生类对象在自身的构造函数开始执行前,不会被作为一个派生类对象,而是被看作一个基类对象。


对于析构函数,也同样适用。一旦派生类的析构函数执行完毕,派生类对象中的派生类特有的成员变量变呈现未定义状态,所以此时,C++编译器视它们如无物,即:进入到基类的析构函数中后,就把派生类对象视为一个基类对象,此时,任何虚函数、typeid和dynamic_cast等等也这么看待它。

C++ primer中说,如果在构造函数或析构函数中调用虚函数,则运行的是构造函数或析构函数自身类型所定义的版本。这句话表达的有歧义,不过指的也是上面文字所说的意思。即:在派生类对象的基类部分构造期间,就把派生类对象视为一个基类对象,这时调用的虚函数版本,就是基类的版本。

由以上分析可以看出,这样做是违背我们的期望的。所以唯一能够避免这种错误的做法就是:确定你的构造函数和析构函数都没有调用虚函数,包括构造函数和析构函数所调用的所有函数也没有调用虚函数。

构造函数的调用顺序是从基类到派生类,逐层构造。在构造的过程中,vptr被指向本层的vtable。而虚函数的行为依赖于vptr。因此,在本层构造函数中,编译器无法获知派生类的任何信息,因此无法形成正确的vtable访问。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值