9.不在构造、析构函数中调用虚函数
1.在构造函数和析构函数中调用虚函数会产生什么结果呢?
#include <iostream>
using namespace std;
class cls1{
public:
cls1(){
newMake();
};
~cls1(){
deleteIt();
};
virtual void newMake(){
cout<<"cls1 make"<<endl;
}
virtual void deleteIt(){
cout<<"cls1 delete"<<endl;
}
};
class cls2:public cls1
{
public:
cls2(){
newMake();
};
~cls2(){
deleteIt();
};
virtual void newMake(){
cout<<"cls2 make"<<endl;
}
virtual void deleteIt(){
cout<<"cls2 delete"<<endl;
}
};
int main(int argc, char const *argv[])
{
cls2 c;
return 0;
}
上述程序会产生什么样的输出呢?
你一定会以为会输出:
cls2 make
cls2 delete
或者是:
cls2 make
cls2 make
cls2 delete
cls2 delete
(如果你想到了后一种,说明你对派生类的构造有一定了解)
因为在构造和析构函数使用了虚函数,应该是迟绑定。但是实际的输出是:
cls1 make
cls2 make
cls2 delete
cls1 delete
为什么呢?
理由如下:
在程序构造一个cls2对象的时候,会调用基类(也就是cls1)的构造函数,但是这时cls2还没有被构造,所以虚表中只有cls1的newMake函数,所以程序只能调用cls1的newMake,然后到cls2的构造函数体执行,这时cls2已经被构造,所以cls2的构造函数会调用cls2的newMake
析构的时候,cls2的部分会率先释放,等到cls1释放的时候,虚表中已经不存在deleteIt的cls2版本了
2.解决方案
不在构造函数中调用虚函数,而是写一个通用的构造函数(或者通用的非构造函数,在基类构造函数中调用)