C++实现事件机制
来源:互联网 发布:ubuntu 卸载软件 编辑:程序博客网 时间:2024/06/08 23:55
http://blog.csdn.net/linzhengqun/article/details/1913236
http://www.cppblog.com/weiym/archive/2013/01/31/197649.html
委托是一种很实用的设计方法,一个模块可以将某些事情委托给其他实体去做,而对于模块本身不需要知道受委托的实体是什么,它只知道这个实体遵循某种接口规范。回调函数可以认为是一种委托,它在Windows编程中起了非常重要的作用。
委托的一个重要应用是事件机制,假设有类A负责加载数据,类B用于实时显示A的加载进度,那么A必须向B引发一些事件,以表明它的加载进度。要实现这种机制可以用观察者模式,Java即使用观察者模式来实现事件监听的。Delphi使用了类似回调函数的技术来实现事件,这样也有一些好处,就是简单高效,对于一些轻量级的应用还是非常合适的。
C++如何实现事件,当然可以用观察者模式来实现,不过这里要介绍另一种方法,就是用成员函数指针,这种方法更类似于Delphi的事件,优点是简单高效。
下面是我写的两个源文件,对通用事件提供了支持,其中涉及到成员函数指针的知识,我就不班门弄斧了,直接给就出源代码如下:
EventUtils.h
#ifndef EVENTUTILS_H_
#define EVENTUTILS_H_
// 用于欺骗编译器,传递This指针
class CMemFunObj
{
};
// 通用函数类型
typedef void (CMemFunObj:: *PFNMEMFUN)();
// 成员函数结构
typedef struct tagMEMBERFUN {
CMemFunObj *Self;
PFNMEMFUN pfnAddr;
} MEMBERFUN, *PMEMBERFUN;
// 生成成员函数结构
MEMBERFUN MakeMemberFun(CMemFunObj *Self, PFNMEMFUN pfnAddr);
// 宏:生成成员函数结构
#define MAKEMEMFUN(Self, pfnAddr) /
MakeMemberFun((CMemFunObj*)Self, (PFNMEMFUN)pfnAddr)
// 宏:回调成员函数,FunType为具体函数类型,MemFun为成员函数结构
#define CALLMEMFUN(FunType, MemFun) /
(MemFun.Self->*(FunType)MemFun.pfnAddr)
// 宏:判断成员函数结构是否有值
#define ISMEMFUNASSIGNED(MemFun) /
(MemFun.Self != NULL) && (MemFun.pfnAddr != NULL)
#endif // EVENTUTILS_H_
EventUtils.cpp
#include "EventUtils.h"
// 生成成员函数结构
MEMBERFUN MakeMemberFun(CMemFunObj *Self, PFNMEMFUN pfnAddr)
{
MEMBERFUN Memfun;
Memfun.pfnAddr = pfnAddr;
Memfun.Self = Self;
return Memfun;
}
其中比较有意思的是用CMemFunObj来做对象绑定,这个类会欺骗编译器,使编译将This指针传进成员函数;MEMBERFUN是成员函数结构,一个成员函数要成功调用必须有两个要素,一个是绑定的对象,一个是函数地址,这就是MEMBERFUN的内容。
下面看看如何用这个单元,有一个CRunner类,提供一个Run方法,我们要实现的是监控Run的进度。
首先声明CRunner,声明进度事件类型,以及在CRunner保存一个事件类型的成员:
#ifndef RUNNER_H_
#define RUNNER_H_
#include "EventUtils.h"
// 进度事件类型
typedef void (CMemFunObj:: *RUNPROCESS)(int nPercent);
class CRunner
{
public:
CRunner();
virtual ~CRunner();
// 设置事件结构
void SetOnProcess(MEMBERFUN OnRunProcess);
// 开始运行
void Run();
private:
MEMBERFUN m_OnRunProcess;
};
#endif // RUNNER_H_
接着实现CRunner,并看看Run如何调用事件:
#include "Runner.h"
#include <string.h>
#include <windows.h>
CRunner::CRunner()
{
memset(&m_OnRunProcess, 0, sizeof(m_OnRunProcess));
}
CRunner::~CRunner(){}
void CRunner::SetOnProcess( MEMBERFUN OnRunProcess )
{
m_OnRunProcess = OnRunProcess;
}
void CRunner::Run()
{
int nTime = 0;
while ((nTime++) < 100)
{
Sleep(10);
if (ISMEMFUNASSIGNED(m_OnRunProcess))
CALLMEMFUN(RUNPROCESS, m_OnRunProcess)(nTime);
}
}
Run函数用ISMEMFUNASSIGNED宏判断m_OnRunProcess是否被赋值,如果有,则用CALLMEMFUN宏来调用具体的事件。关于这几个宏,可以参考EventUtils.h
CRunner支持事件之后,来看看事件如何被接收:
#include "EventUtils.h"
#include "Runner.h"
#include <iostream>
using namespace std;
class EventSink
{
public:
void RunProcess(int Percent)
{
cout<<Percent<<endl;
}
};
int main()
{
EventSink es;
CRunner R;
R.SetOnProcess(MAKEMEMFUN(&es, es.RunProcess));
R.Run();
return 0;
}
MAKEMEMFUN用于合成一个成员函数结构体,调用R.SetOnProcess之后,es便能够监听CRunner的进度事件。
使用这种技术来实现事件机制应该说是通用的,你可以整合到如MFC这类应用程序框架中。该技术的优点是高效,但缺点也很明显,就是只支持单点事件,如果要实现多点事件则要做更多的工作。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- C#事件处理机制
- C# 事件机制
- Unity3D (C#)事件分发机制的实现
- C++ 事件机制实现
- C++ 事件机制实现
- C++实现事件机制
- C++ 事件机制实现
- C++ 事件机制实现
- C++ 事件机制实现
- C++ 事件机制实现
- C++实现事件机制
- C++ 事件机制实现
- C++ 事件机制实现
- C++实现事件机制
- 3.7 event.c:“事件”机制
- 事件机制之C++实现
- lua实现c#事件机制
- ActionScript事件模型实现机制
- Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解
- 黑马程序员---Java 装饰设计模式
- ajax
- BC 2015年百度之星程序设计大赛 - 初赛(1)(矩形面积-旋转卡壳)
- iOS开发UI基础—30在UItableview中实现加载更多功能
- C++实现事件机制
- SAT阅读:态度题型解答方法指导
- Android Design Support Library最新组件
- iOS开发UI基础—31在UITableview的应用中使用动态单元格来完成app应用程序管理界面的搭建
- FatMouse' Trade
- 谈异常控制流
- * failed to start daemon *
- js判断字符串以指定字符串结尾/网上整理
- ajax