博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++中模拟委托事件的方法(三)
阅读量:2180 次
发布时间:2019-05-01

本文共 8220 字,大约阅读时间需要 27 分钟。

转自

 

二、接口模拟事件

对应的例子工程名InterfaceEvent

由于C++不支持接口,但是支持抽象类和多重继承,所以可以通过class或struct模拟实现接口。

1、  具体的实现方法

(1)、事件触发对象类CNotifyClass的类定义如下:

  1. class INotifyClassEvent 
  2. public
  3.     INotifyClassEvent() {}; 
  4.     virtual ~INotifyClassEvent() {}; 
  5. public
  6.     virtual void OnNoParamNoReturnEvent() = 0; 
  7.     virtual int OnNoParamReturnEvent() = 0; 
  8.     virtual void OnParamNoReturnEvent(int) = 0; 
  9.     virtual int OnParamReturnEvent(int) = 0; 
  10. }; 
  11.  
  12. class CNotifyClass 
  13. public
  14.     CNotifyClass(void); 
  15.     ~CNotifyClass(void); 
  16.  
  17. public
  18.     bool RegisterEvent(INotifyClassEvent *pncRecvEvent);
  19.     void UnRegisterEvent(); 
  20.  
  21.     void DoNotifyEventWork(); 
  22.  
  23. protected
  24.     INotifyClassEvent *m_pncRecvEvent; 
  25. }; 

类实现如下:

  1. #include "NotifyClass.h" 
  2.  
  3. CNotifyClass::CNotifyClass(void
  4.     : m_pncRecvEvent(NULL) 
  5.  
  6. CNotifyClass::~CNotifyClass(void
  7.     UnRegisterEvent(); 
  8.  
  9. bool 
  10. CNotifyClass::RegisterEvent(INotifyClassEvent *pncRecvEvent) 
  11.     if (NULL != m_pncRecvEvent) 
  12.         return false
  13.     m_pncRecvEvent = pncRecvEvent; 
  14.     return true
  15.  
  16. void 
  17. CNotifyClass::UnRegisterEvent() 
  18.     m_pncRecvEvent = NULL; 
  19.  
  20. void 
  21. CNotifyClass::DoNotifyEventWork() 
  22.     if (NULL == m_pncRecvEvent) 
  23.         return
  24.  
  25.     int iResult = 0; 
  26.     m_pncRecvEvent->OnNoParamNoReturnEvent(); 
  27.     iResult = m_pncRecvEvent->OnNoParamReturnEvent(); 
  28.  
  29.     iResult = iResult + 10; 
  30.     iResult = m_pncRecvEvent->OnParamReturnEvent(iResult); 
  31.     iResult = iResult + 10; 
  32.     m_pncRecvEvent->OnParamNoReturnEvent(iResult); 

类CNotifyClass声明时要定义事件处理函数集的接口INotifyClassEvent,所有接收事件的类都要继承并实现这个接口来接收事件。

事件接收对象类通过调用RegisterEvent和UnRegisterEvent注册接收消息或取消注册不再接收消息,当会触发事件的工作方法DoNotifyEventWork被调用时,会检测哪些事件被注册了,被注册了就调用,就如同进行了事件通知。

(2)、事件接收对象类或事件处理对象类CRecvEventClass的类定义如下:

  1. class CRecvEventClass : public INotifyClassEvent 
  2. public
  3.     CRecvEventClass(void); 
  4.     ~CRecvEventClass(void); 
  5.  
  6. public
  7.     int DoWork(int iArg); 
  8.  
  9. protected
  10.     virtual void OnNoParamNoReturnEvent(); 
  11.     virtual int OnNoParamReturnEvent(); 
  12.     virtual void OnParamNoReturnEvent(int iArg); 
  13.     virtual int OnParamReturnEvent(int iArg); 
  14.  
  15. protected
  16.     CNotifyClass m_ncNotify; 
  17.     int m_nNum; 
  18. }; 

类实现如下:

  1. #include "RecvEventClass.h" 
  2.  
  3. CRecvEventClass::CRecvEventClass(void
  4.     m_ncNotify.RegisterEvent(this); 
  5.  
  6. CRecvEventClass::~CRecvEventClass(void
  7.     m_ncNotify.UnRegisterEvent(); 
  8.  
  9. int 
  10. CRecvEventClass::DoWork(int iArg) 
  11.     m_nNum = iArg; 
  12.     m_ncNotify.DoNotifyEventWork(); 
  13.     return m_nNum; 
  14.  
  15. void 
  16. CRecvEventClass::OnNoParamNoReturnEvent() 
  17.     _tprintf(_T("Run OnNoParamNoReturnEvent\n")); 
  18.     m_nNum = m_nNum + 10; 
  19.  
  20. int 
  21. CRecvEventClass::OnNoParamReturnEvent() 
  22.     _tprintf(_T("Run OnNoParamReturnEvent\n")); 
  23.     m_nNum = m_nNum + 10; 
  24.     return m_nNum; 
  25.  
  26. void 
  27. CRecvEventClass::OnParamNoReturnEvent(int iArg) 
  28.     _tprintf(_T("Run OnParamNoReturnEvent\n")); 
  29.     m_nNum = iArg + 10; 
  30.  
  31. int 
  32. CRecvEventClass::OnParamReturnEvent(int iArg) 
  33.     int iRet; 
  34.     _tprintf(_T("Run OnParamReturnEvent\n")); 
  35.     iRet = iArg + 10; 
  36.     return iRet; 

这里事件接收对象类或事件处理对象类CRecvEventClass在定义时一定要继承事件通知接口INotifyClassEvent,通过实现这个接口的成员函数来接收事件通知。

当定义了事件处理方法后,可以通过调用类CNotifyClass的方法RegisterEvent和UnRegisterEvent注册接收消息或取消注册不再接收消息,本例是在构造和析构函数中调用的,当CNotifyClass类的DoNotifyEventWork方法被调用时,就会通过接口方法直接事件通知(调用)相应的事件处理方法

  1. void 
  2. CRecvEventClass::OnNoParamNoReturnEvent() 
  3.     _tprintf(_T("Run OnNoParamNoReturnEvent\n")); 
  4.     m_nNum = m_nNum + 10; 

这里可以看到事件处理方法直接就是类成员方法,不需要传递对象的指针this。

(3)、使用的例子及输出

  1. int _tmain(int argc, _TCHAR* argv[]) 
  2.     CRecvEventClass rec1, rec2; 
  3.     int iIn, iOut; 
  4.  
  5.     iIn = 10; 
  6.     iOut = rec1.DoWork(iIn); 
  7.     _tprintf(_T("InterfaceEvent test 1, Init:%d, Result:%d\n"), iIn, iOut); 
  8.     iIn = 30; 
  9.     iOut = rec1.DoWork(iIn); 
  10.     _tprintf(_T("InterfaceEvent test 2, Init:%d, Result:%d\n"), iIn, iOut); 
  11.     iIn = 60; 
  12.     iOut = rec2.DoWork(iIn); 
  13.     _tprintf(_T("InterfaceEvent test 3, Init:%d, Result:%d\n"), iIn, iOut); 
  14.  
  15.     TCHAR c; 
  16.     _tscanf(_T("%c"), &c); 
  17.     return 0; 

输出结果为:

  1. Run OnNoParamNoReturnEvent 
  2. Run OnNoParamReturnEvent 
  3. Run OnParamReturnEvent 
  4. Run OnParamNoReturnEvent 
  5. InterfaceEvent test 1, Init:10, Result:70 
  6. Run OnNoParamNoReturnEvent 
  7. Run OnNoParamReturnEvent 
  8. Run OnParamReturnEvent 
  9. Run OnParamNoReturnEvent 
  10. InterfaceEvent test 2, Init:30, Result:90 
  11. Run OnNoParamNoReturnEvent 
  12. Run OnNoParamReturnEvent 
  13. Run OnParamReturnEvent 
  14. Run OnParamNoReturnEvent 
  15. InterfaceEvent test 3, Init:60, Result:120 

从输出结果上看事件是被顺次调用了,至于程序中的变量值,主要表明这些事件执行的而动作是对应于实例的,不是对应于类的。

2、  实现的要点

(1)、事件触发类的实现要点

a、  事件触发类必须要定义接收事件处理的接口类INotifyClassEvent

b、  事件触发类要定义INotifyClassEvent接口类的成员变量

  1. INotifyClassEvent *m_pncRecvEvent; 

当需要触发事件时通过这个接口类调用相应的函数

c、  或者把上面的INotifyClassEvent接口类的成员变量直接公开被外部修改,或者使用类似RegisterEvent和UnRegisterEvent的方法提供对这些成员的修改,外部事件接收类才能接收事件

d、  在工作时,需要触发事件的地方,通过调用INotifyClassEvent接口类来事件通知事件接收类

(2)、事件接收对象类或事件处理对象类的实现要点

a、  事件接收类必须继承或多重继承自接口类INotifyClassEvent

b、  使用自身的指针this作为参数调用事件触发类的RegisterEvent和UnRegisterEvent的方法,或者直接修改事件触发类的相应成员(如果提供了访问权限)

d、  在事件处理方法中当做普通的成员函数进行编写,然后在工作中,当有事件触发时就可以得到通知被调用。

3、  优缺点

(1)、优点

a、无论事件触发类还是接收事件处理类开发简单,代码量少、简洁

b、数据安全性高,无论对于事件处理函数和接收事件处理类实例都不存在类型转换,这两个数据都可以在编译期间得到类型检查

(2)、缺点

a、不能部分接收消息事件,要实现接口类的所有函数,虽然可以实现时什么都不做,但是需要都实现,为了让事件接收类可以选择接收的事件,事件触发类开发者必须拆分分类成多个事件接口,这样事件接收类可以选择继承,就可以只接收部分消息了,但是如果量太大,事件接收类需要继承的接口列表可能很多,增加了复杂度。

b、接收事件处理方法由于是继承自接口,所以其方法属性必须是public方法,对于事件接收类的封装造成了一定的破坏。

 

转载地址:http://dkskb.baihongyu.com/

你可能感兴趣的文章
Java并发指南6:Java内存模型JMM总结
查看>>
Java并发指南7:JUC的核心类AQS详解
查看>>
Java并发指南8:AQS中的公平锁与非公平锁,Condtion
查看>>
Java网络编程和NIO详解6:Linux epoll实现原理详解
查看>>
Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理
查看>>
Java网络编程与NIO详解8:浅析mmap和Direct Buffer
查看>>
Java网络编程与NIO详解10:深度解读Tomcat中的NIO模型
查看>>
Java网络编程与NIO详解11:Tomcat中的Connector源码分析(NIO)
查看>>
深入理解JVM虚拟机1:JVM内存的结构与消失的永久代
查看>>
深入理解JVM虚拟机3:垃圾回收器详解
查看>>
深入理解JVM虚拟机4:Java class介绍与解析实践
查看>>
深入理解JVM虚拟机5:虚拟机字节码执行引擎
查看>>
深入理解JVM虚拟机6:深入理解JVM类加载机制
查看>>
深入了解JVM虚拟机8:Java的编译期优化与运行期优化
查看>>
深入理解JVM虚拟机9:JVM监控工具与诊断实践
查看>>
深入理解JVM虚拟机10:JVM常用参数以及调优实践
查看>>
深入理解JVM虚拟机11:Java内存异常原理与实践
查看>>
深入理解JVM虚拟机12:JVM性能管理神器VisualVM介绍与实战
查看>>
深入理解JVM虚拟机13:再谈四种引用及GC实践
查看>>
Spring源码剖析1:Spring概述
查看>>