测试代码1:
#include "stdafx.h" using namespace std; class ClassA { public: ClassA(){ cout<<"ClassA::ClassA() begin"<<endl; Print(); cout<<"ClassA::ClassA() end"<<endl;; } virtual void Print(){ cout<<"ClassA::Print()"<<endl; } virtual ~ClassA(){ cout<<"ClassA::~ClassA() begin"<<endl; Print(); cout<<"ClassA::~ClassA() end"<<endl;; } }; class ClassB : public ClassA { public: ClassB(){ cout<<"ClassB::ClassB() begin"<<endl; Print(); cout<<"ClassB::ClassB() end"<<endl;; } void Print(){ cout<<"ClassB::Print()"<<endl; } ~ClassB(){ cout<<"ClassB::~ClassB() begin"<<endl; Print(); cout<<"ClassB::~ClassB() end"<<endl;; } }; int _tmain(int argc, _TCHAR* argv[]) { ClassB* pClassB = new ClassB; cout<<"------------"<<endl; ClassA* pClassA = pClassB; pClassA->Print(); cout<<"------------"<<endl; delete pClassB; getchar(); return 0; }
在vs2003运行结果如下
ClassA::ClassA() begin
ClassA::Print()
ClassA::ClassA() end
ClassB::ClassB() begin
ClassB::Print()
ClassB::ClassB() end
------------
ClassB::Print()
------------
ClassB::~ClassB() begin
ClassB::Print()
ClassB::~ClassB() end
ClassA::~ClassA() begin
ClassA::Print()
ClassA::~ClassA() end
(对代码稍作修改,在gcc中的编译结果也是如此)
可以看到,在new ClassB时,虽然在父类ClassA的构造函数调了的是被ClassB覆盖的虚函数Print(),但是实际上还是调用的ClassA的Print。这是因为
继承类在构造的时候总是首先调用其基类的构造函数来对属于其基类的部分进行构造,在这个时候,整个类被当作基类来处理,继承类的部分对整个类来说好像不存在一样,直到基类的构造函数退出并进入继承类的构造函数,该类才被当作继承类来出来处理。对析构也一样,只是析构的顺序正好相反。
进一步分析,如果在析构函数中调用纯虚函数呢?将ClassA中的Print()改为纯虚函数
测试代码2:
#include "stdafx.h" using namespace std; class ClassA { public: ClassA(){ cout<<"ClassA::ClassA() begin"<<endl; Print(); cout<<"ClassA::ClassA() end"<<endl;; } virtual void Print() = 0; virtual ~ClassA(){ cout<<"ClassA::~ClassA() begin"<<endl; Print(); cout<<"ClassA::~ClassA() end"<<endl;; } }; class ClassB : public ClassA { public: ClassB(){ cout<<"ClassB::ClassB() begin"<<endl; Print(); cout<<"ClassB::ClassB() end"<<endl;; } void Print(){ cout<<"ClassB::Print()"<<endl; } ~ClassB(){ cout<<"ClassB::~ClassB() begin"<<endl; Print(); cout<<"ClassB::~ClassB() end"<<endl;; } }; int _tmain(int argc, _TCHAR* argv[]) { ClassB* pClassB = new ClassB; cout<<"------------"<<endl; ClassA* pClassA = pClassB; pClassA->Print(); cout<<"------------"<<endl; delete pClassB; getchar(); return 0; }编译出错:
Test error LNK2019: 无法解析的外部符号 "public: virtual void __thiscall ClassA::Print(void)" (?Print@ClassA@@UAEXXZ) ,该符号在函数 "public: __thiscall ClassA::ClassA(void)" (??0ClassA@@QAE@XZ) 中被引用
gcc中也有类似提示
稍加改动,继续测试:
测试代码3:
#include "stdafx.h" using namespace std; class ClassA { public: ClassA(){ cout<<"ClassA::ClassA() begin"<<endl; Print(); cout<<"ClassA::ClassA() end"<<endl;; } virtual void Print(){ Print2(); } virtual void Print2() = 0; virtual ~ClassA(){ cout<<"ClassA::~ClassA() begin"<<endl; Print(); cout<<"ClassA::~ClassA() end"<<endl;; } }; class ClassB : public ClassA { public: ClassB(){ cout<<"ClassB::ClassB() begin"<<endl; Print(); cout<<"ClassB::ClassB() end"<<endl;; } void Print(){ cout<<"ClassB::Print()"<<endl; } void Print2(){ cout<<"ClassB::Print2()"<<endl; } ~ClassB(){ cout<<"ClassB::~ClassB() begin"<<endl; Print(); cout<<"ClassB::~ClassB() end"<<endl;; } }; int _tmain(int argc, _TCHAR* argv[]) { ClassB* pClassB = new ClassB; cout<<"------------"<<endl; ClassA* pClassA = pClassB; pClassA->Print(); cout<<"------------"<<endl; delete pClassB; getchar(); return 0; }
成功编译,但是运行时出现runtime error的错误。编译器不会绕弯啊。
最后,建议大家在构造函数中别做太复杂的事,最好只是对成员变量的初始化工作。复杂点的操作另写一个初始化函数。