事件基本概念

  • 操作系统或应用程序内部发生某件事,程序的某个组件需要响应该事件,并进行特定处理

面向对象架构中,事件响应函数最可能为成员函数

  • 问题:指向类成员函数的指针不能转换为哑型指针void *,也不能随意转换为指向另一个类的成员函数的指针
  • 解决方案:使用指向指向类成员函数的指针的指针

实现策略:事件委托模型

  • Event类模板:管理事件响应者对象,实现事件多播
  • EventResponsor类模板:响应者对象与响应者行为配对
  • Empty类:委托模型和指针转换
#include <iostream>
#include <vector>
using namespace std;
//空类,用于指代响应者对象
class Empty{};
//事件响应者类模板,保存特定事件的响应者与响应行为
template<typename EventAction> class EventResponsor
{
public:
EventResponsor():actor(NULL),action(NULL) {}
EventResponsor(Empty *actor,EventAction *action):actor(actor),action(action){}
friend bool operator==(const EventResponsor &lhs, const EventResponsor &rhs)
{
return lhs.actor == rhs.actor && *lhs.action == *rhs.action;
}
public://公开的数据成员,以方便使用者
Empty *actor;
EventAction *action;
};//template<typename EventAction> class EventResponsor
//事件类模板,用于管理特定事件的所有响应者
template<typename EventAction> class Event
{
public:
typedef vector<EventResponsor<EventAction> >EventResponsors;
typeder typename vector<EventResponsor<EventAction> >::iterator EventIterator;
public:
virtual ~Event()
{
for (EventIterator it = this->_ers.begin(); it != this->_ers.end(); ++it)
{
delete it->action, it->action = NULL;
}
}
EventResponsors & GetResponsors() { return this->_ers; } //事件绑定,将实际响应者和响应行为挂接到事件响应者对象上
template<typename Responsor, typename Action>
void Bind(Responsor *actor, Action action)
{
Action *act = new Action(action);
EventResponsor<EventAction> er((Empty*)actor, (EventAction*)act);
bool unbound = true;
for (EventIterator it = this->_ers.begin(); it != this->_ers.end(); ++it)
{
if (*it == er)//发现重复的事件响应者,说明已绑定
{
unbound = false;
break;
}
}
if (unbound)
{
this->_ers.push_back(er);
}
else
{
delete er.action, er.action = NULL;
}
}
//解除事件绑定,删除事件响应者对象
template<typename Responsor,typename Action>
void Unbind(Responsor *actor, Action action)
{
Action *act = new Action(action);
EventResponsor<EventAction> er((Empty*)actor, (EventAction *)act);
for (EventIterator it = this->_ers.begin(); it != this->_ers.end(); ++it)
{
if (*it == er)//找到待删除的事件响应者对象
{
delete it->action, this->_ers.erase(it); break;
}
}
delete er.action, er.action = NULL;
}
private:
EventResponsor _ers;
};//template<typename EventAction> class Event
//定义事件委托模型,指向类成员函数的指针
typedef Empty EventDelegator;
typedef void(EventDelegator::*ValueChanged)(int value, void *tag);
//触发者
class Trigger
{
public:
Trigger() :_value() {}
void SetValue(int value, void *tag);
int GetValue() { return _value; }
public:
//值变化事件,公开属性,方便在类外设定
Event<ValueChanged> value_changed;
private:
int _value;
};
//设定值,遍历特定事件的响应对象列表,逐一触发值变更事件
void Trigger::SetValue(int value, void *tag)
{
if (_value == value)
{
return;
}
_value = value;
Event<ValueChanged>::EventResponsors ers;
ers = this->value_changed.GetResponsors();
if (!ers.empty())
{
Event<ValueChanged>::EventIterator it;
for ( it = ers.begin(); it != ers.end(); ++it)
{
((it->actor)->*(*(it->action)))(value, tag);//响应事件
}
}
}
//行动者
class Actor
{
public:
//侦听事件,绑定本对象的事件响应函数到侦听的事件
void Listen(Trigger *trigger)
{
trigger->value_changed.Bind(this, &Actor::OnValueChanged);
}
//停止侦听,从侦听的事件中取消本对象的事件响应活动
void Unlisten(Trigger *trigger)
{
trigger->value_changed.Unbind(this, &Actor::OnValueChanged);
}
//值变更事件的响应函数
void OnValueChanged(int value, viod *tag)
{
cout << reinterpret_cast<char *>(tag) << value << "." << endl;
}
}; int main()
{
const char *s = "Now the value is";
Trigger t;
Actor a1, a2; a1.Listen(&t);
a2.Listen(&t); cout << "Listening..." << endl;
t.SetValue(, reinterpret_cast<void *>(const_cast<char *>(s))); a2.Unlisten(&t);
cout << "Listening again..." << endl;
t.SetValue(, reinterpret_cast<void *>(const_cast<char *>(s)));
return ;
}

C++学习笔记38:事件机制的更多相关文章

  1. NodeJS学习笔记 (21)事件机制-events(ok)

    模块概览 events模块是node的核心模块之一,几乎所有常用的node模块都继承了events模块,比如http.fs等. 模块本身非常简单,API虽然也不少,但常用的就那么几个,这里举几个简单例 ...

  2. java学习笔记09--反射机制

    java学习笔记09--反射机制 什么是反射: 反射是java语言的一个特性,它允许程序在运行时来进行自我检查并且对内部的成员进行操作.例如它允许一个java的类获取他所有的成员变量和方法并且显示出来 ...

  3. Storm学习笔记 - 消息容错机制

    Storm学习笔记 - 消息容错机制 文章来自「随笔」 http://jsynk.cn/blog/articles/153.html 1. Storm消息容错机制概念 一个提供了可靠的处理机制的spo ...

  4. 学习笔记---Javascript事件Event、IE浏览器下的拖拽效果

    学习笔记---Javascript事件Event.IE浏览器下的拖拽效果     1. 关于event常用属性有returnValue(是否允许事件处理继续进行, false为停止继续操作).srcE ...

  5. Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T>

    Caliburn.Micro学习笔记目录 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现 ...

  6. iOS学习笔记--触摸事件

    最近空闲时间在学习iOS相关知识,几周没有更新文章了,今天总结下这些天的学习内容,也整理下iOS的学习笔记,以便以后查阅翻看- iOS中的事件可以分为3大类型: 触摸事件 加速计事件 远程控制事件 响 ...

  7. java学习笔记13--反射机制与动态代理

    本文地址:http://www.cnblogs.com/archimedes/p/java-study-note13.html,转载请注明源地址. Java的反射机制 在Java运行时环境中,对于任意 ...

  8. [JS学习笔记]Javascript事件阶段:捕获、目标、冒泡

    当你在浏览器上点击一个按钮时,点击的事件不仅仅发生在按钮上,同时点击的还有这个按钮的容器元素,甚至也点击了整个页面. 事件流 事件流描述了从页面接收事件的顺序,但在浏览器发展到第四代时,浏览器开发团队 ...

  9. vue学习笔记(四)事件处理器

    前言 在上一章vue学习笔记(三)class和style绑定的内容中,我们学习了如何在vue中绑定class和style,介绍了常用的绑定方法,class的数组绑定和对象绑定以及style的数组绑定和 ...

  10. JavaScript高级程序设计学习笔记之事件

    1.事件流 事件流描述的是从页面中接收事件的顺序. 事件冒泡 IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播 ...

随机推荐

  1. mq命令帮助文档

    https://www.ibm.com/support/knowledgecenter/zh/SSFKSJ_7.5.0/com.ibm.mq.ref.adm.doc/q083180_.htm

  2. python根据服务名获取服务启动路径

    #coding=utf8 import _winreg as winreg class Win32Environment: """Utility class to get ...

  3. centos 6.5环境下分布式文件系统MogileFS工作原理及分布式部署实现过程

    MogileFS是一套高效的文件自动备份组件,由Six Apart开发,广泛应用在包括LiveJournal等web2.0站点上 MogileFS由3个部分组成:    第1个部分:是server端, ...

  4. 转载:2.2.5 在配置中使用变量《深入理解Nginx》(陶辉)

    原文:https://book.2cto.com/201304/19630.html 有些模块允许在配置项中使用变量,如在日志记录部分,具体示例如下.log_format  main  '$remot ...

  5. Annoy 近邻算法

    Annoy 随机选择两个点,以这两个节点为初始中心节点,执行聚类数为2的kmeans过程,最终产生收敛后两个聚类中心点 二叉树底层是叶子节点记录原始数据节点,其他中间节点记录的是分割超平面的信息 但是 ...

  6. 前端开发必须知道的JS之闭包及应用

    本文讲的是函数闭包,不涉及对象闭包(如用with实现).如果你觉得我说的有偏差,欢迎拍砖,欢迎指教. 在前端开发必须知道的JS之原型和继承一文中说过下面写篇闭包,加之最近越来越发现需要加强我的闭包应用 ...

  7. SeaJS入门教程系列之SeaJS介绍(一)

    前言SeaJS是一个遵循CommonJS规范的JavaScript模块加载框架,可以实现JavaScript的模块化开发及加载机制.与jQuery等JavaScript框架不同,SeaJS不会扩展封装 ...

  8. sql基础笔记备忘

    MySQL中定义数据字段的类型对你数据库的优化是非常重要的. MySQL支持多种类型,大致可以分为三类:数值.日期/时间和字符串(字符)类型. 数值类型:tinyint smallint medium ...

  9. 性能测试五:jmeter进阶之后置处理器(正则、json提取器)

    如,从get返回的json中提取stock的值 作为post的请求参数 1.JSON提取器 专门对json数据进行提取的后置处理器 Debug Sampler:记录之前的请求的所有参数及数据 2.正则 ...

  10. pytest七:assert

    断言是写自动化测试基本最重要的一步,一个用例没有断言,就失去了自动化测试的意义了.什么是断言呢?简单来讲就是实际结果和期望结果去对比,符合预期那就测试 pass,不符合预期那就测试 failed py ...