============================================================================
3-0. 類所佔的內存大小受到三個因素的影響:
(1)語言自己所形成的額外負擔(Virtual base classes);
(2)編譯器對於特殊狀況所提供的優化處理(空基類優化);
(3)Alignment的限制(對齊);
注:Empty Virtual base class提供一個Virtual interface,沒有定義任何數據,某些編譯器對此提供了特殊處理(優化):一個empty virtual base class被視爲derived class object最開頭的一部分,也就是說它並無花費任何額外空間。程序員
============================================================================函數
3-1. Data Member 的綁定
member rewriting rule:一個inline函數實體以內,在整個class 聲明未被徹底看見以前,是不會被評估求值的。也即:佈局
extern int x; class Point3d { public: // 對於函數自己的分析將延遲直至class聲明的右大括號出現纔開始 float X() const { return x; } private: float x; }; // 事實上,分析在這裏進行
對member functions自己的分析,會直到整個class的聲明都出現了纔開始。所以,在一個inline member function軀體以內的一個data member 綁定操做,會在整個class聲明完成以後才發生(這就保證取用到的變量是 data member 而不是 global )。優化
可是對於argument list(函數參數列),仍是會在他們第一次遇到時被適當地決議完成。this
============================================================================
3-2. Data Member 的佈局
Nonstatic data members 的class object 中的排列順序將和其被聲明的順序同樣,任何中間介入的static data members 都不會被放進對象佈局之中。spa
============================================================================3d
3-3. Data Member 的存取
(1)Static Data Members:被編譯器提出於class以外,並被視爲一個global變量(但只在class生命範圍以內可見),其不會致使任何空間上或執行時間上的額外負擔。每個Static Data Members只有一個實體,存放在程序的data segment之中,每次程序取用static member,就會被內部轉化爲對該惟一的extern實體的直接取用操做。指針
(2)Nonstatic Data Members
Nonstatic Data Members:直接存放在每個class object之中,除非經由明確的(explicit)或暗喻的(inplicit)class object,沒有辦法直接存取它們。只要程序員在一個member function中直接處理一個Nonstatic Data Members,所謂「implicit class object」(this指針)就會發生。
每個Nonstatic Data Members的偏移量(offset)在編譯時期便可獲知,甚至member屬於一個base class subobject(派生自單一或多重繼承串鏈)也是同樣。所以,存取一個Nonstatic Data Members,其效率和存取一個C struct member或一個nonderived class 的 member是同樣的。code
注:經由對象(object)和經由ptr取用成員x,若是成員member是從一個Virtual base class繼承而來時,ptr存取操做會延遲至執行期。而經由object的取用操做,members的offset位置在編譯時期就固定了。對象
============================================================================
3-4. 「繼承」與 Data Member
(1)只要繼承不要多態
(2)加上多態
注:a. 單一繼承提供了一種「天然多態」形式,是關於classes 體系中的base type 和 derived type之間的轉換。base class 和 derived class 的objects都是從相同的地址開始,其間差別只在於 derived object 比較大,用以容納它本身的nonstatic data members。
b. 當把vptr放在class object 的起始處,若是base class 沒有virtual function 而derived class 有(如書 圖3.2b),那麼單一繼承的天然多態就會被打破。在這種狀況下,把一個derived object 轉換爲其base 類型,就須要編譯器介入,用以調整地址(因vptr插入之故)。在既是多重繼承又是虛擬繼承的狀況下,編譯器的介入更有必要。
(3)多重繼承
(4)虛擬繼承
《深度探索C++對象模型》中介紹了3種實現模型。這裏只說一下第3種:是在Virtual function table(虛函數表)中放置 Virtual base class 的offset(而不是地址),圖3.5b 顯示這種base class offset 實現模型。至此,Virtual function table 可經由正值或負值來索引。若是是正值,很顯然就是索引到Virtual functions;若是是負值,則是索引到Virtual base class offset。
注:通常而言,Virtual base class 最有效的一種運用形式就是:一個抽象的Virtual base class ,沒有任何data members。
============================================================================
3-6. 指向Data Members 的指針
詳細調查class members 的底層佈局,可用以決定vptr是放在class的起始處或是尾端。也能夠用來決定class 中的access sections 的次序。
假設類有3個float成員,若是vptr放在對象的尾端,則3個成員的offset(& Class::object1)分別是0,4,8. 若是vptr放在對象的起頭,則3個成員在對象佈局中的offset分別是4,8,12. 然而你若去取data members的地址,傳回的值老是多1. 也就是1,59或者5,9,13等等。之因此這樣,緣由以下:
多重繼承下,狀況會有所不一樣:
============================================================================