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

C++ 繼承與多態底層原理(下):單/多/菱形繼承虛表佈局圖解與虛繼承機制

     編輯:關於C++

帶虛函數類的對象模型

含虛函數的類,對象首部為 vptr(指向虛表),緊隨其後為數據成員。虛表為編譯期生成的只讀數組,存虛函數入口地址,按聲明順序排列,以 nullptr 結尾。

class Base { 
    virtual void f1(); virtual void f2(); 
    int data; 
};
// 對象佈局:[vptr] [data]
// 虛表:     [&Base::f1, &Base::f2, nullptr]

單繼承:虛表線性擴展與覆寫替換

class Derived : public Base {
    void f1() override;      // 覆寫
    virtual void f3();       // 新增
    int data2;
};

Derived 對象:[vptr] [Base::data] [data2]
虛表:[&Derived::f1, &Base::f2, &Derived::f3, nullptr]
規則:先複製基類虛表,覆寫函數替換對應槽位,新虛函數追加在末尾。

多重繼承(無覆寫):多 vptr 獨立虛表

class Base1 { virtual void f1(); virtual void f2(); int b1; };
class Base2 { virtual void f3(); virtual void f4(); int b2; };
class Derived : public Base1, public Base2 { virtual void f5(); int d; };

對象佈局:

[Base1 vptr] → Base1 虛表
[Base1::b1]
[Base2 vptr] → Base2 虛表
[Base2::b2]
[Derived::d]

Derived 擁有兩個 vptr,分別指向兩張獨立虛表。Base2 部分在內存中偏移 sizeof(Base1) 位置。

多重繼承(有覆寫):同名虛函數雙重替換

class Base1 { virtual void f1(); virtual void f2(); };
class Base2 { virtual void f1(); virtual void f3(); };
class Derived : public Base1, public Base2 { 
    void f1() override;  // 同時覆寫兩個基類的 f1
    void f3() override;  // 覆寫 Base2::f3
};

關鍵現象:Derived::f1 地址會同時寫入兩張虛表的 f1 槽位。編譯器可能生成 thunk(躍板碼) 調整 this 指針偏移,確保以 Base1* 或 Base2* 調用時 this 正確指向完整對象。

虛繼承:共享虛基類子物件

class Base { virtual void f1(); int b; };
class Derived : virtual public Base { virtual void f2(); int d; };

對象佈局:

[vptr] → Derived 虛表(含 Base::f1, Derived::f2)
[vbptr] → 虛基類表(存 Base 偏移)
[Derived::d]
[Base::b]   // 共享、放在最末尾
  • vptr 指向合併後的虛表(基類虛函數+派生類虛函數)。
  • vbptr 指向虛基類表,運行時查找 Base 真實偏移。
  • 虛基類構造由最派生類直接負責,中間派生類不再調用虛基類構造函數。

菱形繼承對比

繼承方式Base 子物件數訪問歧義空間開銷
普通多重繼承2 份需作用域限定數據冗餘
虛繼承1 份無歧義+vbptr +間接訪問

調試技巧:GDB/Visual Studio 觀察虛表

# GDB
print *(int**)obj          # 取 vptr
print ((void**)vptr)[0]    # 第一個虛函數地址
info vtbl obj              # MSVC 專用命令,直接列出虛表
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved