我们从一个具体的问题入手:
“现在有一堆按钮,以及一堆电器,按钮对它需要控制的对象一无所知,电器也不知道它们开关的具体类型,它们之间的关系可能是一对多,也可能是多对一,并且需要支持动态添加和删除,应该如何设计这个结构?”
这里有个形象的图:
基于静态成员函数的回调
--------------------------------------------------------------------------------
为了实现组件间的控制,我们很容易想到“回调函数”,对于C++开发者,我们肯定不希望一个类自身的处理函数存在于类外,但是类成员函数中被自动添加的隐形this形参造成了函数指针调用的不匹配,于是我们想到了使用static成员函数:
// 被调类
class Tv
{
public:
static void onBtnClicked(bool b)
{
if ( b == true )
cout << "Tv is being turned on.";
else
cout << "Tv is being turned off.";
}
};
// 还有其他可能被调用的对象
// class Lamp...
// class Laptop...
typedef void (*PF)(bool);
class Button
{
public:
//主调函数
void click(PF p, bool b)
{
p(b);
}
};
int main()
{
PF p = &Tv::onBtnClicked;
Button btn;
btn.click(p, true);
return 0;
}
这样我们就可以动态地为Button赋上它需要调用那个函数并执行。但缺点也是显而易见的——被调函数作为静态函数不能访问非静态成员与函数,Button触发的结果对于每一个Tv对象都是一样的,这显然不是我们想要的。因此,我们想到了在Button中动态地传入被调对象的指针,这样,通过这个指针我们就可以调用该对象的非静态成员函数了。由于Button还需要控制其他设备,我们很自然地想到使用模板:
基于非静态成员函数的回调
--------------------------------------------------------------------------------
//被调类
class Tv
{
public:
Tv(int t1, int t2) : bootTime(t1), offTime(t2){}
//被调函数
void onBtnClicked(bool b)
{
if ( b == true )
cout << "Tv is being turned on. bootTime is " << bootTime;
else
cout << "Tv is being turned off. offTime is " << offTime;
}
private:
int bootTime;
int offTime;
};
// 还有其他可能被 Button 类控制的被调类
class Lamp
{
public:
void onBtnClicked()
{
cout << "This Lamp is control by voice";
}
};
// class Laptop...
// 主调类
template<typename Tobject, typename Tparam>
class Button
{
typedef void (Tobject::*Tfunc)(T