转自[https://blog.csdn.net/K346K346/article/details/49872023]ios
虽然能够对虚函数进行实调用,但程序员编写虚函数的本意应该是实现动态联编。在构造函数中调用虚函数,函数的入口地址是在编译时静态肯定的,并未实现虚调用。可是为何在构造函数中调用虚函数,实际上没有发生动态联编呢?程序员
第一个缘由,在概念上,构造函数的工做是为对象进行初始化。在构造函数完成以前,被构造的对象被认为“未彻底生成”。当建立某个派生类的对象时,若是在它的基类的构造函数中调用虚函数,那么此时派生类的构造函数并未执行,所调用的函数可能操做尚未被初始化的成员,将致使灾难的发生。函数
第二个缘由,即便想在构造函数中实现动态联编,在实现上也会遇到困难。这涉及到对象虚指针(vptr)的创建问题。在Visual C++中,包含虚函数的类对象的虚指针被安排在对象的起始地址处,而且虚函数表(vtable)的地址是由构造函数写入虚指针的。因此,一个类的构造函数在执行时,并不能保证该函数所能访问到的虚指针就是当前被构造对象最后所拥有的虚指针,由于后面派生类的构造函数会对当前被构造对象的虚指针进行重写,所以没法完成动态联编。spa
一样的,在析构函数中调用虚函数,函数的入口地址也是在编译时静态决定的。也就是说,实现的是实调用而非虚调用。
考察以下例子。.net
#include <iostream> using namespace std; class A { public: virtual void show(){ cout<<"in A"<<endl; } virtual ~A(){show();} }; class B:public A { public: void show(){ cout<<"in B"<<endl; } }; int main() { A a; B b; }
输出为:指针
in A in A
在类B的对象b退出做用域时,会先调用类B的析构函数,而后调用类A的析构函数,在析构函数~A()中,调用了虚函数show()。从输出结果来看,类A的析构函数对show()调用并无发生虚调用。对象
从概念上说,析构函数是用来销毁一个对象的,在销毁一个对象时,先调用该对象所属类的析构函数,而后再调用其基类的析构函数,因此,在调用基类的析构函数时,派生类对象的“善后”工做已经完成了,这个时候再调用在派生类中定义的函数版本已经没有意义了。blog
所以,通常状况下,应该避免在构造函数和析构函数中调用虚函数,若是必定要这样作,程序猿必须清楚,对虚函数的调用实际上是实调用。
作用域