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

C++ 多態深度解析:虛函數表、動態綁定與內存佈局

     編輯:C++ 入門

靜態綁定 vs 動態綁定

靜態綁定(早綁定):編譯期確定調用哪個函數。
- 非虛函數、函數重載、模板
- 父類指針指向子類對象,調用非虛函數 → 執行父類版本

動態綁定(晚綁定):運行期根據對象實際類型確定調用。
- virtual 虛函數
- 父類指針/引用指向子類對象,調用虛函數 → 執行子類版本

虛函數表(vtable)機制

每個包含虛函數的類,編譯器生成一個虛函數表(靜態數組),存儲虛函數地址。
每個對象實例內部隱含一個虛指針,指向其類的 vtable。

內存佈局演示

class Base {
    int a;          // 4 bytes
    virtual void f(); // 引入 vptr (4/8 bytes)
}; // sizeof(Base) = 8 (32位) 或 16 (64位)

class Derived : public Base {
    int b;          // 4 bytes
    virtual void f(); // 覆寫,vtable 更新
}; // sizeof(Derived) = 12 (32位) 或 24 (64位)

// 內存圖:
// Base 對象:  [vptr] -> Base::vtable -> [Base::f]
//              [a]
// Derived 對象:[vptr] -> Derived::vtable -> [Derived::f]
//              [a]
//              [b]

動態綁定調用過程

  1. 通過對象的 vptr 找到 vtable
  2. 在 vtable 中按固定槽位找到函數地址
  3. 間接調用該地址

關鍵代碼驗證

class Base { public: int a; virtual void f() { cout << "Base"; } };
class Derived : public Base { public: int b; virtual void f() { cout << "Derived"; } };

int main() {
    Base b; Derived d;
    Base* p = &d;
    p->f(); // 輸出 "Derived" - 動態綁定
    
    // 內存探測
    int* pb = (int*)&b;
    int* pd = (int*)&d;
    cout << *pb;        // vptr 地址
    cout << *(pb+1);    // a
    int* vtable_b = (int*)*pb;
    cout << *vtable_b;  // Base::f 地址
}

多態的必要條件

  • 基類函數聲明 virtual
  • 派生類覆寫(同名、同參數、同返回類型、同 const 屬性)
  • 通過基類指針或引用調用

虛析構函數

class Base { public: virtual ~Base() {} }; // 必須虛析構!
class Derived : public Base { public: ~Derived() { delete[] ptr; } };

Base* p = new Derived();
delete p; // 正確調用 Derived::~Derived() 再 Base::~Base()

若基類析構非虛,delete 基類指針只調用基類析構 → 派生類資源洩漏。

純虛函數與抽象類

class Shape { 
public: 
    virtual double area() = 0; // 純虛函數
    virtual ~Shape() {}
}; // Shape 為抽象類,不可實例化

總結

C++ 多態通過 vptr + vtable 實現動態綁定,空間換時間(每對象額外一指針),支撐面向對象的核心特性。理解內存佈局有助於調試、性能分析和避免對象切片等陷阱。

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