一、什麼是拷貝建構函式?
1.對於一個類X,如果一個建構函式的第一個參數是下列之一:
a)X&
b)const X&
c)volatile X&
d)const volatile X&
且沒有其他參數或其他參數都有預設值,那麼這個函數是拷貝建構函式。
按此定義,以下均為類X的拷貝建構函式:
X::X(const X&);
X::X(X&, int=1);
有一點需要注意,這些建構函式必須使用引用,而不能使用普通變數。因為如果使用普通變數,那麼在傳參數的時候需要根據實參構造一個新的對象,而構造這個對象必須調用拷貝建構函式,而拷貝建構函式又需要構造一個對象,這樣無限迴圈就無法構造了。(參考c++primer題解中的某一題)
一個類中允許有多餘一個的拷貝建構函式。
二、拷貝建構函式與operator=的區別?
如果在對象定義時初始化,那麼會調用拷貝建構函式,不管用=還是()初始化都是如此。
然而當對象已經構造完畢,這時將一個對象賦值給另外一個對象時,就會調用operator=。
也許有人會問,為什麼對於以下語句
X x;
x = 4;
會調用建構函式X(int),而x = x就不會?
只要搞清楚賦值過程,這個問題不難回答。
我們知道,x=4實際上等價於x.operator=(4),這時編譯器會進行函數參數解析。我們雖然沒有顯式重載=操作符,但是編譯器會偷偷為我們提供operator=(const X&)(參考effective c++ 2nd條款45),於是編譯器會嘗試將4從int型轉換為const X &類型。又因為我們提供了X(int),因此這個類型轉換可以完成,類型轉換完成後,再通過operator=(const X&)完成賦值操作。也就是說,對於x=4,編譯器實際上將其展開為如下形式:
const X temp(4);
x = temp;
我們可以寫這樣的代碼來測試一下:
#include <iostream><br />#include <string><br />using namespace std;<br />class A{<br />public:<br /> A(){}<br /> A(int a){cout<<"ctor int"<<endl;}<br /> A &operator=(const A &a){cout<<"operator= A&"<<endl;return *this;}<br />};<br />int main()<br />{<br /> A a;<br /> a = 4;<br /> return 0;<br />}<br />
輸出結果為
ctor int
opeartor= A&
完全印證了上面先構造後賦值的說法。注意上面如果拷貝建構函式中不帶const則無法通過編譯。
那麼如果提供了operator=(int)又會是什麼結果呢?
如果上面的解析看明白了這裡很容易知道結果。
這種情況下operator=(int)是精確匹配的函數,而調用opeator=(X&)其實是一個自訂類型轉換然後調用operator=(const X &)的過程,因此自然會優先調用精確匹配的operator=(int)。
而對於x=x,因為編譯器總是提供預設的X &operator=(const X&) ,因此無法使用拷貝建構函式來進行非初始化的賦值操作。
本文參考:
1.http://cpp-circle.group.javaeye.com/group/blog/43289
2.c++primer 中文第三版