C++ 事件机制实现

 

C++ 事件机制实现

分类: win32 SDK 40人阅读 评论(0) 收藏 举报

http://www.cppblog.com/zhuweisky/archive/2005/09/11/193.html

 

 

 事件是面向组件开发的必要特性之一,但C++不直接支持事件,没关系,我自己实现了一个,感觉很好用,分享给大家!
   最开始打算用函数指针模拟事件,但由于C++中成员函数指针不能和void*相互强转,而且 typedef中不能含有模板,所以才不得已以接口继承实现。这样效果也不错 :)


一. 先看看事件接口定义和实现

view plain copy to clipboard print ?
  1. #ifndef IEVENT_H   
  2. #define IEVENT_H   
  3. /* 
  4.  以下各基础设施是在C++中事件机制的完整实现,事件是面向组件开发的必要特性之一。 
  5.    
  6.  创 作 者:sky 
  7.  时    间:2005.06.22  
  8.  修订时间:2005.06.22 
  9. */  
  10. #include "../Collection/SafeArrayList.h"   
  11. template<class SenderType ,class ParaType> class EventPublisher ;  
  12. class NullType  
  13. {  
  14. };  
  15. // IEventHandler  是事件处理句柄,预定事件的类从此接口继承以实现事件处理函数   
  16. template<class SenderType ,class ParaType>  
  17. interface IEventHandler  
  18. {  
  19. public:  
  20.  virtual ~IEventHandler(){}  
  21. private:  
  22.  virtual void HandleEvent(SenderType sender ,ParaType para)  = 0 ;  
  23.  friend class EventPublisher ;  
  24. };  
  25. // IEvent 事件预定方通过此接口预定事件   
  26. template<class SenderType ,class ParaType>  
  27. interface IEvent  
  28. {  
  29. public:  
  30.  virtual ~IEvent(){}  
  31.  virtual void Register  (IEventHandler* handler) = 0 ;    
  32.  virtual void UnRegister(IEventHandler* handler) = 0 ;  
  33. };  
  34. // IEventActivator 事件发布方通过此接口触发事件   
  35. template<class SenderType ,class ParaType>  
  36. interface IEventActivator  
  37. {  
  38. public:  
  39.  virtual ~IEventActivator(){}  
  40.  virtual void Invoke(SenderType sender ,ParaType para) = 0;  
  41.  virtual int  HandlerCount() = 0;  
  42.  virtual IEventHandler* GetHandler(int index) = 0;  
  43. };  
  44. // IEventPublisher 事件发布方发布事件相当于就是发布一个IEventPublisher派生类的对象   
  45. // 不过仅仅将该对象的IEvent接口发布即可。   
  46. template<class SenderType ,class ParaType>  
  47. interface IEventPublisher : public IEvent ,public IEventActivator   
  48. {  
  49. };  
  50. // EventPublisher是IEventPublisher的默认实现   
  51. template<class SenderType ,class ParaType>  
  52. class EventPublisher :public IEventPublisher  
  53. {  
  54. private:  
  55.  SafeArrayList< IEventHandler > handerList ;  
  56.  IEventHandler* innerHandler ;  
  57. public:  
  58.  void Register(IEventHandler* handler)   
  59.  {  
  60.   this->handerList.Add(handler) ;  
  61.  }  
  62.  void UnRegister(IEventHandler* handler)  
  63.  {  
  64.   this->handerList.Remove(handler) ;  
  65.  }  
  66.  void Invoke(SenderType sender ,ParaType para)  
  67.  {  
  68.   int count = this->handerList.Count() ;  
  69.   for(int i=0 ;i
  70.   {  
  71.    IEventHandler* handler = this->handerList.GetElement(i) ;  
  72.    handler->HandleEvent(sender ,para) ;  
  73.   }  
  74.  }   
  75.  int  HandlerCount()  
  76.  {  
  77.   return this->handerList.Count() ;  
  78.  }  
  79.  IEventHandler* GetHandler(int index)  
  80.  {  
  81.   return this->handerList.GetElement(index) ;  
  82.  }  
  83. };  
  84. #endif  
#ifndef IEVENT_H#define IEVENT_H/* 以下各基础设施是在C++中事件机制的完整实现,事件是面向组件开发的必要特性之一。 创 作 者:sky 时 间:2005.06.22 修订时间:2005.06.22*/#include "../Collection/SafeArrayList.h"template class EventPublisher ;class NullType{};// IEventHandler 是事件处理句柄,预定事件的类从此接口继承以实现事件处理函数templateinterface IEventHandler{public: virtual ~IEventHandler(){}private: virtual void HandleEvent(SenderType sender ,ParaType para) = 0 ; friend class EventPublisher ;};// IEvent 事件预定方通过此接口预定事件templateinterface IEvent{public: virtual ~IEvent(){} virtual void Register (IEventHandler* handler) = 0 ; virtual void UnRegister(IEventHandler* handler) = 0 ;};// IEventActivator 事件发布方通过此接口触发事件templateinterface IEventActivator{public: virtual ~IEventActivator(){} virtual void Invoke(SenderType sender ,ParaType para) = 0; virtual int HandlerCount() = 0; virtual IEventHandler* GetHandler(int index) = 0;};// IEventPublisher 事件发布方发布事件相当于就是发布一个IEventPublisher派生类的对象// 不过仅仅将该对象的IEvent接口发布即可。templateinterface IEventPublisher : public IEvent ,public IEventActivator {};// EventPublisher是IEventPublisher的默认实现templateclass EventPublisher :public IEventPublisher{private: SafeArrayList< IEventHandler > handerList ; IEventHandler* innerHandler ;public: void Register(IEventHandler* handler) { this->handerList.Add(handler) ; } void UnRegister(IEventHandler* handler) { this->handerList.Remove(handler) ; } void Invoke(SenderType sender ,ParaType para) { int count = this->handerList.Count() ; for(int i=0 ;i* handler = this->handerList.GetElement(i) ; handler->HandleEvent(sender ,para) ; } } int HandlerCount() { return this->handerList.Count() ; } IEventHandler* GetHandler(int index) { return this->handerList.GetElement(index) ; }};#endif

上面的实现是浅显易懂的,关键是要注意IEventPublisher的双重身份-- 事件发布方最好发布IEvent指针给外部,而该指针实际指向的是一个EventPublisher对象,这是为了避免外部直接调用IEventActivator接口的方法。

二. 一个定时器类Timer,演示如何发布事件。想必大家都知道定时器的用途了哦,这个Timer就像C#中的Timer类一样。

view plain copy to clipboard print ?
  1. #ifndef TIMER_H   
  2. #define TIMER_H   
  3. /* 
  4.  Timer 定时器,每经过一段指定时间就触发事件 
  5.   
  6.  创 作 者:sky 
  7.  时    间:2005.06.22  
  8.  修订时间:2005.06.22 
  9. */  
  10. #include "IEvent.h"   
  11. #include "Thread.h"   
  12. void TimerThreadStart(void* para) ;  
  13. class Timer  
  14. {  
  15. private:  
  16.  int spanInMillSecs ;  
  17.  volatile bool isStop ;  
  18.  volatile bool timerThreadDone ;  
  19.    
  20. public:  
  21.  friend void TimerThreadStart(void* para) ;  
  22.  IEvent* TimerTicked ;  
  23.  Timer(int span_InMillSecs)   
  24.  {  
  25.   this->isStop = true ;  
  26.   this->timerThreadDone = true ;  
  27.   this->spanInMillSecs = span_InMillSecs ;  
  28.   this->TimerTicked = new EventPublisher ;  
  29.  }  
  30.    
  31.  ~Timer()  
  32.  {  
  33.   this->Stop() ;  
  34.   delete this->TimerTicked ;  
  35.  }   
  36.  void Start()  
  37.  {  
  38.   if(! this->isStop)  
  39.   {  
  40.    return ;  
  41.   }  
  42.   this->isStop = false ;  
  43.   Thread thread ;  
  44.   thread.Start(TimerThreadStart ,this) ;  
  45.   //unsigned int  dwThreadId ;   
  46.   //HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0 , (unsigned int (_stdcall*)(void*))&TimerThreadStart , this, 0, &dwThreadId);      
  47.     
  48.  }  
  49.  void Stop()  
  50.  {  
  51.   ifthis->isStop)  
  52.   {  
  53.    return ;  
  54.   }  
  55.     
  56.   this->isStop = true ;  
  57.   //等待工作线程退出   
  58.   while(! this->timerThreadDone)  
  59.   {  
  60.    Sleep(200) ;  
  61.   }  
  62.  }  
  63. private:   
  64.  void WorkerThread()  
  65.  {  
  66.   this->timerThreadDone = false ;  
  67.   while(! this->isStop)  
  68.   {    
  69.    Sleep(this->spanInMillSecs) ;  
  70.    if(this->isStop)  
  71.    {  
  72.     break ;  
  73.    }  
  74.      
  75.    NullType nullObj ;  
  76.    ((EventPublisher*)this->TimerTicked)->Invoke(this ,nullObj) ;  
  77.   }  
  78.   this->timerThreadDone = true ;  
  79.  }  
  80. };  
  81. void TimerThreadStart(void* para)  
  82. {  
  83.     Timer* timer = (Timer*)para ;  
  84.     timer->WorkerThread() ;  
  85. }  
  86. #endif  
#ifndef TIMER_H#define TIMER_H/* Timer 定时器,每经过一段指定时间就触发事件 创 作 者:sky 时 间:2005.06.22 修订时间:2005.06.22*/#include "IEvent.h"#include "Thread.h"void TimerThreadStart(void* para) ;class Timer{private: int spanInMillSecs ; volatile bool isStop ; volatile bool timerThreadDone ; public: friend void TimerThreadStart(void* para) ; IEvent* TimerTicked ; Timer(int span_InMillSecs) { this->isStop = true ; this->timerThreadDone = true ; this->spanInMillSecs = span_InMillSecs ; this->TimerTicked = new EventPublisher ; } ~Timer() { this->Stop() ; delete this->TimerTicked ; } void Start() { if(! this->isStop) { return ; } this->isStop = false ; Thread thread ; thread.Start(TimerThreadStart ,this) ; //unsigned int dwThreadId ; //HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0 , (unsigned int (_stdcall*)(void*))&TimerThreadStart , this, 0, &dwThreadId); } void Stop() { if( this->isStop) { return ; } this->isStop = true ; //等待工作线程退出 while(! this->timerThreadDone) { Sleep(200) ; } }private: void WorkerThread() { this->timerThreadDone = false ; while(! this->isStop) { Sleep(this->spanInMillSecs) ; if(this->isStop) { break ; } NullType nullObj ; ((EventPublisher*)this->TimerTicked)->Invoke(this ,nullObj) ; } this->timerThreadDone = true ; }};void TimerThreadStart(void* para){ Timer* timer = (Timer*)para ; timer->WorkerThread() ;}#endif

上面的示例清晰地说明了如何发布一个事件,如何在适当的时候触发事件,接下来看看如何预定事件。

三. 预定事件例子

view plain copy to clipboard print ?
  1. class TimerEventExample  :public IEventHandler ,CriticalSection  
  2. {  
  3. private:  
  4.  Timer* timer ;  
  5.    
  6. public:  
  7.  TimerEventExample(int checkSpan)   
  8.  {    
  9.   this->timer = new Timer(checkSpan) ;  
  10.   this->timer->TimerTicked->Register(this) ;  
  11.  }  
  12.  ~TimerEventExample()  
  13.  {  
  14.   delete this->timer ;  
  15.  }   
  16. private:  
  17.  //处理定时事件   
  18.  void HandleEvent(Timer* sender ,NullType para)  
  19.  {  
  20.   cout<<"Time ticked !"<
  21.  }  
  22. };  
class TimerEventExample :public IEventHandler ,CriticalSection{private: Timer* timer ; public: TimerEventExample(int checkSpan) { this->timer = new Timer(checkSpan) ; this->timer->TimerTicked->Register(this) ; } ~TimerEventExample() { delete this->timer ; } private: //处理定时事件 void HandleEvent(Timer* sender ,NullType para) { cout<<"Time ticked !"<

 到这里,已经将C++中的事件机制的实现及使用讲清楚了。C#提供了很多便利的基础设施来支持组件开发,而在C++中,这些基础设施需要自己动手来构建,在拥有了这些设施之后,相信使用C++进行组件开发会轻松一点。

上一篇: 异步消息的传递-回调机制 下一篇: C/C++中回调函数初探

你可能感兴趣的:(程序设计,C,C++)