在C語言中的回調很方便。當然,我們可以在C++中使用類似於C方式的回調函數,也就是將全局函數定義爲回調函數,然後再供我們調用。
typedef void(*pCalledFun)(int *);
[cpp] view plaincopyprint?
01.#include <iostream>
02.using namespace std;
03.
04.typedef void (__stdcall *pFun)(void);
05.typedef void (__cdecl *pFunc)(void);
06.
07.void __stdcall TextPrint(void)
08.{
09. cout << "Call Back Like Pascal" << endl;
10.}
11.
12.void __cdecl TextPrintc(void)
13.{
14. cout << "Call Back Like C" << endl;
15.}
16.
17.void ForText(pFun pFun1, pFunc pFun2)
18.{
19. pFun1();
20. pFun2();
21.}
22.
23.void main(void)
24.{
25. //pFun pP = TextPrint;
26. //pFunc pPC = TextPrintc;
27. //pP();
28. //pPC();
29. ForText(TextPrint, TextPrintc);
30.}
#include <iostream>
using namespace std;
typedef void (__cdecl *pFunc)(void);
{
cout << "Call Back Like Pascal" << endl;
}
{
cout << "Call Back Like C" << endl;
}
{
pFun1();
pFun2();
}
{
//pFun pP = TextPrint;
//pFunc pPC = TextPrintc;
//pP();
//pPC();
ForText(TextPrint, TextPrintc);
}
既然使用了C++,就不能總是生活在C的陰影中,我們要使用類,類,類!!!
01.#include <iostream>
02.using namespace std;
03.
04.typedef void (*pFun)(void);
05.
06.class CCallBack
07.{
08.public:
09. static void TextPrint(void)
10. {
11. cout << "Static Callback Function of a Class" << endl;
12. }
13.};
14.
15.void ForText(pFun pFun1)
16.{
17. pFun1();
18.}
19.
20.void main(void)
21.{
22. ForText(CCallBack::TextPrint);
23.}
#include <iostream>
using namespace std;
{
public:
static void TextPrint(void)
{
cout << "Static Callback Function of a Class" << endl;
}
};
{
pFun1();
}
{
ForText(CCallBack::TextPrint);
}
01.#include <iostream>
02.using namespace std;
03.
04.class CCallBack
05.{
06.public:
07. typedef void (*pFun)(void);
08. static void TextPrint(void)
09. {
10. cout << "Static Callback Function of a Class with funtype" << endl;
11. }
12.};
13.
14.void ForText(CCallBack::pFun pFun1)
15.{
16. pFun1();
17.}
18.
19.void main(void)
20.{
21. ForText(CCallBack::TextPrint);
22.}
#include <iostream>
using namespace std;
{
public:
typedef void (*pFun)(void);
static void TextPrint(void)
{
cout << "Static Callback Function of a Class with funtype" << endl;
}
};
{
pFun1();
}
{
ForText(CCallBack::TextPrint);
}
Method3:使用仿函數作爲回調
01.#include <iostream>
02.using namespace std;
03.
04.typedef void(*Fun)(void);
05.
06.inline void TextFun(void)
07.{
08. cout << "Callback Function" << endl;
09.}
10.
11.class TextFunor
12.{
13.public:
14. void operator()(void) const
15. {
16. cout << "Callback Functionor" << endl;
17. }
18.};
19.
20.void ForText(Fun pFun, TextFunor cFun)
21.{
22. pFun();
23. cFun();
24.}
25.
26.void main(void)
27.{
28. TextFunor cFunor;
29. ForText(TextFun, cFunor);
30.}
#include <iostream>
using namespace std;
{
cout << "Callback Function" << endl;
}
{
public:
void operator()(void) const
{
cout << "Callback Functionor" << endl;
}
};
{
pFun();
cFun();
}
{
TextFunor cFunor;
ForText(TextFun, cFunor);
}
援引一點關於仿函數的介紹吧:
我的建議是,如果可以用仿函數實現,那麼你應該用仿函數,而不要用回調。
01.#include <iostream>
02.using namespace std;
03.
04.template < class Class, typename ReturnType, typename Parameter >
05.class SingularCallBack
06.{
07.public:
08. typedef ReturnType (Class::*Method)(Parameter);
09.
10. SingularCallBack(Class* _class_instance, Method _method)
11. {
12. class_instance = _class_instance;
13. method = _method;
14. };
15.
16. ReturnType operator()(Parameter parameter)
17. {
18. return (class_instance->*method)(parameter);
19. };
20.
21. ReturnType execute(Parameter parameter)
22. {
23. return operator()(parameter);
24. };
25.private:
26. Class* class_instance;
27. Method method;
28.};
29.
30.class CCallBack
31.{
32.public:
33. int TextPrint(int iNum)
34. {
35. cout << "Class CallBack Function" << endl;
36. return 0;
37. };
38.};
39.
40.template < class Class, typename ReturnType, typename Parameter >
41.void funTest(SingularCallBack<Class, ReturnType, Parameter> tCallBack)
42.{
43. tCallBack(1);
44.}
45.
46.void main(void)
47.{
48. CCallBack callback;
49. SingularCallBack<CCallBack, int, int> Test(&callback, callback.TextPrint);
50. Test.execute(1);
51. Test(1);
52. funTest(Test);
53.}
#include <iostream>
using namespace std;
class SingularCallBack
{
public:
typedef ReturnType (Class::*Method)(Parameter);
{
class_instance = _class_instance;
method = _method;
};
{
return (class_instance->*method)(parameter);
};
{
return operator()(parameter);
};
private:
Class* class_instance;
Method method;
};
{
public:
int TextPrint(int iNum)
{
cout << "Class CallBack Function" << endl;
return 0;
};
};
void funTest(SingularCallBack<Class, ReturnType, Parameter> tCallBack)
{
tCallBack(1);
}
{
CCallBack callback;
SingularCallBack<CCallBack, int, int> Test(&callback, callback.TextPrint);
Test.execute(1);
Test(1);
funTest(Test);
}
關鍵字
堆棧清除
參數傳遞
__stdcall
被調用者
將參數倒序壓入堆棧(自右向左)
__thiscall
被調用者
壓入堆棧,this指針保存在 ECX 寄存器中
可見兩者的不同之處就是_thiscall把this指針保存到了ECX的寄存器中,其他都是一樣的。所以我們只需要在調用過程中首先把this指針保存到ECX,然後跳轉到期望的成員函數地址就可以了。代碼如下:
[cpp] view plaincopyprint?
01.#include <tchar.h>
02.#include <wtypes.h>
03.#include <iostream>
04.
05.using namespace std;
06.typedef void (*FUNC)(DWORD dwThis);
07.typedef int (_stdcall *FUNC1)(int a, int b);
08.
09.
10.#pragma pack(push,1)
11.//先將當前字節對齊值壓入編譯棧棧頂, 然後再將 n 設爲當前值
12.typedef struct tagTHUNK
13.{
14. BYTE bMovEcx; //MOVE ECX Move this point to ECX
15. DWORD dwThis; // address of this pointer
16. BYTE bJmp; //jmp
17. DWORD dwRealProc; //proc offset Jump Offset
18. void Init(DWORD proc,void* pThis)
19. {
20. bMovEcx = 0xB9;
21. dwThis = (DWORD)pThis;
22. bJmp = 0xE9;
23. dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)));
24. //jmp跳轉的是當前指令地址的偏移,也就是成員函數地址與當前指令的地址偏移
25. FlushInstructionCache(GetCurrentProcess(),this,sizeof(THUNK));
26. // 因爲修改了數據,所以調用FlushInstructionCache,刷新緩存
27. }
28.}THUNK;
29.// BYTE bMovEcx; DWORD dwThis; 這兩句連起來就是把this指針保存到了ECX的寄存器
30.// BYTE bJmp; DWORD dwRealProc;就是跳轉到成員函數的地址
31.#pragma pack(pop)
32.//將編譯棧棧頂的字節對齊值彈出並設爲當前值.
33.template<typename dst_type, typename src_type>
34.dst_type pointer_cast(src_type src)
35.{
36. return *static_cast<dst_type*>(static_cast<void*>(&src));
37.}
38.
39.class Test
40.{
41.public:
42. int m_nFirst;
43. THUNK m_thunk;
44. int m_nTest;
45.
46. Test() : m_nTest(3),m_nFirst(4)
47. {}
48. void TestThunk()
49. {
50. m_thunk.Init(pointer_cast<int>(&Test::Test2),this);
51. FUNC1 f = (FUNC1)&m_thunk;
52. f(1,2);
53. cout << "Test::TestThunk()" << endl;
54. }
55.
56. int Test2(int a, int b)
57. {
58. cout << a << " " << b << " " << m_nFirst << " " << m_nTest << " <<I am in Test2" << endl;
59. return 0;
60. }
61.};
62.
63.
64.int main(int argc, _TCHAR* argv[])
65.{
66. Test t;
67. t.TestThunk();
68. //system("pause");
69. return 0;
70.}
#include <tchar.h>
#include <wtypes.h>
#include <iostream>
typedef void (*FUNC)(DWORD dwThis);
typedef int (_stdcall *FUNC1)(int a, int b);
#pragma pack(push,1)
//先將當前字節對齊值壓入編譯棧棧頂, 然後再將 n 設爲當前值
typedef struct tagTHUNK
{
BYTE bMovEcx; //MOVE ECX Move this point to ECX
DWORD dwThis; // address of this pointer
BYTE bJmp; //jmp
DWORD dwRealProc; //proc offset Jump Offset
void Init(DWORD proc,void* pThis)
{
bMovEcx = 0xB9;
dwThis = (DWORD)pThis;
bJmp = 0xE9;
dwRealProc = DWORD((INT_PTR)proc - ((INT_PTR)this+sizeof(THUNK)));
//jmp跳轉的是當前指令地址的偏移,也就是成員函數地址與當前指令的地址偏移
FlushInstructionCache(GetCurrentProcess(),this,sizeof(THUNK));
// 因爲修改了數據,所以調用FlushInstructionCache,刷新緩存
}
}THUNK;
// BYTE bMovEcx; DWORD dwThis; 這兩句連起來就是把this指針保存到了ECX的寄存器
// BYTE bJmp; DWORD dwRealProc;就是跳轉到成員函數的地址
#pragma pack(pop)
//將編譯棧棧頂的字節對齊值彈出並設爲當前值.
template<typename dst_type, typename src_type>
dst_type pointer_cast(src_type src)
{
return *static_cast<dst_type*>(static_cast<void*>(&src));
}
{
public:
int m_nFirst;
THUNK m_thunk;
int m_nTest;
Test() : m_nTest(3),m_nFirst(4)
{}
void TestThunk()
{
m_thunk.Init(pointer_cast<int>(&Test::Test2),this);
FUNC1 f = (FUNC1)&m_thunk;
f(1,2);
cout << "Test::TestThunk()" << endl;
}
int Test2(int a, int b)
{
cout << a << " " << b << " " << m_nFirst << " " << m_nTest << " <<I am in Test2" << endl;
return 0;
}
};
int main(int argc, _TCHAR* argv[])
{
Test t;
t.TestThunk();
//system("pause");
return 0;
}