總結C++中取成員函數地址的幾種方法


  這里, 我整理了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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM