這里, 我整理了4種C++中取成員函數地址的方法, 第1,2,4種整理於網上的方法, 第3種cdecl_cast是我自己想到的.
其中, 第4種(匯編)的方法不能在VC6上編譯通過. 推薦使用第1,2種方法(pointer_cast 和 union_cast).
至於:為什么要取成員函數的地址? 因為可以通過一定的手段 讓成員函數作為回調函數, 而不再使用全局的靜態函數.
天氣熱,話不多說, 使用方法見最后.
方法1: pointer_cast - 通過靜態轉換
template<typename dst_type,typename src_type> dst_type pointer_cast(src_type src) { return *static_cast<dst_type*>(static_cast<void*>(&src)); }
其實, 我並不明白這個方法為什么成功了, 而且要使用兩個static_cast, 一個不行. 而且函數里面使用的&src,
但我傳入參數的時候還需要以&ClassName::MemFunc的形式, 不然就是錯誤的, 為什么?
方法2: union_cast - 通過聯合體的共享儲存機制
template<typename dst_type,typename src_type> dst_type union_cast(src_type src) { union{ src_type s; dst_type d; }u; u.s = src; return u.d; }
這種方法是最常規, 也是最好理解的一種方法了, 巧妙地利用了聯合體的優點. 當然, 模板的使用恰到好處. 同時,傳入參數時注意數據類型大小一致.
方法3: cdecl_cast - 通過C語言的可變參數不檢測參數類型
__declspec(naked) void* __cdecl cdecl_cast(...) { __asm{ mov eax,dword ptr[esp+4] ret } }
注:在Windows上函數返回值通過eax返回, 所以只需要這么兩條匯編語句就行了. 只用於32位平台, 若用於64位, 需要修改一下寄存器.
雖然使用了三個點形式的參數, 但是參數只需傳入一個.
方法4: asm_cast - 通過匯編的offset語句取成員函數偏移得到地址
#define asm_cast(var,addr) \ { \ __asm{ \ mov var,offset addr \ } \ }
注:這個方法也比較巧妙, 不過貌似在VC6上編譯不過. VS2012沒問題.
使用方法及測試代碼:
#include <iostream> using namespace std; class A { public: void fn(){} }; int main(void) { void* p1 = pointer_cast<void*>(&A::fn); void* p2 = union_cast<void*>(&A::fn); void* p3 = cdecl_cast(&A::fn); void* p4 = 0; asm_cast(p4,A::fn); cout<<p1<<endl<<p2<<endl<<p3<<endl<<p4<<endl; return 0; }
女孩不哭 @ 2013-08-17 10:47:34 @ http://www.cnblogs.com/nbsofer