《深度探索C++對象模型》讀書筆記——第一章

《深度探索C++對象模型》
讀書筆記
前言:知其然,亦知其所以然
1、 本書爲中高級C++程序員所寫;
2、 本書專注於:各種C++對象模型支持的底層實現機制;
3、 程序員應瞭解底層實現模型,才能成爲高手。
Lippman:
1. 任何對象模型都需要的三種轉換風味:
(1) 與編譯器息息相關的轉換
(2) 語言語義轉換
(3) 程序代碼和對象模型的轉換
2. C++對象模型的兩種解釋
(1) 語言中直接支持面向對象程序設計的部分
(2) 對於各種支持的底層實現機制
3. C++ class的完整virtual functions在編譯時期就固定下來了,程序員沒有辦法在執行期動態增加或取代其中某一個。這使得虛擬函數調用操作得以有快速的派送結果,付出的卻是執行期的彈性。
4. 目前所有編譯器對於virtual function的實現都是使用各個class專屬的virtual table,大小固定,並且在程序執行前就構造好了。
5. C++對象模型的底層機制並未標準化,它會因實現品(編譯器)和時間的變動而不同。
第一章 關於對象
本章難點:
1、表格驅動對象模型
2、virtual產生的額外負擔
知識點:
1.0導言
C++在佈局以及存取時間上的主要額外負擔是由virtual引起的,包括:
(1) virtual function
(2) virtual base class(虛擬繼承)
還有一些發生在“一個derived class和其第二或後繼之base class的轉換”上的多重繼承。
1.1 C++對象模型
1、在C++對象模型中,
(1)nonstatic data members被配置於每一個class object之內,
(2)static data members則被存放在所有的class object之外,
static和nonstatic function members也被放在所有的class object之外,
(3) virtual functions則以兩個步驟支持:
1) 每個class產生一堆指向virtual functions的指針,放在virtual table (vtbl)中;
2) 每個class object被添加一個指針vptr,指向相關的virtual table。每個class所關聯的type_info object也經由vtbl指出,通常是放在vtbl的第一個slot處。vptr由每一個class的construtor、destructor以及copy assignment operator自動完成。
以上模型的主要優點在於空間和存取時間的效率,主要缺點是,只要應用程序所用到的class object的nonstatic data members有所修改,那麼應用程序代碼就必須重新編譯。
3. C++最初所採用的繼承模型並不運用任何間接性,base class subobject的data members直接放置於derived class object中。優點是提供對base class members緊湊且高效的存取,缺點是base class members的任何改變,都將導致使用其derived class 的object的應用程序代碼必須重新編譯。
4. virtual base class的原始模型是在class object中爲每一個有關聯的virtual base class加上一個指針,其他演化出來的模型不是導入一個virtual base class table,就是擴充原已存在的vtbl,用以維護每一個virtual base class的位置。

一、簡單對象模型:
• object內存放指向成員的指針,不存放成員。
• 犧牲空間和運行時的效率。解決成員類型不一致帶來的存儲空間不一致問題。
這裏寫圖片描述

二、表格驅動對象模型
表格驅動對象模型:
 需要兩個表,數據成員表和成員函數表,數據成員表直接存放數據本身,成員函數表存放每個函數的地址。
 object存放這指向這兩個表的指針。
 成員函數表的思想可以支持虛函數實現。
這裏寫圖片描述
三、C++對象模型
(1) Stroustrup設計,從簡單對象模型派生而來。
(2) 非靜態數據成員存放在每一個class object之內,靜態數據成員存放在個別的class object之外。
(3) 靜態和非靜態的成員函數也存放在個別的class object之外。
(4) 虛函數則通過虛函數表vtbl和指向虛函數表的指針vptr實現:
(5) 每個class object有一個vptr,指向相關的vtbl。
(6) vptr的設定由類的構造/析構/拷貝函數完成。
(7) vtbl表第一項是每個class關聯的type_info object(用來支持運行時類型識別RTTI),其他的每一項存放着指向虛函數的地址。
這裏寫圖片描述

四、多重繼承

class istream: virtual public IOS{};
class ostream: virtual public IOS{}; 虛擬繼承
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述
1.2關鍵詞所帶來的差異
1. 關鍵詞struct的使用伴隨着一個public接口的聲明,也可以說它的用途只是爲了方便C程序員遷徙至C++部落。
2. C++中凡處於同一個access section的數據,必定保證以聲明次序出現在內存佈局中,然而被放在多個access sections中的各筆數據排列次序就不一定了。同樣,base classes和derived classes的data members的佈局也沒有誰先誰後的強制規定。
3. 組合composition而非繼承纔是把C和C++結合在一起的唯一可行方法。
1.3對象的差異
1. C++程序設計模型支持三種程序設計典範programming paradigms:
(1) 程序模型procedural model
(2) 抽象數據類型模型abstract data type model, ADT
(3) 面向對象數據模型object-oriented model,OO
2. 雖然可以直接或間接處理繼承體系中的一個base class object,但只有通過pointer或reference的間接處理,才能支持OO程序設計所需的多態性質。
3. C++中,多態只存在於public class體系中,nonpublic的派生行爲以及類型爲void*的指針可以說是多態,但它們沒有被語言明白地支持,必須由程序員通過顯示的轉型操作來管理。
4. C++以下列方法支持多態:
(1) 經由一組隱含的轉化操作,如把一個derived class指針轉化爲一個指向其public base type的指針;
(2) 經由虛擬機制;
(3) 經由dynamic_cast和typeid運算符。
5. 多態的主要用途是經由一個共同的接口來影響類型的封裝,這個接口通常被定義在一個抽象的base class中。這個接口是以virtual function機制引發的,它可以在執行期根據object的真正類型解析出是哪一個函數實體被調用。
6. 一個class object所需的內存,由以下部分組成:
 nonstatic data members的總和大小;
 任何由於alignment需求而填補上去的空間;
 爲支持virtual而由內部產生的任何額外負擔。
7. 一個pointer或reference,不管它指向哪一種數據類型,指針本身所需的內存大小是固定的。本質上,一個reference通常是以一個指針來實現,而object語法如果轉換爲間接手法,就需要一個指針。
8. 指向不同類型之指針的差異,既不在其指針表示法不同,也不在其內容不同,而是在其所尋址出來的object類型不同,亦即指針類型會教導編譯器如何解釋某個特定地址中的內存內容及大小。它們之所以支持多態,是因爲它們並不引發內存中任何與類型有關的內存委託操作,會受到改變的只是它們所指向的內存的大小和內容的解釋方式。
9. 轉型cast操作其實是一種編譯指令,大部分情況下它並不改變一個指針所含的真正地址,它只是影響被指向之內存的大小和內容的解釋方式。
10.一個base class object被直接初始化或指定爲一個derived object時,derived object就會被切割sliced,以塞入較小的base type內存中,多態於是不再呈現。一個嚴格的編譯器可以在編譯時期解析一個通過該object而觸發的virtual function調用操作,從而回避virtual機制。這時,如果virtual function被定義爲inline,則會有效率上的收穫。
11.C++通過class的pointer和reference來支持多態,即所謂的OO;也支持具體的ADT程序風格,即object-based OB,不支持多態,不支持類型的擴充。
多態只能由指針或引用(而不能通過實例對象)來實現,根本原因在於:
 指針和引用(通常以指針來實現)的大小是固定的(一個 word),而對象的大小卻是可變的。其類的指針和引用可以指向(或引用)子類,但是基類的對象永遠也只能是基類,沒有變化則不可能引發多態。
 一個指針或引用絕不會引發任何“與類型有關的內存委託操作”,在指針類型轉換時會受到的改變的只有它們所指向內存的解釋方式而已。(例如指針絕不會引發空間的slice,因爲它們大小相同)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章