C++ C++;回叫系统

C++ C++;回叫系统,c++,C++,我正在尝试制作一个简单的事件调度程序系统。简单地说,我有所有派生IEvent接口的事件类。我还有一个EventManager类,其中包含两个方法: void addListener( int eventID, std::function<void( IEvent *event )> callback ); void dispatchEvent( int eventID, IEvent *event ); 调用dispatchEvent时,调用方必须传递IEEvent派生

我正在尝试制作一个简单的事件调度程序系统。简单地说,我有所有派生IEvent接口的事件类。我还有一个EventManager类,其中包含两个方法:

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);
};