日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++构造函数以及类中变量初始化顺序

發布時間:2025/7/25 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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++构造函数以及类中变量初始化顺序的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。