http://blog.csdn.net/xw13106209/article/details/6899370
1.參考文獻
參考1: C++繼承中構造函數、析構函數調用順序及虛函數的動態綁定
參考2: 構造函數、拷貝構造函數和析構函數的的調用時刻及調用順序
參考3: C++構造函數與析構函數的調用順序
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 }

4.3結果解析
構造函數被調用 //point a(15,22);
拷貝構造函數被調用 //point b(a);拷貝構造函數的第一種調用情況: 用類的一個已知的對象去初始化該類的另一個對象時
15 22 //cout<<b.get_x()<<" "<<b.get_y()<<endl;
拷貝構造函數被調用 //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對象的析構
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 }
5.3說明
在實例2中,CPerson是CStudent的父類,而CStudent又是CTeacher的父類,那么在創建CTeacher對象的時候,首先調用基類也就是CPerson的構造函數,然后按照層級,一層一層下來。
