1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | #include <iostream> #include <string> using namespace std; class Base { public: Base() { foo(); } virtual void foo() { cout<<"Base::foo()"<<endl; } }; class Derived:public Base { public: virtual void foo() { cout<<"Derived::foo()"<<endl; } }; int main() { Derived * pD = new Derived; pD->foo(); return 0; } |
程序输出为:
Base::foo() Derived::foo()
而不是
Derived::foo() Derived::foo()
原因是,基类的构造函数调用的foo()是基类的,而不是被子类重写过的foo(),构造基类时,vtable还没有被正确的书写。使我注意到这个问题的是酷壳关于Java类成员构造的一篇文章:Java构造时成员初始化的陷阱
你好!除了代码,此处没有多少原创之物,皆为本人搜集、整理、总结之记录与心得,欢迎转载分享!转载时请尽量注明出处,将不胜感激。祝你健康、快乐!
C++的程序都知道,在C++的世界中在“构造函数中调用虚函数”是不行的,Effective C++ 条款9:Never call virtual functions during construction or destruction,Scott Meyers已经解释得很详细了。
在语言设计的时候,“在构造函数中调用虚函数”是个两难的问题。
如果调用的是父类的函数的话,这个有点违反虚函数的定义。
如果调用的是子类的函数的话,这可能产生问题的:因为在构造子类对象的时候,首先调用父类的构造函数,而这时候如果去调用子类的函数,由于子类还没有构造完成,子类的成员尚未初始化,这么做显然是不安全的。
C++选择了第一种,而Java选择了第二种。
C++类的设计相对比较简陋,通过虚函数表来实现,缺少类的元信息。
而Java类的则显得比较完整,有super指针来导航到父类。
有幸得到专家指点,受教了,耗子哥!
前阵子写的一篇 文字, 刚好也谈一样的题目. 供参考.