C++ 在C+中处理层次结构中成员函数的指针+;

C++ 在C+中处理层次结构中成员函数的指针+;,c++,inheritance,member-function-pointers,C++,Inheritance,Member Function Pointers,我试图对以下情况进行编码: 我有一个基类,它提供了一个处理事件的框架。我试图使用一个指向成员函数的指针数组来实现这一点。具体如下: class EH { // EventHandler virtual void something(); // just to make sure we get RTTI public: typedef void (EH::*func_t)(); protected: func_t funcs_d[10]; protected: void regi

我试图对以下情况进行编码: 我有一个基类,它提供了一个处理事件的框架。我试图使用一个指向成员函数的指针数组来实现这一点。具体如下:

class EH { // EventHandler
   virtual void something(); // just to make sure we get RTTI
public:
  typedef void (EH::*func_t)();
protected:
  func_t funcs_d[10];
protected:
  void register_handler(int event_num, func_t f) {
    funcs_d[event_num] = f;
  }
public:
  void handle_event(int event_num) {
    (this->*(funcs_d[event_num]))();
  }
};
然后,用户应该从这个类派生其他类,并提供处理程序:

class DEH : public EH {
public:
  typedef void (DEH::*func_t)();
  void handle_event_5();
  DEH() {
     func_t f5 = &DEH::handle_event_5;
     register_handler(5, f5); // doesn't compile
     ........
  }
};
此代码无法编译,因为DEH::func\u t无法转换为EH::func\u t。这对我来说很有意义。在我的例子中,转换是安全的,因为
下的对象实际上是DEH。所以我想要这样的东西:

void EH::DEH_handle_event_5_wrapper() {
  DEH *p = dynamic_cast<DEH *>(this);
  assert(p != NULL);
  p->handle_event_5();
}
在DEH::DEH()中 放

所以,最后一个问题(花了我足够长的时间…): 有没有一种方法可以自动创建这些包装(比如
EH::DEH\u handle\u event\u 5\u包装
)呢? 或者做类似的事情? 对于这种情况还有什么其他的解决方案


谢谢。

你真的不应该这样做。检查boost::bind

精化

首先,我敦促你重新考虑你的设计。我见过的大多数事件处理程序系统都涉及一个外部注册器对象,它维护事件到处理程序对象的映射。您在EventHandler类中嵌入了注册,并且正在基于函数指针进行映射,这是不太理想的。您遇到了问题,因为您正在围绕内置虚拟函数行为进行结束运行

boost::bind
等的要点是使用函数指针创建对象,从而允许您利用面向对象的语言特性。因此,以您的设计为起点,基于
boost::bind
的实现将如下所示:

struct EventCallback
{
    virtual ~EventCallback() { }
    virtual void handleEvent() = 0;
};

template <class FuncObj>
struct EventCallbackFuncObj : public IEventCallback
{
    EventCallbackT(FuncObj funcObj) :
        m_funcObj(funcObj) { }
    virtual ~EventCallbackT() { }

    virtual void handleEvent()
    {
        m_funcObj();
    }

    private:
        FuncObj m_funcObj;
};
  void register_handler(int event_num, EventCallback* pCallback) 
  {
      m_callbacks[event_num] = pCallback;
  }
您的注册电话如下所示:

register_handler(event, 
    new EventCallbackFuncObj(boost::bind(&DEH::DEH_handle_event_5_wrapper, this)));

现在,您可以从任何类型的(对象、成员函数)创建回调对象,并将其保存为给定事件的事件处理程序,而无需编写自定义函数包装器对象。

为什么不使用虚拟函数?差不多

class EH {
public:
  void handle_event(int event_num) {

    // Do any pre-processing...

    // Invoke subclass hook
    subclass_handle_event( event_num );

    // Do any post-processing...
  }
private:
  virtual void subclass_handle_event( int event_num ) {}
};

class DEH : public EH {
public:
  DEH() { }
private:
  virtual void subclass_handle_event( int event_num ) {
     if ( event_num == 5 ) {
        // ...
     }
  }
};

您可以简单地使用
static\u cast
DEH::func\u t
转换为
EH::func\u t
,而不是为所有派生类中的每个处理程序创建一个包装器(当然,这远不是一种可行的方法)。成员指针是反变的:它们自然地向下转换层次结构,并且可以使用
static\u cast
手动向上转换层次结构(与普通对象指针相反,它们是协变的)

您正在处理的情况正是扩展
静态\u cast
功能以允许成员指针向上转换的原因。此外,成员函数指针的非平凡内部结构也以这种方式实现,以正确处理此类情况

所以,你可以简单地做

DEH() {
   func_t f5 = &DEH::handle_event_5;
   register_handler(5, static_cast<EH::func_t>(f5));
   ........
}
为了使它看起来更优雅,您可以在
DEH
中为
register\u handler
提供包装,或者使用其他方法(宏?模板?)隐藏强制转换


此方法不提供在调用时验证处理程序指针有效性的任何方法(在基于包装器的版本中,可以使用
dynamic\u cast
)。我不知道你有多在乎这张支票。我想说的是,在这种情况下,这实际上是不必要和过度的。

请您详细说明一下好吗?我有一种感觉,应该有一种方法可以把所有的装订材料都做得更好,但是我想不出来,这是可能的。然而,我想让DEH的实现对用户来说尽可能简单——在所有事件中,“如果”都会非常难看。@anatoli:那么你认为创建派生类的用户会发现指向成员的指针比“如果”或“开关”构造更简单吗?很抱歉,我从网上掉下来了——帐户有问题。我同意你的看法,指向议员的指示是非常恶劣的。然而,我认为,在这种情况下,这些东西大部分是在引擎盖下。用户注册处理程序的方法非常简单,并且遵循一个非常简单的模板。同样,与if/switch解决方案相反,在这种情况下,基类可以做更多的检查——例如,所有事件都有处理程序等等。它解决了这个问题。我知道强制转换是可能的,但根据标准,它有一个未定义的行为。@anatoli:不,行为是定义的,假设调用是有效的。同样,调用的有效性在调用时确定,也就是说,如果对象具有正确的类型并且指针指向正确的方法,那么一切都正常。标准中就是这样定义的。
class EH {
public:
  void handle_event(int event_num) {

    // Do any pre-processing...

    // Invoke subclass hook
    subclass_handle_event( event_num );

    // Do any post-processing...
  }
private:
  virtual void subclass_handle_event( int event_num ) {}
};

class DEH : public EH {
public:
  DEH() { }
private:
  virtual void subclass_handle_event( int event_num ) {
     if ( event_num == 5 ) {
        // ...
     }
  }
};
DEH() {
   func_t f5 = &DEH::handle_event_5;
   register_handler(5, static_cast<EH::func_t>(f5));
   ........
}
DEH() {
   func_t f5 = static_cast<func_t>(&DEH::handle_event_5); 
   // ... where `func_t` is the inherited `EH::func_t`
   register_handler(5, f5);
   ........
}