回调函数与回调机制
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
.
回调函数与回调机制
1. 什么是回调函数
回调函数(callback Function),顾名思义,用于回调的函数。回调函数只是一个功能片段,由用户按照回调函数调用约定来实现的一个函数。回调函数是一个工作流的一部分,由工作流来决定函数的调用(回调)时机。回调函数包含下面几个特性:
•属于工作流的一个部分;
•必须按照工作流指定的调用约定来申明(定义);
•他的调用时机由工作流决定,回调函数的实现者不能直接调用回调函数来实现工作流的功能;
2. 回调机制
回调机制是一种常见的设计模型,他把工作流内的某个功能,按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。
如上图所示,工作流提供了两个对外接口(获取参数、显示结果),以回调函数的形式实现。
•“获取参数”回调函数,需要工作流使用者设定工作流计算需要的参数。
•“显示结果”回调函数,提供计算结果给工作流使用者。
再以Windows的枚举顶级窗体为例。函数EnumWindows用于枚举当前系统中的所有顶级窗口,其函数原型为:
BOOL EnumWindows(
WNDENUMPROC lpEnumFunc, // callback function
LPARAM lParam // application-defined value
);
其中lpEnumFunc是一个回调函数,他用于返回枚举过程中的获得的窗口的句柄。其定义约定为:
BOOL CALLBACK EnumWindowsProc(
HWND hwnd, // handle to parent window
LPARAM lParam // application-defined value
);
在这个例子中,EnumWindows 是一个工作流,这个工作流用于遍历windows的所有窗口并获得其句柄。用户使用EnumWindows工作流的目的是想通过工作流来来获取窗口的句柄以便针对特定的一个或多个窗口进行相关处理。于是EnumWindows就扩展出接口lpEnumFunc,用于返回遍历的窗口句柄。
EnumWindows工作流的结束有两个方式:1,用户在回调函数中返回FALSE;2,再也找不到顶级窗口。我们可以推测EnumWindows的实现机制如下:
注:下列代码中的FindFirstTopWindows(), FindNextTopWindow()为假设的,Windows API 没有此函数,只是为了表明Enumwindows的内部流程。
BOOL EnumWindows(
WNDENUMPROC lpEnumFunc, // callback function
LPARAM lParam // application-defined value
)
{
BOOL bRet = TRUE;
HWND hWnd = ::FindFirstTopWindows(); // 此函数是假设的,查找第一个顶级窗口
// 当hWnd为0时表示再也找不到顶级窗口
while( hWnd )
{
bRet = (*lpEnumFunc)( hWnd, value );
if( !bRet)
break; // 终止EnumWindows工作流;
hWnd = ::FindNextWindow(); // 此函数是假设的,查找下一个顶级窗口
}
}
在EnumWindows(...)函数中,实现了窗口枚举的工作流,他通过回调机制把用户关心(顶级窗口句柄)的和枚举工作流分开,用户不需要知道EnumWindows的具体实现,用户只要知道,设定了lpEnumFunc函数,然后把函数指针传给EnumWindwos就可以获得想要的窗口句柄。
2. 回调机制应用
使用回调机制,可以为工作流实现扩展。可以把工作流中需要用户干预的,或需要提供给用户的数据以回调的模式提供给用户。而用户不需要知道整个工作的流程,只需知道回调函数的说明就可以使用工作流模块提供的功能,这对信息的隐藏也是有作用的。
3. 回调机制的实现形式
•回调函数
•虚拟函数
•事件
example: 以虚函数实现回调机制
class CWorkFlow
{
void init()
{
_a = 0;
_b = 0;
}
int _a;
int _b;
public:
void Start()
{
// 初始化
init();
// 调用处理数据
Handle( a, b );
// 报告结果
Report( a, b );
}
virtual void Handle( int &a, int &b ) = 0;
virtual void Report( int iRet) = 0;
};
class CMain :
public CWorkFlow
{
public:
void Handle( int &a, int &b )
{
a = a + b/2;
}
void Report( int iRet)
{
printf("iRet = %d\n", iRet); }
};
// application
int main()
{
CMain main;
main.Start();
}