传递 Inherited Class 的成员函子

Passing Inherited Class's Member Functor

我正在使用 C++ 编写游戏代码。我想将 Child 的成员函数绑定到委托中。

我想像这样使用简化代码的init_and_bind函数:

class Parent {
protected:
    Widget* widget;
};

class Child : public Parent {
public:
    void foo() {
        widget->init_and_bind(this, &Child::bar);
    }

    void bar() { /* do something */ }
};

我想在Widgetclass中实现init_and_bind,所以我实现了如下代码:

// pre-defined in engine
void Delegate::bind(Parent* object, void(Parent::* function)());

void Widget::init_and_bind(Parent* object, void(Parent::* function)()) {
    init();
    delegate->bind(object, function);
}

但它不起作用。因为init_and_bind的第二个参数只接受Parent的成员仿函数类型。所以我不能通过 Child 的成员仿函数。所以我尝试使用模板和 reinterpret_cast:

template<typename T>
void Widget::init_and_bind(Parent* object, void(T::* function)()) {
    init();
    delegate->bind(object, function); // error
    delegate->bind(object, reinterpret_cast<void(Parent::*)()>(function); // error
}

但这也行不通。因为无法将 Child 的函子转换为 Parent 的函子。

那么,init_and_bind 的第二个参数应该是什么类型?

虽然直接的解决方案是 static_cast,但我认为您不应该将 init_and_bind 变成模板。生成的代码几乎总是一样的。唯一的区别可能在于实际演员表的执行方式。

所以你会得到相当多的代码膨胀,这都是因为一个非常小的差异。我建议您封装这种差异。为此,将辅助类型添加到 Widget

class Widget {
  struct MemFunc {
    void(Parent::* function)();
    template<class T>
    MemFunc(void(T::* func)()) :
      function(static_cast<void(Parent::*)()>(func))
    {}
  };

  void init_and_bind(Parent* object, MemFunc mf) {
    init();
    delegate->bind(object, mf.function);
  }
};

这样,实际上只有非常小的需要模板化的代码片段被模板化了。最好的是,它在 调用方 上透明地发生。而且它可能甚至不会引起任何肿胀。因为您的原始非模板版本无论如何都需要调用者 static_cast