多态与派生成员函数指针?

Rya*_*ell 7 c++ polymorphism inheritance member-function-pointers

(我看到之前已经问过类似的问题,但是我看到的那些问题似乎并没有完全触及我的用例.特别是,我想知道我的编译失败是否是由于一个错误,或者是我尝试什么是verboten的结果.)

背景

我希望实现委托模式,用于事件处理.我想也许对我的需求最好的方法是成员函数指针的映射,由std :: string索引(表示事件类型.)

我开始试图完成这个std::function,但遇到了一些问题,然后决定尝试使用原始MFP.(我仍然愿意考虑std::function,我会接受一个答案,说明如何使用这种方法来完成我的确切需求.但我仍然想知道我目前的方法有什么问题.)

我能够用一个班级来完成这个工作.但是我实际上希望委托映射由抽象基类提供,然后让派生类将其委托注册到该映射中.除非我在下面的代码中犯了一些错误,否则这似乎是不可能的; 似乎成员函数指针不能是多态的.

我得到的编译错误如下:

mfp5.cpp: In constructor ‘Derived::Derived()’:
mfp5.cpp:41:21: error: cannot convert ‘int (Derived::*)(const Base::EventContext&)’ to ‘std::map<std::basic_string<char>, int (Base::*)(const Base::EventContext&)>::mapped_type {aka int (Base::*)(const Base::EventContext&)}’ in assignment
_delegates["foo"] = &Derived::FooEventHandler;
Run Code Online (Sandbox Code Playgroud)

问题

  1. 我在下面的代码中犯了错误,还是真的不允许?简而言之,我有一个std :: map Base::*,我想在其中插入一些Derived::*.
  2. 是否有其他推荐的方法来实现这一目标?

class Base
{
  public:
    struct EventContext
    {
      int data1;
    };
    Base() {}
    virtual int ProcessEvent(std::string event, EventContext ctx) =0;

  protected:
    typedef int (Base::* EventHandler)(const EventContext& context);
    typedef std::map<std::string, EventHandler> EventDelegateMap;
    EventDelegateMap _delegates;
};
Run Code Online (Sandbox Code Playgroud)

.

class Derived: Base
{
  public:
    Derived();
    int ProcessEvent(std::string event, EventContext ctx);

  private:
    int FooEventHandler(const EventContext& context);
    int BarEventHandler(const EventContext& context);
    int QuxEventHandler(const EventContext& context);
};

Derived::Derived() :Base()
{
  _delegates["foo"] = &Derived::FooEventHandler;  // error
  _delegates["bar"] = &Derived::BarEventHandler;  // error
  _delegates["qux"] = &Derived::QuxEventHandler;  // error
}
Run Code Online (Sandbox Code Playgroud)

Nim*_*Nim 4

看来你想使用std::function,我会说:

class Base
{
  public:
    struct EventContext
    {
      int data1;
    };
    Base() {}
    virtual int ProcessEvent(std::string event, EventContext ctx) =0;

  protected:
    typedef std::function<int(const EventContext&)> HandlerType;
    typedef std::map<std::string, HandlerType> EventDelegateMap;
    EventDelegateMap _delegates;
};

class Derived: Base
{
  public:
    Derived();
    int ProcessEvent(std::string event, EventContext ctx){ return 0; }

  private:
    int FooEventHandler(const EventContext& context){ return 0; }
    int BarEventHandler(const EventContext& context){ return 0; }
    int QuxEventHandler(const EventContext& context){ return 0; }
};

Derived::Derived() :Base()
{
    auto self = this; // Some gcc versions cannot capture this correctly.
    _delegates["foo"] = [=](const EventContext& context) { return self->FooEventHandler(context); };
    _delegates["bar"] = [=](const EventContext& context) { return self->BarEventHandler(context); };
    _delegates["qux"] = [=](const EventContext& context) { return self->QuxEventHandler(context); };
}
Run Code Online (Sandbox Code Playgroud)

应该工作...

编辑:正如@Joachim 在他的评论中提到的,您也可以用来std::bind()生成所需的std::function对象,例如

_delegates["foo"] = std::bind(&Derived::FooEventHandler, this, std::placeholders::_1);
Run Code Online (Sandbox Code Playgroud)

我使用 lambda 来表明,实际上,您可以在 lambda 中实现整个逻辑。这种方法的主要优点是,如果您要实现更多的处理程序,那么工作量就会减少,而且我总是赞成减少工作量......:)