让C++也来支持事件?
面向对象发展到今天,人们已经不满足于对一个事物的描述仅停留在属性和方法上了。事件也作为对象的基本组成部分,被新兴的面向对象语言所采纳。 所谓事件就是一个对象在某个特定的条件下触发通知对象的创建者,由创建者来进行相应的处理。我们可以看到事件的真实处理过程并不被包装在对象里。在java,c#,dephi等语言中都提供了对事件的支持,或者以关键字的形式,或者以类库的形式。而c++中见不到任何关于事件的关键字和类库,难道c++就无法拥有事件这个特性吗?只要动动脑筋就没有难事。现在我们就让c++也来支持事件。
这里仅从语言上考虑,而不使用任何平台相关的特性(消息,事件对象...)。因此我拿出两种实现方法,一种是采用函数指针,另一种采用虚函数。
1. 采用函数指针方式,代码如下:
#include <IOSTREAM> using namespace std; //定义事件函数的类型 typedef void (*EOnBeforeInvoke)(); typedef void (*EOnAfterInvoke)(); //一个拥有事件的类 class CSomeObject1 { public: //定义事件 EOnBeforeInvoke OnBeforeInvoke; //调用前事件 EOnAfterInvoke OnAfterInvoke; //调用后事件 public: CSomeObject1() { OnBeforeInvoke = NULL; OnAfterInvoke = NULL; } void Invoke() { //触发OnBeforeInvoke事件 if (OnBeforeInvoke != NULL) OnBeforeInvoke(); cout << "CSomeObject1::Invoke()" <<endl; //触发OnAfterInvoke事件 if (OnAfterInvoke != NULL) OnAfterInvoke(); } }; //CSomeObject1对象的创建者类 class CEventTest1 { CSomeObject1 m_objSome; static void OnBeforeInvoke() { cout<< "调用前..." <<endl; } static void OnAfterInvoke() { cout<< "调用后..." <<endl; } //安装事件 void InstallEvents() { m_objSome.OnBeforeInvoke = OnBeforeInvoke; m_objSome.OnAfterInvoke = OnAfterInvoke; } //卸载事件 void UninstallEvents() { m_objSome.OnBeforeInvoke = NULL; m_objSome.OnAfterInvoke = NULL; } public: CEventTest1() { InstallEvents(); } ~CEventTest1() { UninstallEvents(); } void Invoke() { m_objSome.Invoke(); } }; int main(int argc, char* argv[]) { CEventTest1 test1; test1.Invoke(); }
记得当年在TurboC下编程时,虽然没有c++,但依然可以写出面向对象的代码,就是利用struct里添加函数指针域的方式,来实现现在c++中的class。如今函数指针依然有用武之地。
2. 采用虚拟函数的形式,代码如下:
#include <IOSTREAM> using namespace std; //事件接口 class __declspec(novtable) ISomeObject2Events { friend class CSomeObject2; protected: virtual void OnBeforeInvoke(); virtual void OnAfterInvoke(); }; //一个拥有事件的类 class CSomeObject2 { public: ISomeObject2Events * m_pEvents; void Invoke() { //触发OnBeforeInvoke事件 if (m_pEvents != NULL) m_pEvents->OnBeforeInvoke(); cout<<"CSomeObject2::Invoke()"<<endl; //触发OnAfterInvoke事件 if (m_pEvents != NULL) m_pEvents->OnAfterInvoke(); } }; //CSomeObject2对象的创建者类 class CEventTest2 : public ISomeObject2Events { CSomeObject2 m_objSome; //调用前事件处理 virtual void OnBeforeInvoke() { cout<< "调用前..." <<endl; }; //调用后事件处理 virtual void OnAfterInvoke() { cout << "调用后..." <<endl; }; //安装事件 void InstallEvents() { m_objSome.m_pEvents = this; } //卸载事件 void UninstallEvents() { m_objSome.m_pEvents = NULL; } public: CEventTest2() { InstallEvents(); } ~CEventTest2() { UninstallEvents(); } void Invoke() { m_objSome.Invoke(); } }; int main(int argc, char* argv[]) { CEventTest2 test2; test2.Invoke(); }
这两种方式各有利弊,使用函数指针的好处是触发事件效率高。而采用虚函数的形式的好处是代码更令活更清晰一些。大家可以凭喜好来选择。如果大家看过之后有什么指教或补充,请千万别吝惜你的思想和文字。