該類對象被建立時,編譯系統對象分配內存空間,並自動調用該構造函數,由構造函數完成成員的初始化工做,故:構造函數的做用:初始化對象的數據成員。html
1 class Complex 2 { 3 4 private : 5 double m_real; 6 double m_imag; 7 8 public: 9 10 // 無參數構造函數 11 // 若是建立一個類你沒有寫任何構造函數,則系統會自動生成默認的無參構造函數,函數爲空,什麼都不作 12 // 只要你寫了一個下面的某一種構造函數,系統就不會再自動生成這樣一個默認的構造函數,若是但願有一個這樣的無參構造函數,則須要本身顯示地寫出來 13 Complex(void) 14 { 15 m_real = 0.0; 16 m_imag = 0.0; 17 } 18 19 // 通常構造函數(也稱重載構造函數) 20 // 通常構造函數能夠有各類參數形式,一個類能夠有多個通常構造函數,前提是參數的個數或者類型不一樣(基於c++的重載函數原理) 21 // 例如:你還能夠寫一個 Complex( int num)的構造函數出來 22 // 建立對象時根據傳入的參數不一樣調用不一樣的構造函數 23 Complex(double real, double imag) 24 { 25 m_real = real; 26 m_imag = imag; 27 } 28 29 // 複製構造函數(也稱爲拷貝構造函數) 30 // 複製構造函數參數爲類對象自己的引用,用於根據一個已存在的對象複製出一個新的該類的對象,通常在函數中會將已存在對象的數據成員的值複製一份到新建立的對象中 31 // 若沒有顯示的寫複製構造函數,則系統會默認建立一個複製構造函數,但當類中有指針成員時,由系統默認建立該複製構造函數會存在風險,具體緣由請查詢有關 「淺拷貝」 、「深拷貝」的文章論述 32 Complex(const Complex & c) 33 { 34 // 將對象c中的數據成員值複製過來 35 m_real = c.m_real; 36 m_img = c.m_img; 37 } 38 39 // 類型轉換構造函數,根據一個指定的類型的對象建立一個本類的對象 40 // 例如:下面將根據一個double類型的對象建立了一個Complex對象 41 Complex::Complex(double r) 42 { 43 m_real = r; 44 m_imag = 0.0; 45 } 46 47 // 等號運算符重載 48 // 注意,這個相似複製構造函數,將=右邊的本類對象的值複製給等號左邊的對象,它不屬於構造函數,等號左右兩邊的對象必須已經被建立 49 // 若沒有顯示的寫=運算符重載,則系統也會建立一個默認的=運算符重載,只作一些基本的拷貝工做 50 Complex &operator=(const Complex &rhs) 51 { 52 // 首先檢測等號右邊的是否就是左邊的對象本,如果本對象自己,則直接返回 53 if ( this == &rhs ) 54 { 55 return *this; 56 } 57 58 // 複製等號右邊的成員到左邊的對象中 59 this->m_real = rhs.m_real; 60 this->m_imag = rhs.m_imag; 61 62 // 把等號左邊的對象再次傳出 63 // 目的是爲了支持連等 eg: a=b=c 系統首先運行 b=c 64 // 而後運行 a= ( b=c的返回值,這裏應該是複製c值後的b對象) 65 return *this; 66 } 67 };
下面使用上面定義的類對象來講明各個構造函數的用法:ios
1 void main() 2 { 3 // 調用了無參構造函數,數據成員初值被賦爲0.0 4 Complex c1,c2; 5 6 // 調用通常構造函數,數據成員初值被賦爲指定值 7 Complex c3(1.0,2.5); 8 // 也可使用下面的形式 9 Complex c3 = Complex(1.0,2.5); 10 11 // 把c3的數據成員的值賦值給c1 12 // 因爲c1已經事先被建立,故此處不會調用任何構造函數 13 // 只會調用 = 號運算符重載函數 14 c1 = c3; 15 16 // 調用類型轉換構造函數 17 // 系統首先調用類型轉換構造函數,將5.2建立爲一個本類的臨時對象,而後調用等號運算符重載,將該臨時對象賦值給c1 18 c2 = 5.2; 19 20 // 調用拷貝構造函數( 有下面兩種調用方式) 21 Complex c5(c2); 22 Complex c4 = c2; // 注意和 = 運算符重載區分,這裏等號左邊的對象不是事先已經建立,故須要調用拷貝構造函數,參數爲c2 23 24 }
參考:http://www.cnblogs.com/xkfz007/archive/2012/05/11/2496447.htmlc++
幾個原則:函數
C++ primer p406 :複製構造函數是一種特殊的構造函數,具備單個形參,該形參(經常使用const修飾)是對該類類型的引用。當定義一個新對象並用一個同類型的對象對它進行初始化時,將顯示使用複製構造函數。當該類型的對象傳遞給函數或從函數返回該類型的對象時,將隱式調用複製構造函數。this
C++支持兩種初始化形式:複製初始化(int a = 5;)和直接初始化(int a(5);)對於其餘類型沒有什麼區別,對於類類型直接初始化直接調用實參匹配的構造函數,複製初始化老是調用複製構造函數,也就是說:spa
A x(2); //直接初始化,調用構造函數
A y = x; //複製初始化,調用複製構造函數.net
必須定義複製構造函數的狀況:設計
只包含類類型成員或內置類型(但不是指針類型)成員的類,無須顯式地定義複製構造函數也能夠複製;有的類有一個數據成員是指針,或者是有成員表示在構造函數中分配的其餘資源,這兩種狀況下都必須定義複製構造函數。指針
什麼狀況使用複製構造函數:code
類的對象須要拷貝時,拷貝構造函數將會被調用。如下狀況都會調用拷貝構造函數:
(1)一個對象以值傳遞的方式傳入函數體
(2)一個對象以值傳遞的方式從函數返回
(3)一個對象須要經過另一個對象進行初始化。
深拷貝和淺拷貝:
所謂淺拷貝,指的是在對象複製時,只對對象中的數據成員進行簡單的賦值,默認拷貝構造函數執行的也是淺拷貝。在「深拷貝」的狀況下,對於對象中動態成員,就不能僅僅簡單地賦值了,而應該從新動態分配空間
若是一個類擁有資源,當這個類的對象發生複製過程的時候,資源從新分配,這個過程就是深拷貝
上面提到,若是沒有自定義複製構造函數,則系統會建立默認的複製構造函數,但系統建立的默認複製構造函數只會執行「淺拷貝」,即將被拷貝對象的數據成員的值一一賦值給新建立的對象,若該類的數據成員中有指針成員,則會使得新的對象的指針所指向的地址與被拷貝對象的指針所指向的地址相同,delete該指針時則會致使兩次重複delete而出錯。下面是示例:
1 #include <iostream.h> 2 #include <string.h> 3 class Person 4 { 5 public : 6 7 // 構造函數 8 Person(char * pN) 9 { 10 cout << "通常構造函數被調用 !\n"; 11 m_pName = new char[strlen(pN) + 1]; 12 //在堆中開闢一個內存塊存放pN所指的字符串 13 if(m_pName != NULL) 14 { 15 //若是m_pName不是空指針,則把形參指針pN所指的字符串複製給它 16 strcpy(m_pName ,pN); 17 } 18 } 19 20 // 系統建立的默認複製構造函數,只作位模式拷貝 21 Person(Person & p) 22 { 23 //使兩個字符串指針指向同一地址位置 24 m_pName = p.m_pName; 25 } 26 27 ~Person( ) 28 { 29 delete m_pName; 30 } 31 32 private : 33 char * m_pName; 34 }; 35 36 void main( ) 37 { 38 Person man("lujun"); 39 Person woman(man); 40 41 // 結果致使 man 和 woman 的指針都指向了同一個地址 42 43 // 函數結束析構時 44 // 同一個地址被delete兩次 45 } 46 47 48 // 下面本身設計複製構造函數,實現「深拷貝」,即不讓指針指向同一地址,而是從新申請一塊內存給新的對象的指針數據成員 49 Person(Person & chs); 50 { 51 // 用運算符new爲新對象的指針數據成員分配空間 52 m_pName=new char[strlen(p.m_pName)+ 1]; 53 54 if(m_pName) 55 { 56 // 複製內容 57 strcpy(m_pName ,chs.m_pName); 58 } 59 60 // 則新建立的對象的m_pName與原對象chs的m_pName再也不指向同一地址了 61 }
重載賦值操做符:
經過定義operate=的函數,能夠對賦值進行定義。像其餘任何函數同樣,操做符函數有一個返回值和形參表。形參表必須具備與該操做符操做數書目相同的形參(若是操做符是一個成員,則包括隱式this形參)。賦值是二元運算,因此該操做符函數有兩個形參:第一個形參(隱含的this指針)對應着左操做數,第二個形參對應右操做數。
一個應用了對賦值號重載的拷貝構造函數的例子:
1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int);//構造函數 9 A(const A &);//拷貝構造函數 10 ~A(); 11 void print(); 12 int *point; 13 A &operator=(const A &); 14 }; 15 16 A::A(int p) 17 { 18 point = new int; 19 *point = p; 20 } 21 22 A::A(const A &b) 23 { 24 *this = b; 25 cout<<"調用拷貝構造函數"<<endl; 26 } 27 28 A::~A() 29 { 30 delete point; 31 } 32 33 void A::print() 34 { 35 cout<<"Address:"<<point<<" value:"<<*point<<endl; 36 } 37 38 A &A::operator=(const A &b) 39 { 40 if( this != &b) 41 { 42 delete point; 43 point = new int; 44 *point = *b.point; 45 } 46 } 47 48 49 int main() 50 { 51 A x(2); 52 A y = x; 53 x.print(); 54 delete x.point; 55 y.print(); 56 57 return 0; 58 }
參見:C++拷貝構造函數詳解:http://blog.csdn.net/lwbeyond/article/details/6202256