C++:派生类的构造函数和析构函数的调用顺序

1、派生类

在C++编程中,咱们在编写一个基类的派生类时,大体能够分为四步ios

• 吸取基类的成员:不管是数据成员仍是函数成员,派生类吸取除基类的构造函数和析构函数以外的所有成员。编程

• 改造基类函数:在派生类中声明一个或多个与其(某个)基类中的成员函数同名的成员函数,并将它(们)根据新的需求进行重写函数

• 发展新的成员:在派生类中添加新的成员变量和成员函数,其中新添加的成员要求必须和基类中的成员不一样名,而且应当保证新添加的成员会使派生类在功能上相比其基类有所发展spa

• 重写派生类的构造函数和析构函数3d

特别注意:code

在重写派生类的构造函数时,一般将其基类们的构造函数变成新构造函数的一部分对象

语法:派生类名::派生类名(参数总表):基类名1(参数表1),基类名2(参数表2),......,新增成员名1(参数1),新增成员名2(参数2){}

示例:blog

 1 #include<iostream>
 2 using namespace std;
 3 class Father{ //基类 
 4 public: 5 Father()=default; //默认构造函数 6 Father(int value):father_value(value){} //带参数的构造函数 7 ~Father(){} //析构函数 8 void show(){ 9 cout<<"这是基类Father"<<endl; 10 } 11 void father_func(){ 12 cout<<"这是基类Father的方法father_func:"<<endl; 13 cout<<"\t成员father_value的值为:"<<father_value<<endl; 14 } 15 private: 16 int father_value; 17 }; 18 
19 class Son:public Father{ //Father类的派生类Son 20 public: 21 /*步骤一:吸取Father类中除构造函数和析构函数以外的全部成员 22 void show(){ 23 cout<<"这是基类Father"<<endl; 24 } 25 void father_func(){ 26 cout<<"这是基类Father的方法father_func:"<<endl; 27 cout<<"\t成员father_value的值为:"<<father_value<<endl; 28 } 29 */ 30 //步骤二:改造基类Father中的成员 31 void show(){ 32 cout<<"这是派生类Son"<<endl; 33 } 34 //步骤三:发展新的成员 35 void son_func(){ 36 cout<<"这是派生类Son的方法son_func: "<<endl; 37 cout<<"\t成员son_value的值为:"<<son_value<<endl; 38 } 39 //步骤四:重写构造函数和析构函数 40 Son()=default; 41 Son(int value):Father(value),son_value(value){} 42 ~Son(){} 43 private: 44 /*步骤一:吸取Father类中除构造函数和析构函数以外的全部成员 45  int father_value; 46 */ 47 //步骤三:发展新的成员 48 int son_value; 49 }; 50 int main(){
51     Father father(10);
52     father.show();
53     father.father_func();
54     cout<<"------------分界线--------------------"<<endl;
55     Son son(20);
56     son.show();
57     son.father_func();
58     son.son_func(); 
59     return 0;
60 }

 

2、派生类的构造函数的调用顺序

咱们先来看一个示例:继承

 1 #include<iostream>
 2 using namespace std;
 3 class Father1{ //基类1 
 4 public:
 5     Father1(){
 6         cout<<"这是Father1类的构造函数"<<endl;  7     } 
 8 };
 9 
10 class Father2{ //基类2
11 public:
12     Father2(){
13         cout<<"这是Father2类的构造函数"<<endl; 14     } 
15 }; 
16 
17 class Father3{ //基类3
18 public:
19     Father3(){
20         cout<<"这是Father3类的构造函数"<<endl; 21     } 
22 };
23 
24 class Son:public Father1,public Father2,public Father3{ //派生类
25 public:
26     Son(){
27         cout<<"这是Son类的构造函数"<<endl; 28     } 
29 };
30 
31 int main(){
32     Son s;
33     return 0;
34 }

由上面的例子能够看出,派生类在建立对象时会先调用其基类们的构造函数,而后才会调用本身的构造函数。下面是类Son的对象s在内存中的存放形式:内存

那么派生类调用基类的构造函数的顺序又是如何肯定的呢?咱们在来看一个例子:

 1 #include<iostream>
 2 using namespace std;
 3 class Father1{ //基类1 
 4 public:
 5     Father1(){
 6         cout<<"这是Father1类的构造函数"<<endl;
 7     } 
 8 };
 9 
10 class Father2{ //基类2
11 public:
12     Father2(){
13         cout<<"这是Father2类的构造函数"<<endl;
14     } 
15 }; 
16 
17 class Father3{ //基类3
18 public:
19     Father3(){
20         cout<<"这是Father3类的构造函数"<<endl;
21     } 
22 };
23 
24 class Son:public Father3,public Father1,public Father2{ //派生类
25 public:
26     Son(){
27         cout<<"这是Son类的构造函数"<<endl;
28     } 
29 private:
30 Father1 father1; 31 Father2 father2; 32 Father3 father3; 33 };
34 
35 int main(){
36     Son s;
37     return 0;
38 }

因而可知,派生类在建立对象时其调用构造函数的顺序是:

先按照派生类对基类的继承顺序调用基类的构造函数。上例中由语句“class Son:public Father3,public Father1,public Father2”可知类Son先继承基类Father3,而后继承基类Father1,最后继承基类Father2,所以其调用基类的构造函数的顺序也是先Fathe3,再Father1,最后Father2。

•( 若派生类的成员变量中存在其基类的对象 )接着按照基类的对象在派生类定义中声明的前后顺序调用基类的构造函数。上例中按照成员对象的定义顺序依次调用Father一、Father2和Father3的构造函数。

• 最后调用派生类本身的构造函数

特别注意:

1.若是基类中没有定义默认构造函数或带有缺省值的构造函数而只有带参数的构造函数时,派生类的构造函数中必须显式的给出基类名和参数表,不然编译器将报错

 1 #include<iostream>
 2 using namespace std;
 3 class Father1{ //基类1 
 4 public:
 5     Father1(int v):value1(v){
 6         cout<<"这是Father1类的构造函数"<<endl;
 7     } 
 8 private:
 9     int value1;
10 };
11 
12 class Father2{ //基类2
13 public:
14     Father2(int v):value2(v){
15         cout<<"这是Father2类的构造函数"<<endl;
16     } 
17 private:
18     int value2;
19 }; 
20 
21 class Father3{ //基类3
22 public:
23     Father3(int v):value3(v){
24         cout<<"这是Father3类的构造函数"<<endl;
25     } 
26 private:
27     int value3;
28 };
29 
30 class Son:public Father1,public Father2,public Father3{ //派生类
31 public:
32     Son(int v):Father1(v),Father2(v),Father3(v),value4(v){ //派生类的构造函数中必须显式的给出基类名和参数表 33         cout<<"这是Son类的构造函数"<<endl;
34     } 
35 private:
36     int value4;
37 };
38 
39 int main(){
40     Son s(10);
41     return 0;
42 }

2.若是基类中没有定义构造函数,这派生类也能够不定义构造函数,系统会自动在类中添加默认的构造函数的

3.若是基类中定义了带有参数表的构造函数时,派生类就应当定义相应的构造函数

 

QUESTION:基类在派生类的构造函数的初始化列表中的顺序是否会影响派生类的构造函数调用顺序?

ANSWER: 咱们先来看一个示例:

 1 #include<iostream>
 2 using namespace std;
 3 class Father1{ //基类1 
 4 public:
 5     Father1(int v):value1(v){
 6         cout<<"这是Father1类的构造函数"<<endl;
 7     } 
 8 private:
 9     int value1;
10 };
11 
12 class Father2{ //基类2
13 public:
14     Father2(int v):value2(v){
15         cout<<"这是Father2类的构造函数"<<endl;
16     } 
17 private:
18     int value2;
19 }; 
20 
21 class Father3{ //基类3
22 public:
23     Father3(int v):value3(v){
24         cout<<"这是Father3类的构造函数"<<endl;
25     } 
26 private:
27     int value3;
28 };
29 
30 class Son:public Father3,public Father1,public Father2{ //派生类
31 public:
32     Son(int v):Father1(v),Father2(v),Father3(v),value4(v){
33         cout<<"这是Son类的构造函数"<<endl;
34     } 
35 private:
36     int value4;
37 };
38 
39 int main(){
40     Son s(10);
41     return 0;
42 }

 

上面的例子中派生类Son是以顺序Father三、Father一、Father2来继承基类的,但在其构造函数中基类的顺序确实Father一、Father二、Father3。最终的结果代表类Son仍以其继承基类的顺序来调用基类的构造函数,而非基类在派生类构造函数中的顺序。所以可见基类在派生类的构造函数的初始化列表中的顺序不会影响派生类的构造函数调用顺序

 

3、派生类的析构函数的调用顺序

• 在派生类中,其析构函数只须要关心新增的通常成员的“善后工做”。而对于新增的成员对象和基类的“善后工做”,系统会本身调用成员对象和基类的析构函数来完成,而不须要用户来关心。

• 在派生类中,析构函数各部分的执行顺序与其构造函数的调用顺序恰好相反,即派生类的析构函数先对其新增的通常成员进行析构,而后对新增的成员对象进行析构,最后按照与其继承基类的相反顺序来调用基类的析构函数

 1 #include<iostream>
 2 using namespace std;
 3 class Father1{ //基类1 
 4 public:
 5     Father1(){
 6         cout<<"这是Father1类的构造函数"<<endl;
 7     } 
 8     ~Father1(){
 9         cout<<"这是Father1类的析构函数"<<endl;
10     }
11 };
12 
13 class Father2{ //基类2
14 public:
15     Father2(){
16         cout<<"这是Father2类的构造函数"<<endl;
17     } 
18     ~Father2(){
19         cout<<"这是Father2类的析构函数"<<endl;
20     }
21 }; 
22 
23 class Father3{ //基类3
24 public:
25     Father3(){
26         cout<<"这是Father3类的构造函数"<<endl;
27     } 
28     ~Father3(){
29         cout<<"这是Father3类的析构函数"<<endl;
30     }
31 };
32 
33 class Son:public Father3,public Father1,public Father2{ //派生类
34 public:
35     Son(){
36         cout<<"这是Son类的构造函数"<<endl;
37     } 
38     ~Son(){
39         cout<<"这是Son类的析构函数"<<endl;
40     }
41 private:
42     Father1 father1;
43     Father2 father2;
44     Father3 father3;
45 };
46 
47 int main(){
48     Son s;
49     return 0;
50 }

相关文章
相关标签/搜索