C++ C++;回叫系统
我正在尝试制作一个简单的事件调度程序系统。简单地说,我有所有派生IEvent接口的事件类。我还有一个EventManager类,其中包含两个方法:C++ C++;回叫系统,c++,C++,我正在尝试制作一个简单的事件调度程序系统。简单地说,我有所有派生IEvent接口的事件类。我还有一个EventManager类,其中包含两个方法: void addListener( int eventID, std::function<void( IEvent *event )> callback ); void dispatchEvent( int eventID, IEvent *event ); 调用dispatchEvent时,调用方必须传递IEEvent派生
void addListener( int eventID, std::function<void( IEvent *event )> callback );
void dispatchEvent( int eventID, IEvent *event );
调用dispatchEvent时,调用方必须传递IEEvent派生类,例如MouseeEvent:
// dispatching an Event
EventManager::dispatchEvent(Event_MouseMove, new MouseEvent());
我的问题与回调方法有关。
假设您要侦听MouseEvent,则对象将具有如下方法:
void eventHandler( MouseEvent *event );
问题是回调无法传递给addListener方法,因为它需要的是IEEvent*而不是MouseeEvent*。为了使它工作,我只使用IEvent类型,然后事件处理程序方法必须将该IEvent*强制转换为它所期望的派生类型;在本例中,鼠标事件*。
如何使addListener方法获取指向将接收任何IEvent派生类的方法的指针
例如:
// add an event listener
EventManager::addListener(Event_MouseMove, std::bind(&Obj::callback, this, std::placeholders::_1));
// the callback method
void Obj::callback( MouseEvent *e ) { ... }
// dispatching an Event
EventManager::dispatchEvent(Event_MouseMove, new MouseEvent());
如果不将addListener()的函数参数改为MouseEvent*参数(或从MouseEvent派生的参数)而不是IEvent*参数,我认为这是不可能的 如果您的EventHandler将指向其他类(从IEvent派生)的指针作为参数,那么您需要为每个类分别使用addListener()函数,这可能不是您想要的 简单地传递一个IEvent*,然后在eventHandler中将其强制转换为适当的类型(正如您当前所做的)可能是一种方法
例如,Qt实际上为其eventFilters做了一些类似的事情:有点浪费,因为它在每个侦听器周围创建了一个虚拟包装器。但是,我不知道是否可以干净地转换
std::function
对象。如果在addListener()
中只接受函数指针(但随后lambda被排除,meh),则可以直接转换。另外,一些reinterpret\u cast
可能会有所帮助,但我觉得这并不容易,因此解决方案没有一个功能
#include <functional>
#include <iostream>
struct IEvent { };
struct MouseEvent : IEvent { };
template <typename type>
std::function <void (IEvent*)>
convert_callback (const std::function <void (type*)>& callback)
{
static_assert (std::is_convertible <type*, IEvent*>::value, "wrong type");
return [=] (IEvent* event) { return callback (static_cast <MouseEvent*> (event)); };
}
struct dispatcher
{
template <typename type>
void
addListener (std::function <void (type*)> callback)
{
std::function <void (IEvent*)> real_callback (convert_callback (callback));
MouseEvent event;
real_callback (&event);
}
};
void
callback (MouseEvent*)
{
std::cout << "hello\n";
}
int
main ()
{
dispatcher x;
x.addListener <MouseEvent> (&callback);
}
#包括
#包括
结构事件{};
结构MouseEvent:IEvent{};
模板
std::函数
convert_回调(const std::function&callback)
{
静态断言(std::is_convertable::value,“类型错误”);
return[=](IEvent*事件){返回回调(static_cast(event));};
}
结构调度器
{
模板
无效的
addListener(std::函数回调)
{
std::函数real_回调(convert_回调(callback));
MouseEvent事件;
实时回调(和事件);
}
};
无效的
回调(MouseEvent*)
{
std::cout这可能不是您想要的,但为什么不采取不同的方法呢。与其存储函数,不如存储指向具有handleEvent
函数的对象的指针(或smart_ptr
s)。类似于:
struct EventHander {
virtual ~EventHandler() {}
virtual void handle_event(IEvent *e) = 0;
};
struct Myhandler : public Eventhandler {
virtual void handle_event(IEvent *e) {
// Do whatever
}
};
因此,您只需存储EventHandler
指针,然后调用handler->handle\u事件(e)
在事件到达时为每个类调用。解决这个问题很容易。只需添加一个回调接口,例如可调用的
。请参见下面的代码示例,该类充当可调用的
,并包装事件的任何子类
template<typename Arg, /*traits here*/>
class FunctionWrapper : public Callable<void, Event*>
{
public:
FunctionWrapper(Callable<void, Arg*> *func)
{
mInternal = func;
}
FunctionWrapper(void (*func)(Arg*))
{
mInternal = new Function<void(Arg*)>(func);
}
template<typename T>
FunctionWrapper(T* obj, void (T::*func)(Arg*))
{
mInternal = new Function<void(T::*)(Arg*)>(obj, func);
}
void call(Event *e)
{
return mInternal->call(static_cast<Arg*>(e));
}
void operator ()(Event *e)
{
return call(e);
}
operator void*() const
{
return mInternal ? 0 : this;
}
operator bool() const
{
return mInternal != 0;
}
bool operator==(const FunctionWrapper& wrapper) const
{
return mInternal == wrapper.mInternal;
}
bool operator!=(const FunctionWrapper& wrapper) const
{
return mInternal != wrapper.mInternal;
}
virtual ~FunctionWrapper()
{
if(mInternal){
delete mInternal;
mInternal = 0;
}
}
private:
Callable<void, Arg*> *mInternal;
FunctionWrapper(const FunctionWrapper& wrapper);
const FunctionWrapper& operator=(const FunctionWrapper& wrapper);
};
模板
类FunctionWrapper:公共可调用
{
公众:
FunctionWrapper(可调用*func)
{
mInternal=func;
}
函数包装器(void(*func)(Arg*))
{
mInternal=新函数(func);
}
模板
函数包装器(T*obj,void(T::*func)(Arg*))
{
mInternal=新函数(obj,func);
}
无效调用(事件*e)
{
return mInternal->call(static_cast(e));
}
void运算符()(事件*e)
{
回电(e);
}
运算符void*()常量
{
return mInternal?0:这个;
}
运算符bool()常量
{
返回mInternal!=0;
}
布尔运算符==(常量函数包装器和包装器)常量
{
return mInternal==wrapper.mInternal;
}
布尔运算符!=(常量函数包装器和包装器)常量
{
return mInternal!=wrapper.mInternal;
}
虚拟函数包装器()
{
if(mInternal){
删除mInternal;
mInternal=0;
}
}
私人:
可调用*最小内部;
FunctionWrapper(常量FunctionWrapper&wrapper);
常量函数包装器和运算符=(常量函数包装器和包装器);
};
既然你说的是std::function
,我打赌你也可以安全地编写
,而不需要空格。什么是eventID
,它是如何连接到事件类型的?eventID是一个唯一的标识符,它是一个int,用作回调映射的键。
struct EventHander {
virtual ~EventHandler() {}
virtual void handle_event(IEvent *e) = 0;
};
struct Myhandler : public Eventhandler {
virtual void handle_event(IEvent *e) {
// Do whatever
}
};
template<typename Arg, /*traits here*/>
class FunctionWrapper : public Callable<void, Event*>
{
public:
FunctionWrapper(Callable<void, Arg*> *func)
{
mInternal = func;
}
FunctionWrapper(void (*func)(Arg*))
{
mInternal = new Function<void(Arg*)>(func);
}
template<typename T>
FunctionWrapper(T* obj, void (T::*func)(Arg*))
{
mInternal = new Function<void(T::*)(Arg*)>(obj, func);
}
void call(Event *e)
{
return mInternal->call(static_cast<Arg*>(e));
}
void operator ()(Event *e)
{
return call(e);
}
operator void*() const
{
return mInternal ? 0 : this;
}
operator bool() const
{
return mInternal != 0;
}
bool operator==(const FunctionWrapper& wrapper) const
{
return mInternal == wrapper.mInternal;
}
bool operator!=(const FunctionWrapper& wrapper) const
{
return mInternal != wrapper.mInternal;
}
virtual ~FunctionWrapper()
{
if(mInternal){
delete mInternal;
mInternal = 0;
}
}
private:
Callable<void, Arg*> *mInternal;
FunctionWrapper(const FunctionWrapper& wrapper);
const FunctionWrapper& operator=(const FunctionWrapper& wrapper);
};