複製構造函數:只有單個形參,而且形參是對本類類型對象的引用(常用const修飾),這樣的構造函數稱爲複製構造函數。與默認構造函數一樣,複製構造函數可由編譯器隱式調用。複製構造函數可以用於:
- 根據另一個同類型的對象顯式或隱式初始化一個對象
- 複製一個對象,將它作爲實參傳給一個函數
- 從函數返回時複製一個對象
- 初始化順序容器中的元素
- 根據元素初始化列表初始化數組元素
下面我寫了一個程序對以上描述做出解釋。
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Test
{
public:
Test(){str="Kevin";x=10;cout<<"default constructor"<<endl;} //construction function
Test(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 constructor
vector<Test> vec1(5):
default constructor
copy 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 constructor
default constructor
default constructor
default constructor
default constructor
Test t2(t):
copy construction was used!
f(t2):
copy construction was used!
f function
copy construction was used!
default constructor
operator=
copy construction was used!
default constructor
operator=
由上面程序中的第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。這正好是複製構造函數的作用。