带有接受派生类参数的基类参数的成员函数指针

Posted

技术标签:

【中文标题】带有接受派生类参数的基类参数的成员函数指针【英文标题】:Member Function Pointer with base class argument accepting derived class argument 【发布时间】:2010-02-06 17:29:20 【问题描述】:

所以我正在学习这个事件管理课程。我正在存储一个指向签名 void (Event*) 的成员函数的指针列表,其中 Event 只是一个当前存储一些随机数据的结构。

typedef boost::function<void(Event*)> Callback;
typedef vector<Callback> CallbackList;

class EventManager

public:
   template<typename T>
   void RegisterEventHandler(const std::string& type, void (T::*handler)(Event*), T* obj)
   
      mCallbackList[type].push_back(boost::bind(handler, obj, _1));
   

   void DispatchEvent(const std::string& type, Event* evt)
   
      for(CallbackList::iterator it = mCallbackList[type].begin(); it != mCallbackList[type].end(); ++it)
      
         Callback callback = (*it);
         callback(evt);
         
   
private:
   hash_map<std::string, CallbackList> mCallbackList;
;

我想知道,我是否有可能派生不同版本的事件,并将指向这些成员函数的指针传递给这个类?目前我正在尝试这个。

class MouseEvent : public Event

public:
   int testMouseData1;
   int testMouseData2;
   int testMouseData3;
;

class HelloWorld 

public:
   void Display(MouseEvent* evt)
   
      cout << "Hello, world!" << endl;
   
;


int main(void)

   MouseEvent* evt = new MouseEvent();

   HelloWorld* world = new HelloWorld();
   eventManager->RegisterEventHandler("testType", &HelloWorld::Display, world);

   return 0;

这给了我 XCode 中的以下错误。

错误:没有匹配函数调用'EventManager::RegisterEventHandler(const char [9], void (HelloWorld::*)(MouseEvent*), HelloWorld*&amp;)'

你知道我怎样才能安全地传递一个指针,该指针在其函数签名中期望派生类吗?谢谢。

【问题讨论】:

【参考方案1】:

所以我找到了一个似乎对我有用的解决方案,但我不确定这样做是否完全安全。我更改了 RegisterEventHandler 方法以将我发送的所有函数指针转换为相同的类型...

 template<typename T1, typename T2>
   void RegisterEventHandler(const String& type, T1 handler, T2* obj)
   
      void (T2::*evtHandler)(Event*) = (void (T2::*)(Event*)) (handler);
      mCallbackList[type].push_back(boost::bind(evtHandler, obj, _1));
   

现在这一切似乎都按我最初的预期工作了。但我对这一切都很陌生,所以我不完全确定这是否安全。有什么想法吗?谢谢

【讨论】:

【参考方案2】:

如果您的原型需要“事件”类型,那么您需要确保void Display(MouseEvent* evt) 函数接受“Event”类型。所以把它改成void Display(Event *evt) 然后在调用中你可以将它类型转换回MouseEvent,假设调用者传递了一个实际的MouseEvent,引用为“Event”。

其次,我相信您调用RegisterEventHandler 的方式可能还有其他问题,因为它在模板中,但您没有指定模板类型。

【讨论】:

@Harley - 模板函数具有类型推断,所以我会说他调用 RegisterEventHandler 的方式是可以的 函数模板参数可以从函数参数中推断出来,但是显式指定模板类型将有助于操作确定实例化失败的原因 同意,只是试图消除这里的所有变量。很确定@Morgan 需要在这里查看的要点是“事件”类型与“鼠标事件”。

以上是关于带有接受派生类参数的基类参数的成员函数指针的主要内容,如果未能解决你的问题,请参考以下文章

无法从派生类构造函数参数访问受保护的基类成员[重复]

为啥我可以通过指向派生对象的基类指针访问派生私有成员函数?

虚函数的调用

C++虚函数

c++ virtual总结

朋友类对象可以在其成员函数中访问派生类对象上的基类私有成员吗?