生活随笔
收集整理的這篇文章主要介紹了
c++构造函数以及类中变量初始化顺序
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
c++構造函數以及類中變量初始化順序
Submitted by?
ant ?on?
Fri, 03/29/2013 - 20:05 構造函數 c++ 的類提供了一種抽象機制,使用起來要比 c 方便很多。為了安全等,c++ 中的每一個對象都要經過構造,跑出作用域之外的對象(非 free-store 上的)都要析構,不管是使用自定義的構造/析構函數也好,還是使用默認的。為了對象的正確拷貝構造或是賦值,me 們要自己寫拷貝構造函數/拷貝賦值,為了所謂的效率,還得自己寫移動構造函數/移動賦值。默認生成的若干個函數有:
Test(); // 默認構造函數,可以不帶參數的構造函數,T t;
Test(Test& t); // 拷貝構造函數,T t2 = t;
Test(Test&& t); // 移動構造函數,T t3 = fun(); fun() 返回一個 T 的臨時對象
Test& operate=(Test& t); // 拷貝賦值,t3 = t2;
Test& operate=(Test&& t); // 移動賦值,t2 = fun();
~Test(); // 析構函數
默認構造函數比較簡單,兩個移動 (move) 函數是 c++11 中加入的,其實也可以先不關心,拷貝賦值也先不關心,就說拷貝構造函數,神馬時候會調用的問題,根據 wiki 的說法:
直接使用一個對象構造一個對象,如 T t2 = t; 或是 T t2(t); 將一個對象以值(不是引用)的形式遞給一個函數,比如 test(t); 將函數中的一個對象的值(不是引用)傳遞出函數外,比如 fun(); throw 一個對象,catch 一個對象的值(不是引用); 基本規則是上面說的,但是卻不是總是那樣,據說 c++標準允許編譯器優化拷貝,實際上 gcc 在函數返回值是否拷貝的問題上很多時候跟 vc++ 就不一致。有一項技術叫 RVO (return value optimization ) —— 返回值優化,貌似就是說的那個。me 的實際運行結果是:gcc 在函數返回一個對象的值的時候可能不調用拷貝構造函數/移動構造函數,而 vc++ 就要循規蹈矩得多一些,雖然說是數據多拷了幾次。 真的是 maybe,即使是 vc++ 在函數中直接 return T(); 和 Test t; return t; 結果都可能不一樣,gcc 中的結果可能更離奇一點。
很多時候真不用關心這一點細節問題,拷貝也不會出什么問題。不過拷貝構造 maybe 有“副作用”,比如不是等值拷貝,而是放大一倍拷貝,這個時候,如果拷貝構造函數調用的次數都不一樣,程序結果可能就不一樣,實際上是,結果的確就不一樣!所以,拷貝還是盡可能遵循原有的“語義”,等值拷貝,否則都是合法的 c++程序,在 vc 和 gcc 中結果不一樣讓人有些驚訝!
現在說,移動構造的問題,可以先看下右值引用。有了移動構造的話,有時候就影響拷貝構造,比如 T t=fun(); 以前肯定會說是調用“拷貝構造函數”,現在就不一定了,可能就是“移動構造函數”了,也就是直接將返回來的臨時對象,作為新構造的對象使用;而按其那面 gcc 的邏輯,可能這里神馬“構造函數”都不調用,因為就沒有構造!如果說對于 A a = testA(); 會調用“移動構造”,而 B b = testB(); 卻不調用“移動構造”,這也令 me 很震驚,都是返回一個臨時對象,都有移動構造函數,為嘛有時候就調用,有時候就不調用?O__O"…竟然跟里面是神馬變量有關?!!!可以修改下面的程序,自己看運行結果:(移動構造是 c++11 新加的,gcc 編譯的話,需要加上 -std=c++11,or =std=c++0x)。
#include <iostream> using ?namespace ?std; class ?Test{ public : Test( ) { ?value?= ?0 ; ??cout ?<< ?"default constructor." ?<< ?"\n " ; ?} Test( Test& ?t) { ??value?= ?42 ; ?cout ?<< ?"non-const copy constructor." ?<< ?"\n " ; ?} ?? ?// can modify t.value ! Test( const ?Test& ?t) { ?? ?cout ?<< ?"const copy constructor." ?<< ?"\n " ; ?} Test( Test&& ?t) : ?value( t.value ) { ?cout ?<< ?"move constructor." ?<< ?"\n " ; ?} ~Test( ) { ???cout ?<< ?"destructor." ?<< ?"\n " ; ?} int ?getValue( ) { ?return ?value; ?} ; private : int ?value; } ; Test fun( Test tmp) { Test a; return ?a; } int ?main( ) { Test a; cout ?<< ?"a.value:" ?<< ?a.getValue ( ) ?<< ?"\n " ; Test b?= ?fun( a) ; cout ?<< ?"b.value:" ?<< ?b.getValue ( ) ?<< ?"\n " ; Test c?= ?a; cout ?<< ?"c.value:" ?<< ?c.getValue ( ) ?<< ?"\n " ; return ?0 ; } 類中變量的初始化順序 c++ 中類變量的初始化順序,大體如下:
基類的靜態成員初始化; 派生類的靜態成員初始化; 基類的對象成員初始化; 基類的構造函數; 派生類的對象成員初始化; 派生類的構造函數; 貌似 c++11 允許類中變量直接初始化,跟 Java 的使用方法類似,me 么試過。其次,類中對象成員的初始化順序跟構造函數中初始化列表的順序無關,只跟聲明時候的順序有關。
測試程序:
#include <iostream> using ?namespace ?std; class ?Inner{ public : Inner( int ?i= 0 ) : ?in( i) ?{ ?cout ?<< ?"Inner.constructor." ?<< ?"\n " ; } Inner( Inner& ?inner) : ?in( inner.in ) ?{ ?cout ?<< ?"Inner.copy consturctor" ?<< ?"\n " ; } ; int ?getValue( ) { ?return ?in; ?} private : int ?in; } ; class ?Inner2{ public : Inner2( double ?i= 0.0 ) : ?in2( i) ?{ ?cout ?<< ?"Inner2.constructor." ?<< ?"\n " ; } Inner2( Inner2& ?inner2) : ?in2( inner2.in2 ) ?{ ?cout ?<< ?"Inner2.copy consturctor" ?<< ?"\n " ; } ; int ?getValue( ) { ?return ?in2; ?} private : double ?in2; } ; class ?Base{ public : Base( int ?v= 0 ) : ?value( v) ?{ ?value?= ?1 ; ?cout ?<< ?"Base.constructor." ?<< ?"\n " ; } Base( Base& ?b) : ?value( b.value ) ?{ ?cout ?<< ?"Base.copy consturctor" ?<< ?"\n " ; } int ?getValue( ) { ?return ?value; ?} protected : int ?value; } ; class ?Derive: ?public ?Base{ public : // Derive(string s = "hello", int base=0, int i=0, double i2=0): derive(s), in2(i2), in(i) { cout << "derive.derive == " << derive << ", Derive.consturctor" << "\n";}; Derive( string s?= ?"hello" ,?int ?base= 0 ,?int ?i= 0 ,?double ?i2= 0 ) { ?cout ?<< ?"Derive.consturctor" ?<< ?"\n " ; } ; Derive( Derive& ?d) : ?derive( d.derive ) ?{ ?cout ?<< ?"Derive.copy consturctor" ?<< ?"\n " ; } void ?printValue( ) { ??cout ?<< ?"derive.base.value == " ?<< ?value?<< ?", derive.derive == " ?<< ?derive?<< ?", derive.in == " ?<< ?in.getValue ( ) ?<< ?", derive.in2 == " ?<< in2.getValue ( ) ?<< ?"\n " ; ?} private : string derive; Inner in; Inner2 in2; } ; int ?main( ) { Derive d( "world" ,?10 ,?20 ,?30.0 ) ; d.printValue ( ) ; // Derive d2 = d; cout ?<< ?endl; }
總結
以上是生活随笔 為你收集整理的c++构造函数以及类中变量初始化顺序 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。