《深度探索C++对象模型》--2 构造函数语意学
1、default constructor的構造操作
??C++standard:對于class X,如果沒有任何user-declared constructor,那么會有一個default constructor 被暗中(implicitly)聲明出來,一個被暗中聲明出來的default constructor將是一個trivial constructor。但是這個生成的defaultconstructor只能滿足編譯器的需要,而不是程序的需要,所有的nonstaticdata member都不會被初始化,要注意。
??一個nontrivialdefault constructor在ARM的術語中就是編譯器所需要的那種,必要的話會由編譯器合成出來。下面討論nontrivial defaultconstructor的四種情況。
(1)帶有defaultconstructor的memberclass object:如果一個類沒有任何constructor,但它內含一個memberobject,而后者有defaultconstructor,那么這個class的implicitdefault constructor就是”nontrivial“的。
??既然編譯器會合成默認構造函數,那么在C++各個不同的編譯模塊中,編譯器如何避免合成出多個默認構造函數(比如一個是a.c文件,另一個是b.c文件)呢?解決辦法是吧合成的default constructor、copyconstructor、destructor、assignmentcopy operator都以inline方式完成,一個inline函數有靜態鏈接,不會被文件以外看到。如果函數太復雜,不適合做成inline,就會合成出一個explicitnon-inline static實體。
?如果class內含一個以上的memberclass objects,那么此class的每一個constructor必須調用每一個memberclass的defaultconstructor。編譯器會擴張已經存在的constructor,在其中安插一些代碼,似的user code被執行之前,先調用必要的defaultconstructor,且以聲明順序調用。
(2)帶有DefaultConstructor的BaseClass:如果一個沒有任何constructor的class派生自一個帶有defaultconstructor的base class,那么這個derivedclass的defaultconstructor會被視為nontrivial,并因此需要被合成出來。
(3)帶有一個VirtualFunction的Class:兩種情況
(a)class聲明(或繼承)一個virtual function
?(b) class派生自一個繼承串鏈,其中有一個或更多的virtual base classes
有兩個擴張會在編譯期間發生:一個virtualfunction table會被編譯器產生出來,內放class的virtualfunctions地址;在每一個classobject中,一個額外的pointer member會被編譯器合成出來,內含相關的class vtbl的地址。
(4)帶有一個VIrtualBase Class的Class: VirtualBase Class的實現法在不同的編譯器之間有極大差異,然而,每一種實現法必須使virtualbase class在每一個derivedclass object中的位置,能夠于執行期準備妥當。
2、Copy Constructor的構建操作
(1)當classobject以相同class的另一個object作為初值時,其內部是以所謂的default memberwise(按成員)initialization手法完成的。
(2)如果class沒有聲明一個copyconstructor,就會有隱含的聲明或隱含的定義出現,C++standard把copyconstructor區分為trivial何nontrivial兩種,只有nontrivial的實體才會被合成于程序之中。決定一個copy constructor是否為trivial的標準在于class是否展現出所謂的”bitwisecopy semantics“。
(3)BitwiseCopy Semantics(逐位拷貝)
不要BitwiseCopy Semantics的情況有四種:
?(a)當class內含一個memberobject而后者的class聲明有一個copyconstructor時(不論是被class設計者明確地聲明,還是被編譯器合成);
?(b)當class繼承自一個baseclass而后者存在一個copyconstructor時(不論是被明確聲明還是被合成而得);
?(c)當class聲明了一個或多個virtualfunctions時;
?(d)當class派生自一個繼承串鏈,其中有一個或多個virtual base class時。
前兩種情況,編譯器需將member或baseclass的copyconstructor調用操作安插到被合成的copyconstructor中,情況3和4有點復雜。
重新設定VirtualTable的指針:增加一個virtualfunction table(vtbl),內含每一個有作用的virtual function地址;將一個指向vtbl的指針(vptr),安插在每一個classobject內。
處理VirtualBase Class Subobject:一個classobject以另一個object作為初值,而后者有一個virtual base class subobject,也會使bitwisecopy semantics失效。
3、程序轉化語意學
(1)返回值的初始化
已知函數定義:
X bar()
{
X xx;
//...
return xx;
}
bar()返回值如何從局部對象拷貝?
Stroustrup在cfront的解決方法是一個雙階段轉化:
????加上一個額外參數,類型是reference
????在return前安插一個copy constructor操作
//函數轉化
void bar(X& _result)//加上一個額外參數
{
X xx;
xx.X::X();//編譯器產生的default constructor調用操作
//....處理xx
_result.X::XX(xx);//編譯器產生的copyconstructor調用
return;
}
一個bar()調用被轉化為:
X xx = bar();
轉為:
X xx;
bar(xx);//注意不必調用default constructor
(2)在編譯器層面做優化
以_result參數取代namedreturn value,稱為NamedReturn Value(NRV)優化。由于NRV需要調用默認拷貝構造,如果編譯器不生成,則需要手動添加拷貝構造。
(3)拷貝構造要還是不要?
如果class需要大量的memberwise初始化操作,例如以傳值的方式傳回value,則提供一個explicit copy constructor inline會更有效率。
4、成員的初始化隊伍
必須使用member initialization list的情況:初始化一個reference member時;初始化const member;調用base class的constructor,而它擁有一組參數;調用member class的constructor,而它擁有一組參數。
使用成員初始化列表,可以提高效率,因為initializationlist的項目被放于explicituser code之前,但是要注意如果初始化某一項依賴于另一項時初始化的順序,好的方法是將依賴某一項的成員放于constructor體內。
總結
以上是生活随笔為你收集整理的《深度探索C++对象模型》--2 构造函数语意学的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《深度探索C++对象模型》--1 关于对
- 下一篇: 一份好的简历应该是这样的(This Is