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"
}
對象 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()
// 正常多態調用
A* ptr = new A();
ptr->test(); // 編譯器自動生成:(*ptr->vptr[0])(ptr)
// 若必須手動(極少見,如插件系統、腳本綁定)
using MemberFunc = void (A::*)();
MemberFunc func = &A::test;
(a.*func)(); // 標準成員函數指針調用,安全、可移植
此代碼演示了**虛函數調用的底層機制**:對象 → vptr → 虛表 → 函數地址。理解此原理有助於掌握多態性能開銷、調試釋放後使用、逆向分析等場景,但生產代碼嚴禁此類硬編碼內存布局操作。