復制構造函數、賦值操作符和析構函數總稱為復制控制。編譯器自動實現這些操作,但類也可以定義自己的版本。
實現復制控制操作最困難的部分,往往在于識別何時需要覆蓋默認版本。有一種特別常見的情況需要類定義自己的復制控制成員:類具有指針成員。
一、復制構造函數
特點:只有單個形參;該形參是對本類型對象的引用(const T&)。
復制構造函數可以用于:
1. 根據另一個同類型的對象顯式或隱式地初始化一個對象。
2. 復制一個對象,將它作為實參傳給一個函數。
3. 從函數返回時復制一個對象。
4. 初始化順序容器中的元素。
5. 根據元素初始化式列表初始化數組元素。
1.1、初始化:復制初始化和直接初始化
int i(1024); ? ? ?//direct initialization.
? ? ? int a = 1024; ? //copy initialization.
兩者之間的不同:
直接初始化直接調用與實參匹配的構造函數;復制初始化總是調用復制構造函數。復制初始化首先使用指定構造函數創建一個臨時對象,然后用復制構造函數將那個臨時對象復制到正在創建的對象:
string null_book = "aaaaaaaaaa"; ? ? ? ? ? //copy initialization
string dot(10, '.'); ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //direct initialization
string empty_copy = string(); ? ? ? ? ? ? ? //copy
string empty_direct; ? ? ? ? ? ? ? ? ? ? ? ? ? ? //direct
1.2、形參與返回值
正如我們所知,當形參為非飲用類型的時候,將復制實參的值。類似地,以非引用類型作為返回值時,將返回return語句中的副本。
當形參或返回值為類類型時,由復制構造函數進行復制。當形參或返回值為類型引用時,不能復制。如:
? ? ? //copy constructor used to copy the return value.
? ? ? //parameters are references, so they aren't copied.
string make(size_t, const string&, const string&);
1.3、合成的復制構造函數
如果我們沒有定義復制構造函數,編譯器就會為我們合成一個。
與合成的默認構造函數不同,即使我們定義了其他構造函數,也會合成復制構造函數。合成復制構造函數的行為是:執行逐個成員(非static 成員)初始化,將對新對象初始化為原對象的副本。
例如:
class Sales_item { private:str::string isbn;int sold;double revenue; }合成復制構造函數如下:Sales_item::Sales_item(const Sales_item&obj) {isbn(obj.isbn); //uses string copy construtor sold(obj.sold);revenue(obj.revenue); }
?
二、禁止復制
有的類需要完全禁止復制。例如:iostream類。
如果復制構造函數是private的,將不會允許用戶代碼復制該類類型的對象,編譯器將拒絕任何進行復制的嘗試。
然而,友元和成員仍可以進行復制。如果想要連友元和成員中的復制也禁止,就可以聲明一個private復制構造函數但不對其定義。
這是因為:聲明而不定義成員函數是合法的,但是,使用未定義的成員的任何嘗試將導致鏈接失敗。
?