事件基本概念

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

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

  • 问题:指向类成员函数的指针不能转换为哑型指针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. ES系列十四、ES聚合分析(聚合分析简介、指标聚合、桶聚合)

    一.聚合分析简介 1. ES聚合分析是什么? 聚合分析是数据库中重要的功能特性,完成对一个查询的数据集中数据的聚合计算,如:找出某字段(或计算表达式的结果)的最大值.最小值,计算和.平均值等.ES作为 ...

  2. java并发编程系列一、多线程

    一.什么是线程 一个应用就是一个进程.一个进程由多个线程组成.一个生产车间比作是一个进程.工人比作是线程.当任务比较多的时候,增加工人可以提高效率,同时成本就是支付费用(机器资源,内存)也会增加. p ...

  3. Mysql复习大全(转)

    基础知识: 1.数据库的连接 mysql -u -p -h -u 用户名 -p 密码 -h host主机 2.库级知识 显示数据库: show databases; 选择数据库: use dbname ...

  4. Linux(CentOS7)安装zip、unzip命令

    安装命令: yum install -y unzip zip

  5. 深入对比TOML,JSON和YAML

    坦率地说,在我开始与Hugo TOML合作之前,我感到羞耻是一个需要发现的新领域,但我对YAML和JSON非常熟悉.本文将帮助您了解如何通过不同的数据格式构建数据.       在Hugo中,您可以将 ...

  6. == 和 equal 区别

    在初学 Java 时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = new String(" ...

  7. java多线程快速入门(八)

    设置线程优先级:join() package com.cppdy; class MyThreadA extends Thread{ MyThreadB b; public MyThreadA(MyTh ...

  8. Laravel collection 报错 join(): Invalid arguments passed

    混淆了 array 与 collection,join 并不支持 collection. array 与 collection 不同的 join 实现 collect([1, 2, 3, 4, 5]) ...

  9. composer 安装依赖缓慢,查看 composer 的详细执行日志

    在 windows WSL 上安装 composer 依赖 composer install 发现执行异常缓慢,怀疑没有走国内的镜像,而是直接访问的 github. 需要能看到 composer 的执 ...

  10. HDU 5988 Coding Contest(费用流+浮点数)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5988 题目大意: 给定n个点,m条有向边,每个点是一个吃饭的地方,每个人一盒饭.每个点有S个人,有B盒 ...