在C++实现回调(续)
Method6:使用类的非静态函数作为回调(采用thunk的方法2)
在上面的实现过程中,可以看出来主要的部分就是这里:
bMovEcx = 0xB9;
在上面的实现过程中,可以看出来主要的部分就是这里:
bMovEcx = 0xB9;
dwThis = (DWORD)pThis;
bJmp = 0xE9;
dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)));
意思就是Move Ecx pThis; 即把this指针保存到了ECX的寄存器,JMP dwRealProc;就是跳转到成员函数的地址并进行调用。
对于调用类的非静态方法时中需要传入this指针的问题,我们再找一种方法进行解决,上面的类方法使用的是默认的thiscall的调用规则,下面我们使用stdcall的方式,也就是不使用ecx传递this指针,而直接使用栈进行this指针的传递。见代码:
[cpp] view plaincopyprint?
01.#include <iostream>
02.#include <windows.h>
03.using namespace std;
04.
05.template<typename ToType, typename FromType>
06.void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
07.{
08. union
09. {
10. FromType _f;
11. ToType _t;
12. }ut;
13. ut._f = f;
14. addr = ut._t;
15.}
16.
17.class Test
18.{
19.public:
20. void __stdcall Print(int x,char c,char *s)
21. {
22. cout << "m_a=" << m_a << "," << x << c << s << endl;
23. }
24. int m_a;
25.};
26.
27.
28.void main(void)
29.{
30. typedef void (__stdcall *FUNCTYPE)(void *This,int x,char c,char *s);
31.
32. Test test;
33. test.m_a = 111;
34. DWORD ptr;
35. GetMemberFuncAddr_VC6(ptr,Test::Print);
36. FUNCTYPE fnPrintPtr = (FUNCTYPE)ptr;
37. fnPrintPtr(&test,3,'Q',"abcde");
38.}
#include <iostream>
#include <windows.h>
using namespace std;
01.#include <iostream>
02.#include <windows.h>
03.using namespace std;
04.
05.template<typename ToType, typename FromType>
06.void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
07.{
08. union
09. {
10. FromType _f;
11. ToType _t;
12. }ut;
13. ut._f = f;
14. addr = ut._t;
15.}
16.
17.class Test
18.{
19.public:
20. void __stdcall Print(int x,char c,char *s)
21. {
22. cout << "m_a=" << m_a << "," << x << c << s << endl;
23. }
24. int m_a;
25.};
26.
27.
28.void main(void)
29.{
30. typedef void (__stdcall *FUNCTYPE)(void *This,int x,char c,char *s);
31.
32. Test test;
33. test.m_a = 111;
34. DWORD ptr;
35. GetMemberFuncAddr_VC6(ptr,Test::Print);
36. FUNCTYPE fnPrintPtr = (FUNCTYPE)ptr;
37. fnPrintPtr(&test,3,'Q',"abcde");
38.}
#include <iostream>
#include <windows.h>
using namespace std;
template<typename ToType, typename FromType>
void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
{
union
{
FromType _f;
ToType _t;
}ut;
ut._f = f;
addr = ut._t;
}
void GetMemberFuncAddr_VC6(ToType& addr,FromType f)
{
union
{
FromType _f;
ToType _t;
}ut;
ut._f = f;
addr = ut._t;
}
class Test
{
public:
void __stdcall Print(int x,char c,char *s)
{
cout << "m_a=" << m_a << "," << x << c << s << endl;
}
int m_a;
};
{
public:
void __stdcall Print(int x,char c,char *s)
{
cout << "m_a=" << m_a << "," << x << c << s << endl;
}
int m_a;
};
void main(void)
{
typedef void (__stdcall *FUNCTYPE)(void *This,int x,char c,char *s);
Test test;
test.m_a = 111;
DWORD ptr;
GetMemberFuncAddr_VC6(ptr,Test::Print);
FUNCTYPE fnPrintPtr = (FUNCTYPE)ptr;
fnPrintPtr(&test,3,'Q',"abcde");
}
test.m_a = 111;
DWORD ptr;
GetMemberFuncAddr_VC6(ptr,Test::Print);
FUNCTYPE fnPrintPtr = (FUNCTYPE)ptr;
fnPrintPtr(&test,3,'Q',"abcde");
}
这里我们使用stdcall的约定定义函数方法,在调用的过程中在函数的参数列表的最左端添入一个this指针参数,也就是在栈的最下面,函数返回值之前加入this指针,达到可以调用的目的。
Method7:使用类的非静态函数作为回调(采用直接调用虚函数的方法)
其实这种方法跟上面的也类似,规避this指针的方法也是采用嵌入汇编的方式,将this指针赋值到ecx中。不过就是获取函数地址的方法有点不同了,上面都是使用pointer_cast<int>(&Test::Test2)这种方法,直接转化类的方法,这次我们将类函数的写成虚函数,通过虚函数表获取函数地址,进行调用。
[cpp] view plaincopyprint?
01.#include <windows.h>
02.#include <iostream>
03.
04.using namespace std;
05.
06.class Test {
07.public:
08. Test()
09. {
10. m_nFlag = 10;
11. }
12. virtual void f(int nNum)
13. {
14. cout<<"The number is "<<nNum<< " ,Flag is " <<m_nFlag << endl;
15. }
16. int m_nFlag;
17.};
18.
19.void main(void)
20.{
21. typedef void(__stdcall *Fun)(int);
22.
23. Test test;
24. DWORD pThis = (DWORD)&test;
25. int i = 1250;
26.
27. //-----------------------------------------
28. int** pVtbl = (int**)&test;
29. Fun pFun = (Fun) pVtbl[0][0];
30. _asm
31. {
32. mov ecx,pThis;
33. }
34. pFun(i);
35. //-----------------------------------------
36.
37. //-----------------------------------------
38. pFun = (Fun)*((DWORD*)*(DWORD*)(&test));
39. _asm
40. {
41. mov ecx,pThis;
42. }
43. pFun(i);
44. //-----------------------------------------
45.
46.}
#include <windows.h>
#include <iostream>
01.#include <windows.h>
02.#include <iostream>
03.
04.using namespace std;
05.
06.class Test {
07.public:
08. Test()
09. {
10. m_nFlag = 10;
11. }
12. virtual void f(int nNum)
13. {
14. cout<<"The number is "<<nNum<< " ,Flag is " <<m_nFlag << endl;
15. }
16. int m_nFlag;
17.};
18.
19.void main(void)
20.{
21. typedef void(__stdcall *Fun)(int);
22.
23. Test test;
24. DWORD pThis = (DWORD)&test;
25. int i = 1250;
26.
27. //-----------------------------------------
28. int** pVtbl = (int**)&test;
29. Fun pFun = (Fun) pVtbl[0][0];
30. _asm
31. {
32. mov ecx,pThis;
33. }
34. pFun(i);
35. //-----------------------------------------
36.
37. //-----------------------------------------
38. pFun = (Fun)*((DWORD*)*(DWORD*)(&test));
39. _asm
40. {
41. mov ecx,pThis;
42. }
43. pFun(i);
44. //-----------------------------------------
45.
46.}
#include <windows.h>
#include <iostream>
using namespace std;
class Test {
public:
Test()
{
m_nFlag = 10;
}
virtual void f(int nNum)
{
cout<<"The number is "<<nNum<< " ,Flag is " <<m_nFlag << endl;
}
int m_nFlag;
};
public:
Test()
{
m_nFlag = 10;
}
virtual void f(int nNum)
{
cout<<"The number is "<<nNum<< " ,Flag is " <<m_nFlag << endl;
}
int m_nFlag;
};
void main(void)
{
typedef void(__stdcall *Fun)(int);
{
typedef void(__stdcall *Fun)(int);
Test test;
DWORD pThis = (DWORD)&test;
int i = 1250;
DWORD pThis = (DWORD)&test;
int i = 1250;
//-----------------------------------------
int** pVtbl = (int**)&test;
Fun pFun = (Fun) pVtbl[0][0];
_asm
{
mov ecx,pThis;
}
pFun(i);
//-----------------------------------------
int** pVtbl = (int**)&test;
Fun pFun = (Fun) pVtbl[0][0];
_asm
{
mov ecx,pThis;
}
pFun(i);
//-----------------------------------------
//-----------------------------------------
pFun = (Fun)*((DWORD*)*(DWORD*)(&test));
_asm
{
mov ecx,pThis;
}
pFun(i);
//-----------------------------------------
pFun = (Fun)*((DWORD*)*(DWORD*)(&test));
_asm
{
mov ecx,pThis;
}
pFun(i);
//-----------------------------------------
}
PS:上面的代码中使用了两种方法获取函数的地址,好好琢磨一下吧~
Method8:使用类的非静态函数作为回调(采用成员函数指针的方法)
使用成员函数指针,不过这个弄的有点不像回调了,仅供参考吧:
[cpp] view plaincopyprint?
01.#include <iostream>
02.using namespace std;
03.
04.class CTest{
05.public:
06. CTest(int nNum) : m_nNum(nNum)
07. {
08. }
09.
10. int m_nNum;
11. void func(int x, char *p) {
12. cout << m_nNum << x << p << endl;;
13. };
14.};
15.
16.typedef void (CTest::*Func)(int, char *);
17.
18.void CallFun(CTest* pCls, Func pFunc,int x, char* p)
19.{
20. (pCls->*pFunc)(x, p);
21.}
22.
23.int main() {
24.
25. Func pFunc;
26. pFunc = CTest::func;
27.
28. CTest test(5);
29. CTest* pClass = &test;
30.
31. (pClass->*pFunc)(1, "234");
32. CallFun(pClass, pFunc, 2, "abc");
33.
34. return 0;
35.}
#include <iostream>
using namespace std;
01.#include <iostream>
02.using namespace std;
03.
04.class CTest{
05.public:
06. CTest(int nNum) : m_nNum(nNum)
07. {
08. }
09.
10. int m_nNum;
11. void func(int x, char *p) {
12. cout << m_nNum << x << p << endl;;
13. };
14.};
15.
16.typedef void (CTest::*Func)(int, char *);
17.
18.void CallFun(CTest* pCls, Func pFunc,int x, char* p)
19.{
20. (pCls->*pFunc)(x, p);
21.}
22.
23.int main() {
24.
25. Func pFunc;
26. pFunc = CTest::func;
27.
28. CTest test(5);
29. CTest* pClass = &test;
30.
31. (pClass->*pFunc)(1, "234");
32. CallFun(pClass, pFunc, 2, "abc");
33.
34. return 0;
35.}
#include <iostream>
using namespace std;
class CTest{
public:
CTest(int nNum) : m_nNum(nNum)
{
}
public:
CTest(int nNum) : m_nNum(nNum)
{
}
int m_nNum;
void func(int x, char *p) {
cout << m_nNum << x << p << endl;;
};
};
void func(int x, char *p) {
cout << m_nNum << x << p << endl;;
};
};
typedef void (CTest::*Func)(int, char *);
void CallFun(CTest* pCls, Func pFunc,int x, char* p)
{
(pCls->*pFunc)(x, p);
}
{
(pCls->*pFunc)(x, p);
}
int main() {
Func pFunc;
pFunc = CTest::func;
pFunc = CTest::func;
CTest test(5);
CTest* pClass = &test;
CTest* pClass = &test;
(pClass->*pFunc)(1, "234");
CallFun(pClass, pFunc, 2, "abc");
CallFun(pClass, pFunc, 2, "abc");
return 0;
}
}
Method9:使用类的非静态函数作为回调(采用FastDelegate)
很多大牛们早就开始研究这个问题了,解决方法也有很多,FastDelegate就是一个,可以参看下面的网址:
当然中译本也有了,搜一下“成员函数指针与高性能的C++委托”就可以了,不多说了。
Method10:使用类的非静态函数作为回调(采用Tr1::function + bind)
C++ Technical Report 1 (TR1)是ISO/IEC TR 19768, C++ Library Extensions(函式库扩充)的一般名称。TR1是一份文件,内容提出了对C++标准函式库的追加项目。这些追加项目包括了正则表达式、智能指针、哈希表、随机数生成器等。TR1自己并非标准,他是一份草稿文件。然而他所提出的项目很有可能成为下次的官方标准。这份文件的目标在于「为扩充的C++标准函式库建立更为广泛的现成实作品」。
C++ tr1是针对C++标准库的第一次扩展。即将到来的下一个版本的C++标准c++0x会包括它,以及一些语言本身的扩充。tr1包括大家期待已久的smart pointer,正则表达式以及其他一些支持范型编程的东东。草案阶段,新增的类和模板的名字空间是std::tr1。
这个没怎么研究过,先列到这里,以后再慢慢研究~~
Method11:使用类的非静态函数作为回调(采用Boost::Function + bind)
BOOST库接触的比较少,也不敢多说啥,看到网上写的供给回调的方案有下面几种吧
Boost::Function + bind
Boost::Functor + Signal/Slot
Boost::lamda
大家可以研究一下,这个也以后再细细的说吧~
PS:大家可以看看下面的这个博客,讨论了一下各种方法的速度,没有具体考察过,大家权作参考吧~
方法太多了,用的场合也多种多样,还要细细的研究啊~
回调,To be, or not to be...