如果類包含內(nèi)置或復(fù)合類型的成員,則該類就不應(yīng)該依賴于合成的默認(rèn)構(gòu)造函數(shù),它應(yīng)該定義自己的構(gòu)造函數(shù)來初始化這些成員。
當(dāng)一個(gè)類含有一些數(shù)據(jù)成員,你需要在實(shí)例化類的時(shí)候就初始化這些成員,你就需要自己定義構(gòu)造函數(shù)。例如Person類含有m_strName成員,你在聲明該類是就將其賦值 Person myPerson("張三")對(duì)于拷貝構(gòu)造函數(shù),為了防止淺拷貝造成的兩個(gè)對(duì)象指向同一內(nèi)存,當(dāng)刪除其中一個(gè)對(duì)象后導(dǎo)致另一對(duì)象指向內(nèi)容為空的時(shí)候,我們就需要定義自己的拷貝構(gòu)造函數(shù)來進(jìn)行深拷貝。當(dāng)你的類數(shù)據(jù)成員中使用了動(dòng)態(tài)分配的內(nèi)存,你就需要定義自己的析構(gòu)函數(shù)來釋放這部分內(nèi)存,防止內(nèi)存泄露。系統(tǒng)定義的默認(rèn)構(gòu)造函數(shù)和析構(gòu)函數(shù)函數(shù)名和類名相同,如Person類:Person()構(gòu)造函數(shù)~Person()析構(gòu)函數(shù)
類定義中,如果未提供自己的拷貝構(gòu)造函數(shù),則C++提供一個(gè)默認(rèn)拷貝構(gòu)造函數(shù),就像沒有提供構(gòu)造函數(shù)時(shí),C++提供默認(rèn)構(gòu)造函數(shù)一樣。C++提供的默認(rèn)拷貝構(gòu)造函數(shù)工作的方法是:完成一個(gè)成員一個(gè)成員的拷貝,如果成員是類對(duì)象,則調(diào)用其拷貝構(gòu)造函數(shù)或者默認(rèn)拷貝構(gòu)造函數(shù)。/*--------------------------------------在默認(rèn)拷貝構(gòu)造函數(shù)中,拷貝的策略是逐個(gè)成員依次拷貝,但是,一個(gè)類可能會(huì)擁有資源,如果拷貝構(gòu)造函數(shù)簡(jiǎn)單地制作了一個(gè)該資源的拷貝,而不對(duì)它本身分配,就得面臨一個(gè)麻煩的局面:兩個(gè)對(duì)象都擁有同一個(gè)資源。當(dāng)對(duì)象析構(gòu)時(shí),該資源將經(jīng)歷兩次資源返還。下面的程序描述了Person對(duì)象被簡(jiǎn)單拷貝后,面臨析構(gòu)時(shí)的困惑。--------------------------------------------------*/#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 *//*---------------------------程序開始運(yùn)行時(shí),創(chuàng)建p1對(duì)象,p1對(duì)象的構(gòu)造函數(shù)從堆中分配空間并賦給數(shù)據(jù)成員pName,執(zhí)行,p2=p1時(shí),因?yàn)闆]有定義拷貝構(gòu)造函數(shù),于是就調(diào)用默認(rèn)拷貝構(gòu)造函數(shù),使得p2與p1完全一樣,并沒有新分配堆空間給p2, p1與p2的pName都是同一個(gè)值。析構(gòu)p2時(shí),將堆中字符串清成空串,然后將堆空間返還給系統(tǒng); 析構(gòu)p1時(shí),因?yàn)檫@是pName指向的是空串,所以第三行輸出中顯示的只是Destructing,當(dāng)執(zhí)行 delete pName ; 按道理系統(tǒng)應(yīng)該報(bào)錯(cuò),但在gcc中沒有創(chuàng)建p2時(shí),對(duì)象p1被復(fù)制了p2,但資源并未復(fù)制,因此,p1和p2指向同一個(gè)資源,這稱為淺拷貝。當(dāng)一個(gè)對(duì)象創(chuàng)建時(shí),分配了資源,這時(shí),就需要定義自己的拷貝構(gòu)造函數(shù),使之不但拷貝成員,也拷貝資源#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創(chuàng)建p2時(shí),對(duì)象p1被復(fù)制給了p2,同時(shí)資源也作了復(fù)制,因此p1和p2指向不同的資源,這稱為深拷貝。堆內(nèi)存并不是唯一需要拷貝構(gòu)造函數(shù)的資源,但它是最常用的一個(gè)。打開文件,占有硬設(shè)備(例如打印機(jī))服務(wù)也需要深拷貝。他們也是析構(gòu)函數(shù)必須返還的資源類型。因此一個(gè)很好的經(jīng)驗(yàn)是:如果你的類需要析構(gòu)函數(shù)來析構(gòu)資源,則它也需要一個(gè)拷貝構(gòu)造函數(shù)。因?yàn)橥ǔ?duì)象是自動(dòng)被析構(gòu)的,如果需要一個(gè)自定義的析構(gòu)函數(shù),那就意味著有額外資源要在對(duì)象被析構(gòu)之前釋放,此時(shí),對(duì)象的拷貝就不是淺拷貝了。---------------------------------------------*/新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注