C++编程过程中,常常使用回调函数的形式来通知某个类一个事件。例如,使用图形引擎实现了一个滚动条控件,当滚动条滚动的时候,需要通知其父窗口进行滚动,这时可以注册一个回调函数到滚动条类中接收滚动事件。
回调函数分两种:静态回调函数和类成员回调函数。其中静态回调函数比较常用,例如,我们定义如下静态函数指针:
typedef void(*Func)();
这个类型的函数指针,可以指向一个没有参数并且返回值为void的函数。在消息源中,我们定义如下函数指针变量:
Func pf;
并且提供一些接口对这个变量进行赋值,当需要发送消息时,只需如下调用:
if(NULL != pf)
pf();
这样就能发送消息给消息接收者了。
在消息接收者一端,我们只要定义一个函数如下:
void MsgReceive();
即可接收消息。如果消息接收者是一个类,那么我们需要一个静态函数:
class A
{
protected:
static void MsgReceive();
};
但这样有一个问题,如果在消息接收函数中需要处理本类中的一些变量的状态,则因为是静态成员函数,而不能访问非静态成员。有一个解决办法是在消息接收函数中定义一个用户自定义参数,例如:
typedef void(*Func)(LPARAM);
这个消息接收函数带一个自定义参数,消息接收类可以设置将自身的this指针存储其中,当接收消息时,由发送者返回这个参数。不过,这种方法需要在消息接收类中将自定义参数强制转换为本类指针,然后由该指针访问成员变量,不是很方便。
还有另一个解决方案,就是使用类成员函数指针:
class SomeClass
{
public:
void testFunc() {}
};
typedef void(SomeClass::*Func)();
这时,我们在消息发送者中定义Func pf;并将pf赋值为&SomeClass::testFunc,然后提供一个接口传递SomeClass的一个实例指针(SomeClass* pobj),就可以使用pobj和pf访问SomeClass::testFunc。访问方法如下:
(pobj->*pf)();
这种方式,可以直接注册成员函数来接收消息,方便了不少。但是,由于Func定义为SomeClass的某个空参成员函数指针,如果我们有另一个类,也需要接收消息,就不好做了,因为Func只能指向SomeClass的一个成员函数,不能指向其他类的成员函数。
为解决上述问题,很容易联想到使用模板,将Func定义为一个模板函数指针,于是我们“尝试”者写出如下代码:
template<class T>
typedef void(T::*Func)();
但是很不幸,C++不支持模板类型定义,具体原因请自行查询C++标准。
那么没办法了么?我们可以绕开C++这一限制,即将消息发送者制作成模板类,如下所示:
在模板类中定模板函数是C++所允许的,模板参数T就是我们需要的消息接收者。怎么样,是不是能够方便很多呢?