C++事件(Event)机制的实现

C++实操 - Event概念介绍和定义一个Event类 关于事件 事件驱动系统通常用于有一些需要由程序处理的异步外部活动;例如,用户按下鼠标上的一个按钮。一个事件驱动的系统通常运行一个事件循环,持续等待此类活动,例如来自设备的输入或内部警报。当这些活动之一发生时,它收集关于该事件的数据,并将该事件分配给处理该事件的程序。 一个程序可以选择忽略事件,而且可能有一些库将一个事件分配给多个处理程序,这些处理程序可能被编程为监听一个特定的事件。与事件相关的数据至少要指定它是什么类型的事件,但也可能包括其他信息,如它发生的时间、谁或什么导致了它的发生,以及由事.. 阅读详情
 
2007-10-01 14:13 752人阅读 评论(0) 收藏 举报

用C++实现事件机制我以前写过一个小例子,但不是很完善,比如Event只能接受全局函数作为handler,类成员方法不可以,还有一个Event只能添加一个handler等……最近我的一个程序刚好要用到Event机制,所以我就抽了些时间,重新实现了一下。这个版本应该说是比较完善的,基本上和C#中的Event一样了。点击这里下载源代码。

要使用Event机制主要用到两个模板类:一个是Delegate,它实现了对C++函数指针的封装,当然,如上所述包括类成员函数的指针;另一个是Event,顾名思义它就是主角“事件”了。用以实现Event机制的所有类都被我“圈”在CppEvent命名空间里了,以免“污染”我们的global namespace。需要提醒的是,这个版本的实现中用到的C++的RTTI,所以用VC编译是别忘了加上/GR编译参数。

 

一 Delegate

先看一下Delegate类的原型:

namespace CppEvent

{

     … …

 

     /*

     *公开给程序使用的Delegate模板类

     *ReturnType 函数返回值类型

     *ArgsType 函数参数类型

     */

     template <typename ReturnType = void , typename ArgsType = void*>

     class Delegate

     {

     public:

         /*

         *构造函数

         *用于包装一个对象的成员函数

         * object 成员函数所属的对象指针

         * function 成员函数的指针

         */

          template<class ObjectType>

              Delegate(ObjectType* object,  ReturnType(ObjectType::*function)(ArgsType))

         {

              … …

         }

         /*

         *构造函数

         *用于包装一个全局函数/类static函数

         * function 函数指针

         */

         Delegate(ReturnType(*function)(ArgsType))

         {

              … …

         }

};

}

Delegate有两个模板参数ReturnType和ArgsType,第一个指定被代理封装的函数(全局函数/类静态方法或类非成员方法)的返回值类型,第二个指定这个函数的参数类型。注意,由于C++模板只能有固定个数的参数,所以Delegate必须对所封装的函数的参数个数加以限制,也就是说Delegate参数的个数必须固定。既然个数必须固定,那就一个好了,反正我们可以传递结构作参数:)。

Delegate有两个重载的构造函数。第二个是针对全局函数或类静态(static)函数的,只有一个参数,就是把ReturnType作为返回值且带一个ArgsType类型参数的函数的指针(ReturnType(*function)(ArgsType) 注意C风格的函数指针的定义方法)。第一个构造函数是针对类的非静态方法(成员方法)的,它本身也是“模板函数”,模板参数指定被它封装的成员方法所属的类。两个参数,第一个为对象指针,第二个为成员方法的指针。比如有如下类:

class C

{

public:

     int M (double param)

     {

         ......

         return ......;

     }

     … …

};

且有一个类C的实例对象objc:

C objc;

那么,对于ojbc的M方法可以使用下面的DelegateM进行封装:

Delegate<int, double> DelegateM (&objc, C::M);

有了delegate,就可以调用它的Invoke方法来调用它所封装的函数,另外,Delegate重载了()操作符(operator)所以,你可以直接在Delegate对象后面加括号和参数进行调用了。比如int n =DelegateM.Invoke(0.2);或直接使用更简便的形式int n= DelegateM(0.2);

 

二 Event

看一下Event的原型:

namespace CppEvent

{

     /*

     *事件 模板类

     */

     template <typename ReturnType = void, typename ArgsType = void*, bool MultiCast = true>

     class Event

     {

     public:

         /*

         *该事件处理函数所对应的代理类型

         */

         typedef Delegate<ReturnType, ArgsType> EventHandler;

     public:

         /*

         *构造函数

         */

         Event()

         {

         }

         … …

};

… …

}

它有三个模板参数,分别为该事件代理(handler)的返回值类型、参数类型和一个标志该事件是否为多播(multicast)的bool值。前两个参数是说明可以用来“订阅”(下面会说明)该事件的Delegate的函数(全局/static或类成员)原型。所谓的“多播”指的是一个事件可以有多个订阅的代理,也就是说当这个事件被激发时,可能会有多个函数被调用,MultiCast的默认值为true,即允许多播。

一旦定义了一个事件,就可以调用它的+=操作符来把一个合适类型的Delegate对象订阅到改事件。-=运算符可以用来取消一个已经订阅的Delegate对象。订阅到某个事件的代理会在该事件被激发是被调用,该代理被从这个事件取消订阅后就不会再被该事件调用了。

比如有如下Event类型:

typedef CppEvent::Event<void, size_t> BalanceChanged;

和一个该类型的Event:

BalanceChanged OnBalanceChanged;

可以用如下的方法把一个全局函数代理订阅到该事件:

OnBalanceChanged += Delegate<void, size_t> (OnTomsAccountBalanceChanged);

其中OnTomsAccountBalanceChanged的原型如下:

void OnTomsAccountBalanceChanged(size_t balance)

{

     … …

}

这样,在OnBalanceChanged被激发时OnTomsAccountBalanceChanged函数就会被调用。激发一个事件可以有下面两种方法:

调用Event的Invoke()方法

OnBalanceChanged.Invoke(100);

或直接利用Event的()操作符

OnBalanceChanged(100);

三 一个例子

下面我们以“银行帐户操作”为例子,来说明Event机制的使用。

首先是Account类:

//Account.h

#ifndef _ACCOUNT_H_

#define _ACCOUNT_H_

 

#include "../CppEvent/Event.h"

namespace CppEventExampleAccount

{

     class Account

     {

     public:

         //帐户操作

         enum OperationType{DepositOp/*存款*/, WithdrawOp/*取款*/};

 

         class BalanceEventArgs

         {   

         public:

              BalanceEventArgs(OperationType operation, size_t ammount)

                   :theOperation(operation)

                   ,theAmmount(ammount)

              {

              };

              virtual ~BalanceEventArgs()

              {

              };

              OperationType Operation(void) const

              {

                   return theOperation;

              }

              size_t Amount(void) const

              {

                   return theAmmount;

              }

         private:

              OperationType theOperation;

              size_t theAmmount;

          };

     public:

         //定义"帐户即将被改变"事件

         //该事件接收一个BalanceEventArgs&参数,指定本次操作的具体信息

         //第三个模板参数false指定该事件为"单播(Singlecast)",即只能有一个handler

         typedef CppEvent::Event<bool, BalanceEventArgs&, false> BalanceChanging;

         //定义"帐户已改变"事件

         typedef CppEvent::Event<void, size_t> BalanceChanged;

     public:

         //定义两个事件对象

         BalanceChanging OnBalanceChanging;

         BalanceChanged OnBalanceChanged;

     public:

         //构造函数

         Account(size_t balance = 0)

              :Balance(balance)

         {

         }

         virtual ~Account()

         {

         }

     public:

         //查询余额

         size_t GetBalance(void) const

         {

              return Balance;

         }

         //存款方法

         //参数指定所存金额

         bool Deposit(size_t amount)

         {

              bool ReturnValue = false;

              //激发"帐户即将被改变"事件,并接收其返回值

              bool AllowOp = FireChangingEvent(DepositOp, amount);

              if(AllowOp)//如果允许改变

              {

                   //增加余额

                   Balance += amount;

                   //激发"帐户已改变"事件

                   FireChangedEvent();

                   ReturnValue = true;

              }

              else

              {

                   ReturnValue = false;

              }

              return ReturnValue;

         }

         //取款方法

         //参数指定取款金额

         bool Withdraw(size_t amount)

         {

              bool ReturnValue = false;

              if(Balance >= amount)//如果余额足够本次取款

              {

                   //激发"帐户即将被改变"事件,并接收其返回值

                   bool AllowOp = FireChangingEvent(WithdrawOp, amount);

                   if(AllowOp)

                   {

                       //减少余额

                       Balance -= amount;

                       //激发"帐户已改变"事件

                       FireChangedEvent();

                       ReturnValue = true;

                   }

              }

              else//余额不足

              {

                   ReturnValue = false;

              }

              return ReturnValue;

         }

     protected:

         //激发"帐户即将被改变"事件

         bool FireChangingEvent(OperationType operation, size_t amount)

         {

              bool ReturnValue = false;

              if(OnBalanceChanging != NULL)

              {

                   BalanceEventArgs args(operation, amount);

                   ReturnValue =  OnBalanceChanging(args);

              }

              else //如果该事件没有handler则默认允许操作

              {

                   ReturnValue = true;

              }

              return ReturnValue;

         }

         //激发"帐户已改变"事件

         void FireChangedEvent(void)

         {

              OnBalanceChanged(Balance);

         }

     private:

         //帐户余额

         size_t Balance;

     };

}

#endif

然后定义要订阅到Account两个事件的全局函数和MobilePhone类的成员函数:

//Changing事件的handler

bool OnTomsAccountBalanceChanging(Account::BalanceEventArgs& args)

{

     TCHAR* OpName = args.Operation() == Account::DepositOp ? "存款" : "取款";

     cout << "---系统日志 : Tom的帐户余额即将被改动, "

         << OpName << args.Amount() << "元";

 

     cout << " 此操作被允许---" << endl;

     return true;

}

//Changed事件的handler

void OnTomsAccountBalanceChanged(size_t balance)

{

     cout << "---系统日志 : Tom的帐户余额被改动了,当前余额为: " << balance << "元*---" << endl;

}

//手机

class MobilePhone

{

public:

     void OnAccountBalanceChanged(size_t amount)

     {

         cout << ">>>> 手机短信 : 尊敬的用户,您的帐户余额发生了变化,当前余额为" << amount << "元,请注意!" << endl;

     }

 

     bool OnAccountBalanceChanging(Account::BalanceEventArgs&)

     {

         cout << "该方法不会执行" << endl;

         return false;

     }

     //......

     //更多的成员和方法

     //......

};

 

然后定义类的实例对象,并编写main函数:

//建立Tom的帐号

Account TomsAccount(99999);

 

//Tom的手机

MobilePhone TomsPhone;

 

int _tmain(int argc, _TCHAR* argv[])

{

 

     //为系统订阅Tom的帐号的"帐户即将被改动"事件

     TomsAccount.OnBalanceChanging += Account::BalanceChanging::EventHandler(OnTomsAccountBalanceChanging);

     //上一行代码也可写为: ........+= Delegate<bool ,Account::BalanceEventArgs&>(OnTomsAccountBalanceChanging);

 

     //为系统订阅Tom的帐号的"帐号已被改动"事件

     TomsAccount.OnBalanceChanged += Account::BalanceChanged::EventHandler(OnTomsAccountBalanceChanged);

 

     //为Tom的手机订阅他的帐号的"帐户已被改动"事件

     TomsAccount.OnBalanceChanged += Account::BalanceChanged::EventHandler(&TomsPhone, MobilePhone::OnAccountBalanceChanged);

     //为Tom的手机订阅Tom的帐号的"帐号已被改动"事件

     //由于该事件为Singlecast,所以此订阅会失败

     TomsAccount.OnBalanceChanging += Account::BalanceChanging::EventHandler(&TomsPhone, MobilePhone::OnAccountBalanceChanging);

 

 

     bool Success = false;

     //执行一些操作,激发一些事件.相应的事件handler函数会调用

     cout << "即将执行 存款100元 的操作" << endl;

     Success = TomsAccount.Deposit(100);

     cout << (Success ? "操作成功!" : "操作失败!") << endl << endl;

 

     cout << "即将执行 存款5000元 的操作" << endl;

     Success = TomsAccount.Deposit(5000);

     cout << (Success ? "操作成功!" : "操作失败!") <<endl << endl;

 

     cout << "即将执行 取款10000元 的操作" << endl;

     Success = TomsAccount.Withdraw(10000);

     cout << (Success ? "操作成功!" : "操作失败!") <<endl << endl;

 

     cout << "-应Tom的要求,退订了他的手机短信通知-"<< endl;

     //退订了Tom的手机短信通知

     TomsAccount.OnBalanceChanged -= Account::BalanceChanged::EventHandler(&TomsPhone, MobilePhone::OnAccountBalanceChanged);

     //退订后TomsPhone将不再接收本事件

     cout << "即将执行 取款50元 的操作" << endl;

     Success = TomsAccount.Withdraw(50);

     cout << (Success ? "操作成功!" : "操作失败!") <<endl << endl;

 

}

 

运行该程序,可以看到输出如下:

 

即将执行 存款100元 的操作

---系统日志 : Tom的帐户余额即将被改动, 存款100元 此操作被允许---

---系统日志 : Tom的帐户余额被改动了,当前余额为: 100099元*---

>>>> 手机短信 : 尊敬的用户,您的帐户余额发生了变化,当前余额为100099元,请注意!

操作成功!

 

即将执行 存款5000元 的操作

---系统日志 : Tom的帐户余额即将被改动, 存款5000元 此操作被允许---

---系统日志 : Tom的帐户余额被改动了,当前余额为: 105099元*---

>>>> 手机短信 : 尊敬的用户,您的帐户余额发生了变化,当前余额为105099元,请注意!

操作成功!

 

即将执行 取款10000元 的操作

---系统日志 : Tom的帐户余额即将被改动, 取款10000元 此操作被允许---

---系统日志 : Tom的帐户余额被改动了,当前余额为: 95099元*---

>>>> 手机短信 : 尊敬的用户,您的帐户余额发生了变化,当前余额为95099元,请注意!

操作成功!

 

-应Tom的要求,退订了他的手机短信通知-

即将执行 取款50元 的操作

---系统日志 : Tom的帐户余额即将被改动, 取款50元 此操作被允许---

---系统日志 : Tom的帐户余额被改动了,当前余额为: 95049元*---

操作成功!

 

Press any key to continue

在main函数里对Account的实例TomsAccount进行操作时,订阅了指定事件的函数和方法会被调用,而当退订了某个函数或方法后,该函数或方法就不再在事件激发时被调用了。

以上代码在vc7.1中调试通过。最后再提醒一遍,别忘了VC的/GR参数哦。

<完>
 
分享到:
VC++ 线程同步之事件对象(event) 阅读详情

相关推荐

C++事件(Event)机制的实现一例[源代码下载链接已修复]

作者:袁晓辉(farproc@gmail.com) 声明:1、   本文为作者原创,如需转载请保持本文的完整性并注明出自 www.farproc.com 和 http://blog.youkuaiyun.com/uoyevoli. 2、   本文附件中的源代码你可以免费使用并无需注明出处。 用C++实现事件机制我以前写过一个小例子,但不是很完善,比如Event只能接受全局函数作为

farproc's blog 1万+

C++ 事件(event)使用总结

事件最常用在多线程同步互斥机制。 常用的函数有: 1、CreateEvent 创建事件。 函数原型如下所示,一共四个参数: HANDLE CreateEvent(  LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL  BOOL bManualReset, // 手动/自动   // TRUE:表示手动,在WaitF...

AI浩 1万+

[原创]用C++模拟C#的event机制

本文章为farproc.com站长袁晓辉(海洋)的原创文章,作者保留所有权利。如果转载,请务必注明来自www.farproc.com!! 作为一个C++程序员,学习C#应该不是一件很困难的事情,因为C#的许多特性都是从C++“继承”(不精确的说法)来的。但是C#作为一门全新的编程语言,它必然有自己的新特性,而这些C++中并不存在的新特性正是我们从C++转向C#的过程中必须认真重新学

farproc's blog 8184

【C++】事件机制

【代码】【C++】事件机制。

AntigravityC的博客 800

c++仿C# event

[原创]用C++模拟C#的event机制document.title="[原创]用C++模拟C#的event机制 - "+document.title 本文章为farproc.com站长袁晓辉(海洋)的原创文章,作者保留所有权利。如果转载,请务必注明来自www.farproc.com!! 作为一个C++程序员,学习C#应该不是一件很困难的事情,因为C#的许多特性都是从C++“继承”(不精确

zhengshifei的专栏 2033

用C++模拟C#事件机制

    C#中的事件机制可以很方便的实现设计模式中的Observer模式,C#提供了delegate 和 event 来实现这种机制,实际上只要delagate就可以实现event效果,event语法完全没必要,因为delegate是多播的。本文提供了一个C++版本的实现,与C#原生的事件机制相比,只有一点不同,我实现的delegate是单播的(为了避免delegate 和 event 功能重复的

1122

C++事件(Event)机制的实现一例

作者:袁晓辉(farproc@gmail.com) 声明:1、   本文为作者原创,如需转载请保持本文的完整性并注明出自 www.farproc.com 和 http://blog.youkuaiyun.com/uoyevoli. 2、   本文附件中的源代码你可以免费使用并无需注明出处。 用C++实现事件机制我以前写过一个小例子,但不是很完善,比如Event只能接受全局函数作为han

冷剑魂的专栏——垃圾场 1859

C++Event机制的简单实现

C++Event机制的简单实现

C++事件(Event)机制的实现一例(转载)

C++事件(Event)机制的实现一例[源代码下载链接已修复] 作者:袁晓辉(farproc@gmail.com) 声明: 1、 本文为作者原创,如需转载请保持本文的完整性并注明出自 www.farproc.com 和 http://blog.youkuaiyun.com/uoyevoli. 2、 本文附件中的源代码你可以免费使用并无需注明出处。 用C++实现事件机制我以前写过一个小例子,但不是很完善,比如E...

baiguomeng 355

C++事件(event)

C++事件相关介绍,对C++程序开发很有帮助。

C++中事件机制的简洁实现

事件模型是被广泛使用的好东西,但是C++标准库里没有现成的,其他实现又复杂或者不优雅,比如需要使用宏。现在VC11可以用在XP下了,那么痛快的拿起C++11提供的先进设施组合出一个轻便的实现吧。   为了达到简洁的目的,需要放弃一些特性:   1、不支持判断函数是否已经绑定过(因为std::function不提供比较方法,自己实现function的话代码又变多了)   2、需要使用者接收返回的回调函数标识来移除事件绑定(原因同上)   3、事件没有返回值,不支持回调函数优先级、条件回调等事件高级特性(比如返回所有处理结果中的大小值;只回调与指定参数匹配的事件处理函数)   

C++事件(Event)机制的实现一例(zz)

作者:袁晓辉(farproc@gmail.com) 声明: 1、 本文为作者原创,如需转载请保持本文的完整性并注明出自 www.farproc.com 和 http://blog.youkuaiyun.com/uoyevoli. 2、 本文附件中的源代码你可以免费使用并无需注明出处。用C++实现事件机制我以前写过一个小例子,但不是很完善,比如Event只能接受全局函数作为han...

weixin_30795127的博客 81

深入浅出:CosineLRScheduler 调度器的原理与实战应用

本文深入解析了CosineLRScheduler调度器的核心原理与实战应用,详细介绍了余弦退火算法及其在深度学习模型训练中的优势。通过参数配置建议、PyTorch实现示例和常见问题解决方案,帮助开发者高效应用该调度器提升模型性能,特别适用于计算机视觉和自然语言处理任务。

sss66的博客 859

用 cpp-httplib 实现 SSE 服务器:基于 `text/event-stream` 的 HTTP 长连接实时推送实战

Server-Sent Events(SSE)是一种基于 HTTP 的单向服务器推送协议:连接建立后保持打开,服务器可以在任意时刻向客户端推送数据。与 WebSocket 相比,它更轻量、完全建立在标准 HTTP 之上,天然兼容浏览器 `EventSource`、代理与负载均衡。本文以 [cpp-httplib](https://link.gitcode.com/i/45a8a8a7c7f03a2

gitblog_00480的博客 287

5G NR 双连接与载波聚合:PCell、SCell、PScell、SpCell 角色全解析

本文全面解析了5G NR中双连接与载波聚合技术的关键概念,详细介绍了PCell、SCell、PScell和SpCell的角色与功能。通过实际案例和配置示例,帮助读者理解这些小区在提升网络覆盖和速率方面的作用,以及在实际组网中的优化策略。

weixin_33220360的博客 373

从Frenet坐标系到多项式拟合:Lattice Planner核心原理拆解与调参指南

本文深入解析了自动驾驶轨迹规划中Lattice Planner的核心原理,重点阐述了其在Frenet坐标系下解耦横纵向规划、利用五次和四次多项式拟合轨迹的数学基础。文章提供了从坐标系转换、采样策略到成本函数设计的完整工程实践指南,并分享了关键的参数调优经验,旨在帮助开发者高效实现稳定、平滑且安全的轨迹规划。

tech5的博客 1111
上一篇: 我的架构经验小结(一)-- 常用的架构模型
下一篇: 内存池的简单试验(C++)
junecau
博客等级 码龄19年 125粉丝 3原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值