C++ FastDelegate 扩展,实现与.net类似的事件处理功能

熟悉.NET的人都知道,  .NET使用委托可以快速实现观察者模式,免去写很多繁杂重复的代码。遗憾的是,C++并没有提供这样的模型,为了达到相似的目的,需要继承一个类并重写virtual方法,这种做法需要写很多代码,效率比较低下。然而,在强大的C++面前,没有什么是不可能的,已经有很多人针对这个问题进行过研究,并且实现了各种委托模型,其中最著名的就是FastDelegate。为了让使用FastDelegate更象.NET,我新添加几个模板,主要如下:

首先添加一个两个类用于模拟事件发生源及事件参数类:

   1: // 定义事件发送源(类似于.net的sender)
   2: class IEventSource
   3: {
   4: public:
   5:     virtual ~IEventSource (){}
   6: };
   7:  
   8: using namespace fastdelegate;
   9:  
  10: // 定义标准的事件参数
  11: class CEventArgs
  12: {
  13: public:
  14:     CEventArgs (void)
  15:     {
  16:         bHandled = FALSE;
  17:     }
  18:  
  19:     BOOL    bHandled;
  20: };

然后是定义一个事件句柄管理类:

   1: // 定义事件句柄,用于管理事件中加入的委托
   2: template <class TBase>
   3: class CEventHandlerBase
   4: {
   5: public:
   6:     virtual ~CEventHandlerBase ()
   7:     {
   8:         for (int i = _delegates.GetSize () - 1; i >= 0; i --)
   9:         {
  10:             delete (TBase*) _delegates[i];
  11:         }
  12:         _delegates.Empty ();
  13:     }
  14:  
  15:     size_t GetCount (void) { return _delegates.GetSize (); }
  16:  
  17:     // 添加委托
  18:     void operator += (TBase& eventDelegate)
  19:     {
  20:         _delegates.Add (new TBase (eventDelegate));
  21:     }
  22:  
  23:     // 删除委托
  24:     void operator -= (TBase& eventDelegate)
  25:     {
  26:         for (int i = _delegates.GetSize () - 1; i >= 0; i --)
  27:         {
  28:             if (*((TBase*) _delegates[i]) == eventDelegate)
  29:             {
  30:                 delete (TBase*) _delegates[i];
  31:                 _delegates.Remove (i);
  32:             }
  33:         }
  34:     }
  35:  
  36: public:
  37:     CStdPtrArray _delegates;
  38: };

最后定义一个宏用于快速创建事件句柄:

   1: // 定义生成事件句柄的类 handleClass 为句柄类名称,eventClass 为参数类名称
   2: #define DEFINE_EVENT_HANDLER(handleClass, eventClass) 
   3:     typedef FastDelegate2<IEventSource *, eventClass *> eventClass##Delegate;
   4:     class UILIB_API handleClass : public CEventHandlerBase<eventClass##Delegate>
   5:     {
   6:         public:
   7:         void Fire (IEventSource* sender, eventClass* e)
   8:         {
   9:             for (int i = _delegates.GetSize () - 1; i >= 0; i --)
  10:             {
  11:                 (*(eventClass##Delegate*) _delegates[i]) (sender, e);
  12:             }
  13:         }
  14:     }
  15:  
  16: DEFINE_EVENT_HANDLER (CStdEventHandler, CEventArgs);

使用如有两种情况,一是只用CEventArgs参数类型就可以满足要求,二是需扩展自己的参数类型。如果需要扩展参数,代码如下:

   1: class CMouseEventArgs : public CEventArgs
   2: {
   3: public:
   4:     CMouseEventArgs (MouseButtons button1, int clicks1, int x1, int y1, int delta1);
   5:  
   6:     MouseButtons button; int clicks; int x; int y; int delta;
   7: };
   8:  
   9: // void handler (IEventSource* sender, CMouseEventArgs* e);
  10: DEFINE_EVENT_HANDLER (CMouseEventDelegate, CMouseEventArgs);

应用代码示例如下:

   1: class CGlobalWindowMsgHook : public IEventSource
   2: {
   3: private:
   4:     CGlobalWindowMsgHook (void);
   5: public:
   6:     ~CGlobalWindowMsgHook (void);
   7:  
   8:     static CGlobalWindowMsgHook* instance (void);
   9:  
  10:     // 定义鼠标点击事件
  11:     CMouseEventDelegate MouseClick;
  12:  
  13:     ……
  14: protected:
  15:     static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
  16:     {
  17:         CGlobalWindowMsgHook* This = instance();
  18:         PMSLLHOOKSTRUCT hookStruct = (PMSLLHOOKSTRUCT)lParam;
  19:         
  20:         int msg = wParam;
  21:         int x = hookStruct->pt.x;
  22:         int y = hookStruct->pt.y;
  23:         int delta = (short)((hookStruct->mouseData >> 16) & 0xffff);
  24:         
  25:         if (msg == WM_LBUTTONUP)
  26:         {
  27:             // 触发鼠标点击事件
  28:             This->MouseDown.Fire (This, &CMouseEventArgs (Left, 0, x, y, delta));
  29:         }
  30:         ……
  31:     }
  32:     ……
  33: };
  34:  
  35: // 测试类
  36: class CTest
  37: {
  38: public:
  39:     CTest ()
  40:     {
  41:         CGlobalWindowMsgHook::instance()->MouseClick += MakeDelegate (this, &CTest::MouseDownHandler);
  42:     }
  43:     ~CTest ()
  44:     {
  45:         CGlobalWindowMsgHook::instance()->MouseClick -= MakeDelegate (this, &CTest::MouseDownHandler);
  46:     }
  47:  
  48:     void MouseDownHandler (IEventSource* sender, CMouseEventArgs* e)
  49:     {
  50:         printf (_T("hello"));
  51:     }
  52: }
原文地址:https://www.cnblogs.com/ihaoqi/p/3239156.html