複製建構函式和賦值運算子根本的不同

2021-07-15 03:58:05 字數 2240 閱讀 3289

在進行c++類編寫的過程之中,通常會涉及到類的拷貝建構函式與類的賦值函式。初涉類編寫的**,對於兩類函式的用法一直是挺讓人困惑的內容。這篇文章我們會詳細來梳理拷貝建構函式與賦值函式的區別。

1、呼叫了哪個函式?

class line ;

line& operator=(const line &obj)

delete ptr;

ptr = new int;

*ptr = *obj.ptr;

return *this;

};~line(); // 析構函式

private:

int *ptr;

};

這裡我們顯式宣告了拷貝建構函式與賦值建構函式,接下來我們用一小段**測試一下上面定義的類。(其他函式的定義並不完整,讀者可以之行補全)

int main()
輸出結果如下:

看似很相似的兩個表示式,卻呼叫了不同的兩個函式。初學c++時,這樣的結果讓我很困惑,所以我們接下來梳理一下這兩個函式。

2、拷貝建構函式

上面的**我們可以看到** line l2 = l1呼叫了拷貝建構函式。

拷貝建構函式,顧名思義,是乙個建構函式,但是它特殊的點就在於在建立物件時,是使用同一類中之前建立的物件來初始化新建立的物件。所以對於它的使用場合也很簡單,只有在構造物件時才會呼叫到拷貝建構函式,顯然line l2 = l1是乙個物件初始化的過程。我們知道每個類都會有建構函式,在物件初始化的過程之中,拷貝建構函式提供了乙個通過乙個同型別的物件對它進行初始化。

c++支援兩種初始化形式:拷貝初始化(int a = 5;)和直接初始化(int a(5);)對於其他型別沒有什麼區別,對於類型別直接初始化直接呼叫實參匹配的建構函式,拷貝初始化總是呼叫拷貝建構函式,也就是說:

在c++中,下面幾個場景中,拷貝建構函式會被呼叫:

1、乙個物件需要通過另乙個物件進行初始化

2、乙個物件以值傳遞的方式作為引數傳入函式

3、乙個物件以值傳遞的方式作為返回值從函式返回

如果我們沒有顯式宣告定義對應類的拷貝建構函式,c++編譯器會預設生成對應的拷貝建構函式。既然c++編譯器會自動生成拷貝建構函式,為什麼我們又需要顯式的去定義它呢?

因為由c++編譯器提供的拷貝建構函式工作方式是淺拷貝。它單純的使用了=操作符來拷貝類中的成員。但是如果類中用到了需要動態分配記憶體的成員(如line類之中的ptr指標),則會出現記憶體安全的問題。同時對於類的封裝性也是一種變相破壞,因為淺拷貝只是單純拷貝了該成員的記憶體位址,但所指向的空間內容並沒有複製,而是由兩個物件共用,就容易出現double free等問題。所以此時就要手動過載拷貝建構函式,實現深拷貝

3、賦值函式

許多文章,部落格喜歡把line& operator=(const line &obj)過載=操作符的函式稱之為賦值建構函式。個人認為其實是不準確的,會產生乙個理解誤區。其實過載的=操作符就是乙個賦值函式。

賦值函式:是把乙個新的物件賦值給乙個原有的物件,如果原來的物件中有記憶體分配需要先把記憶體釋放掉。如果我們沒有在類之中顯式過載對應類的賦值函式,c++編譯器也會預設生成對應的賦值函式。生成的規則與拷貝建構函式類似,也是一種淺拷貝的形式。所以我們過載賦值函式的原因也與拷貝建構函式型別,需要實現深度賦值。

由上文的**也可以看出,賦值函式與拷貝建構函式定義的內容之中,所做的工作大同小異。唯一需要注意的點是:在賦值函式之中需要檢察一下兩個物件是不是同乙個物件,如果是,不做任何操作,直接返回。

所以現在回頭再來看看前文的**,我們應該可以理解c++編譯器呼叫不同函式的理由了:

當物件不存在,且用別的物件來初始化,此時呼叫的便是拷貝建構函式。而當物件已經存在,用別的物件來給它進行賦值操作時,呼叫的就是賦值函式了。 

最後的小tips:一旦在類之中宣告了拷貝建構函式與賦值函式,編譯器將不會生成預設的對應函式。所以我們可以通過將拷貝建構函式和賦值函式宣告為私有函式,來阻止編譯器生成的預設函式,在編譯階段來拒絕不安全的淺拷貝。

好的,關於拷貝建構函式與賦值函式,就先寫到這裡。 

複製建構函式和賦值運算子

進行c 類設計時,如果不對複製建構函式和賦值運算子進行重寫的話,編譯器會預設呼叫預設函式。預設的複製建構函式和賦值運算子會造成許多問題。先看下面一段 include include class my string int my string num string 0 my string my str...

12 1 複製建構函式和賦值運算子

特點 靜態資料成員,永遠只建立乙個儲存空間,所有物件共享,可以用來判斷建立了多少個物件的功能。在類的宣告時不分配記憶體 靜態類成員不是物件的組成部分 例項 class badstring 若要實現計數建立物件個數,則建構函式可以為 badstring badstring char n,int a 初...

C 複製建構函式和賦值運算子過載函式

宣告乙個空的類testsize,sizeof testsize 為1,為其宣告建構函式和析構函式,依舊為1 建構函式不能使用關鍵字virtual,析構函式可以 一旦類中存在虛函式,就會為該類生成虛函式表,並在每乙個例項中新增乙個指向虛函式表的指標,從而大小為乙個指標大小,32位機器上為4,64位機器...