引言
對中高級程序員來說,C++內存模型是C++知識點裏比較重要的一部分,對此瞭解之後便可對C++類的實現機制以及多態性有更多的理解,尤其是C++運行過程中各個對象在內存裏的分佈情況,以下對這些知識點做簡要介紹。
C++類的構成:
C++的類由兩部分構成,類裏的數據和類裏的函數,類數據有兩種,靜態的非靜態的,類函數有三種,靜態的非靜態的,virtual的
對象模型
不同的對象模型會造成佈局和存取時間上的負擔,下面主要介紹三種模型
- 簡單對象模型,每一個類由一系列slots構成,每一個slots指向每一個類成員(每一個數據成員和函數成員),每個類成員按聲明順序制定一個slots,但是類成員本身並不放在類裏面,類裏面只存放指向類成員的指針,這樣可以解決不同類型的成員所需要的不同的存儲空間的問題,此外,成員是以類中slot的索引值來尋址的, 如下圖所示:
- 表格驅動對象模型,把類成員相關的信息抽出來,分別放在數據成員表和函數成員表裏面,類本身含有指向這兩個表的指針,數據成員表裏包含數據本身,而函數成員表裏面類似於簡單對象模型,裏面由一系列slots構成,每一個slots指向每一個成員,如圖:
- C++對象模型,由簡單對象模型派生而來,並對內存存儲空間和存取時間做了優化。在此數據模型裏面,非靜態數據成員放在類裏面,靜態數據成員放在類外面,類的成員函數則均放在類外面,虛函數由以下兩個步驟實現:
(1)虛函數表 virtual table,每個類會產生一堆指向虛函數的指針,這些指針被統一放在一個表格中,這個表則即虛函數表
(2)虛表指針 vptr, 每個類會被安插一個指針,指向類的虛函數表,虛表指針 vptr的設定和重置由類的構造、析構、賦值構
造函數運算符自動完成,每個類所關聯的類型信息type_info object也由虛函數表指出,通常放在虛函數表的第一個slot.
C++對象模型以實際類舉例,如下所示:
C++虛繼承
虛繼承是指繼承由virtual修飾,具體形式如下所示:
class derived : virtual public base
{
}
在虛繼承情況下,base類不管在繼承結構中被派生了多少次,永遠只會存在一個實例
C++多態
C++中有3種方式支持多態
經由一組隱式的裝換操作來實現,即把子類對象賦值給基類指針;
通過虛函數機制,在執行期間確定調用子類的某個行爲;
通過dynamic_cast和typeid運算符,dynamic_cast用於執行繼承體系中安全的向下轉型
C++類所需存儲內存
一個類所需要的內存主要包括
類中非靜態數據成員所佔總內存的大小;
由於alignment需求而填補上去的空間;
爲了支持virtual而由內部產生的額外負擔。
C++單一繼承情況下的運行內存佈局
在單一繼承的結構下,其運行內存佈局如下所示
注意當基類直接被初始化爲子類時,子類就會被切割,然後塞入基類大小的內存中,而子類的特性就會消失,也就不會有多態。
總結
瞭解C++模型之後可以對虛函數,虛繼承,虛接口,有更進一步的認識,可以在C++編程模型中對效率和空間有更深刻的理解,從而可以進一步合理的使用C++中的各種語法。
參考:
深入探索C++對象模型第一章。