C++C++中構造函數與析構函數的調用順序

http://blog.csdn.net/xw13106209/article/details/6899370

1.參考文獻

參考1: C++繼承中構造函數、析構函數調用順序及虛函數的動態綁定html

參考2: 構造函數、拷貝構造函數和析構函數的的調用時刻及調用順序ios

參考3: C++構造函數與析構函數的調用順序ide

2.構造函數、析構函數與拷貝構造函數介紹

2.1構造函數

 

  • 構造函數不能有返回值
  • 缺省構造函數時,系統將自動調用該缺省構造函數初始化對象,缺省構造函數會將全部數據成員都初始化爲零或空 
  • 建立一個對象時,系統自動調用構造函數

2.2析構函數

  • 析構函數沒有參數,也沒有返回值。不能重載,也就是說,一個類中只可能定義一個析構函數
  • 若是一個類中沒有定義析構函數,系統也會自動生成一個默認的析構函數,爲空函數,什麼都不作
  • 調用條件:1.在函數體內定義的對象,當函數執行結束時,該對象所在類的析構函數會被自動調用;2.用new運算符動態構建的對象,在使用delete運算符釋放它時。

2.3拷貝構造函數

拷貝構造函數實際上也是構造函數,具備通常構造函數的全部特性,其名字也與所屬類名相同。拷貝構造函數中只有一個參數,這個參數是對某個同類對象的引用。它在三種狀況下被調用:函數

  • 用類的一個已知的對象去初始化該類的另外一個對象時;
  • 函數的形參是類的對象,調用函數進行形參和實參的結合時;
  • 函數的返回值是類的對象,函數執行完返回調用者。

3.構造函數與析構函數的調用順序

對象是由「底層向上」開始構造的,當創建一個對象時,首先調用基類的構造函數,而後調用下一個派生類的構造函數,依次類推,直至到達派生類次數最多的派生次數最多的類的構造函數爲止。由於,構造函數一開始構造時,老是要調用它的基類的構造函數,而後纔開始執行其構造函數體,調用直接基類構造函數時,若是無專門說明,就調用直接基類的默認構造函數。在對象析構時,其順序正好相反。
 

4.實例1

4.1代碼

 
 1 #include<iostream>
 2 #include <stdio.h>
 3 using namespace std;
 4 class point
 5 {
 6 private:
 7     int x,y;//數據成員
 8 public:
 9     point(){cout << "point()" << endl;}
10     point(int xx=0,int yy=0)//構造函數
11     {
12         x=xx;
13         y=yy;
14         cout<<"構造函數被調用"<<endl;
15     }
16     point(point &p);//拷貝構造函數,參數是對象的引用
17     ~point(){cout<<"析構函數被調用"<<endl;}
18     int get_x(){return x;}//方法
19     int get_y(){return y;}
20 };
21 
22 point::point(point &p)
23 {
24     x=p.x;//將對象p的變相賦值給當前成員變量。
25     y=p.y;
26     cout<<"拷貝構造函數被調用"<<endl;
27 }
28 
29 void f(point p)
30 {
31     cout<<p.get_x()<<"    "<<p.get_y()<<endl;
32 }
33 
34 point g()//返回類型是point
35 {
36     printf("*********%s %d\n",__func__, __LINE__);
37     point a(7,33);
38     printf("*********%s %d\n",__func__, __LINE__);
39     return a;
40 }
41 
42 int main()
43 {
44     point a(15,22);
45     printf("*********%s %d\n",__func__, __LINE__);
46     point b(a);//構造一個對象,使用拷貝構造函數。
47     printf("*********%s %d\n",__func__, __LINE__);
48     cout<<b.get_x()<<"    "<<b.get_y()<<endl;
49     printf("*********%s %d\n",__func__, __LINE__);
50     f(b);
51     printf("*********%s %d\n",__func__, __LINE__);
52     b=g();
53     printf("*********%s %d\n",__func__, __LINE__);
54     cout<<b.get_x()<<"    "<<b.get_y()<<endl;
55     printf("*********%s %d\n",__func__, __LINE__);
56 }
View Code
 

 

 
4.3結果解析
構造函數被調用 //point a(15,22);
拷貝構造函數被調用 //point b(a);拷貝構造函數的第一種調用狀況: 用類的一個已知的對象去初始化該類的另外一個對象時
15 22 //cout<<b.get_x()<<" "<<b.get_y()<<endl;
拷貝構造函數被調用 //f(b);拷貝構造函數的第二種調用狀況: 函數的形參是類的對象,調用函數進行形參和實參的結合時
15 22 //void f(point p)函數輸出對象b的成員
析構函數被調用 //f(b);析構函數的第一種調用狀況: 在函數體內定義的對象,當函數執行結束時,該對象所在類的析構函數會被自動調用
構造函數被調用 //b=g();的函數體內point a(7,33);建立對象a
拷貝構造函數被調用 //b=g();拷貝構造函數的第三種調用狀況,拷貝a的值賦給b: 函數的返回值是類的對象,函數執行完返回調用者
析構函數被調用 //拷貝構造函數對應的析構函數
析構函數被調用 //b=g();的函數體內對象a析構
7 33
析構函數被調用 //主函數體b對象的析構
析構函數被調用 //主函數體a對象的析構
 

5.實例2

5.1代碼

 

 1 #include <iostream>
 2 using namespace std;
 3 //基類
 4 class CPerson
 5 {
 6     char *name;        //姓名
 7     int age;            //年齡
 8     char *add;        //地址
 9 public:
10     CPerson(){cout<<"constructor - CPerson! "<<endl;}
11     ~CPerson(){cout<<"deconstructor - CPerson! "<<endl;}
12 };
13 
14 //派生類(學生類)
15 class CStudent : public CPerson
16 {
17     char *depart;    //學生所在的系
18     int grade;        //年級
19 public:
20     CStudent(){cout<<"constructor - CStudent! "<<endl;}
21     ~CStudent(){cout<<"deconstructor - CStudent! "<<endl;}
22 };
23 
24 //派生類(教師類)
25 //class CTeacher : public CPerson//繼承CPerson類,兩層結構
26 class CTeacher : public CStudent//繼承CStudent類,三層結構
27 {
28     char *major;    //教師專業
29     float salary;    //教師的工資
30 public:
31     CTeacher(){cout<<"constructor - CTeacher! "<<endl;}
32     ~CTeacher(){cout<<"deconstructor - CTeacher! "<<endl;}
33 };
34 
35 //實驗主程序
36 int main()
37 {
38     CPerson person;
39     CStudent student;
40     CTeacher teacher;
41 }
View Code

 

5.3說明

在實例2中,CPerson是CStudent的父類,而CStudent又是CTeacher的父類,那麼在建立CTeacher對象的時候,首先調用基類也就是CPerson的構造函數,而後按照層級,一層一層下來。
相關文章
相關標籤/搜索