C++的複製建構函式講解

來源:互聯網
上載者:User

複製建構函式,直接初始化,複製初始化,賦值,臨時對象

  複製建構函式應弄清的幾個問題:何時調用複製建構函式,複製建構函式有何功能,為什麼要定義自已的複製建構函式。

  1.複製建構函式:當使用者沒有定義自已的複製建構函式時系統將產生一個預設的複製建構函式。當按值傳遞對象時,就會建立一個形參的臨時對象,然後調用複製建構函式把臨時對象的值複製給實參。

  2.預設複製建構函式的功能:將一個對象的非靜態成員的值逐個複製給另一個對象,注意複製的是成員的值,這種複製方式也稱為淺複製。因為靜態成員屬於整個類,而不屬於某個對象,所以調用複製建構函式時靜態成員不會受到影響。

  3.何時產生臨時對象:情形1按值傳遞對象注意是按值傳遞對象,按值傳遞意味著會建立一個原始對象的副本,

  情形2函數反回對象時。

  情形3用一個對象初始化另一個對象時即複製初始化,語句hyong x=y和hyong x=hyong(y)這裡y是hyong類型的對象。都將調用複製建構函式,但有可能建立臨時對象也有可能不建立臨時對象而用複製建構函式直接初始化對象,這取決於編譯器。

  4.臨時對象是由複製建構函式建立的,當臨時對象消失時會調用相應的解構函式。也就是說只要建立了臨時對象就會多調用一次解構函式。

  5.何時使用複製建構函式:按值傳遞對象,函數反回對象,用一個對象初始化另一個對象即複製初始化時,根據元素初始化列表初始化數組元素。這四種情況都將調用複製建構函式。記住,複製建構函式只能用於初始化,不能用於賦值,賦值時不會調用複製建構函式,而是使用賦值操作符。

  6.直接初始化:直接初始化是把初始化式放在圓括弧中的,對於類類型來說,直接初始化總是調用與實參匹配的建構函式來初始化的,

  7.複製初始化與複製建構函式:複製初始化使用=等於符號來初始化,複製初始化也是建立一個新對象,並且其初值來自於另一個已存在的對象,複製初始化總是調用複製建構函式來初始化的,複製初始化時首先使用指定的建構函式建立一個臨時對象,然後用複製建構函式將臨時對象的每個非static成員依次的複製到新建立的對象。複製建構函式執行的是逐個成員初始化。注意這裡是用一個已存在的對象建立另一個新對象,與用建構函式直接建立一個新對象不一樣,使用建構函式初始化時不會使用另一個對象。比如有類hyong,則語句hyong m(1,2)調用建構函式直接初始化,而語句hyong n=m則是用已存在的對象m去初始化一個新對象n,屬於複製初始化。

  8.理解賦值與複製初始化的區別(重點)賦值是在兩個已存在的對象間進行的,也就是用一個已存在的對象去改變另一個已存在對象的值。賦值將調用賦值操作符對對象進行操作,賦值操作符將在操作符重載中講解。比如有類hyong,有語句hyong x(1);hyong y(1,2)則x=y;這就是賦值,因為對象x和y是已經存在的對象,而語句hyong x=y;則是複製初始化,是用一個已存在的對象y去建立一個新對象x,所以是複製初始化。

  9.複製初始化和賦值是在兩個對象之間進行的操作,而直接初始化則不是。

  10.注意:使用複製建構函式不一定建立臨時對象就如語句hyong x=hyong(y),其中y是hyong類型的對象,就有可能不建立臨時對象,這取決於編譯器。這裡如果建立了臨時對象則當臨時對象消亡時將調用一次解構函式,而如果沒有調用而是直接用複製建構函式初始化對象的就不會調用解構函式。

  11.複製建構函式的形式:hyong(const hyong & obj);它接受一個指向類對象的常量引用作為參數。定義為const是必須的,因為複製建構函式只是複製對象,所以沒必要改變傳遞來的對象的值,聲明為引用可以節省時間,如果是按值傳遞的話就會產生對象的副本,會浪費資源,而引用就不會。

  12.為什麼需要定義自已的複製建構函式:如果類只包含類類型成員和內建類型的成員,則可以不用顯示定義複製建構函式。但如果類中包含有指標或者有分配其他類型資源時就必須重新定義複製建構函式。因為類中有指標成員,當把用一個對象初始化另一個對象時,這時兩個對象中的指標都指向同一段記憶體,這時如果其中一個對象被消毀了,這時對象中指標所指向的記憶體也同樣被消毀,但另一個對象確不知道這種情況,這時就會出現問題。比如hyong類中含有一個成員指標p,當聲明了hyong x=y其中y也是hyong類的對象,這時對象x和y中的指標成員p都指向同一段記憶體,而如果y被消毀,但x還沒被消毀時就會出問題,這時y中對象的成員指標p已經釋放了該記憶體資源,而x中的成員指標p還不知道已經釋放了該資源,這時就會出問題。因為對象x和y中的成員指標共用同一段記憶體,所以對y中的成員指標p的修改就會影響到對象x中的成員指標。所有這些情況都需要重定義複製建構函式來顯示的初始化成員的值,這種初始化方式也被稱為深度複製。

  13.如果顯示定義了複製建構函式則調用顯示複製建構函式來直接初始化對象,如果沒有顯示定義複製建構函式,則調用預設的複製建構函式直接初始化對象。

  14.注意:1在VC++中語句hyong n=m不產生臨時對象,但如果顯示定義了複製建構函式則調用顯示複製建構函式來直接初始化對象n,如果沒有顯示定義複製建構函式,則調用預設的複製建構函式直接初始化對象n。

  2.在VC++中語句hyong m1=hyong(m)有可能產生臨時對象也有可能不產生臨時對象,如果顯示定義了複製建構函式則用複製建構函式直接初始化對象m1,不產生臨時對象。如果沒有顯示定義複製建構函式則複製建構函式將創造臨時對象,初始化對象m1

  15.C++自動提供的成員函數,有:預設建構函式,複製建構函式,預設解構函式,賦值操作符,地址操作符即this指標,這五種函數如果使用者沒有定義,則系統會自動建立一個。

  16.直接調用類中的建構函式:可以在類中的函數,類外的獨立函數,即main()函數中直接調用某一個類的建構函式,比如在main函數中可以有語句n=A(4);這裡n是類A的對象,這裡就是直接調用類A的建構函式建立一個類A的臨時對象,然後把該臨時對象的值賦給類A的對象n。在類中的函數和在類外的函數調用類的建構函式的方法和這裡類似。注意語句n.A(4)是錯誤的語句,不能由對象調用類中的建構函式。

  例:複製建構函式的使用

  class hyong

  {public: int a,b,c; hyong(){a=b=c=0;cout<<"gouchao"<<"/n";} hyong(int i){a=b=c=i;cout<<"gouchao2"<<"/n";}

  ~hyong(){cout<<"xigou"<<"/n";} hyong(const hyong &obj){a=b=c=9;cout<<"fuzi"<<"/n";} //複製建構函式。};

  void h(hyong k){cout<<"haoshu"<<k.a<<k.b<<"/n";} //按值傳遞對象

  hyong f(){hyong m3(5); return m3;} //反回對象。

  //如果顯示定義了複製建構函式則調用顯示複製建構函式來直接初始化對象,如果沒有顯示定義複製建構函式,則調用預設的複製建構函式直接初始化對象。

  int main()

  {//以下為幾種複製初始化的方式。

  hyong m(1);

  // hyong n=m和hyong m1=hyong(m)是否產生臨時對象依編譯器而定

  hyong n=m; //在VC++中此語句不產生臨時對象,調用顯示定義的複製建構函式初始化對象

  cout<<m.a<<m.b<<"/n";//輸出99

  cout<<n.a<<n.b<<"/n";//,輸出99,調用顯示定義的複製建構函式初始化對象n,而不會產生臨時對象。

  hyong m1=hyong(m); //此語句要特別注意,因為此語句有可能產生臨時對象也有可能不產生臨時對象,如果顯示定義了複製建構函式則用複製建構函式直接初始化對象m1,而不會產生臨時對象。如果沒有顯示定義複製建構函式則複製建構函式將產生臨時對象,然後對m1進行初始化。

  cout<<m1.a<<m1.b<<"/n"; //輸出輸出11,調用顯示定義的複製建構函式初始化對象m1,不產生臨時對象。如果沒有定義複製建構函式則輸出,同時會產生臨時對象,臨時對象撤消時會調用解構函式。

  hyong m2(m); cout<<m2.a<<m2.b<<"/n"; //輸出11,直接調用複製建構函式,因此不會產生臨時對象

  hyong *p=new hyong(m); cout<<p->a<<p->b<<"/n"; //不產生臨時對象,直接調用複製建構函式初始化。

  //按值傳遞和反回對象的例子。

  h(m); cout<<"kkk"<<"/n"; //按值傳遞對象m,當調用函數h時就會使用複製控制函數產生一個臨時對象,然後把這個臨時對象複製給實參,當函數調用完畢時就會撤消臨時對象,此時會調用一個解構函式,解構函式在h函數的範圍消失時才調用,也就是說在執行了h的函數體後才會調用解構函式。

  hyong m4=f(); cout<<m4.a<<m4.b<<"/n"; //輸出55,用返回的對象初始化對象m4,此語句沒有產生臨時對象,原因還不清楚,待考證,可能與語句是複製初始化有關。

  hyong m5; m5=f(); //此語句調用函數f,f反回一個對象,在反回時會調用複製建構函式產生一個臨時對象,並把這個臨時對象作為預設賦值操作符的一個參數,因此這裡不但調用了複製建構函式還調用了賦值操作符。

  cout<<m5.a<<m5.b<<"/n";

  hyong m6; m6=m; //把m的值賦給m6,注意這裡不會調用複製建構函式,也不會產生臨時對象,因為這裡會把m當成是默賦值操作符的一個參數,調用的是預設賦值操作符。}

  例:直接調用類中的建構函式

  class A {public: int a; A(){a=0;} A(int i){a=i;} ~A(){cout<<"xi"<<"/n";}

  A f(){return A(3);} }; //在類中調用類的建構函式,當該函數被對象調用時反回由建構函式A構造的一個臨時對象。

  A g() {return A(5);} //類外的函數調用類的建構函式的方法,注意,這裡是直接使用函數名的。

  int main()

  { A m(1); A n(2); n=m.f(); cout<<n.a<<"/n"; //輸出3,調用類中的f函數,f函數用建構函式反回一個臨時對象。

  n=g(); cout<<n.a<<"/n"; //輸出5,調用類外的函數g

  n=A(6); cout<<n.a; //在main函數中直接調用建構函式創造一個臨時對象,然後把這個臨時對象的值賦給對象n。

  //n.A(7); } //錯誤,不能用類的對象來調用建構函式。

 

轉至:百度百科

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.