




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第c++詳細(xì)講解構(gòu)造函數(shù)的拷貝流程http:http:
s1、s2、s3、s4以及func()的形參str,都是使用拷貝的方式來初始化的。
對(duì)于s1、s2、s3、s4,都是將其它對(duì)象的數(shù)據(jù)拷貝給當(dāng)前對(duì)象,以完成當(dāng)前對(duì)象的初始化。
對(duì)于func()的形參str,其實(shí)在定義時(shí)就為它分配了內(nèi)存,但是此時(shí)并沒有初始化,只有等到調(diào)用func()時(shí),才會(huì)將其它對(duì)象的數(shù)據(jù)拷貝給str以完成初始化。
當(dāng)以拷貝的方式初始化一個(gè)對(duì)象時(shí),會(huì)調(diào)用一個(gè)特殊的構(gòu)造函數(shù),就是拷貝構(gòu)造函數(shù)(CopyConstructor)。
#includeiostream
#includestring
usingnamespacestd;
classStudent{
public:
Student(stringname="",intage=0,floatscore=0.0f);//普通構(gòu)造函數(shù)
Student(constStudentstu);//拷貝構(gòu)造函數(shù)(聲明)
public:
voiddisplay();
private:
stringm_name;
intm_age;
floatm_score;
Student::Student(stringname,intage,floatscore):m_name(name),m_age(age),m_score(score){}
//拷貝構(gòu)造函數(shù)(定義)
Student::Student(constStudentstu){
this-m_name=stu.m_name;
this-m_age=stu.m_age;
this-m_score=stu.m_score;
cout"Copyconstructorwascalled."endl;
voidStudent::display(){
coutm_name"的年齡是"m_age",成績(jī)是"m_scoreendl;
intmain(){
constStudentstu1("小明",16,90.5);
Studentstu2=stu1;//調(diào)用拷貝構(gòu)造函數(shù)
Studentstu3(stu1);//調(diào)用拷貝構(gòu)造函數(shù)
stu1.display();
stu2.display();
stu3.display();
return0;
}
運(yùn)行結(jié)果:
Copyconstructorwascalled.
Copyconstructorwascalled.
小明的年齡是16,成績(jī)是90.5
小明的年齡是16,成績(jī)是90.5
小明的年齡是16,成績(jī)是90.5
第8行是拷貝構(gòu)造函數(shù)的聲明,第20行是拷貝構(gòu)造函數(shù)的定義??截悩?gòu)造函數(shù)只有一個(gè)參數(shù),它的類型是當(dāng)前類的引用,而且一般都是const引用。
1)為什么必須是當(dāng)前類的引用呢?
如果拷貝構(gòu)造函數(shù)的參數(shù)不是當(dāng)前類的引用,而是當(dāng)前類的對(duì)象,那么在調(diào)用拷貝構(gòu)造函數(shù)時(shí),會(huì)將另外一個(gè)對(duì)象直接傳遞給形參,這本身就是一次拷貝,會(huì)再次調(diào)用拷貝構(gòu)造函數(shù),然后又將一個(gè)對(duì)象直接傳遞給了形參,將繼續(xù)調(diào)用拷貝構(gòu)造函數(shù)這個(gè)過程會(huì)一直持續(xù)下去,沒有盡頭,陷入死循環(huán)。
只有當(dāng)參數(shù)是當(dāng)前類的引用時(shí),才不會(huì)導(dǎo)致再次調(diào)用拷貝構(gòu)造函數(shù),這不僅是邏輯上的要求,也是C++語法的要求。
2)為什么是const引用呢?
拷貝構(gòu)造函數(shù)的目的是用其它對(duì)象的數(shù)據(jù)來初始化當(dāng)前對(duì)象,并沒有期望更改其它對(duì)象的數(shù)據(jù),添加const限制后,這個(gè)含義更加明確了。
另外一個(gè)原因是,添加const限制后,可以將const對(duì)象和非const對(duì)象傳遞給形參了,因?yàn)榉莄onst類型可以轉(zhuǎn)換為const類型。如果沒有const限制,就不能將const對(duì)象傳遞給形參,因?yàn)閏onst類型不能轉(zhuǎn)換為非const類型,這就意味著,不能使用const對(duì)象來初始化當(dāng)前對(duì)象了。
當(dāng)然,你也可以再添加一個(gè)參數(shù)為非const引用的拷貝構(gòu)造函數(shù),這樣就不會(huì)出錯(cuò)了。換句話說,一個(gè)類可以同時(shí)存在兩個(gè)拷貝構(gòu)造函數(shù),一個(gè)函數(shù)的參數(shù)為const引用,另一個(gè)函數(shù)的參數(shù)為非const引用。
classBase{
public:
Base():m_a(0),m_b(0){}
Base(inta,intb):m_a(a),m_b(b){}
private:
intm_a;
intm_b;
intmain(){
inta=10;
intb=a;//拷貝
Baseobj1(10,20);
Baseobj2=obj1;//拷貝
return0;
}
b和obj2都是以拷貝的方式初始化的,具體來說,就是將a和obj1所在內(nèi)存中的數(shù)據(jù)按照二進(jìn)制位(Bit)復(fù)制到b和obj2所在的內(nèi)存,這種默認(rèn)的拷貝行為就是淺拷貝,這和調(diào)用memcpy()函數(shù)的效果非常類似。
對(duì)于簡(jiǎn)單的類,默認(rèn)的拷貝構(gòu)造函數(shù)一般就夠用了,我們也沒有必要再顯式地定義一個(gè)功能類似的拷貝構(gòu)造函數(shù)。但是當(dāng)類持有其它資源時(shí),例如動(dòng)態(tài)分配的內(nèi)存、指向其他數(shù)據(jù)的指針等,默認(rèn)的拷貝構(gòu)造函數(shù)就不能拷貝這些資源了,我們必須顯式地定義拷貝構(gòu)造函數(shù),以完整地拷貝對(duì)象的所有數(shù)據(jù)。
下面我們通過一個(gè)具體的例子來說明顯式定義拷貝構(gòu)造函數(shù)的必要性。
#includeiostream
#includecstdlib
usingnamespacestd;
//變長(zhǎng)數(shù)組類
classArray{
public:
Array(intlen);
Array(constArrayarr);//拷貝構(gòu)造函數(shù)
~Array();
public:
intoperator[](inti)const{returnm_p[i];}//獲取元素(讀?。?/p>
intoperator[](inti){returnm_p[i];}//獲取元素(寫入)
intlength()const{returnm_len;}
private:
intm_len;
int*m_p;
Array::Array(intlen):m_len(len){
m_p=(int*)calloc(len,sizeof(int));
Array::Array(constArrayarr){//拷貝構(gòu)造函數(shù)
this-m_len=arr.m_len;
this-m_p=(int*)calloc(this-m_len,sizeof(int));
memcpy(this-m_p,arr.m_p,m_len*sizeof(int));
Array::~Array(){free(m_p);}
//打印數(shù)組元素
voidprintArray(constArrayarr){
intlen=arr.length();
for(inti=0;ii++){
if(i==len-1){
coutarr[i]endl;
}else{
coutarr[i]",";
intmain(){
Arrayarr1(10);
for(inti=0;ii++){
arr1[i]=i;
Arrayarr2=arr1;
arr2[5]=100;
arr2[3]=29;
printArray(arr1);
printArray(arr2);
return0;
}
運(yùn)行結(jié)果:
0,1,2,3,4,5,6,7,8,9
0,1,2,29,4,100,6,7,8,9
本例中我們顯式地定義了拷貝構(gòu)造函數(shù),它除了會(huì)將原有對(duì)象的所有成員變量拷貝給新對(duì)象,還會(huì)為新對(duì)象再分配一塊內(nèi)存,并將原有對(duì)象所持有的內(nèi)存也拷貝過來。這樣做的結(jié)果是,原有對(duì)象和新對(duì)象所持有的動(dòng)態(tài)內(nèi)存是相互獨(dú)立的,更改一個(gè)對(duì)象的數(shù)據(jù)不會(huì)影響另外一個(gè)對(duì)象,本例中我們更改了arr2的數(shù)據(jù),就沒有影響arr1。
這種將對(duì)象所持有的其它資源一并拷貝的行為叫做深拷貝,我們必須顯式地定義拷貝構(gòu)造函數(shù)才能達(dá)到深拷貝的目的。深拷貝的例子比比皆是,除了上面的變長(zhǎng)數(shù)組類,使用的動(dòng)態(tài)數(shù)組類也需要深拷貝;此外,標(biāo)準(zhǔn)模板庫(STL)中的string、vector、stack、set、map等也都必須使用深拷貝。
讀者如果希望親眼目睹不使用深拷貝的后果,可以將上例中的拷貝構(gòu)造函數(shù)刪除,那么運(yùn)行結(jié)果將變?yōu)椋?,1,2,29,4,100,6,7,8,9
0,1,2,29,4,100,6,7,8,9
可以發(fā)現(xiàn),更改arr2的數(shù)據(jù)也影響到了arr1。這是因?yàn)?,在?chuàng)建arr2對(duì)象時(shí),默認(rèn)拷貝構(gòu)造函數(shù)將arr1.m_p直接賦值給了arr2.m_p,導(dǎo)致arr2.m_p和arr1.m_p指向了同一塊內(nèi)存,所以會(huì)相互影響。
另外需要注意的是,printArray()函數(shù)的形參為引用類型,這樣做能夠避免在傳參時(shí)調(diào)用拷貝構(gòu)造函數(shù);又因?yàn)閜rintArray()函數(shù)不會(huì)修改任何數(shù)組元素,所以我們添加了const限制,以使得語義更加明確。
到底是淺拷貝還是深拷貝
如果一個(gè)類擁有指針類型的成員變量,那么絕大部分情況下就需要深拷貝,因?yàn)橹挥羞@樣,才能將指針指向的內(nèi)容再復(fù)制出一份來,讓原有對(duì)象和新生對(duì)象相互獨(dú)立,彼此之間不受影響。如果類的成員變量沒有指針,一般淺拷貝足以。
另外一種需要深拷貝的情況就是在創(chuàng)建對(duì)象時(shí)進(jìn)行一些預(yù)處理工作,比如統(tǒng)計(jì)創(chuàng)建過的對(duì)象的數(shù)目、記錄對(duì)象創(chuàng)建的時(shí)間等,請(qǐng)看下面的例子:
#includeiostream
#includectime
#includewindows.h//在Linux和Mac下要換成unistd.h頭文件
usingnamespacestd;
classBase{
public:
Base(inta=0,intb=0);
Base(constBaseobj);//拷貝構(gòu)造函數(shù)
public:
intgetCount()const{returnm_count;}
time_tgetTime()const{returnm_time;}
private:
intm_a;
intm_b;
time_tm_time;//對(duì)象創(chuàng)建時(shí)間
staticintm_count;//創(chuàng)建過的對(duì)象的數(shù)目
intBase::m_count=0;
Base::Base(inta,intb):m_a(a),m_b(b){
m_count++;
m_time=time((time_t*)NULL);
Base::Base(constBaseobj){//拷貝構(gòu)造函數(shù)
this-m_a=obj.m_a;
this-m_b=obj.m_b;
this-m_count++;
this-m_time=time((time_t*)NULL);
intmain(){
Baseobj1(10,20);
cout"obj1:count="obj1.getCount()",time="obj1.getTime()endl;
Sleep(3000);//在Linux和Mac下要寫作sleep(3);
Baseobj2=obj1;
cout"obj2:count="obj2.getCount
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 云計(jì)算平臺(tái)穩(wěn)定維護(hù)與資源管理合同
- 《流感狀態(tài)下內(nèi)科教研室》課件
- 政薪火相傳的傳統(tǒng)美德+課件-2024-2025學(xué)年統(tǒng)編版道德與法治七年級(jí)下
- 《健康飲食與營(yíng)養(yǎng)配餐》課件
- 《職業(yè)探索與決策》課件
- 《腦卒中后遺癥的康復(fù)訓(xùn)練課件》
- 壓力管理與挫折應(yīng)對(duì)
- 超聲內(nèi)鏡培訓(xùn)大綱
- 計(jì)算機(jī)科學(xué)基本數(shù)據(jù)結(jié)構(gòu)課件
- 《錦繡江山美談》課件
- 廣東省2024-2025學(xué)年佛山市普通高中教學(xué)質(zhì)量檢測(cè)生物試卷(二)高三試卷(佛山二模)
- 商業(yè)銀行資產(chǎn)配置與風(fēng)險(xiǎn)管理
- 《第六單元 音樂知識(shí) 下滑音》(教學(xué)設(shè)計(jì))-2023-2024學(xué)年人教版(2012)音樂三年級(jí)下冊(cè)
- 外研版(三起)(2024)三年級(jí)下冊(cè)英語Unit 3 單元測(cè)試卷(含答案)
- 項(xiàng)目評(píng)估保密協(xié)議書(2篇)
- 清洗清潔功能無人機(jī)
- 農(nóng)產(chǎn)品批發(fā)市場(chǎng)運(yùn)營(yíng)方案
- 富士數(shù)碼相機(jī)finepix-S205EXR使用說明書簡(jiǎn)體中文版
- 電子健康記錄優(yōu)化-深度研究
- 會(huì)計(jì)法律法規(guī)答題答案
- 生長(zhǎng)刺激表達(dá)基因2蛋白介紹
評(píng)論
0/150
提交評(píng)論