事件基本概念

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

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

  • 问题:指向类成员函数的指针不能转换为哑型指针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. #ifndef详解

    #ifndef 是"if not defined"的简写,是预处理功能(宏定义.文件包含.条件编译)当中的条件编译,可以根据是否已经定义了一个变量来进行分支选择,其作用是: 1.防 ...

  2. 解决报错error the @annotation pointcut expression is only supported at Java 5

    eclipse搭建环境后报错 error the @annotation pointcut expression is only supported at Java 5 错误意思大致是:注释切入点表达 ...

  3. 如何查看centos系统cpu/内存使用情况

    1.查看硬盘 [mushme@investide ~]$ df -ah 文件系统              容量  已用 可用 已用% 挂载点 /dev/cciss/c0d0p1     123G   ...

  4. mysql语句判断是否存在记录,没有则插入新纪录否则不执行

    1 前言 由于项目需要,当某个表如果有记录,就不执行加入语句,否则加入新纪录(测试数据).思路是:判断表的记录是否为空,然后再决定是否插入 2 代码 DROP PROCEDURE IF EXISTS ...

  5. STM32应用实例六:与MS5837压力传感器的I2C通讯

    MS5837压力传感器是一种可用于电路板上,适用于检测10-1200mbar压力范围的传感器,灵敏度非常高,理论上能够检测到0.01mbar的压力变化,实际使用过程中测试并无明显的变化. MS5837 ...

  6. (八)CXF添加自定义拦截器

    前面我们说到CXF添加内置的拦截器,今天的话,我们来讲下如何添加自定义拦截器: 我们的实例是客户端访问服务端webservice接口要加权限认证. 我们思路先说下.我们可以通过在SOAP消息的Head ...

  7. 学习Struts2经验总结

    一.struts 访问路径问题 1) Struts2的思想:主要围着“action”转,只要找到“action”它就知道自己该干嘛了. 首先配置struts.xml ,我们可以明白的看到,action ...

  8. python 全栈开发,Day112(内容回顾,单例模式,路由系统,stark组件)

    一.内容回顾 类可否作为字典的key 初级 举例: class Foo(object): pass _registry = { Foo:123 } print(_registry) 执行输出: {&l ...

  9. 【AtCoder】AGC019

    A - Ice Tea Store 算一下每种零售最少的钱就行,然后优先买2,零头买1 #include <bits/stdc++.h> #define fi first #define ...

  10. Codeforces 739C Alyona and towers 线段树

    Alyona and towers 这个题写起来真的要人命... 我们发现一个区间被加上一个d的时候, 内部的结构是不变的, 改变的只是左端点右端点的值, 这样就能区间合并了. 如果用差分的话会简单一 ...