首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

函数对象实现回调,该怎么解决

2012-02-08 
函数对象实现回调哪位能够用函数对象实现回调举个例子,http://dev.csdn.net/article/83007.shtm除外[解决

函数对象实现回调
哪位能够用函数对象实现回调举个例子,
http://dev.csdn.net/article/83007.shtm
除外

[解决办法]

/*-======================- Copyright (c) 2006 -======================-

程序作者:
张鲁夺(zhangluduo) : 为所有爱我的人和我爱的人努力!

联系方式:
oopfans@msn.com
[oopfans]群:34064264

修改时间:
2007-02-01

功能描述:
thunk技术实现.利用这个类可以把回调函数完全封装成类成员函数.使用这
个类时,一定要确保类实例的生命周期,如下所示:

-----------------------------

正确调用如下(一):
class T
{
private:
ZThunk m_thunk; // 将ZThunk声明为数据成员
public:
void MemberFunction()
{
m_thunk.CallBack(parameters ... ); // ok!
}
}

-----------------------------

正确调用如下(二):
ZThunk m_thunk; // 将ZThunk声明全局对像
class T
{
public:
void MemberFunction()
{
m_thunk.CallBack(parameters ... ); // ok!
}
}

-----------------------------

错误调用如下:

class T
{
public:
void MemberFunction()
{
ZThunk m_thunk; // 将ZThunk声明为局部对像,
// 不会有语法错误,但是下面的调用会失败!
m_thunk.CallBack(parameters ... ); // error!
}
}

-----------------------------

调用综合示例:
class CTimer
{
private:

//thunk对像
ZThunk m_thunk;

//定时器回调函数
void TimerProc(HWND hWnd, DWORD dwMsg , WPARAM wPa, LPARAM lPa);

public:

//安装定时器
void Set(HWND hWnd,int TimerID,int TimerSpeed)
{
//(TIMERPROC)m_thunk.CallBack(this,&CTimer::TimerProc,ZThunk::THISCALL)
//上面一句指示了定时器回调函数为CTimer类的TimerProc成员函数,也可以指定
//其他类中的成员函数
::SetTimer(hWnd,TimerID,TimerSpeed,
(TIMERPROC)m_thunk.CallBack(this,&CTimer::TimerProc,ZThunk::THISCALL));
}
};


版权声明:
许可任何单位,个人随意使用,拷贝,修改,散布及出售这份代码,但是必须保
留此版权信息,以慰藉作者辛勤的劳动,及表明此代码的来源,如若此份代码
有任何BUG,请通知作者,以便弥补作者由于水平所限而导致的一些错误和不
足,谢谢!

此份代码是作者跟据一位网友[JERKII.SHANG (JERKII@HOTMAIL.COM)]的一
篇文章[一种实现Win32窗口过程函数(Window Procedure)的新方法--
基于Thunk实现的类成员消息处理函数]修改而成,在此对原作者开源的精神
致敬!

-======================- Copyright (c) 2006 -======================-*/

#ifndef _ZTHUNK
#define _ZTHUNK

class ZThunk
{
private:
unsigned char m_ThiscallCode[10];
unsigned char m_StdcallCode[16];
public:
enum CALLINGCONVENTIONS
{
STDCALL = 1,
THISCALL= 2
};
public:
template <class T>
void* CallBack(void* pThis,T MemberAddr,CALLINGCONVENTIONS WhichCalling=STDCALL)
{
// these codes only use in stdcall
if(WhichCalling==STDCALL)
{
// Encoded machine instruction Equivalent assembly languate notation
// --------------------------- -------------------------------------
// FF 34 24 push dword ptr [esp] ; Save (or duplicate) ; the Return Addr into stack
// C7 44 24 04 ?? ?? ?? ?? mov dword ptr [esp+4], pThis ; Overwite the old ; Return Addr with 'this pointer '
// E9 ?? ?? ?? ?? jmp target addr ; Jump to target message handler



char Buf[33]={0};
sprintf(Buf, "%d ",MemberAddr);
unsigned long JmpAddr = (unsigned long) atol(Buf) - (unsigned long) &m_StdcallCode[0] - 16;

m_StdcallCode[11] = 0xE9;
*((unsigned long *) &m_StdcallCode[ 0]) = 0x002434FF;
*((unsigned long *) &m_StdcallCode[ 3]) = 0x042444C7;
*((unsigned long *) &m_StdcallCode[ 7]) = (unsigned long) pThis;
*((unsigned long *) &m_StdcallCode[12]) = JmpAddr;

return (void*)m_StdcallCode;
}
// these codes only use in thiscall
else if(WhichCalling==THISCALL)
{
// Encoded machine instruction Equivalent assembly languate notation
// --------------------------- -------------------------------------
// B9 ?? ?? ?? ?? mov ecx, pThis ; Load ecx with this pointer
// E9 ?? ?? ?? ?? jmp target addr ; Jump to target message handler

char Buf[33]={0};
sprintf(Buf, "%d ",MemberAddr);
unsigned long JmpAddr = (unsigned long) atol(Buf) - (unsigned long) &m_ThiscallCode[0] - 10;

m_ThiscallCode[0] = 0xB9;
m_ThiscallCode[5] = 0xE9;
*((unsigned long *) &m_ThiscallCode[1]) = (unsigned long) pThis;
*((unsigned long *) &m_ThiscallCode[6]) = JmpAddr;

return (void*)m_ThiscallCode;
}return 0;
}
};

#endif

[解决办法]
怎么又变成“同步”和“异步”了?
这完全要取决于真正使用回调函数的部分是否与当前线程处于同一线程之中。
如果LZ自己写过一个函数,提供回调函数的参数接口给别人用,自然就会明白回调函数是怎么回事了。

[解决办法]
Mark~
[解决办法]
会起线程吧
那就是一个很好的例子
CreateThread
[解决办法]
这就恍然大悟了?那再给你一个常用的API例子的SetTimer,当HWND填NULL的时候,最后一个作为回调函数的参数,是在同一线程中调用!
[解决办法]
通常使用回调函数的函数都会提供一个void*指针或者其他的参数作为额外参数,为你的对象编写一个static函数作为回调函数,然后将this作为参数传给调用函数。

thunk技术一般用在这种情况:回调函数不能直接访问到对象指针,而是给出类似句柄这样的索引,而通过索引寻找对象需要维护查找表,而且比较费时。

使用thunk这种“数据型”函数毕竟限制太多,只能局限在一个平台上,跟平台甚至编译器的联系太紧密了。
[解决办法]
#include "iostream "

using namespace std;


struct ICheck {
virtual bool operator()(int n) = 0;
};

struct Multiple10Check : public ICheck {
bool operator()(int n) {
if (n % 10 == 0)
return true;
return false;
}
};

struct EvenCheck : public ICheck {
bool operator()(int n) {
if (n % 2 == 0)
return true;
return false;
}
};

void do_check(int _start, int _end, ICheck& CheckFun)
{
for (int i = _start; i < _end; ++i)
{
if (CheckFun(i))
cout < <i < <endl;
}
}


void main()
{
cout < < "1 -- 100 能被10整除的数学 : " < <endl;
do_check(1, 100, Multiple10Check());

cout < <endl < <endl;
cout < < "1 -- 100 的偶数 : " < <endl;
do_check(1, 100, EvenCheck());
}

热点排行