日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

理解C++中拷贝构造函数

發(fā)布時(shí)間:2023/12/20 c/c++ 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 理解C++中拷贝构造函数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

拷貝構(gòu)造函數(shù)的功能是用一個(gè)已有的對(duì)象初始化一個(gè)被創(chuàng)建的同樣對(duì)象,是一種特殊的構(gòu)造函數(shù),具有一般構(gòu)造函數(shù)的所有特性,當(dāng)創(chuàng)建一個(gè)新對(duì)象的時(shí)候系統(tǒng)會(huì)自動(dòng)調(diào)用它;其形參是本類對(duì)象的引用,它的特殊功能是將參數(shù)代表的對(duì)象逐域拷貝到新創(chuàng)建的對(duì)象中。

?用戶可以根據(jù)實(shí)際需要定義特定的拷貝構(gòu)造函數(shù),以實(shí)現(xiàn)同類對(duì)象之間數(shù)據(jù)成員的傳遞。如果用戶沒有聲明類的拷貝構(gòu)造函數(shù),系統(tǒng)會(huì)自動(dòng)生成一個(gè)默認(rèn)的拷貝構(gòu)造函數(shù),它的功能就是把初始對(duì)象的每個(gè)數(shù)據(jù)成員的值復(fù)制到新建立的對(duì)象當(dāng)中。它定義為:類名(類名&對(duì)象名)

class dog {private:int age;float weight;char *color;public:dog();dog(dog&);void play();void hunt(); };dog::dog(dog&other) {age = other.age;weight = other.weight;color = other.color; }

? ?在以下四種情況下會(huì)調(diào)用拷貝構(gòu)造函數(shù)

? (1)用類的一個(gè)對(duì)象去初始化另一個(gè)對(duì)象:

????dog dog1;

? ? ?dog dog2(dog1);

? (2)用類的一個(gè)對(duì)象去初始化另一個(gè)對(duì)象的另一種形式:

? ?dog dog2 = dog1;

? (3) 對(duì)象作為參數(shù)傳遞,調(diào)用拷貝構(gòu)造函數(shù):

? f(dog a){}

? dog b;

? f(b);

? (4)如果函數(shù)的返回值是類的對(duì)象,函數(shù)調(diào)用返回時(shí),調(diào)用拷貝構(gòu)造函數(shù)

? dog f{

? ?dog a;

? ?.....

? ?return a;

? }

? dog b;

? b = f();

// 拷貝構(gòu)造函數(shù)分為深拷貝和淺拷貝

淺拷貝只是復(fù)制對(duì)象的空間而不復(fù)制資源,深拷貝需要同時(shí)復(fù)制對(duì)象空間和資源。

淺復(fù)制:只是對(duì)指針的復(fù)制,復(fù)制后兩個(gè)指針指向同一個(gè)內(nèi)存空間(*p ---> 內(nèi)存空間A <---*q)

深復(fù)制:不但對(duì)指針復(fù)制,而且對(duì)指針指向的內(nèi)容進(jìn)行拷貝,經(jīng)深復(fù)制后的指針指向兩個(gè)不同地址的指針(*p ---> 內(nèi)存空間A ; *q ---> 內(nèi)存空間B)

-----------------------------------------------------------------------------------------------------------------------------

C++構(gòu)造函數(shù)詳解(復(fù)制構(gòu)造函數(shù))

構(gòu)造函數(shù)是干什么的

該類對(duì)象被創(chuàng)建時(shí),編譯系統(tǒng)對(duì)象分配內(nèi)存空間,并自動(dòng)調(diào)用該構(gòu)造函數(shù),由構(gòu)造函數(shù)完成成員的初始化工作,故:構(gòu)造函數(shù)的作用:初始化對(duì)象的數(shù)據(jù)成員。

構(gòu)造函數(shù)的種類

1 class Complex 2 { 4 private : 5 double m_real; 6 double m_imag; 7 8 public: 9 10 // 無參數(shù)構(gòu)造函數(shù) 11 // 如果創(chuàng)建一個(gè)類你沒有寫任何構(gòu)造函數(shù),則系統(tǒng)會(huì)自動(dòng)生成默認(rèn)的無參構(gòu)造函數(shù),函數(shù)為空,什么都不做 12 // 只要你寫了一個(gè)下面的某一種構(gòu)造函數(shù),系統(tǒng)就不會(huì)再自動(dòng)生成這樣一個(gè)默認(rèn)的構(gòu)造函數(shù),如果希望有一個(gè)這樣的無參構(gòu)造函數(shù),則需要自己顯示地寫出來 13 Complex(void) 14 { 15 m_real = 0.0; 16 m_imag = 0.0; 17 } 18 19 // 一般構(gòu)造函數(shù)(也稱重載構(gòu)造函數(shù)) 20 // 一般構(gòu)造函數(shù)可以有各種參數(shù)形式,一個(gè)類可以有多個(gè)一般構(gòu)造函數(shù),前提是參數(shù)的個(gè)數(shù)或者類型不同(基于c++的重載函數(shù)原理) 21 // 例如:你還可以寫一個(gè) Complex( int num)的構(gòu)造函數(shù)出來 22 // 創(chuàng)建對(duì)象時(shí)根據(jù)傳入的參數(shù)不同調(diào)用不同的構(gòu)造函數(shù) 23 Complex(double real, double imag) 24 { 25 m_real = real; 26 m_imag = imag; 27 } 28 29 // 復(fù)制構(gòu)造函數(shù)(也稱為拷貝構(gòu)造函數(shù)) 30 // 復(fù)制構(gòu)造函數(shù)參數(shù)為類對(duì)象本身的引用,用于根據(jù)一個(gè)已存在的對(duì)象復(fù)制出一個(gè)新的該類的對(duì)象,一般在函數(shù)中會(huì)將已存在對(duì)象的數(shù)據(jù)成員的值復(fù)制一份到新創(chuàng)建的對(duì)象中 31 // 若沒有顯示的寫復(fù)制構(gòu)造函數(shù),則系統(tǒng)會(huì)默認(rèn)創(chuàng)建一個(gè)復(fù)制構(gòu)造函數(shù),但當(dāng)類中有指針成員時(shí),由系統(tǒng)默認(rèn)創(chuàng)建該復(fù)制構(gòu)造函數(shù)會(huì)存在風(fēng)險(xiǎn),具體原因請查詢有關(guān) “淺拷貝” 、“深拷貝”的文章論述 32 Complex(const Complex & c) 33 { 34 // 將對(duì)象c中的數(shù)據(jù)成員值復(fù)制過來 35 m_real = c.m_real; 36 m_img = c.m_img; 37 } 38 39 // 類型轉(zhuǎn)換構(gòu)造函數(shù),根據(jù)一個(gè)指定的類型的對(duì)象創(chuàng)建一個(gè)本類的對(duì)象 40 // 例如:下面將根據(jù)一個(gè)double類型的對(duì)象創(chuàng)建了一個(gè)Complex對(duì)象 41 Complex::Complex(double r) 42 { 43 m_real = r; 44 m_imag = 0.0; 45 } 46 47 // 等號(hào)運(yùn)算符重載 48 // 注意,這個(gè)類似復(fù)制構(gòu)造函數(shù),將=右邊的本類對(duì)象的值復(fù)制給等號(hào)左邊的對(duì)象,它不屬于構(gòu)造函數(shù),等號(hào)左右兩邊的對(duì)象必須已經(jīng)被創(chuàng)建 49 // 若沒有顯示的寫=運(yùn)算符重載,則系統(tǒng)也會(huì)創(chuàng)建一個(gè)默認(rèn)的=運(yùn)算符重載,只做一些基本的拷貝工作 50 Complex &operator=(const Complex &rhs) 51 { 52 // 首先檢測等號(hào)右邊的是否就是左邊的對(duì)象本,若是本對(duì)象本身,則直接返回 53 if ( this == &rhs ) 54 { 55 return *this; 56 } 57 58 // 復(fù)制等號(hào)右邊的成員到左邊的對(duì)象中 59 this->m_real = rhs.m_real; 60 this->m_imag = rhs.m_imag; 61 62 // 把等號(hào)左邊的對(duì)象再次傳出 63 // 目的是為了支持連等 eg: a=b=c 系統(tǒng)首先運(yùn)行 b=c 64 // 然后運(yùn)行 a= ( b=c的返回值,這里應(yīng)該是復(fù)制c值后的b對(duì)象) 65 return *this; 66 } 67 };

?下面使用上面定義的類對(duì)象來說明各個(gè)構(gòu)造函數(shù)的用法:

1 void main() 2 { 3 // 調(diào)用了無參構(gòu)造函數(shù),數(shù)據(jù)成員初值被賦為0.0 4 Complex c1,c2; 5 6 // 調(diào)用一般構(gòu)造函數(shù),數(shù)據(jù)成員初值被賦為指定值 7 Complex c3(1.0,2.5); 8 // 也可以使用下面的形式 9 Complex c3 = Complex(1.0,2.5); 10 11 // 把c3的數(shù)據(jù)成員的值賦值給c1 12 // 由于c1已經(jīng)事先被創(chuàng)建,故此處不會(huì)調(diào)用任何構(gòu)造函數(shù) 13 // 只會(huì)調(diào)用 = 號(hào)運(yùn)算符重載函數(shù) 14 c1 = c3; 15 16 // 調(diào)用類型轉(zhuǎn)換構(gòu)造函數(shù) 17 // 系統(tǒng)首先調(diào)用類型轉(zhuǎn)換構(gòu)造函數(shù),將5.2創(chuàng)建為一個(gè)本類的臨時(shí)對(duì)象,然后調(diào)用等號(hào)運(yùn)算符重載,將該臨時(shí)對(duì)象賦值給c1 18 c2 = 5.2; 19 20 // 調(diào)用拷貝構(gòu)造函數(shù)( 有下面兩種調(diào)用方式) 21 Complex c5(c2); 22 Complex c4 = c2; // 注意和 = 運(yùn)算符重載區(qū)分,這里等號(hào)左邊的對(duì)象不是事先已經(jīng)創(chuàng)建,故需要調(diào)用拷貝構(gòu)造函數(shù),參數(shù)為c2 23 24 }

參考:http://www.cnblogs.com/xkfz007/archive/2012/05/11/2496447.html

復(fù)制構(gòu)造函數(shù)

幾個(gè)原則:

C++ primer p406 :復(fù)制構(gòu)造函數(shù)是一種特殊的構(gòu)造函數(shù),具有單個(gè)形參,該形參(常用const修飾)是對(duì)該類類型的引用。當(dāng)定義一個(gè)新對(duì)象并用一個(gè)同類型的對(duì)象對(duì)它進(jìn)行初始化時(shí),將顯示使用復(fù)制構(gòu)造函數(shù)。當(dāng)該類型的對(duì)象傳遞給函數(shù)或從函數(shù)返回該類型的對(duì)象時(shí),將隱式調(diào)用復(fù)制構(gòu)造函數(shù)。

?

C++支持兩種初始化形式:復(fù)制初始化(int a = 5;)和直接初始化(int a(5);)對(duì)于其他類型沒有什么區(qū)別,對(duì)于類類型直接初始化直接調(diào)用實(shí)參匹配的構(gòu)造函數(shù),復(fù)制初始化總是調(diào)用復(fù)制構(gòu)造函數(shù),也就是說:

A x(2);  //直接初始化,調(diào)用構(gòu)造函數(shù)
A y = x;  //復(fù)制初始化,調(diào)用復(fù)制構(gòu)造函數(shù)

?

必須定義復(fù)制構(gòu)造函數(shù)的情況:

只包含類類型成員或內(nèi)置類型(但不是指針類型)成員的類,無須顯式地定義復(fù)制構(gòu)造函數(shù)也可以復(fù)制;有的類有一個(gè)數(shù)據(jù)成員是指針,或者是有成員表示在構(gòu)造函數(shù)中分配的其他資源,這兩種情況下都必須定義復(fù)制構(gòu)造函數(shù)。

?

什么情況使用復(fù)制構(gòu)造函數(shù):

類的對(duì)象需要拷貝時(shí),拷貝構(gòu)造函數(shù)將會(huì)被調(diào)用。以下情況都會(huì)調(diào)用拷貝構(gòu)造函數(shù):
(1)一個(gè)對(duì)象以值傳遞的方式傳入函數(shù)體?
(2)一個(gè)對(duì)象以值傳遞的方式從函數(shù)返回?
(3)一個(gè)對(duì)象需要通過另外一個(gè)對(duì)象進(jìn)行初始化。

?

深拷貝和淺拷貝:

所謂淺拷貝,指的是在對(duì)象復(fù)制時(shí),只對(duì)對(duì)象中的數(shù)據(jù)成員進(jìn)行簡單的賦值,默認(rèn)拷貝構(gòu)造函數(shù)執(zhí)行的也是淺拷貝。在“深拷貝”的情況下,對(duì)于對(duì)象中動(dòng)態(tài)成員,就不能僅僅簡單地賦值了,而應(yīng)該重新動(dòng)態(tài)分配空間

如果一個(gè)類擁有資源,當(dāng)這個(gè)類的對(duì)象發(fā)生復(fù)制過程的時(shí)候,資源重新分配,這個(gè)過程就是深拷貝

上面提到,如果沒有自定義復(fù)制構(gòu)造函數(shù),則系統(tǒng)會(huì)創(chuàng)建默認(rèn)的復(fù)制構(gòu)造函數(shù),但系統(tǒng)創(chuàng)建的默認(rèn)復(fù)制構(gòu)造函數(shù)只會(huì)執(zhí)行“淺拷貝”,即將被拷貝對(duì)象的數(shù)據(jù)成員的值一一賦值給新創(chuàng)建的對(duì)象,若該類的數(shù)據(jù)成員中有指針成員,則會(huì)使得新的對(duì)象的指針?biāo)赶虻牡刂放c被拷貝對(duì)象的指針?biāo)赶虻牡刂废嗤?#xff0c;delete該指針時(shí)則會(huì)導(dǎo)致兩次重復(fù)delete而出錯(cuò)。下面是示例:

1 #include <iostream.h> 2 #include <string.h> 3 class Person 4 { 5 public : 6 7 // 構(gòu)造函數(shù) 8 Person(char * pN) 9 { 10 cout << "一般構(gòu)造函數(shù)被調(diào)用 !\n"; 11 m_pName = new char[strlen(pN) + 1]; 12 //在堆中開辟一個(gè)內(nèi)存塊存放pN所指的字符串 13 if(m_pName != NULL) 14 { 15 //如果m_pName不是空指針,則把形參指針pN所指的字符串復(fù)制給它 16 strcpy(m_pName ,pN); 17 } 18 } 19 20 // 系統(tǒng)創(chuàng)建的默認(rèn)復(fù)制構(gòu)造函數(shù),只做位模式拷貝 21 Person(Person & p) 22 { 23 //使兩個(gè)字符串指針指向同一地址位置 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 // 結(jié)果導(dǎo)致 man 和 woman 的指針都指向了同一個(gè)地址 42 43 // 函數(shù)結(jié)束析構(gòu)時(shí) 44 // 同一個(gè)地址被delete兩次 45 } 46 47 48 // 下面自己設(shè)計(jì)復(fù)制構(gòu)造函數(shù),實(shí)現(xiàn)“深拷貝”,即不讓指針指向同一地址,而是重新申請一塊內(nèi)存給新的對(duì)象的指針數(shù)據(jù)成員 49 Person(Person & chs); 50 { 51 // 用運(yùn)算符new為新對(duì)象的指針數(shù)據(jù)成員分配空間 52 m_pName=new char[strlen(p.m_pName)+ 1]; 53 54 if(m_pName) 55 { 56 // 復(fù)制內(nèi)容 57 strcpy(m_pName ,chs.m_pName); 58 } 59 60 // 則新創(chuàng)建的對(duì)象的m_pName與原對(duì)象chs的m_pName不再指向同一地址了 61 }

?

重載賦值操作符:

通過定義operate=的函數(shù),可以對(duì)賦值進(jìn)行定義。像其他任何函數(shù)一樣,操作符函數(shù)有一個(gè)返回值和形參表。形參表必須具有與該操作符操作數(shù)書目相同的形參(如果操作符是一個(gè)成員,則包括隱式this形參)。賦值是二元運(yùn)算,所以該操作符函數(shù)有兩個(gè)形參:第一個(gè)形參(隱含的this指針)對(duì)應(yīng)著左操作數(shù),第二個(gè)形參對(duì)應(yīng)右操作數(shù)。

?一個(gè)應(yīng)用了對(duì)賦值號(hào)重載的拷貝構(gòu)造函數(shù)的例子:

1 #include <iostream> 2 3 using namespace std; 4 5 class A 6 { 7 public: 8 A(int);//構(gòu)造函數(shù) 9 A(const A &);//拷貝構(gòu)造函數(shù) 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<<"調(diào)用拷貝構(gòu)造函數(shù)"<<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++拷貝構(gòu)造函數(shù)詳解:http://blog.csdn.net/lwbeyond/article/details/6202256



總結(jié)

以上是生活随笔為你收集整理的理解C++中拷贝构造函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。