熟悉高级语言像c#的人应该都知道,c#中有事件的机制,qt有信号槽的机制,设想我们有个简单的任务,窗口上一个按钮,按钮内部是一个button类,我们用鼠标点击一下他,他会发出一个鼠标点击的通知,我们需要在这个通知里面做一些自己的事情。我大概总结了三种方法。
1 多态
这是最一般的方法,继承button,利用多态性质覆盖button中鼠标点击的虚方法,在虚方法里面写自己的代码即可。
2 回调
可是我们要是这样做,我们就无法方便的取到放在窗口类里面的公共数据了,这就是多态的一个不好的地方。像这样一个简单的任务,还是用回调的机制比较好一点。回调类似c#中的事件机制,在c++里实现,我们首先提供一个回调注册的方法,将回调对象保存起来,然后在事件发生的时候调用他就可以啦。回调对象用boos::funcktion类型来表达,回调对象可以是函数指针,函数对象,类成员函数,lamda表达式。
class baseClass
{
public:
typedef boost::function<int(std::string&)> CBFunc;
baseClass()
{
}
void RaiseEvent(std::string& str)
{
if(cb)
cb(str);
}
void registerCB(CBFunc cb)
{
this->cb=cb;
}
private:
CBFunc cb;
};
int main()
{
baseClass bc;
bc.registerCB([](std::string& a){std::cout<<a<<std::endl;return 0;});
std::string info("fuck you");
bc.RaiseEvent(info);
}
3 策略模式
上面两种方法可以解决大部分应用场合,但考虑到这样一种应用场合,你需要编写一个画图程序,有不同的工具,画矩形的,画圆的,变形的,拖动的等,你是在一个panel上面绘制。这时候怎么办?最原始的办法档让就是设置一个标记,记下当下选择的是什么工具,然后在panel的鼠标事件里进去区分,如果是判断是画圆的,就在鼠标点击的时候放一个圆对象,拖动的时候缩放;如果是画框的有不一样。如果你这样写,等你下次要扩充一个工具的时候,就累死了。因为你各种鼠标事件里面都要改一遍。优雅的实现方式是这样,你定义个事件接口,里面有各种鼠标事件,鼠标按下,鼠标释放,鼠标移动等,然后不同的工具进行不同的实现,每一个成为一个工具类,标准叫法是事件处理器,你将这个事件处理器在用户选择工具时传递给panel,panel在自身的事件里面调用事件处理器里面的相应的方法。因此工具类就可以获取到各种事件了。他可以在里面自定义自己的操作。选择不同的工具只需要切换不同的事件处理器给panel就行了,是不是很魔幻?下面上代码解释
class IEventhandle
{
public :
virtual void onEvent1()=0;
virtual void onEvent2()=0;
virtual void onEvent3()=0;
};
class myEventhandle:public IEventhandle
{
public:
void onEvent1()
{
std::cout<<"me fuck event 1"<<std::endl;
}
void onEvent2()
{
std::cout<<"me fuck event 2"<<std::endl;
}
void onEvent3()
{
std::cout<<"me fuck event 3"<<std::endl;
}
};
class youEventhandle:public IEventhandle
{
public:
void onEvent1()
{
std::cout<<"you fuck event 1"<<std::endl;
}
void onEvent2()
{
std::cout<<"you fuck event 2"<<std::endl;
}
void onEvent3()
{
std::cout<<"you fuck event 3"<<std::endl;
}
};
class baseClass
{
public:
baseClass():handle(NULL)
{
}
void RaiseEvent1()
{
if(handle)
handle->onEvent1();
}
void RaiseEvent2()
{
if(handle)
handle->onEvent2();
}
void RaiseEvent3()
{
if(handle)
handle->onEvent3();
}
void registerHandle(IEventhandle* hd)
{
this->handle=hd;
}
private:
IEventhandle* handle;
};
int main()
{
baseClass bc;
myEventhandle mh;
bc.registerHandle(&mh);
bc.RaiseEvent1();
bc.RaiseEvent2();
bc.RaiseEvent3();
youEventhandle yh;
bc.registerHandle(&yh);
bc.RaiseEvent1();
bc.RaiseEvent2();
bc.RaiseEvent3();
}
ok,这就是事实的全部真相,c#中能实现的,c++照样可以,c++中可以实现的c#不一定可以。