如果類包含內置或復合類型的成員,則該類就不應該依賴于合成的默認構造函數,它應該定義自己的構造函數來初始化這些成員。
當一個類含有一些數據成員,你需要在實例化類的時候就初始化這些成員,你就需要自己定義構造函數。例如Person類含有m_strName成員,你在聲明該類是就將其賦值 Person myPerson("張三")對于拷貝構造函數,為了防止淺拷貝造成的兩個對象指向同一內存,當刪除其中一個對象后導致另一對象指向內容為空的時候,我們就需要定義自己的拷貝構造函數來進行深拷貝。當你的類數據成員中使用了動態分配的內存,你就需要定義自己的析構函數來釋放這部分內存,防止內存泄露。系統定義的默認構造函數和析構函數函數名和類名相同,如Person類:Person()構造函數~Person()析構函數
類定義中,如果未提供自己的拷貝構造函數,則C++提供一個默認拷貝構造函數,就像沒有提供構造函數時,C++提供默認構造函數一樣。C++提供的默認拷貝構造函數工作的方法是:完成一個成員一個成員的拷貝,如果成員是類對象,則調用其拷貝構造函數或者默認拷貝構造函數。/*--------------------------------------在默認拷貝構造函數中,拷貝的策略是逐個成員依次拷貝,但是,一個類可能會擁有資源,如果拷貝構造函數簡單地制作了一個該資源的拷貝,而不對它本身分配,就得面臨一個麻煩的局面:兩個對象都擁有同一個資源。當對象析構時,該資源將經歷兩次資源返還。下面的程序描述了Person對象被簡單拷貝后,面臨析構時的困惑。--------------------------------------------------*/#include <iostream>using namespace std;class Person{ public: Person(char *pN) { cout <<"Constructing "<<pN<<endl; pName=new char (strlen(pN)+1); if (pName!=0) { strcpy(pName,pN); } } ~Person() { cout<<"Destructing "<<pName<<endl; pName[0]='/0'; delete pName; } PRotected: char *pName;} ;int main(){ Person p1("Randy"); Person p2=p1; //即Person p2 (p1); }/*result is :Constructing RandyDestructing RandyDestructing *//*---------------------------程序開始運行時,創建p1對象,p1對象的構造函數從堆中分配空間并賦給數據成員pName,執行,p2=p1時,因為沒有定義拷貝構造函數,于是就調用默認拷貝構造函數,使得p2與p1完全一樣,并沒有新分配堆空間給p2, p1與p2的pName都是同一個值。析構p2時,將堆中字符串清成空串,然后將堆空間返還給系統; 析構p1時,因為這是pName指向的是空串,所以第三行輸出中顯示的只是Destructing,當執行 delete pName ; 按道理系統應該報錯,但在gcc中沒有創建p2時,對象p1被復制了p2,但資源并未復制,因此,p1和p2指向同一個資源,這稱為淺拷貝。當一個對象創建時,分配了資源,這時,就需要定義自己的拷貝構造函數,使之不但拷貝成員,也拷貝資源#include <iostream>using namespace std;class Person{ public: Person(char *pN) { cout <<"Constructing "<<pN<<endl; pName=new char (strlen(pN)+1); if (pName!=0) { strcpy(pName,pN); } } Person(Person& p) { cout <<"copying "<<p.pName<<"into its own block/n"; pName=new char [sizeof(p.pName)]; if (pName!=0) strcpy(pName,p.pName); } ~Person() { cout<<"Destructing "<<pName<<endl; pName[0]='/0'; delete pName; } protected: char *pName;} ;int main(){ Person p1("Randy"); Person p2=p1; //即Person p2 (p1); }result is :Constructing Randycopying Randyinto its own blockDestructing RandyDestructing Randy創建p2時,對象p1被復制給了p2,同時資源也作了復制,因此p1和p2指向不同的資源,這稱為深拷貝。堆內存并不是唯一需要拷貝構造函數的資源,但它是最常用的一個。打開文件,占有硬設備(例如打印機)服務也需要深拷貝。他們也是析構函數必須返還的資源類型。因此一個很好的經驗是:如果你的類需要析構函數來析構資源,則它也需要一個拷貝構造函數。因為通常對象是自動被析構的,如果需要一個自定義的析構函數,那就意味著有額外資源要在對象被析構之前釋放,此時,對象的拷貝就不是淺拷貝了。---------------------------------------------*/新聞熱點
疑難解答