生活随笔
收集整理的這篇文章主要介紹了
c++构造函数以及类中变量初始化顺序
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
c++構造函數(shù)以及類中變量初始化順序
Submitted by?
ant ?on?
Fri, 03/29/2013 - 20:05 構造函數(shù) c++ 的類提供了一種抽象機制,使用起來要比 c 方便很多。為了安全等,c++ 中的每一個對象都要經(jīng)過構造,跑出作用域之外的對象(非 free-store 上的)都要析構,不管是使用自定義的構造/析構函數(shù)也好,還是使用默認的。為了對象的正確拷貝構造或是賦值,me 們要自己寫拷貝構造函數(shù)/拷貝賦值,為了所謂的效率,還得自己寫移動構造函數(shù)/移動賦值。默認生成的若干個函數(shù)有:
Test(); // 默認構造函數(shù),可以不帶參數(shù)的構造函數(shù),T t;
Test(Test& t); // 拷貝構造函數(shù),T t2 = t;
Test(Test&& t); // 移動構造函數(shù),T t3 = fun(); fun() 返回一個 T 的臨時對象
Test& operate=(Test& t); // 拷貝賦值,t3 = t2;
Test& operate=(Test&& t); // 移動賦值,t2 = fun();
~Test(); // 析構函數(shù)
默認構造函數(shù)比較簡單,兩個移動 (move) 函數(shù)是 c++11 中加入的,其實也可以先不關心,拷貝賦值也先不關心,就說拷貝構造函數(shù),神馬時候會調(diào)用的問題,根據(jù) wiki 的說法:
直接使用一個對象構造一個對象,如 T t2 = t; 或是 T t2(t); 將一個對象以值(不是引用)的形式遞給一個函數(shù),比如 test(t); 將函數(shù)中的一個對象的值(不是引用)傳遞出函數(shù)外,比如 fun(); throw 一個對象,catch 一個對象的值(不是引用); 基本規(guī)則是上面說的,但是卻不是總是那樣,據(jù)說 c++標準允許編譯器優(yōu)化拷貝,實際上 gcc 在函數(shù)返回值是否拷貝的問題上很多時候跟 vc++ 就不一致。有一項技術叫 RVO (return value optimization ) —— 返回值優(yōu)化,貌似就是說的那個。me 的實際運行結果是:gcc 在函數(shù)返回一個對象的值的時候可能不調(diào)用拷貝構造函數(shù)/移動構造函數(shù),而 vc++ 就要循規(guī)蹈矩得多一些,雖然說是數(shù)據(jù)多拷了幾次。 真的是 maybe,即使是 vc++ 在函數(shù)中直接 return T(); 和 Test t; return t; 結果都可能不一樣,gcc 中的結果可能更離奇一點。
很多時候真不用關心這一點細節(jié)問題,拷貝也不會出什么問題。不過拷貝構造 maybe 有“副作用”,比如不是等值拷貝,而是放大一倍拷貝,這個時候,如果拷貝構造函數(shù)調(diào)用的次數(shù)都不一樣,程序結果可能就不一樣,實際上是,結果的確就不一樣!所以,拷貝還是盡可能遵循原有的“語義”,等值拷貝,否則都是合法的 c++程序,在 vc 和 gcc 中結果不一樣讓人有些驚訝!
現(xiàn)在說,移動構造的問題,可以先看下右值引用。有了移動構造的話,有時候就影響拷貝構造,比如 T t=fun(); 以前肯定會說是調(diào)用“拷貝構造函數(shù)”,現(xiàn)在就不一定了,可能就是“移動構造函數(shù)”了,也就是直接將返回來的臨時對象,作為新構造的對象使用;而按其那面 gcc 的邏輯,可能這里神馬“構造函數(shù)”都不調(diào)用,因為就沒有構造!如果說對于 A a = testA(); 會調(diào)用“移動構造”,而 B b = testB(); 卻不調(diào)用“移動構造”,這也令 me 很震驚,都是返回一個臨時對象,都有移動構造函數(shù),為嘛有時候就調(diào)用,有時候就不調(diào)用?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++ 中類變量的初始化順序,大體如下:
基類的靜態(tài)成員初始化; 派生類的靜態(tài)成員初始化; 基類的對象成員初始化; 基類的構造函數(shù); 派生類的對象成員初始化; 派生類的構造函數(shù); 貌似 c++11 允許類中變量直接初始化,跟 Java 的使用方法類似,me 么試過。其次,類中對象成員的初始化順序跟構造函數(shù)中初始化列表的順序無關,只跟聲明時候的順序有關。
測試程序:
#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++构造函数以及类中变量初始化顺序 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。