不要在构造或析构的过程中调用虚函数
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++在这个方面和其他语言的不同。知道今天才知道!原来其中还另有隐情!
[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++在这个方面和其他语言的不同。知道今天才知道!原来其中还另有隐情!
相关文章推荐
- 永远 不要在构造或析构的过程中调用虚函数
- 条款09 绝不在构造和析构过程中调用 virtual 函数
- 条款9:不要在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual 函数
- c++ 构造没完成 别的对象不能访问 析构时基类不要调用虚函数
- C++ 构造和析构期间不要调用虚函数
- Rule9:绝不在构造和析构过程中调用Virtual函数
- 条款9:绝不在构造和析构过程中调用virtual函数
- Item 9:绝不在构造和析构过程中调用虚函数【effective C++读书笔记】
- 条款09:不要在构造过程和析构过程中调用 virtual 方法
- 第9条:绝不在构造或析构的过程中调用虚函数
- Effective C++ Item 9 绝不在构造和析构过程中调用virtual函数
- (8)绝不在构造和析构过程中调用virtual函数
- [翻译] Effective C++, 3rd Edition, Item 9: 绝不要在 construction(构造)或 destruction(析构)期间调用 virtual functions(虚拟函数)
- C++-不要在构造和析构函数中调用虚函数
- 不要在构造和析构函数中调用虚函数
- Effective C++ -----条款09:绝不在构造和析构过程中调用virtual函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- effective c++绝不在构造和析构过程中调用virtual函数
- 决不在基类的构造和析构过程中调用virtual函数