标签:
在C++中,成员函数的指针是个比较特殊的东西。对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用。但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法。C++专门为成员指针准备了三个运算符: "::*"用于指针的声明,而"->*"和".*"用来调用指针指向的函数。
// Thunk.cpp : Defines the entry point for the console application. // #include "stdafx.h" typedef unsigned int DWORD; //取类成员函数的地址.vc8版本.可以取私有成员函数地址. #define GetMemberFuncAddr_VC8(FuncAddr,FuncType)\ { __asm { mov eax,offset FuncType }; __asm { mov FuncAddr, eax }; } //取类成员函数的地址.vc6版本. template <class ToType, class FromType> void GetMemberFuncAddr_VC6(ToType& addr,FromType f) { union { FromType _f; ToType _t; }ut; ut._f = f; addr = ut._t; } //调用类成员函数 DWORD CallMemberFunc(int callflag,DWORD funcaddr,void *This,int count,...) { DWORD re; if(count>0)//有参数,将参数压入栈. { __asm { mov ecx,count;//参数个数,ecx,循环计数器. mov edx,ecx; shl edx,2; add edx,0x14; edx = count*4+0x14; next: push dword ptr[ebp+edx]; sub edx,0x4; dec ecx jnz next; } } //处理this指针. if(callflag==0) //__thiscall,vc默认的成员函数调用类型. { __asm mov ecx,This; } else//__stdcall { __asm push This; } __asm//调用函数 { call funcaddr; //call 1.向堆栈中压入下一行程序的地址;2.JMP到call的子程序地址处。 mov re,eax; } return re; } ////////////////////////////////////////////////////////////////////////////////////////////////// void test1()//演示c++成员函数指针的用法. { class tt { public: void foo(int x){ printf("\n %d \n",x); } }; typedef void (tt::* FUNCTYPE)(int); FUNCTYPE ptr = &tt::foo; //给一个成员函数指针赋值. tt a; (a.*ptr)(5); //调用成员函数指针. tt *b = new tt; (b->*ptr)(6); //调用成员函数指针. delete b; // DWORD dwFooAddrPtr= 0; // dwFooAddrPtr = (DWORD) &tt::foo; /* Error C2440 */ // dwFooAddrPtr = reinterpret_cast<DWORD> (&tt::foo); /* Error C2440 */ } void test2()//示范如何取成员函数地址. { class tt { public: void foo(int x){ printf("\n %d \n",x); } }; #if _MSC_VER >1200 DWORD dwAddrPtr1; GetMemberFuncAddr_VC8(dwAddrPtr1,tt::foo); printf("\n test2 tt::foo %08x",dwAddrPtr1); #endif DWORD dwAddrPtr2; GetMemberFuncAddr_VC6(dwAddrPtr2,&tt::foo); printf("\n test2 tt::foo %08x",dwAddrPtr2); } void test3()//示范如何调用成员函数地址. { class tt { public: void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall. { printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s); } void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定. { printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s); } int m_a; }; typedef void (__stdcall *FUNCTYPE) ( int,char,char*);//定义对应的非成员函数指针类型,注意指定__stdcall. typedef void (__stdcall *FUNCTYPE2)(void *,int,char,char*);//注意多了一个void *参数. tt abc; abc.m_a = 123; DWORD ptr; DWORD This = (DWORD)&abc; GetMemberFuncAddr_VC6(ptr,&tt::foo); //取成员函数地址. FUNCTYPE fnFooPtr = (FUNCTYPE) ptr;//将函数地址转化为普通函数的指针. __asm //准备this指针. { mov ecx, This; } fnFooPtr(5,‘a‘,"7xyz"); //象普通函数一样调用成员函数的地址. GetMemberFuncAddr_VC6(ptr,&tt::foo2); //取成员函数地址. FUNCTYPE2 fnFooPtr2 = (FUNCTYPE2) ptr;//将函数地址转化为普通函数的指针. fnFooPtr2(&abc,5,‘a‘,"7xyz"); //象普通函数一样调用成员函数的地址,注意第一个参数是this指针. } void test4()//示范通过CallMemberFunc调用成员函数 { class tt { public: void foo(int x,char c,char *s)//没有指定类型,默认是__thiscall. { printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s); } void __stdcall foo2(int x,char c,char *s)//成员函数指定了__stdcall调用约定. { printf("\n m_a=%d, %d,%c,%s\n",m_a,x,c,s); } int m_a; }; tt abc; abc.m_a = 123; DWORD ptr1,ptr2; GetMemberFuncAddr_VC6(ptr1,&tt::foo); //取成员函数地址. GetMemberFuncAddr_VC6(ptr2,&tt::foo2); //取成员函数地址. CallMemberFunc(0,ptr1,&abc,3,5,‘a‘,"7xyz");//第一个参数0,表示采用__thiscall调用. CallMemberFunc(1,ptr2,&abc,3,5,‘a‘,"7xyz");//第一个参数1,表示采用非__thiscall调用. } void test5()//示范在继承情况下使用函数地址. { class tt1 { public: void foo1(){ printf("\n hi, i am in tt1::foo1\n"); } virtual void foo3(){ printf("\n hi, i am in tt1::foo3\n"); } }; class tt2 : public tt1 { public: void foo2(){ printf("\n hi, i am in tt2::foo2\n"); } virtual void foo3(){ printf("\n hi, i am in tt2::foo3\n"); } }; DWORD tt1_foo3,tt2_foo1,tt2_foo2,tt2_foo3; GetMemberFuncAddr_VC6(tt1_foo3,&tt1::foo3); GetMemberFuncAddr_VC6(tt2_foo1,&tt2::foo1); GetMemberFuncAddr_VC6(tt2_foo2,&tt2::foo2); GetMemberFuncAddr_VC6(tt2_foo3,&tt2::foo3); tt1 x; tt2 y; CallMemberFunc(0,tt1_foo3,&x,0); // tt1::foo3 CallMemberFunc(0,tt2_foo1,&x,0); // tt2::foo1 = tt1::foo1 CallMemberFunc(0,tt2_foo2,&x,0); // tt2::foo2 CallMemberFunc(0,tt2_foo3,&x,0); // tt2::foo3 CallMemberFunc(0,tt1_foo3,&y,0); // tt1::foo3 CallMemberFunc(0,tt2_foo1,&y,0); // tt2::foo1 = tt1::foo1 CallMemberFunc(0,tt2_foo2,&y,0); // tt2::foo2 CallMemberFunc(0,tt2_foo3,&y,0); // tt2::foo3 } int main(int argc, char* argv[]) { test1(); test2(); test3(); test4(); test5(); return 0; }
http://download.csdn.net/download/tikycc2/1580557
直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)
标签:
原文地址:http://www.cnblogs.com/findumars/p/5050029.html