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

C++菱形繼承與虛繼承記憶體模型深度解析

     編輯:關於C++

菱形繼承問題

菱形繼承(鑽石繼承)指兩個派生類繼承同一基類,再由底層類繼承這兩個派生類。若無虛繼承,底層類會包含兩份基類副本,導致數據冗余與二義性:

class B { int b; };
class C1 : public B { int c1; };
class C2 : public B { int c2; };
class D : public C1, public C2 { int d; };

sizeof(D) = 20(含兩個 b),訪問 b 會報「ambiguous access」。

虛繼承解決方案

使用 virtual public B 使基類在繼承體系中共享單一實例。編譯器透過 vbptr(虛基類表指針) 實現共享:

  • 虛繼承類對象開頭存放 vbptr,指向虛基類表
  • 虛基類表存儲偏移量:[this - vbptr, base - vbptr]
  • 無虛函數時第一個偏移量為 0

無數據成員時的記憶體佈局

sizeof(B)=1(佔位符),sizeof(C1)=sizeof(C2)=4(單一 vbptr),sizeof(D)=12(兩個 vbptr + 共享的 B):

D 對象佈局:
[vbptr_C1] [C1 無數據] [vbptr_C2] [C2 無數據] [D 無數據] [B 共享部分]

每個 vbptr 指向各自的虛基類表,表中記錄偏移量定位共享的 B。

含數據成員時的詳細佈局

B{int b}、C1{int c1}、C2{int c2}、D{int d}:

  • sizeof(B)=4,sizeof(C1)=sizeof(C2)=12(vbptr + c1/c2 + 共享 B)
  • sizeof(D)=24:[vbptr1][c1][vbptr2][c2][d][b]

虛基類表偏移量動態計算:
第一個 vbptr 表:[0, 14](B 相對 vbptr1 偏移 14)
第二個 vbptr 表:[0, 12](B 相對 vbptr2 偏移 12)

關鍵機制總結

  1. vbptr:虛繼承類對象開頭的指針,指向虛基類表
  2. 虛基類表:存儲偏移量,用於定位共享基類與完整對象起始位置
  3. 共享實例:最派生類構造函數負責構造虛基類,確保僅構造一次
  4. 訪問路徑:透過 vbptr → 虛基類表 → 偏移量 → 目標成員

本文不涉及虛函數多態情況,後續將分析帶虛函數的菱形繼承模型。

菱形繼承圖 期望模型 實際模型 虛基類vs非虛基類 無數據成員輸出 c1記憶體 虛基類表內容 c2記憶體 D對象記憶體 D虛基類表 D記憶體佈局圖 含數據成員輸出 C1含數據記憶體 C1虛基類表 C1記憶體佈局 D含數據記憶體 D第一個vbptr表 D第二個vbptr表 D完整佈局圖

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