您的位置:首页 > 其它

不要在构造或析构的过程中调用虚函数

2008-05-28 23:22 495 查看
C++在程序进行构造或析构期间,你绝不能调用虚函数,这是因为这样的调用并不会按你所期望的执行。C++中,如果在某个类的构造函数或者构造过程中调用了某个虚函数,该调用不会完全按照虚函数的多态性调用到其派生类的重写的函数,而只会调用到本类这个函数。下面是一个例子:

[align=left]例1:[/align]
[align=left]class B[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] B()[/align]
[align=left] {[/align]
[align=left] f();[/align]
[align=left] } [/align]
[align=left] virtual void f()[/align]
[align=left] {[/align]
[align=left] cout<<"B::f()"<<endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]class D1:public B[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] D1()[/align]
[align=left] {[/align]
[align=left] };[/align]
[align=left] void f()[/align]
[align=left] {[/align]
[align=left] cout<<"D1::f()"<<endl;[/align]
[align=left] }[/align]
[align=left]}; [/align]

[align=left][/align]

[align=left]int main(int argc, char* argv[])[/align]
[align=left]{[/align]
[align=left] D1 d;[/align]
[align=left] system("pause");[/align]
[align=left] return 0;[/align]
}

以上代码,运行输出为:B::f()
上面的例子稍微改变一下,比较隐蔽的一个例子:

[align=left]例2:[/align]
[align=left]class B[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] B() { } [/align]
[align=left] void t()[/align]
[align=left] {[/align]
[align=left] f();[/align]
[align=left] } [/align]
[align=left] virtual void f()[/align]
[align=left] {[/align]
[align=left] cout<<"B::f()"<<endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]class D1:public B[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] D1()[/align]
[align=left] {[/align]
[align=left] t();[/align]
[align=left] };[/align]
[align=left] void f()[/align]
[align=left] {[/align]
[align=left] cout<<"D1::f()"<<endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]class D2:public D1[/align]
[align=left]{[/align]
[align=left]public:[/align]
[align=left] D2(){};[/align]
[align=left] void f()[/align]
[align=left] {[/align]
[align=left] cout<<"D2::f()"<<endl;[/align]
[align=left] }[/align]
[align=left]};[/align]
[align=left] [/align]
[align=left]int main(int argc, char* argv[])[/align]
[align=left]{[/align]
[align=left] D2 d;[/align]
[align=left] system("pause");[/align]
[align=left] return 0;[/align]
}

以上代码,运行输出为:D1::f()

从以上例子可以看出,某个类在构造过程中,绝不可能调用其派生类的函数,即使是虚函数。析构构成中同样。其原因,一种说法是在构造或者析构过程中,其派生类还没有创建或已经销毁,其虚函数表也不存在。所以无法调用。

在上面的例1中,如果class B中的f()定义为纯虚函数,则将是个更大的错误隐患,经测试在CB6和VC2003中编译都不会报错,运行时则会报运行时错误。如,VC报:pure virtual function call。

如果你曾经是一个 Java 或 C# 的程序员,并且在最近期望返回 C++ 的怀抱,那么请你格外的注意这一条,因为在这一问题上, C++ 与其他语言走的是完全不同的两条路线。在Java中这都是没有问题的。

我就深受Java的影响,在刚开始使用C++的时候,在一个项目中写下了类似于上面例2中的代码,是多个有继承关系的VCL form之间。不过奇怪的是,在CB的VCL form中,并没有出现上面两个例子中的问题,完全和在Java中一样,完全按照我原本的期望在基类form的构造函数中调用到了其派生类的虚函数。真是歪打正着,错误的写法,居然在CB的VCL中没有问题!这也让我没有及时发现C++在这个方面和其他语言的不同。知道今天才知道!原来其中还另有隐情!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: