首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C++ 類大小深度測試:空類、虛函數、靜態成員、單/多重繼承、虛繼承完整分析

     編輯:關於C

C++ 類的記憶體佈局直接影響物件大小、效能與多態行為。本文通過系統性測試,揭示 sizeof 在各種繼承、虛函數、靜態成員組合下的具體數值與底層原理,包含虛表指標 (vptr)、虛基類指標、空類優化、記憶體對齊等核心機制。

測試環境與前提

  • 32 位元系統:指標 4 bytes,int 4 bytes
  • 編譯器:MSVC (Visual Studio),符合 Itanium C++ ABI 風格
  • 記憶體對齊:預設 4/8 bytes 對齊

基礎測試案例

類別定義sizeof解析
class CEmptyClass {};1空類大小非 0,確保每個物件有唯一位址
class A { virtual void a(); };4含虛函數 → 編譯器注入 vptr (4 bytes)
class A2 { static int m_sNum; };1靜態成員不佔物件空間,屬於類別而非實例
class A3 { virtual void a(); static int m_sNum; };4vptr 4 bytes,靜態成員不計入
class A4 { bool m_b; int m_n; static int m_s; };8bool(1) + padding(3) + int(4) = 8 (對齊)

單一繼承測試

繼承方式定義sizeof解析
非虛繼承class B : public A {};4共享基類 vptr,無額外開銷
虛繼承class B1 : virtual public A {};8+4 bytes:虛基類指標 (vbptr 或偏移量)

結論:虛繼承比非虛繼承多 4 bytes (32位元),本質是額外的指標用於執行期解析虛基類位址。

多重繼承測試 (非虛)

定義sizeof解析
class B2 : public A, public A1 {}; (雙虛函數基類)4單一 vptr,多重繼承不增加虛表指標
class B3 : public A1, public A2 {}; (一虛一非虛)4僅虛函數基類貢獻 vptr

關鍵發現:一個類別只有一個虛表,一個物件只有一個 vptr,與繼承多少基類無關。

虛多重繼承測試

定義sizeof解析
class B4 : public A, virtual public A1 {};12A(4) + A1(4) + vbptr(4)
class B5 : virtual public A, virtual public A1 {};12同前,虛繼承只增加單一 vbptr

結論:無論單一或多重虛繼承,只增加一個虛基類指標 (4 bytes)。

鑽石繼承與虛基類共享機制


class A { virtual void a(); };      // sizeof=4
class B1 : virtual public A {};     // sizeof=8 (vptr + vbptr)
class C2 : public B1, virtual public A {};  // sizeof=8
class C3 : public B1 {};            // sizeof=8
class C4 : virtual public B1 {};    // sizeof=12
class C5 : virtual public B1, virtual public A {}; // sizeof=12
類別sizeof關鍵機制
C28虛基類共享:virtual public A 被 B1 已虛繼承,C2 再次虛繼承 A 不增加空間
C38非虛繼承 B1,B1 已含虛基類機制,直接複用
C412虛繼承 B1 → 新增 vbptr 指向 B1 的虛基類表
C512雙重虛繼承但 A 已被 B1 虛繼承,共享機制生效,等同 C4

虛表指標 (vptr) 驗證


A a1, a2;
if (&a1 == &a2)  // 錯誤寫法:比較物件位址
// 正確驗證:取得 vptr 位址 (編譯器相關)
int* vptr1 = *reinterpret_cast(&a1);
int* vptr2 = *reinterpret_cast(&a2);
assert(vptr1 == vptr2);  // 同類別物件共享虛表指標值

鐵律:同一類別的所有物件,vptr 指向同一虛表。虛表屬於類別,不屬於物件。

總結速查表

| 情況 | 大小變化 | 核心原因 | |------|----------|----------| | 空類 | 1 | 物件唯一位址 | | 增加虛函數 | +4 | 注入 vptr | | 增加靜態成員 | +0 | 不屬於物件 | | 非虛單繼承 (基有虛) | +0 | 共享 vptr | | 虛單繼承 | +4 | 注入 vbptr | | 非虛多重繼承 | +0~4 | 取決於基類是否有虛函數 | | 虛多重繼承 | +4 | 單一 vbptr | | 鑽石虛繼承 | 共享 | 虛基類單一實例 |

實戰啟示

  1. 虛繼承代價:每層虛繼承 +4/+8 bytes,多態設計需權衡
  2. 空類優化 (EBO):空基類在非虛繼承中可併入衍生類,不佔空間
  3. 記憶體對齊:bool + int 因對齊佔 8 bytes,重排欄位可省空間
  4. 虛表機制:理解 vptr/vtable 是掌握多態、RTTI、dynamic_cast 的前提

熟練掌握類大小計算規則,是 C++ 物件模型、效能優化、序列化、跨語言互操作的核心功力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved