事件处理程序回调中的调用模块函数 我在C++中编写了一个事件系统,这在当时有点无用,因为它所能做的就是说它是处理和事件的。但是,它可以发射和处理任何负载类型的事件。计划是保持事件的简单性,只需向其附加某种类型的数据(可以根据需要进行复杂化)
然后事件处理程序回调中的调用模块函数 我在C++中编写了一个事件系统,这在当时有点无用,因为它所能做的就是说它是处理和事件的。但是,它可以发射和处理任何负载类型的事件。计划是保持事件的简单性,只需向其附加某种类型的数据(可以根据需要进行复杂化),c++,C++,然后EventHandlers处理事件。因为Event是一个模板,EventHandlers也必须被模板化,并且它的HandleEvent方法不能是虚拟的。如果可以的话,故事就到此结束了(您只需扩展EventHandler并实现HandleEvent来使用您自己的ref) 因此,现在我一直在试图弄清楚如何让EventHandler::HandleEvent(Event&Event)能够调用对象的方法,从而实际对事件执行一些有用的操作。这是我第八次重写这个系统。到目前为止,我所走的每一条路线都以我
EventHandler
s处理事件。因为Event
是一个模板,EventHandler
s也必须被模板化,并且它的HandleEvent
方法不能是虚拟的。如果可以的话,故事就到此结束了(您只需扩展EventHandler
并实现HandleEvent
来使用您自己的ref)
因此,现在我一直在试图弄清楚如何让EventHandler::HandleEvent(Event&Event)
能够调用对象的方法,从而实际对事件执行一些有用的操作。这是我第八次重写这个系统。到目前为止,我所走的每一条路线都以我无法随心所欲地处理事件而告终。我不在乎这个方法是否难看,我只是想让它易于使用
注:卡在C++ 98
注意:阅读EventEmitter代码对于理解问题并不重要
#包括
#包括
#包括
#包括
事件
模板
班级活动{
公众:
事件(int-id);
int-id;
T有效载荷;
};
样板
事件::事件(int-id):id(id){}
事件处理程序
类事件处理程序{
公众:
EventHandler();
样板
无效处理事件(事件和事件);
};
EventHandler::EventHandler(){}
样板
void EventHandler::HandleEvent(事件和事件){
std::cout秒;
}
否则{
std::vector\u处理器;
这->events.insert(std::pair(id,_handlers));
it=this->events.find(id);
handlers=&it->second;
}
}
//订阅活动
void EventSystem::On(int-id,EventHandler*handler){
std::vector*处理程序=0;
此->GetEventHandlers(id,handlers);
if(处理程序){
处理程序->推回(处理程序);
}
}
//发出事件
样板
void EventSystem::Emit(事件和事件){
std::map::iterator it=this->events.find(event.id);
如果(it!=this->events.end()){
对于(size_t i=0;isecond.size();i++){
it->second[i]->HandleEvent(事件);
}
}
}
模块
类模块{
公众:
事件处理器事件处理器;
事件处理程序报警处理程序;
无效事件(事件);
无效事件(事件);
无效事件(事件);
};
//我很乐意为每个相关事件调用这些
void模块::OnEvent(事件){
}
void模块::OnEvent(事件){
}
void模块::OnEvent(事件){
}
主要
int main(){
事件系统;
事件a(1);
事件b(2);
事件报警(3);
模块;
es.On(1,&module.event_处理程序);
es.On(2和模块报警处理程序);
es.On(3,&module.event_处理程序);
发射(eventa);
es.Emit(eventb);
发射(警报);
}
EventHandler还必须是模板化的,并且其HandleEvent方法不能是虚拟的
当然,事件处理程序可以是模板化的,也可以是虚拟的
在构建了这类事情的更复杂版本(异步事件调度器,在对象之间和线程之间封送事件)之后,我知道您正在尝试做什么
解决办法包括:
- 有一个非模板基类,
,用于派生BaseEventHandler
EventHandler
- 然后,
类在很大程度上引用指向基类的指针,而不是派生的EventSystem
类EventHandler
向救援人员施救dynamic_cast
#include <iostream>
#include <vector>
#include <map>
#include <string>
template <class T>
class Event {
public:
Event(int idvalue) : id(idvalue)
{
}
int id;
T payload;
};
class BaseEventHandler
{
public:
virtual ~BaseEventHandler() {} ; // need at least 1 virtual method for dynamic cast
};
template <typename T>
class EventHandler : public BaseEventHandler {
public:
virtual void HandleEvent(Event<T>& event) = 0;
};
class EventSystem {
public:
void On(int id, BaseEventHandler* handler);
template <class T>
void Emit(Event<T>& event)
{
std::map<int, std::vector<BaseEventHandler*> >::iterator it = this->events.find(event.id);
if (it != this->events.end()) {
for (size_t i = 0; i < it->second.size(); i++) {
BaseEventHandler* pBaseEventHandler = it->second[i];
EventHandler<T>* pHandler = dynamic_cast<EventHandler<T>*>(pBaseEventHandler);
if (pHandler){
pHandler->HandleEvent(event);
}
}
}
}
void GetEventHandlers(int id, std::vector<BaseEventHandler*>*& handlers);
std::map<int, std::vector<BaseEventHandler*> > events;
};
void EventSystem::GetEventHandlers(int id, std::vector<BaseEventHandler*>*& handlers) {
std::map<int, std::vector<BaseEventHandler*> >::iterator it = this->events.find(id);
if (it != this->events.end()) {
handlers = &it->second;
}
else {
std::vector<BaseEventHandler*> _handlers;
this->events.insert(std::pair<int, std::vector<BaseEventHandler*> >(id, _handlers));
it = this->events.find(id);
handlers = &it->second;
}
}
// subscribe to an event
void EventSystem::On(int id, BaseEventHandler* handler) {
std::vector<BaseEventHandler*>* handlers = 0;
this->GetEventHandlers(id, handlers);
if (handlers) {
handlers->push_back(handler);
}
}
class Module : public EventHandler<int>,
public EventHandler<float>,
public EventHandler<std::string>
{
public:
void HandleEvent(Event<int>& event);
void HandleEvent(Event<float>& event);
void HandleEvent(Event<std::string>& event);
void RegisterEvents(EventSystem& es);
};
// would love to call these somehow for each associated event
void Module::HandleEvent(Event<int>& event) {
std::cout << "Integer event\n";
}
void Module::HandleEvent(Event<float>& event) {
std::cout << "Float event\n";
}
void Module::HandleEvent(Event<std::string>& event) {
std::cout << "String event\n";
}
void Module::RegisterEvents(EventSystem& es)
{
es.On(1, (EventHandler<int>*)this);
es.On(2, (EventHandler<float>*)this);
es.On(3, (EventHandler<std::string>*)this);
}
int main() {
EventSystem es;
Event<int> eventa(1);
Event<float> eventb(2);
Event<std::string> alarm(3);
Module module;
module.RegisterEvents(es);
es.Emit(eventa);
es.Emit(eventb);
es.Emit(alarm);
}
现在,当您将代码发展到生产级别时,我希望您考虑几个设计问题
- 当事件处理程序发出另一个事件(或同一事件)时会发生什么
- 事件处理程序如何取消订阅?如果事件处理程序在回调中注销自身(或另一个处理程序),会发生什么情况
- 考虑让Emit接受paylaod参数并代表调用者构造事件对象。也就是说,
而不是要求调用方自己费力地创建一个es.Emit(3,“发生了什么事”)
事件
- 如果你能找到一种聪明的方法让事件获取一组有效载荷而不是单一类型的载荷,你就可以获得额外的积分。(再次使用动态强制转换和基类技巧)
- 考虑将事件和事件有效负载作为常量传递给回调,这样一个回调就不会干扰另一个调用方接收的内容
template <class T>
class Event {
public:
Event(int id);
int id;
T payload;
};
template <class T>
Event<T>::Event(int id):id(id){}
class EventHandler {
public:
EventHandler();
template <class T>
void HandleEvent(Event<T> &event);
};
EventHandler::EventHandler(){}
template <class T>
void EventHandler::HandleEvent(Event<T> &event){
std::cout << "Handled event " << event.id << std::endl;
}
class EventSystem {
public:
void On(int id, EventHandler *handler);
template <class T>
void Emit(Event<T> &event);
void GetEventHandlers(int id, std::vector<EventHandler*> *&handlers);
std::map<int, std::vector<EventHandler*> > events;
};
void EventSystem::GetEventHandlers(int id, std::vector<EventHandler*> *&handlers){
std::map<int, std::vector<EventHandler*> >::iterator it = this->events.find(id);
if(it != this->events.end()){
handlers = &it->second;
}
else {
std::vector<EventHandler*> _handlers;
this->events.insert(std::pair<int, std::vector<EventHandler*> >(id, _handlers));
it = this->events.find(id);
handlers = &it->second;
}
}
// subscribe to an event
void EventSystem::On(int id, EventHandler *handler){
std::vector<EventHandler*> *handlers = 0;
this->GetEventHandlers(id, handlers);
if(handlers){
handlers->push_back(handler);
}
}
// emit an event
template <class T>
void EventSystem::Emit(Event<T> &event){
std::map<int, std::vector<EventHandler*> >::iterator it = this->events.find(event.id);
if(it != this->events.end()){
for(size_t i = 0; i < it->second.size(); i++){
it->second[i]->HandleEvent(event);
}
}
}
class Module {
public:
EventHandler event_handler;
EventHandler alarm_handler;
void OnEvent(Event<int> event);
void OnEvent(Event<float> event);
void OnEvent(Event<std::string> event);
};
// would love to call these somehow for each associated event
void Module::OnEvent(Event<int> event){
}
void Module::OnEvent(Event<float> event){
}
void Module::OnEvent(Event<std::string> event){
}
int main(){
EventSystem es;
Event<int> eventa(1);
Event<float> eventb(2);
Event<std::string> alarm(3);
Module module;
es.On(1, &module.event_handler);
es.On(2, &module.alarm_handler);
es.On(3, &module.event_handler);
es.Emit(eventa);
es.Emit(eventb);
es.Emit(alarm);
}
#include <iostream>
#include <vector>
#include <map>
#include <string>
template <class T>
class Event {
public:
Event(int idvalue) : id(idvalue)
{
}
int id;
T payload;
};
class BaseEventHandler
{
public:
virtual ~BaseEventHandler() {} ; // need at least 1 virtual method for dynamic cast
};
template <typename T>
class EventHandler : public BaseEventHandler {
public:
virtual void HandleEvent(Event<T>& event) = 0;
};
class EventSystem {
public:
void On(int id, BaseEventHandler* handler);
template <class T>
void Emit(Event<T>& event)
{
std::map<int, std::vector<BaseEventHandler*> >::iterator it = this->events.find(event.id);
if (it != this->events.end()) {
for (size_t i = 0; i < it->second.size(); i++) {
BaseEventHandler* pBaseEventHandler = it->second[i];
EventHandler<T>* pHandler = dynamic_cast<EventHandler<T>*>(pBaseEventHandler);
if (pHandler){
pHandler->HandleEvent(event);
}
}
}
}
void GetEventHandlers(int id, std::vector<BaseEventHandler*>*& handlers);
std::map<int, std::vector<BaseEventHandler*> > events;
};
void EventSystem::GetEventHandlers(int id, std::vector<BaseEventHandler*>*& handlers) {
std::map<int, std::vector<BaseEventHandler*> >::iterator it = this->events.find(id);
if (it != this->events.end()) {
handlers = &it->second;
}
else {
std::vector<BaseEventHandler*> _handlers;
this->events.insert(std::pair<int, std::vector<BaseEventHandler*> >(id, _handlers));
it = this->events.find(id);
handlers = &it->second;
}
}
// subscribe to an event
void EventSystem::On(int id, BaseEventHandler* handler) {
std::vector<BaseEventHandler*>* handlers = 0;
this->GetEventHandlers(id, handlers);
if (handlers) {
handlers->push_back(handler);
}
}
class Module : public EventHandler<int>,
public EventHandler<float>,
public EventHandler<std::string>
{
public:
void HandleEvent(Event<int>& event);
void HandleEvent(Event<float>& event);
void HandleEvent(Event<std::string>& event);
void RegisterEvents(EventSystem& es);
};
// would love to call these somehow for each associated event
void Module::HandleEvent(Event<int>& event) {
std::cout << "Integer event\n";
}
void Module::HandleEvent(Event<float>& event) {
std::cout << "Float event\n";
}
void Module::HandleEvent(Event<std::string>& event) {
std::cout << "String event\n";
}
void Module::RegisterEvents(EventSystem& es)
{
es.On(1, (EventHandler<int>*)this);
es.On(2, (EventHandler<float>*)this);
es.On(3, (EventHandler<std::string>*)this);
}
int main() {
EventSystem es;
Event<int> eventa(1);
Event<float> eventb(2);
Event<std::string> alarm(3);
Module module;
module.RegisterEvents(es);
es.Emit(eventa);
es.Emit(eventb);
es.Emit(alarm);
}
class AlarmEventHandler : public EventHandler<std::string> {
public:
AlarmEventHandler(Module* module) : _module(module) {}
HandleEvent(Event<std::string>& event) {
_module->OnEvent(event);
}
Module* _module;
};