为什么不要在构造函数和析构函数中调用虚函数?

铁律一:最好不要在构造函数和析构函数中调用虚函数!

构造派生类对象时,首先调用基类构造函数初始化对象的基类部分。在执行基类构造函数时,对象的派生类部分是未初始化的。实际上,此时的对象还不是一个派生类对象。

析构派生类对象时,首先撤销/析构他的派生类部分,然后按照与构造顺序的逆序撤销他的基类部分。

因此,在运行构造函数或者析构函数时,对象都是不完整的。为了适应这种不完整,编译器将对象的类型视为在调用构造/析构函数时发生了变换,即:视对象的类型为当前构造函数/析构函数所在的类的类类型。由此造成的结果是:在基类构造函数或者析构函数中,会将派生类对象当做基类类型对象对待。

而这样一个结果,会对构造函数、析构函数调用期间调用的虚函数类型的动态绑定对象产生影响,最终的结果是:如果在构造函数或者析构函数中调用虚函数,运行的都将是为构造函数或者析构函数自身类类型定义的虚函数版本。 无论有构造函数、析构函数直接还是间接调用虚函数

 

详细情况在该文中有详细的论述, 其主要结论如下:

1. 不要在构造函数和析构函数中调用虚函数,因为这种情况下的虚函数调用不会调用到外层派生类的虚函数(参考:http://www.artima.com/cppsource/nevercall.htmlhttp://www.parashift.com/c%2B%2B-faq-lite/strange-inheritance.html#faq-23.5)。

2. 对象的虚函数表地址在对象的构造和析构过程中会随着部分类的构造和析构而发生变化,这一点应该是编译器实现相关的。

注:以上的讨论是基于简单的单继承,对于多重继承或虚继承会有一些细节上的差别。

posted @ 2013-09-08 16:39  jiayouwyhit  阅读(1911)  评论(0编辑  收藏  举报