做个实验,看一下成员变量的构造析构,父类子类的构造析构,以及虚函数对调用的影响。
1 #include <iostream> 2 using namespace std; 3 4 class Member 5 { 6 public: 7 Member(int n):m_n1(n) 8 { 9 cout<<"Member::Member("<<m_n1<<")"<<endl; 10 } 11 ~Member() 12 { 13 cout<<"Member::~Member("<<m_n1<<")"<<endl; 14 } 15 private: 16 const int m_n1; 17 }; 18 19 class Base 20 { 21 public: 22 Base():m_m1(1) 23 { 24 cout<<"Base::Base()"<<endl; 25 OnConstruct(); 26 } 27 ~Base() //这里目前不是虚函数 28 { 29 cout<<"Base::~Base()"<<endl; 30 OnDistruct(); 31 } 32 virtual void OnConstruct() 33 { 34 cout<<"Base::OnConstruct()"<<endl; 35 } 36 virtual void OnDistruct() 37 { 38 cout<<"Base::OnDistruct()"<<endl; 39 } 40 virtual void Foo1() 41 { 42 cout<<"Base::Foo1()"<<endl; 43 } 44 void Foo2() 45 { 46 cout<<"Base::Foo2()"<<endl; 47 } 48 49 private: 50 Member m_m1;//这是个类对象 51 }; 52 53 class Drived:public Base 54 { 55 public: 56 Drived():m_m2(2) 57 { 58 cout<<"Drived::Drived()"<<endl; 59 OnConstruct(); 60 } 61 ~Drived() 62 { 63 cout<<"Drived::~Drived()"<<endl; 64 OnDistruct(); 65 } 66 virtual void OnConstruct() 67 { 68 cout<<"Drived::OnConstruct()"<<endl; 69 } 70 virtual void OnDistruct() 71 { 72 cout<<"Drived::OnDistruct()"<<endl; 73 } 74 virtual void Foo1() 75 { 76 cout<<"Drived::Foo1()"<<endl; 77 } 78 void Foo2()//这个不是虚函数 79 { 80 cout<<"Drived::Foo2()"<<endl; 81 } 82 private: 83 Member m_m2;//这是个类对象 84 }; 85 86 int main(int argc, char *argv[]) 87 { 88 Base* p = new Drived; 89 p->Foo1(); 90 p->Foo2(); 91 delete p; 92 return 0; 93 }
这段代码的运行输出为:
1 Member::Member(1) //父类的初始化列表被执行 2 Base::Base() //父类构造 3 Base::OnConstruct()//父类构造中只会调用父类的函数。父类构造完毕 4 Member::Member(2) //子类构造的初始化列表 5 Drived::Drived() //子类构造 6 Drived::OnConstruct()//子类构造中只会调用子类的函数。子类构造完毕 7 Drived::Foo1()//发生多态,调用子类重写的函数 8 Base::Foo2() //未多态,调用父类版本的函数 9 Base::~Base() //父类开始析构 10 Base::OnDistruct()//父类析构只会调用父类中的函数 11 Member::~Member(1)//父类成员反初始化
同学们可以看到,子类的析构没有被执行,怎么让它能值执行呢?把父类的析构修饰为virtual即可:
27 ~Base() //这里目前不是虚函数
这样在执行一遍,可以看到结果如果(注释出来的是新增的输出):
1 Member::Member(1) 2 Base::Base() 3 Base::OnConstruct() 4 Member::Member(2) 5 Drived::Drived() 6 Drived::OnConstruct() 7 Drived::Foo1() 8 Base::Foo2() 9 Drived::~Drived() //子类析构,在父类之前执行 10 Drived::OnDistruct()//子类析构只会调用子类的函数 11 Member::~Member(2) //子类成员反初始化 12 Base::~Base() 13 Base::OnDistruct() 14 Member::~Member(1)
小结一下:
通过父类指针指向子类对象实现多态。
多态的时候,父类析构修饰为虚函数,以保证子类析构被调用。
构造顺序是:先父类后子类(这是最主要流程,后两条都再此前提下);初始化列表在构造前执行;构造函数中值调用本类的函数(无论是否为虚函数)。
析构顺序是:先子类后父类(注意虚析构);析构中只调用本类的函数;本类析构后再析构初始化列表中的成员。