7月26日更新:html
過了這麼長的時間回過頭來看,發現文章中有幾個點說錯(用紅字標出):數組
《《=========================================================================》》函數
C++類用三個特殊的成員函數:複製構造函數、賦值操做符和析構函數 來決定類對象之間的初始化或賦值時發生什麼。所謂的「複製控制」即經過這三個成員函數控制對象複製的過程。本篇文章將介紹複製構造函數。spa
複製構造函數是什麼指針
複製構造函數首先是一個構造函數,它同全部其餘的構造函數同樣與類同名,沒有返回值。它有一個惟一的參數(錯誤),是該類類型的引用(通常將它聲明爲const,源於用於賦值的對象通常不用改變它自己的值)。因而複製構造函數的原型爲:code
class BOOK { public: BOOK(const BOOK& rhs); //構造函數一 BOOK(string &name,float price = 0):_bookName(name),_price(price){}; //構造函數二 BOOK():_price(0),_bookName(""){}; //構造函數三
private: float _price ; string _bookName; //.... };
何時被調用htm
複製構造函數在須要複製類對象的時候被調用,這些調用狀況能夠總結爲:對象
當定義一個新對象並用一個同類型的對象對它進行初始化的時候,將顯式使用複製構造函數,如:blog
BOOK book1;
BOOK book2(book1);
當將該類型的對象傳遞給函數或從函數返回該類型的對象時,將隱式地調用複製構造函數。ci
如:
vector<string> svec(5);
編譯器首先調用string類默認構造函數建立一個臨時值,再用複製構造函數將臨時值複製到每個元素。
如:
BOOK books[]={ string("book1"), string("book2"), string("book3"), BOOK() };
book數組的前三個元素將調用構造函數二進行隱式類型轉換(C++隱式類型轉換),而後調用複製構造函數進行數組元素的複製。若是類禁止隱式類型轉換(構造函數使用了explicit聲明),或但願不指定實參或多個實參,須要使用完整的構造函數語法,如數組最後一個元素的初始化。
若是沒有爲類聲明覆制構造函數會怎樣
若是你沒有聲明一個複製構造函數,那麼編譯器會給聲明一個。實際上,若是你本身沒有聲明,編譯器會爲類聲明一個複製構造函數 ,一個賦值操做符以及一個析構函數,此外若是你沒有聲明任何構造函數的話,編譯器也會爲你聲明一個合成默認構造函數。(錯誤)全部這些編譯器自動生成的類成員函數皆爲pubilc 且 inline。(這部份內容能夠參考《Effective C++》條款05)編譯器建立的複製構造函數單純地未來源對象的每個非static成員拷貝到目標對象,這在不少時候是不能知足類需求的,特別是類中含有指針時,這時候就須要咱們本身來寫複製控制的三個特殊成員函數了。
編譯器合成的複製構造函數作了什麼
合成複製構造函數的行爲是:對每個非static成員進行逐個成員初始化。成員類型不一樣,初始化方式不同:
內置類型(如int):直接複製值。
類類型:調用該類的複製構造函數進行復制。
數組:這個比較特殊,由於咱們知道通常不能複製數組,但在類中,複製數組時合成複製構造函數將複製數組的每個值。
另外,合成複製構造函數對類數據成員的初始化都是放在構造函數初始化列表中進行的。
禁止複製
若是咱們想禁止某個類的複製行爲,咱們固然不會想去定義一個複製構造函數,然而編譯器卻會自動爲咱們定義一個,那麼到底該如何阻止一個類的複製行爲呢?
咱們能夠將複製構造函數定義爲private,不容許用戶代碼複製該類類型的對象,若進行復制將在編譯時發生錯誤。然而類的友元和成員仍能夠進行復制,解決辦法是咱們能夠聲明一個private複製構造函數卻不進行定義,類成員或友元進行復制嘗試時,將在程序運行時發生錯誤。
總結:爲駁回編譯器自動提供的機能,可將相應的成員函數聲明爲private而且不予實現。(具體可參考《Effective C++》條款06 若不想使用編譯器自動生成的函數,就該明確拒絕)