Chp 1 關於對象
1.1 C++對象模式
每個類對應的type_info對象,通常由Vtable的第一個slot指向。
1.2 關鍵字所帶來的差異
如果不是為了努力維持與C的相容性,C++遠可以比現在更簡單些。
C++標準保證,同一個access section中的資料成員,其記憶體布局同其聲明次序保持一致。
組合,而非繼承,才是將C和C++的記憶體布局結構結合在一起唯一可行的方法。
1.3 對象的差異
轉型操作在大多數情況下不會改變指標所含的地址內容,改變的只是編譯器對"指標所指向的記憶體的大小和內容"的解釋方式。
OO(Object-Oriented)和OB(Object-Oriented)的區別集中體現在彈性和效率上。
Chp 2 建構函式語意學
2.1 Default Constructor
被編譯器合成出來的Default Constructor的目的是滿足編譯器的需要,而不是程式的需要。
4種合成的 non-trivial default constructor
1. 類中包含對象成員,其具有defalut constructor
2. 類的base class具有default constructor
2. 類包含virtual function
3. 類具備virtual base class
除此四種情況之外,對於未顯式聲明default constructor 的類,其在語義上擁有implicit trivial default constructor,但實際上這些constructor並不會被合成出來。
常見的兩個誤解:
1.任何類如果程式員沒有定義default constructor,就會被編譯器合成出一個來。
2.編譯器合成出來的default constructor,會將class內的每個data member都設定為預設值。
2.2 copy constructor 語意學
2.2.1 Default Member-wise Initialization(遞迴進行)
類似於default constructor,C++標準也將copy constructor分為 trivial 和non-trivial,只有non-trivial的才會被合成出來
而判斷一個copy constructor是否 trivial的標準則是,class是否具備"bitwise copy semantics"
2.2.3 不要bitwise copy semantics!
以下四種情況下,class不具備"bitwise copy semantics"
1.class包含一個member object,且後者具備copy constructor
2.class的base class具有copy constructor
3.class具有virtual function
4.class具有virtual base class
2.2.4 重新設定 vptr 指標
當class具備了vtable後,該class就不再具備 bitwise copy semantics。
2.3 程式轉換語意學
2.3.2 參數的初始化
語意:copy-initialization
相同語意前提下的兩種實現機制: 1.臨時對象 2 直接構建
2.3.3 傳回值的初始化
NRV(Named return value)最佳化:將copy constructor的調用最佳化掉,直接對要返回的對象執行各種操作。
注,通常NRV最佳化的啟用,是以class具備copy constructor為前提的
一般而言,對於copy constructor 的最佳化,標準允許實現有很大的自由發揮空間。這樣的好處在於獲得機器碼效率的提升,缺點在於無法安全的在copy constructor 中引入副作用並期望其一定會發生。
2.4 成員初始化列表
編譯器會一一操作初始化列表的成員,以適當的順序在class的constructor中插入初始化操作,並且保證它們都發生在任何explicit user code 之前。
Chp 3 Data語意學
3.4 繼承與Data Member
一般而言,任何規則碰到virtual base class 都要例外
3.4.2 加上多態的繼承
vptr在對象中放在什麼位置才好?
選擇1 放在class object 的尾部
優點:保持記憶體布局與C最大程度的一致
缺點:不利於實現virtual inheritance
選擇2 放在class object 的頭部
優點:易於實現virtual inheritance 和multiple inheritance
缺點:喪失了和C的記憶體布局相容性
3.4.3 多重繼承
自然多態(natural polymorphism):derived class pointer 到base class pointer 的轉換無需編譯器對指標指向的地址進行調整
多重繼承的主要麻煩在於derived class object和繼承列表中第二個或更靠後的base class object之間的地址轉換關係。
3.4.4 虛擬繼承
一如語意表面的複雜度,編譯器要支援虛擬繼承,難度也是很高的。
實現虛擬繼承的一般方法: 若一個class擁有virtual base class ,則該class 的對象被分割成兩部分: invariant region 和 shared region。
invariant region中的資料,無論後繼如何派生,都擁有固定的offset(從object的頭部算起)
shared region 則代表 virtual base class object,這一部分的資料,其位置與後續派生有關,無法直接存取,而只能間接存取
一般而言,virtual base class 最有效應用形式是:一個抽象的virtual base,不包含任何data member
3.6 指向data member 的指標
對於指向 data member 的指標,實際上是data member在 class object中的位移量;更確切的說,是 offset +1——也就是說,位於object 頭部的成員對應的data member pointer 的值為1
這種位移從1開始的特性()是基於如下考慮:如何區分"沒有指向任何data member"的data member pointer 和 "指向第一個data member "的data member pointer?
Chp 4 Function語意學
4.1 Member Function的各種調用方式
4.1.1 Non-static member function
C++的設計準則之一,就是non-static member function 的調用至少必須和一般的non-member function 有一樣的效率。
編譯器在內部會將 "non-static member function" 轉化為等價的"non-member function"
4.1.2 Virtual member function
4.1.3 Static member function
4.2 Virtual member functions
在單一繼承體系中, virtual function 機制運轉良好;然而在多重繼承和虛繼承中,對 Virtual Function的支援就不是如此簡單了
4.2.1 多繼承體系下的Virtual Function
問題的複雜性,來自於第二個及後繼base class身上,以及"必須在運行期調整this指標"。
問題1 virtual destructor
解決調整this指標較有效率的解決方案是thunk技術,即一小段彙編代碼,其負責完成兩個任務:(1) 調整this指標 (2) 調用對應的函數
利用thunk技術, vtable 中的slot就可以繼續簡單的包含一個指標,這個指標可能直接指向一個virtual function,也可能指向一個相關的thunk(如果該virtual 需要調整this指標的話)。
4.4 指向Member function的指標
取一個non-static member function的地址,得到的是其在記憶體中的位置。
static member function 對應著普通的函數指標,而不是"成員指標"。
virtual function,multiple inheritance 和virtual inheritance 的存在,會導致member function 指標變得非常複雜。
4.4.1 指向"virtual member function"的指標
對一個"virtual member function"取地址,得到的是只是vtable的一個索引值,並不是記憶體位址。
Chp 5 構造、析構、拷貝語意學
純虛函數可以被靜態調用,但無法動態調用。
5.1 無繼承體系下的物件建構
vptr的初始化由編譯器在constructor中插入的程式碼完成;這些代碼位於base class constructor的調用之後,但在任何user code之前。
既然標準保證在member initialization list對應的代碼執行前,該對象的vptr已經被正確的設定好,那麼在member
initialization list中調用virtual member
function,從vptr的角度來看,是安全的;但如果考慮到可能存在的member之間的依賴關係,這種風格顯然是不安全、不推薦使用的。
一般而言,如果程式中頻繁的在函數中返回一個local class object,那麼在設計class時,提供一個copy constructor就比較合理,它的存在會觸發NRV最佳化。
5.3 對象複製語意學
一個class的預設assignment operator,在如下情況下不具備bitwise copy語意:
1. class含有一個member object,且其具有assignment ooprator
2. class的base class 具有 assignment operator
3. class包含virtual function
4. class有virtual base class
概括的說,non-trivial的assignment operator 不具備bitwise copy semantics。只有non-trivial的assignment operator 才會被編譯器合成出來。
需要注意的時,並不存在與member initialization list 相對應的copy assignment list。
assignment operator 在 virtual inheritance 下表現不佳。
任何解決方案如果是以程式操作為基礎,導致較高的複雜度和較大的錯誤傾向,一般公認,這表明語言在該方面存在弱點。