遇见
在我们使用一些第三方SDK、不同框架层之间的事件通知或第三方的C库时,经常需要用相应的接口来注册一些回调函数来处理特定的事件。这里以NOLO SDK为例来描述这样的一个问题。
typedef enum ExpandMsgType {
DoubleClickMenu=1,
DoubleClickSystem
}ExpandMsgType;
typedef void(__cdecl *expandMsg_FuncCallBack)(ExpandMsgType expandMsgType);
NOLO_API bool _cdecl expandDataNotify_FuncCallBack(expandMsg_FuncCallBack fun);
我们注册一个expandMsg_FuncCallBack类型的回调函数,代码如下:
#include "stdafx.h"
#include <windows.h>
#include "nolo_api.h"
using namespace NOLO;
class HeadMountDevice{
public:
HeadMountDevice() {};
~HeadMountDevice() {};
void CallBackFunction(ExpandMsgType expandMsgType) {};
};
int main()
{
HeadMountDevice *p_hmd = new HeadMountDevice();
expandDataNotify_FuncCallBack(p_hmd->CallBackFunction);
system("Pause");
return 0;
}
报错:
error C3867: 'HeadMountDevice::CallBackFunction': non-standard syntax; use '&' to create a pointer to member
似乎是需要使用’&’来指向成员函数,修改后如下:
#include "stdafx.h"
#include <windows.h>
#include "nolo_api.h"
using namespace NOLO;
class HeadMountDevice{
public:
HeadMountDevice() {};
~HeadMountDevice() {};
void CallBackFunction(ExpandMsgType expandMsgType) {};
};
int main()
{
HeadMountDevice *p_hmd = new HeadMountDevice();
expandDataNotify_FuncCallBack(&p_hmd->CallBackFunction);//modify this line
system("Pause");
return 0;
}
还是报错:
error C2276: '&': illegal operation on bound member function expression
使用”&类名::函数名”方式访问成员函数的地址:
...
expandDataNotify_FuncCallBack(&HeadMountDevice::CallBackFunction);
...
依然报错:
error C2664: 'bool NOLO::expandDataNotify_FuncCallBack(NOLO::expandMsg_FuncCallBack)': cannot convert argument 1 from 'void (__thiscall HeadMountDevice::* )(NOLO::ExpandMsgType)' to 'NOLO::expandMsg_FuncCallBack'
分析
这里成员函数作为回调函数,不能通过这种方式来指定,主要原因有两个:
1. 成员函数属于类本身,而不属于任何一个特定的实体.
2. 成员函数默认隐藏了一个”this”指针参数,填充在参数列表的第一个位置,所以你的回调函数与SDK上的回调函数实际上并不匹配!
上面第一点,很容易理解,关