14-巧用联合体

巧用联合体获取成员函数地址

union {
    void *pv;
    void(A::*pfn)();
} u;
u.pfn = &A::show;

//u.pv即可以使用

方法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:

cdecl_cast - 通过C语言的可变参数不检测参数类型

#define asm_cast(var,addr)  
{                           
    __asm{                  
        mov var,offset addr 
    }                       
}

example:

#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;
}

相关文档:
总结C++中取成员函数地址的几种方法

comments powered by Disqus