拷貝構造函數是C++獨有的一種特殊的構造函數,以同型對象初始化自我對象。ios
拷貝構造函數是一種特殊的構造函數,具備單個形參,該形參(經常使用const修飾)是對該類類型的引用。當定義一個新對象並用一個同類型的對象對它進行初始化時,將顯示使用拷貝構造函數。當該類型的對象傳遞給函數或從函數返回該類型的對象時,將隱式調用拷貝構造函數。c++
拷貝構造函數是一種特殊的構造函數,它在建立對象時,是使用同一類中以前建立的對象來初始化新建立的對象。拷貝構造函數一般用於:函數
若是用戶沒有定義拷貝構造函數,可是調用了拷貝構造函數,那麼編譯器會自動生成一個默認的拷貝構造函數。可是若是本身定義了拷貝構造函數,編譯器則不在生成。this
最多見的形式以下:spa
classname (const classname& obj){ // code here }
下面對三種調用拷貝構造函數的狀況進行一一說明:code
#include <iostream> using namespace std; class Student { public: Student(); // default構造函數 Student(const Student& obj); // 拷貝構造函數 int getNumber(); private: int number; }; // 定義默認構造函數 Student::Student(){ this->number = 0; cout << "default constructor" << endl; } // 定義拷貝構造函數 Student::Student(const Student& obj) { this->number = obj.number; cout << "copy constructor" << endl; } int Student::getNumber() { return this->number; } int main(){ Student s1; // 調用默認構造函數 Student s2(s1); // 調用拷貝構造函數 Student s3 = s2; // 調用拷貝構造函數 cout << s1.getNumber() << endl; cout << s2.getNumber() << endl; cout << s3.getNumber(); return 0; } /* Output default constructor copy constructor copy constructor 0 0 0 */
這裏建立了三個對象,s1 s2 s3。對象
s1是調用了默認的構造函數,number爲0。字符串
s2是調用了拷貝構造函數,傳入了s1,複製了s1的number,輸出了"copy constructor"。get
s3的建立是一種特殊的調用拷貝構造函數的方法。注意,若是有一個新對象被建立,那麼必定會調用構造函數。這裏就是傳入了s2到咱們定義的拷貝構造函數裏。編譯器
可見,經過使用另外一個同類型的對象來初始化新建立的對象,拷貝構造函數的用處是很明顯的。
拷貝構造函數是一個很是重要的函數,其之因此重要,是由於它定義了一個對象如何以值傳遞給函數。
試想以下代碼:
#include <iostream> using namespace std; class Student { public: Student(); // default構造函數 Student(const Student& obj); // 拷貝構造函數 int getNumber(); private: int number; }; // 定義默認構造函數 Student::Student(){ this->number = 0; cout << "default constructor" << endl; } // 定義拷貝構造函數 Student::Student(const Student& obj) { this->number = obj.number; cout << "copy constructor" << endl; } int Student::getNumber() { return this->number; } // 輸出某個對象的number void showNumber(Student a) { cout << a.getNumber(); } int main(){ Student s; // 調用默認構造函數 showNumber(s); return 0; }
你認爲輸出結果會是什麼?首先確定會輸出一個"default constructor",由於s的默認構造函數輸出了該字符串。那麼,showNumber()會輸出什麼呢?正確的輸出是:
default constructor copy constructor 0
這就回到了咱們開頭的那句話,拷貝構造函數定義了一個對象如何以值傳遞給函數。
在函數showNumber()中,參數a是以值傳遞的方式傳入的。因此主函數中調用showNumber()時,對象s被複制到了形參a當中。這個複製操做是經過調用了拷貝構造函數完成的,因此調用了自身的拷貝構造函數,天然會輸出一遍"copy constructor"。
至關於執行了這樣一個操做
Student a(s);
等待showNumber()結束以後,再析構a這個對象。
這也就是爲何傳遞用戶自定類型一般用引用傳遞,同時也解釋了,爲何拷貝構造函數傳參爲何是引用傳參?
設想,若是拷貝構造函數這麼寫,會發生什麼?
Student (const Student obj);
假設有個Student對象s。我值傳遞s進入了拷貝構造函數,那麼按照以前所說,編譯器會去申請一個空間給形參obj,同時調用自身的拷貝構造函數把s的數據成員的值傳給obj。可是這個調用拷貝構造函數的過程,又是一個值傳遞,又須要開闢一個空間....
因此,只要以值傳遞的方式調用拷貝構造函數,就會申請空間,申請空間的過程當中又會申請空間,又申請空間的過程又又申請空間。如此往復,會陷入無限套娃的死循環。
因此拷貝構造函數必定不能是值傳遞。
返回類型爲類對象的函數,若是返回類型不是引用,在執行return時,會建立一個臨時對象,並調用拷貝構造函數給這個臨時對象賦值。
#include <iostream> using namespace std; class Student { public: Student(); // default構造函數 Student(const Student& obj); // 拷貝構造函數 int getNumber(); private: int number; }; // 定義默認構造函數 Student::Student(){ this->number = 0; cout << "default constructor" << endl; } // 定義拷貝構造函數 Student::Student(const Student& obj) { this->number = obj.number; cout << "copy constructor" << endl; } int Student::getNumber() { return this->number; } Student returnS() { Student s; return s; } int main(){ cout << returnS().getNumber(); return 0; } // output /* default constructor copy constructor 0 */
咱們在函數returnS()中,建立了局部對象s。s在建立的時候,調用了默認的構造函數,輸出"default constructor"。然而在return的時候,調用了拷貝構造函數,建立了一個看不見的對象,因此再次輸出"copy constructor"。
因此,咱們能夠經過返回類對象的引用,這樣就會返回現存對象,而不是臨時建立的對象。(固然,局部變量是不能夠引用傳回的,臨時變量在函數結束時銷燬,引用爲空)