在C++实现回调(续)

在C++实现回调(续)
 Method6:使用类的非静态函数作为回调(采用thunk的方法2)
在上面的实现过程中,可以看出来主要的部分就是这里:
        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;
template<typename ToType, typename FromType> 
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;
};

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"); 
}
 
这里我们使用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>
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;
};
void main(void)
{
    typedef void(__stdcall *Fun)(int);
    Test test;
 DWORD  pThis = (DWORD)&test;
 int i = 1250;
 //-----------------------------------------
 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);
 //-----------------------------------------
}
 
 

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;
class CTest{
public:
 CTest(int nNum) : m_nNum(nNum)
 {
 }
 int m_nNum;
 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);
}
int main() {
 Func pFunc;
 pFunc = CTest::func;
 CTest test(5);
 CTest* pClass = &test;
 (pClass->*pFunc)(1, "234");
 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...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值