C++编程经验:不要在构造函数和析构函数中使用虚函数
Posted 看,未来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++编程经验:不要在构造函数和析构函数中使用虚函数相关的知识,希望对你有一定的参考价值。
这个事情呢,其实我们平时也不会去做的,对吧。
当然要是做了的话,那也可以做好某些天连夜加班的准备。
构造函数中调用虚函数
首先构造函数中不能调用虚函数,不是说语法不允许,最重要的原因在于,当有继承的时候,父类会调用到子类的函数,但是此时子类并没有初始化,会导致数据错误,就这一点足已让你不能在构造函数中调用虚函数。
在基类的构造过程中,虚函数调用从不会被传递到派生类中。代之的是,派生类对象表现出来的行为好象其本身就是基类型。不规范地说,在基类的构造过程中,虚函数并没有被"构造"。
简单的说就是,在子类对象的基类子对象构造期间,调用的虚函数的版本是基类的而不是子类的。
对上面这种看上去有点违背直觉的行为可以用一个理由来解释:因为基类构造器是在派生类之前执行的,所以在基类构造器运行的时候派生类的数据成员还没有被初始化。如果在基类的构造过程中对虚函数的调用传递到了派生类, 派生类对象当然可以参照引用局部的数据成员,但是这些数据成员其时尚未被初始化。这将会导致无休止的未定义行为和彻夜的代码调试。沿类层次往下调用尚未初始化的对象的某些部分本来就是危险的,所以C++干脆不让你这样做。
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A构造函数";
Test();
}
~A()
{
cout << "A析构函数";
cout << "A::Test()" << endl;
}
virtual void Test()
{
cout << "A::Test()" << endl;
}
};
class B:public A
{
public:
B()
{
cout << "B构造函数";
Test();
}
~B()
{
cout << "B析构函数";
Test();
}
virtual void Test()
{
cout << "B::Test()" << endl;
}
};
int main()
{
A* pA = new B();
cout << "动态调用:";
pA->Test();
delete pA;
return 0;
}
对于这段代码,可能会执行出结果来,但是不要过于庆幸,新版的编译器会拒绝你在构造函数中调用了虚函数,然后帮你调整了方向。。。
因为编译器不这么做就导致你不确定的数据错误。
对于这个问题,看到一个很nice的说法:在一些平台正常,在另一些平台未必正常。今天正常,以后未必正常。
析构函数中调用虚函数
在对象的析构期间,存在与上面同样的逻辑。一旦一个派生类的析构器运行起来,该对象的派生类数据成员就被假设为是未定义的值,这样以来,C++就把它们当做是不存在一样。一旦进入到基类的析构器中,该对象即变为一个基类对象,C++中各个部分(虚函数,dynamic_cast运算符等等)都这样处理。
以上是关于C++编程经验:不要在构造函数和析构函数中使用虚函数的主要内容,如果未能解决你的问题,请参考以下文章