成员函数指针,其基类参数接受派生类参数

时间:2010-02-06 17:29:20

标签: c++ events generics member-function-pointers

所以我正在研究这个活动管理课程。我正在存储一个指向签名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;
};

我想知道,如果我可以派生出不同版本的Event,并将指向这些成员函数的指针传递给这个类?目前我正在尝试这个。

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*&)

你知道我怎么能安全地传入一个指向期望在其函数签名中派生类的指针吗?感谢。

2 个答案:

答案 0 :(得分:2)

所以我找到了一个似乎对我有用的解决方案,但我不确定它是否完全安全。我更改了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));
   }

现在它似乎只是像我原先的意图一样工作。但我对这一切都很陌生,所以我不完全确定这是否安全。有什么想法吗?感谢

答案 1 :(得分:1)

如果您的原型需要“事件”类型,那么您需要确保void Display(MouseEvent* evt)函数接受“Event”类型。因此,将其更改为void Display(Event *evt)然后在调用内部,您可以将其类型转换回MouseEvent,假设调用方传递了实际MouseEvent,引用为“Event”。

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