1. 程式人生 > >C++中類的建構函式與複製建構函式

C++中類的建構函式與複製建構函式

1 相關定義

1.1 建構函式

建構函式是類的特殊的成員函式,只要建立類型別的新物件,都要執行建構函式。建構函式的工作是保證每個物件的資料成員具有合適的初始值。建構函式的名字與類的名字相同,並且不能指定返回型別。像其他任何函式一樣,它們可以沒有形參,也可以定義多個形參。

1.2 複製建構函式

複製建構函式是一種特殊建構函式,具有單個形參,該形參(常用const修飾)是對該類型別的引用。當定義一個新物件並用一個同類型的物件對它進行初始化時,將顯式使用複製建構函式。

2 兩種初始化方式

C++支援兩種初始化方式:直接初始化和複製初始化。

2.1 兩種初始化方式的實現

複製初始化使用=符號,而直接初始化將初始化式放在圓括號中。

自定義一個名為MyClass的類。並且定義MyClass類的預設建構函式、自定義建構函式和複製建構函式。

class MyClass
{
public:
MyClass()
{
cout << "進入MyClass的預設建構函式" << endl;
}
MyClass(const char* pc)
{
cout << "進入MyClass自定義建構函式" << endl;
}
MyClass(const ClassTest& ct)
{
cout << "進入MyClass複製建構函式" << endl;
}
};

接下來使用直接初始化和複製初始化定義MyClass類的物件:

MyClass mc1(“myclass”);
MyClass mc2 = mc1;

執行後的效果如圖所示

 

從上圖可以看出,第1行程式碼呼叫了MyClass類的自定義建構函式,第2行程式碼呼叫了MyClass類的複製建構函式。

2.2 兩種初始化方式的關係

對於MyClass類物件的定義,還有一種方式,如下所示

MyClass mc3 = “myclass”;

這種定義方式是採用了哪種初始化呢?《C++ Primer中文版第4版》P407頁提到,以上這種定義方式,“編譯器首先呼叫接受一個C風格字串形參的建構函式,建立一個臨時物件,然後,編譯器使用複製建構函式將類的物件初始化為那個臨時物件的副本”。也就是說,以上程式碼應該呼叫了

MyClass類的兩個建構函式,一個是自定義的引數為const char*的建構函式,一個是複製建構函式。然而,程式執行後的效果如圖所示

 

此時,只調用了MyClass類的自定義函式,而沒有呼叫複製建構函式。產生這個現象的原因,在網路上有朋友提到“主要原因在於編譯器的優化,當複製建構函式是public時,編譯器就會根據這個特性來對程式碼進行優化。當程式執行時,編譯器發現複製建構函式是public,則說明程式允許物件之間的複製,此時就會通過直接呼叫自定義建構函式來初始化物件,而不再呼叫複製建構函式,完成優化”。這位朋友還提到,如果將複製建構函式改為private,此時如下程式碼

MyClass mc3 = “myclass”;

編譯時就會報錯。

但是,至少在VC++6.0及以上版本的編譯器中,並不是這樣的。在VC++6.0/VS2005/VS2008/VS2010/VS2015中進行測試,當將MyClass類的複製建構函式改為private後,上述程式碼編譯時並不報錯,而且都僅顯示“呼叫了自定義建構函式”。這就說明,至少在VC++6.0/VS2005/VS2008/VS2010/VS2015的編譯器當中,如下程式碼

MyClass mc3 = “myclass”;

並沒有像《C++ Primer中文版第4版》中提到的那樣,呼叫了兩次建構函式,而是隻呼叫了自定義的建構函式。可以說,在VC++6.0/VS2005/VS2008/VS2010/VS2015

MyClass mc1(“myclass”);

MyClass mc3 = “myclass”;

是等價的。

3 編譯器優化

VC++6.0/VS2005/VS2008/VS2010/VS2015中進行測試時,確實發現了在“2.2”中提到的編譯器優化問題。對於如下程式碼

MyClass mc4 = MyClass();

VC++6.0中進行測試時,執行結果顯示編譯器先呼叫MyClass類預設建構函式,之後呼叫複製建構函式;而在VS2005/VS2008/VS2010/VS2015中則只顯示編譯器呼叫了預設建構函式。並且如果將複製建構函式設定為private,編譯器會報錯,如下所示:

 error C2248: ClassTest::ClassTest: 無法訪問 private 成員(在“ClassTest”類中宣告)

這就說明,在VS2005/VS2008/VS2010/VS2015中,編譯器進行了優化,當發現複製建構函式是public時,直接呼叫預設建構函式。而當複製建構函式是private時,就會報錯。