複製建構函式:只有單個形參,而且形參是對本類類型對象的引用(常用const修飾),這樣的建構函式稱為複製建構函式。與預設建構函式一樣,複製建構函式可由編譯器隱式調用。複製建構函式可以用於:
- 根據另一個同類型的對象顯式或隱式初始化一個對象
- 複製一個對象,將它作為實參傳給一個函數
- 從函數返回時複製一個對象
- 初始化順序容器中的元素
- 根據元素初始化列表初始化數組元素
賦值操作符:與複製建構函式一樣,如果沒有定義自己的賦值操作符,則編譯器會合成一個。
下面我寫了一個程式對以上描述做出解釋。
#include<iostream>#include<string>#include<vector>using namespace std;class Test{public:Test(){str="Kevin";x=10;cout<<"default constructor"<<endl;}//construction functionTest(const Test& t){str=t.str;x=t.x; cout<<"copy construction was used!"<<endl;}//copy constructor Test& operator=(const Test& t){str=t.str;x=t.x;cout<<"operator="<<endl;return *this;}private:string str;int x;};Test f(Test t){cout<<"f function"<<endl;return t;}main(){cout<<"Test t:"<<endl;Test t;cout<<endl<<"vector<Test> vec1(5):"<<endl;vector<Test> vec1(5);cout<<endl<<"vector<Test> vec2(5,t):"<<endl;vector<Test> vec2(5,t);cout<<endl<<"Test te[5]:"<<endl;Test te[5];cout<<endl<<"Test t2(t):"<<endl;Test t2(t);cout<<endl<<"f(t2):"<<endl;f(t2);cout<<endl<<""<<endl;Test* p1=new Test();*p1=t;Test* p2=&t;Test t3=t;Test t4;t4=t;}
以上程式的輸出結果是:
default constructorvector<Test> vec1(5):default constructorcopy construction was used!copy construction was used!copy construction was used!copy construction was used!copy construction was used!vector<Test> vec2(5,t):copy construction was used!copy construction was used!copy construction was used!copy construction was used!copy construction was used!Test te[5]:default constructordefault constructordefault constructordefault constructordefault constructorTest t2(t):copy construction was used!f(t2):copy construction was used!f functioncopy construction was used!default constructoroperator=copy construction was used!default constructoroperator=
由上面程式中的第26行可以看出,複製建構函式被用於初始化容器元素的時候,如果沒有之處元素的初始值,則編譯器會首先調用預設的建構函式建立一個臨時制,然後使用複製建構函式將臨時制複製到每一個元素中。當指明了元素的初始值(如29行所示)時,編譯器會直接將其複製到每一個元素。
由程式中第32行的運行結果可以看出,定義一個類類型的數組時,編譯器會利用類的預設建構函式初始化每一個元素。
由程式中第38行的運行結果可以看出,當類類型被用做形參與傳回值時,各自發生了一次複製。C++ primer中這樣描述:“當函數的形參為非參考型別的時候,將複製實參的值。類似的,以非參考型別做傳回值時,將返回return語句中的值的副本”。按照我的理解就是“當形參和傳回值都不是引用時,進入函數時發生一次複製,離開函數時發生一次複製”。
程式的第41行至第46行是為了說明複製建構函式與賦值操作符的區別設計的。我們可以看到*p1=t;這一句用到了賦值操作符,t4=t;這一句也用到了賦值操作符,其他各種形式的語句都用的是複製建構函式。從中可以總結出一句話“從無到有是copy,從有到有是賦值”。這句話怎麼理解呢?大家看,*p1=t這一句中的*p是早已經聲明了的,在*p1聲明的時候已經完成了它的初始化。在*p1=t這句中*p是已經初始化過的,所以這裡*p1=t應用的是賦值操作符。同理第46行的中的t4也是一個已經聲明過,完成了初始化的變數,所以在語句t4=t中使用的也是賦值操作符。而在Test t3=t;
這樣的語句中,t3是剛剛聲明出來的,還沒有初始化,要求編譯器按照t的內容初始化t3。這正好是複製建構函式的作用。