轉自:“http://www.cnblogs.com/nbsofer/p/get_member_function_address_cpp.html

這裡, 我整理了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;
}

...