C++內存佈局

轉自http://www.cnblogs.com/kekec/archive/2013/01/27/2822872.html

#類中的元素

0. 成員變量   1. 成員函數   2. 靜態成員變量   3. 靜態成員函數   4. 虛函數   5. 純虛函數

#影響對象大小的因素

0. 成員變量     1. 虛函數表指針(_vftptr)   2. 虛基類表指針(_vbtptr)   3. 內存對齊

_vftptr、_vbtptr的初始化由對象的構造函數, 賦值運算符自動完成;對象生命週期結束後,由對象的析構函數來銷燬。
對象所關聯的類型(type_info),通常放在virtual table的第一個slot中。

虛繼承:在繼承定義中包含了virtual關鍵字的繼承關係;
虛基類:在虛繼承體系中的通過virtual繼承而來的基類,需要注意的是:
class CDerive : public virtual CBase {}; 其中CBase稱之爲CDerive的虛基類,而不是說CBase就是個虛基類,因爲CBase還可以爲不是虛繼承體系中的基類。

虛函數被派生後,仍然爲虛函數,即使在派生類中省去virtual關鍵字

注:【下文中_vbptr即_vbtptr】

#對象內存佈局分類討論

vc6變量查看器中(Locals,Watch1等),也可以看到部分對象佈局的情況(不完整,且虛繼承是錯誤的)。

vs2005及以後版本的編譯器提供了/d1reportSingleClassLayout[類名]編譯選項來查看對象完整的內存佈局:

cl classLayout.cpp /d1reportSingleClassLayoutCChildren

0. 單一類

(1). 空類

sizeof(CNull)=1(用於標識該對象

(2). 只有成員變量的類

int nVarSize = sizeof(CVariable) = 12

 

內存佈局:

(3). 只有虛函數的類

int nVFuntionSize = sizeof(CVFuction) = 4(虛表指針)

 

內存佈局:

(4). 有成員變量、虛函數的類

 

int nParentSize = sizeof(CParent) = 8

內存佈局:

1. 單一繼承(含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 12

vc中顯示的結果(注:還有1個虛函數CChildren::g1沒有被顯示出來):

d1reportSingleClass查看:

內存佈局:

2. 多繼承 (含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 20

vc中顯示的結果(注:還有2個虛函數CChildren::f2,CChildren::h2沒有被顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

3. 深度爲2的繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 24

vc中顯示的結果(注:還有3個虛函數CGrandChildren::f2,CChildren::h2,CGrandChildren::f3沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

4 重複繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 28

vc中顯示的結果(注:還有大量的虛函數沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

d1reportSingleClass查看:

內存佈局:

由於m_nAge在內容中存在兩個拷貝,因此我們不能直接通過pGrandChildrenA->m_nAge來訪問該變量,

這樣會存在二義性,編譯器無法知道應該訪問CChildren1中的m_nAge,還是CChildren2中的m_nAge。

爲了標識唯一的m_nAge,就需要帶上其所在範圍的類名了。如下:

1 pGrandChildrenA->CChildren1::m_nAge = 1;
2 pGrandChildrenA->CChildren2::m_nAge = 2;

5. 單一虛繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

內存佈局:

 

6. 多虛繼承(含成員變量、虛函數、虛函數覆蓋)

(1) virtual CParent1, CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(2) CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(3) virtual CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

內存佈局:

7. 鑽石型的虛擬多重繼承(含成員變量、虛函數、虛函數覆蓋)

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

內存佈局:

#外部參考

C++類對應的內存結構

陳皓- C++ 虛函數表解析

陳皓 - C++ 對象的內存佈局(上)

陳皓 - C++ 對象的內存佈局(下)

#類中的元素

0. 成員變量   1. 成員函數   2. 靜態成員變量   3. 靜態成員函數   4. 虛函數   5. 純虛函數

#影響對象大小的因素

0. 成員變量     1. 虛函數表指針(_vftptr)   2. 虛基類表指針(_vbtptr)   3. 內存對齊

_vftptr、_vbtptr的初始化由對象的構造函數, 賦值運算符自動完成;對象生命週期結束後,由對象的析構函數來銷燬。
對象所關聯的類型(type_info),通常放在virtual table的第一個slot中。

虛繼承:在繼承定義中包含了virtual關鍵字的繼承關係;
虛基類:在虛繼承體系中的通過virtual繼承而來的基類,需要注意的是:
class CDerive : public virtual CBase {}; 其中CBase稱之爲CDerive的虛基類,而不是說CBase就是個虛基類,因爲CBase還可以爲不是虛繼承體系中的基類。

虛函數被派生後,仍然爲虛函數,即使在派生類中省去virtual關鍵字

注:【下文中_vbptr即_vbtptr】

#對象內存佈局分類討論

vc6變量查看器中(Locals,Watch1等),也可以看到部分對象佈局的情況(不完整,且虛繼承是錯誤的)。

vs2005及以後版本的編譯器提供了/d1reportSingleClassLayout[類名]編譯選項來查看對象完整的內存佈局:

cl classLayout.cpp /d1reportSingleClassLayoutCChildren

0. 單一類

(1). 空類

sizeof(CNull)=1(用於標識該對象

(2). 只有成員變量的類

int nVarSize = sizeof(CVariable) = 12

 

內存佈局:

(3). 只有虛函數的類

int nVFuntionSize = sizeof(CVFuction) = 4(虛表指針)

 

內存佈局:

(4). 有成員變量、虛函數的類

 

int nParentSize = sizeof(CParent) = 8

內存佈局:

1. 單一繼承(含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 12

vc中顯示的結果(注:還有1個虛函數CChildren::g1沒有被顯示出來):

d1reportSingleClass查看:

內存佈局:

2. 多繼承 (含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 20

vc中顯示的結果(注:還有2個虛函數CChildren::f2,CChildren::h2沒有被顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

3. 深度爲2的繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 24

vc中顯示的結果(注:還有3個虛函數CGrandChildren::f2,CChildren::h2,CGrandChildren::f3沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

4 重複繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 28

vc中顯示的結果(注:還有大量的虛函數沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

d1reportSingleClass查看:

內存佈局:

由於m_nAge在內容中存在兩個拷貝,因此我們不能直接通過pGrandChildrenA->m_nAge來訪問該變量,

這樣會存在二義性,編譯器無法知道應該訪問CChildren1中的m_nAge,還是CChildren2中的m_nAge。

爲了標識唯一的m_nAge,就需要帶上其所在範圍的類名了。如下:

1 pGrandChildrenA->CChildren1::m_nAge = 1;
2 pGrandChildrenA->CChildren2::m_nAge = 2;

5. 單一虛繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

內存佈局:

 

6. 多虛繼承(含成員變量、虛函數、虛函數覆蓋)

(1) virtual CParent1, CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(2) CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(3) virtual CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

內存佈局:

7. 鑽石型的虛擬多重繼承(含成員變量、虛函數、虛函數覆蓋)

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

內存佈局:

#外部參考

C++類對應的內存結構

陳皓- C++ 虛函數表解析

陳皓 - C++ 對象的內存佈局(上)

陳皓 - C++ 對象的內存佈局(下)

#類中的元素

0. 成員變量   1. 成員函數   2. 靜態成員變量   3. 靜態成員函數   4. 虛函數   5. 純虛函數

#影響對象大小的因素

0. 成員變量     1. 虛函數表指針(_vftptr)   2. 虛基類表指針(_vbtptr)   3. 內存對齊

_vftptr、_vbtptr的初始化由對象的構造函數, 賦值運算符自動完成;對象生命週期結束後,由對象的析構函數來銷燬。
對象所關聯的類型(type_info),通常放在virtual table的第一個slot中。

虛繼承:在繼承定義中包含了virtual關鍵字的繼承關係;
虛基類:在虛繼承體系中的通過virtual繼承而來的基類,需要注意的是:
class CDerive : public virtual CBase {}; 其中CBase稱之爲CDerive的虛基類,而不是說CBase就是個虛基類,因爲CBase還可以爲不是虛繼承體系中的基類。

虛函數被派生後,仍然爲虛函數,即使在派生類中省去virtual關鍵字

注:【下文中_vbptr即_vbtptr】

#對象內存佈局分類討論

vc6變量查看器中(Locals,Watch1等),也可以看到部分對象佈局的情況(不完整,且虛繼承是錯誤的)。

vs2005及以後版本的編譯器提供了/d1reportSingleClassLayout[類名]編譯選項來查看對象完整的內存佈局:

cl classLayout.cpp /d1reportSingleClassLayoutCChildren

0. 單一類

(1). 空類

sizeof(CNull)=1(用於標識該對象

(2). 只有成員變量的類

int nVarSize = sizeof(CVariable) = 12

 

內存佈局:

(3). 只有虛函數的類

int nVFuntionSize = sizeof(CVFuction) = 4(虛表指針)

 

內存佈局:

(4). 有成員變量、虛函數的類

 

int nParentSize = sizeof(CParent) = 8

內存佈局:

1. 單一繼承(含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 12

vc中顯示的結果(注:還有1個虛函數CChildren::g1沒有被顯示出來):

d1reportSingleClass查看:

內存佈局:

2. 多繼承 (含成員變量、虛函數、虛函數覆蓋)

int nChildSize = sizeof(CChildren) = 20

vc中顯示的結果(注:還有2個虛函數CChildren::f2,CChildren::h2沒有被顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

3. 深度爲2的繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 24

vc中顯示的結果(注:還有3個虛函數CGrandChildren::f2,CChildren::h2,CGrandChildren::f3沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

d1reportSingleClass查看:

內存佈局:

4 重複繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nGrandSize = sizeof(CGrandChildren) = 28

vc中顯示的結果(注:還有大量的虛函數沒有顯示出來,this指針的adjustor[調整值]也沒打印出):

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

d1reportSingleClass查看:

內存佈局:

由於m_nAge在內容中存在兩個拷貝,因此我們不能直接通過pGrandChildrenA->m_nAge來訪問該變量,

這樣會存在二義性,編譯器無法知道應該訪問CChildren1中的m_nAge,還是CChildren2中的m_nAge。

爲了標識唯一的m_nAge,就需要帶上其所在範圍的類名了。如下:

1 pGrandChildrenA->CChildren1::m_nAge = 1;
2 pGrandChildrenA->CChildren2::m_nAge = 2;

5. 單一虛繼承(含成員變量、虛函數、虛函數覆蓋)

 

int nChildSize = sizeof(CChildren) = 20

d1reportSingleClass查看:

內存佈局:

 

6. 多虛繼承(含成員變量、虛函數、虛函數覆蓋)

(1) virtual CParent1, CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(2) CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 24

d1reportSingleClass查看:

內存佈局:

(3) virtual CParent1, virtual CParent2

int nChildSize = sizeof(CChildren) = 28

d1reportSingleClass查看:

內存佈局:

7. 鑽石型的虛擬多重繼承(含成員變量、虛函數、虛函數覆蓋)

int nGrandChildSize = sizeof(CGrandChildren) = 36

d1reportSingleClass查看:

thunk函數:一種形實轉換輔助函數;主要做this指針調整函數調用重定向

內存佈局:

#外部參考

C++類對應的內存結構

陳皓- C++ 虛函數表解析

陳皓 - C++ 對象的內存佈局(上)

陳皓 - C++ 對象的內存佈局(下)

發佈了132 篇原創文章 · 獲贊 14 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章