首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++虛函數表原理實戰:手動解析vtable指針調用虛函數

     編輯:程式設計綜合問答

代碼還原與分析

class A {
public:
    virtual void test() { cout << "A::test" << endl; }
};

int main() {
    A a;
    // 核心代碼:通過對象內存布局手動調用虛函數
    typedef void (*FuncPtr)();
    FuncPtr myfunc = (FuncPtr)(*((int*)*((int*)&a)));
    myfunc(); // 輸出 "A::test"
}

內存布局圖解(32位系統)

對象 a 內存佈局:
+------------------+
| vptr (4 bytes)   |  ← 指向虛表
+------------------+
| 其他成員變量...   |
+------------------+

虛表 (靜態存儲區):
+------------------+
| &A::test         |  ← 第0個槽位
+------------------+
| ...              |
+------------------+

核心表達式逐層拆解

(int*)&a           // 1. 取對象a地址,強轉為 int*(視為指向整數的指針)
*((int*)&a)        // 2. 解引用,讀取對象前4字節 → 即 vptr(虛表地址)
(int*)(*((int*)&a)) // 3. 將虛表地址強轉為 int*(視為指向函數指針數組)
*((int*)(*((int*)&a))) // 4. 解引用虛表首地址 → 讀取虛表第0項 → &A::test
(FuncPtr)...       // 5. 強轉為函數指針類型
myfunc()           // 6. 調用 → 實際調用 A::test()

關鍵前提條件

  • 類包含虛函數 → 編譯器生成虛表,對象首地址存放 vptr
  • 32位系統:指針 4 字節,`int` 足夠容納指針(64位需用 `long long`/`uintptr_t`)
  • 單繼承、無虛繼承:虛表布局簡單,首項即為第一個虛函數
  • 調用約定匹配:`FuncPtr` 定義為 `void(*)()` 需與成員函數調用約定兼容(實際需 `thiscall`,此處簡化演示)

現代C++正規寫法

// 正常多態調用
A* ptr = new A();
ptr->test(); // 編譯器自動生成:(*ptr->vptr[0])(ptr)

// 若必須手動(極少見,如插件系統、腳本綁定)
using MemberFunc = void (A::*)();
MemberFunc func = &A::test;
(a.*func)(); // 標準成員函數指針調用,安全、可移植

總結

此代碼演示了**虛函數調用的底層機制**:對象 → vptr → 虛表 → 函數地址。理解此原理有助於掌握多態性能開銷、調試釋放後使用、逆向分析等場景,但生產代碼嚴禁此類硬編碼內存布局操作。

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