C++中多态中构造函数与析构函数的调用

做个实验,看一下成员变量的构造析构,父类子类的构造析构,以及虚函数对调用的影响。

 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)

 小结一下:

通过父类指针指向子类对象实现多态。

多态的时候,父类析构修饰为虚函数,以保证子类析构被调用。

构造顺序是:先父类后子类(这是最主要流程,后两条都再此前提下);初始化列表在构造前执行;构造函数中值调用本类的函数(无论是否为虚函数)。

析构顺序是:先子类后父类(注意虚析构);析构中只调用本类的函数;本类析构后再析构初始化列表中的成员。


原文地址:https://www.cnblogs.com/zhaojk2010/p/4649269.html