91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

詳解C++中構造函數,拷貝構造函數和賦值函數的區別和實現

發布時間:2020-10-13 17:05:18 來源:腳本之家 閱讀:139 作者:Zmyths 欄目:編程語言

C++中一般創建對象,拷貝或賦值的方式有構造函數,拷貝構造函數,賦值函數這三種方法。下面就詳細比較下三者之間的區別以及它們的具體實現

1.構造函數

構造函數是一種特殊的類成員函數,是當創建一個類的對象時,它被調用來對類的數據成員進行初始化和分配內存。(構造函數的命名必須和類名完全相同)

首先說一下一個C++的空類,編譯器會加入哪些默認的成員函數

默認構造函數和拷貝構造函數

析構函數

賦值函數(賦值運算符)

取值函數

**即使程序沒定義任何成員,編譯器也會插入以上的函數!

注意:構造函數可以被重載,可以多個,可以帶參數;析構函數只有一個,不能被重載,不帶參數

而默認構造函數沒有參數,它什么也不做。當沒有重載無參構造函數時,

A a就是通過默認構造函數來創建一個對象

下面代碼為構造函數重載的實現

<span >class A
{
int m_i;
Public:
 A() 
{
 Cout<<”無參構造函數”<<endl;
}
A(int i):m_i(i) {} //初始化列表
}</span>

2.拷貝構造函數

拷貝構造函數是C++獨有的,它是一種特殊的構造函數,用基于同一類的一個對象構造和初始化另一個對象。

當沒有重載拷貝構造函數時,通過默認拷貝構造函數來創建一個對象

A a;

A b(a);

A b=a;  都是拷貝構造函數來創建對象b

強調:這里b對象是不存在的,是用a 對象來構造和初始化b的!!

先說下什么時候拷貝構造函數會被調用:

在C++中,3種對象需要復制,此時拷貝構造函數會被調用

  1. 1)一個對象以值傳遞的方式傳入函數體
  2. 2)一個對象以值傳遞的方式從函數返回
  3. 3)一個對象需要通過另一個對象進行初始化

什么時候編譯器會生成默認的拷貝構造函數:

  1. 1)如果用戶沒有自定義拷貝構造函數,并且在代碼中使用到了拷貝構造函數,編譯器就會生成默認的拷貝構造函數。但如果用戶定義了拷貝構造函數,編譯器就不在生成。
  2. 2)如果用戶定義了一個構造函數,但不是拷貝構造函數,而此時代碼中又用到了拷貝構造函數,那編譯器也會生成默認的拷貝構造函數。

因為系統提供的默認拷貝構造函數工作方式是內存拷貝,也就是淺拷貝。如果對象中用到了需要手動釋放的對象,則會出現問題,這時就要手動重載拷貝構造函數,實現深拷貝。

下面說說深拷貝與淺拷貝:

  1. 淺拷貝:如果復制的對象中引用了一個外部內容(例如分配在堆上的數據),那么在復制這個對象的時候,讓新舊兩個對象指向同一個外部內容,就是淺拷貝。(指針雖然復制了,但所指向的空間內容并沒有復制,而是由兩個對象共用,兩個對象不獨立,刪除空間存在)
  2. 深拷貝:如果在復制這個對象的時候為新對象制作了外部對象的獨立復制,就是深拷貝。

拷貝構造函數重載聲明如下:

A (const A&other)

下面為拷貝構造函數的實現:

<span >class A
{
 int m_i
 A(const A& other):m_i(other.m_i)
{
 Cout<<”拷貝構造函數”<<endl;
}
}</span>

3.賦值函數

當一個類的對象向該類的另一個對象賦值時,就會用到該類的賦值函數。

當沒有重載賦值函數(賦值運算符)時,通過默認賦值函數來進行賦值操作

A a;

A b;

b=a; 

強調:這里a,b對象是已經存在的,是用a 對象來賦值給b的!!

賦值運算的重載聲明如下:

 A& operator = (const A& other)

通常大家會對拷貝構造函數和賦值函數混淆,這兒仔細比較兩者的區別:

1)拷貝構造函數是一個對象初始化一塊內存區域,這塊內存就是新對象的內存區,而賦值函數是對于一個已經被初始化的對象來進行賦值操作。

<span >class A;
A a;
A b=a;  //調用拷貝構造函數(b不存在)
A c(a) ;  //調用拷貝構造函數
 
/****/
 
class A;
A a;
A b;  
b = a ;  //調用賦值函數(b存在)</span>

2)一般來說在數據成員包含指針對象的時候,需要考慮兩種不同的處理需求:一種是復制指針對象,另一種是引用指針對象。拷貝構造函數大多數情況下是復制,而賦值函數是引用對象

3)實現不一樣。拷貝構造函數首先是一個構造函數,它調用時候是通過參數的對象初始化產生一個對象。賦值函數則是把一個新的對象賦值給一個原有的對象,所以如果原來的對象中有內存分配要先把內存釋放掉,而且還要檢察一下兩個對象是不是同一個對象,如果是,不做任何操作,直接返回。(這些要點會在下面的String實現代碼中體現)

!!!如果不想寫拷貝構造函數和賦值函數,又不允許別人使用編譯器生成的缺省函數,最簡單的辦法是將拷貝構造函數和賦值函數聲明為私有函數,不用編寫代碼。如:

<span >class A
{
 private:
 A(const A& a); //私有拷貝構造函數
 A& operate=(const A& a); //私有賦值函數
}</span>

如果程序這樣寫就會出錯:

<span >A a;
A b(a); //調用了私有拷貝構造函數,編譯出錯
 
A b;
b=a; //調用了私有賦值函數,編譯出錯</span>

所以如果類定義中有指針或引用變量或對象,為了避免潛在錯誤,最好重載拷貝構造函數和賦值函數。

下面以string類的實現為例,完整的寫了普通構造函數,拷貝構造函數,賦值函數的實現。String類的基本實現見我另一篇博文。

<span >String::String(const char* str)  //普通構造函數
 
{
 
 cout<<construct<<endl;
 
 if(str==NULL)    //如果str 為NULL,就存一個空字符串“”
 
{
 m_string=new char[1];
 *m_string ='\0';
}
 
 else
 
{
 
 m_string= new char[strlen(str)+1] ;  //分配空間
 strcpy(m_string,str);
 
}
 
}
 
 
String::String(const String&other)  //拷貝構造函數
 
{
 cout<<"copy construct"<<endl;
 m_string=new char[strlen(other.m_string)+1]; //分配空間并拷貝
 strcpy(m_string,other.m_string);
}
 
String & String::operator=(const String& other) //賦值運算符
{
 cout<<"operator =funtion"<<endl ;
 if(this==&other) //如果對象和other是用一個對象,直接返回本身
 {
 return *this;
 }
 delete []m_string; //先釋放原來的內存
 m_string= new char[strlen(other.m_string)+1];
 strcpy(m_string,other.m_string);
 return * this;
}</span>

一句話記住三者:

對象不存在,且沒用別的對象來初始化,就是調用了構造函數;

對象不存在,且用別的對象來初始化,就是拷貝構造函數(上面說了三種用它的情況!)

對象存在,用別的對象來給它賦值,就是賦值函數。

以上為本人結合很多資料和圖書整理出來的,將核心的點都系統的理出來,全自己按條理寫的,現在大家對普通構造函數,拷貝構造函數,賦值函數的區別和實現應該都清楚了。

以上所述是小編給大家介紹的C++中構造函數,拷貝構造函數和賦值函數的區別和實現詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對億速云網站的支持!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

湄潭县| 崇信县| 赣榆县| 宝应县| 大厂| 襄汾县| 威海市| 陇川县| 扎囊县| 祥云县| 临沂市| 罗源县| 康保县| 湟中县| 鹤壁市| 灌南县| 临高县| 济宁市| 齐齐哈尔市| 木兰县| 岳池县| 富锦市| 长宁县| 曲水县| 长海县| 光泽县| 陆丰市| 德格县| 榆中县| 新巴尔虎右旗| 锦屏县| 石嘴山市| 宁陕县| 宜君县| 黄龙县| 绵阳市| 东乡县| 嘉兴市| 汽车| 贞丰县| 阳新县|