C 物件的記憶體布局

2021-06-18 00:48:07 字數 3191 閱讀 8513

記憶體布局是屬於較深層次的知識,很多問題往深了講都是不清楚記憶體布局的原理。最近讀到一本書,裡面講了一部分c++物件的記憶體布局,讓我對很多以前的問題都豁然開朗了。書上篇幅較大,我加上自己的理解總結了下。

分為三部分:簡單物件,單繼承,多繼承

非靜態成員變數和虛函式是決定類大小的唯一兩個因素

非靜態成員變數在類的記憶體裡會有位元組對齊

如果物件中包含虛函式,會增加4個位元組的空間,不論有多少個虛函式。

靜態成員變數,靜態成員函式和非靜態成員函式不會影響物件記憶體的大小。靜態成員變數儲存在記憶體的靜態資料區。另外:非靜態成員函式和程式普通函式的函式區別是,類的非靜態成員函式函式有this指標,所以可以訪問類的成員。靜態成員函式不可以呼叫類的非靜態成員,因為靜態成員函式不含this指標。

class ******class

; virtual ~******class(){};

int getvalue(void);

virtual void foo(void){};

static void addcount(){};

};int main()

輸出: 

object start address:1efdec

nvalue address: 1efdf4

c address:1efdfc

d address: 1efdfd

size: 24

因為double是8個位元組,所以虛函式表和兩個char的的成員都按照8位元組對齊,所以總大小是24。

8位元組vptr 虛函式指標

8位元組double nvalue

8位元組char c,d

先舉例

class ******class

; virtual ~******class(){};

int getvalue(void);

virtual void foo(void){};

static void addcount(){};

};class derivedclass:public ******class

; ~derivedclass(){};

virtual void foo(void){};

};int main()

輸出:object start address:23fa5c

nvalue address: 23fa60

c address:23fa64

nsubvalue address: 23fa68

size: 16

可見:

在構造乙個派生類的例項時首先夠著乙個基類的例項,而這個基類的例項在派生類的例項銷毀之後銷毀。derivedclass的大小是16位元組,基類******class的大小是12位元組。派生類增加了乙個整型變數nsubvalue,在記憶體布局中放在基類的後面。而且派生類在構造時不會再建立乙個新的虛函式表,而是在基類的虛函式表中增加或者修改。

與但繼承相同,建立派生類的物件時,要首先建立基類的物件。由於多繼承中乙個派生類有多個基類,因此建立基類的物件要遵循派生類宣告的順序。

******class1 的乙個物件的大小是12位元組,******class2的乙個物件的大小是8位元組。而派生類增加了4個位元組的整型成員資料,大小是24位元組。

在多繼承中藥注意避免二義性。如上面的例子兩個基類都定義了getvalue()函式。如果乙個派生類的例項呼叫getvalue函式會報二義性錯誤。

若******class1和******class2的記憶體對齊不一樣,那麼派生類繼承他們以後,會重新統一記憶體對齊。比如若******class1是按4位元組對齊,******class2是按8位元組對齊。當derivedclass繼承他們以後,******class1也會按照8位元組對齊。

下面看例子:

class ******class1

; virtual ~******class1(){};

int getvalue(void);

virtual void foo1(void){};

};class ******class2

; virtual ~******class2(){};

int getvalue(void);

virtual void foo2(void){};

};class derivedclass:public ******class1,public ******class2

; ~derivedclass(){};

virtual void foo2(void){};

};int main()

輸出:object start address:1bfe04

考慮如下的菱形繼承

如果不適用虛擬繼承,記憶體布局將會如上面右圖所示:會有兩個baseclass例項。

如果使用虛擬繼承,則記憶體布局如下

使用虛擬繼承以後

baseclass只建立了乙個例項,其資料成員的位址相同

baseclass的例項放在derivedclass例項的記憶體空間中的最後

為了使用虛擬繼承,每個使用虛擬繼承的類都會新增乙個虛基類表的指標(virtual base table)來實現,因此照成空間變大。

C 物件的記憶體布局

一篇寫的比較好的部落格 這篇文章中主要想說以下幾個問題 1 如何通過物件獲得虛函式表中虛函式的位址 2 分幾種情況討論記憶體布局 1 單一繼承 2 多重繼承 3 重複繼承 4 鑽石虛擬繼承 為了解決重複繼承中出現問題而產生的虛擬繼承 1 虛函式主要是通過一張虛函式的位址表來實現的,簡稱v table...

C 物件的記憶體布局

主要有三個因素對物件的記憶體布局有較大影響 類成員型別 static成員變數,virtual成員函式 繼承方式 記憶體對齊。以下分別詳細說明了具體的影響。一 static與virtual對記憶體布局的影響 物件的記憶體分布與類的成員有關,static成員變數與非static成員變數會造成不同的記憶體...

c 物件的記憶體布局

以下均為linux64位編譯器上實驗資料,指標大小為8位元組 1.空類 class n n n sizeof n 等於1編譯器會安插乙個char位元組以保證其每個例項都有唯一的位址 2.無虛函式無繼承類 class a a a sizeof a 等於8class和struct一樣會滿足記憶體對齊,a...