2 Jul 2012

C++ Tips: 获得成员函数地址

c++编程有时需要获得成员函数地址,然后转换,如果要使用类c的方法,得到函数指针后再赋值,需要使用_stdcall关键字来指定参数压栈顺序,否则会毁坏栈结构,出错. 先是获得成员函数指针


#include <iostream>
using namespace std;

typedef unsigned long DWORD;

class A
{
public:
    A (int val):i(val){}

    void show(){ cout << i << endl;}

    void getFunctionAddr();

private:
    int i;
};

typedef void (A::* funcPtr)();

void A::getFunctionAddr()
{
    union
    {
        funcPtr _f;
        DWORD   _t;
    }ut;

    funcPtr ptr = &A::show;
    ut._f =  ptr;
    DWORD addr = ut._t;

    printf("%#Xl\n", addr);
    return;
}

int main()
{
    A a(2);
    A b(3);
    a.getFunctionAddr();
    b.getFunctionAddr();
    return 0;
}

如果需要类c一样使用得到的函数指针,需要_stdcall关键字,测试如下:
#include <iostream>
using namespace std;

typedef unsigned long DWORD;

class A {
public :
    void testFuncPtr(int i) {     //没有指定类型,默认是__thiscall.
        cout << "A::testFuncPtr" << endl;
        cout << "i = " << i << "\tj = " << this->j << endl;
    }
    int j;
};

typedef void (A::* funcPtr)(int);           // 成员函数指针
typedef void (__stdcall *FUNCTYPE)(int);    // 定义对应的非成员函数指针类型,注意指定__stdcall

int main() {
    A a;
    a.j = 9;
    union
    {
        funcPtr  _f;
        DWORD _t;
    }ut;

    funcPtr memPtr = &A::testFuncPtr;           //成员函数指针,这里必须加&
    ut._f =  memPtr;                            //通过union转换
    DWORD memAddr = ut._t;

    FUNCTYPE fnFooPtr1 = (FUNCTYPE)memAddr;     //将DWORD转换成指针

    // 这几句汇编非常重要,否则会破坏堆栈,造成错误
    DWORD This = (DWORD)&a;
    __asm
    {
        mov ecx, This                           //将this指针移动到ecx寄存器
    }

    fnFooPtr1(1);                               //通过普通函数指针调用成员函数

    return 0;
}
更详细请参考来源文章: 这里

No comments :

Post a Comment