Указатель на функцию-член с аргументом базового класса, принимающим аргумент производного класса - PullRequest
2 голосов
/ 06 февраля 2010

Итак, я работаю над этим классом управления событиями. Я храню список указателей на функции-члены сигнатуры 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 ]

2 голосов
/ 06 февраля 2010

Итак, я нашел решение, которое, похоже, работает для меня, но я не уверен, что это совершенно безопасно. Я изменил метод 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 голос
/ 06 февраля 2010

Если ваш прототип ожидает тип «Событие», то вам необходимо убедиться, что функция void Display(MouseEvent* evt) принимает тип «Event». Так что измените его на void Display(Event *evt) Затем внутри вызова вы можете типизировать его обратно на MouseEvent, предполагая, что вызывающий абонент передал фактический MouseEvent, называемый "Event".

Во-вторых, я полагаю, что у вас могут быть другие проблемы с тем, как вы вызываете RegisterEventHandler, поскольку он находится в шаблоне, но вы не указываете тип шаблона.

...