Неявное приведение для обработчика метода? - PullRequest
2 голосов
/ 10 декабря 2010

Какой-то код

typedef void (*EventHandler) (EventObject* sender, EventArgs* args, void* closure);

class Control
{
void AddHandler(int eventId, EventHandler handler, void* data)
}

class SubControl
{
static void mousemove_cb(EventObject* sender, MouseEventArgs* calldata, void* closure);
}

Ошибка

error C2664: 'Control::AddHandler' : cannot convert parameter 2 from 'void (__cdecl *)(EventObject *,MouseEventArgs *,void *)' to 'EventHandler'

Вот строка, которая выдает ошибку:

control.AddHandler(MouseMoveEvent, mousemove_cb, 0);

Описание

Проблема в том, что MouseEventArgs является подклассом EventArgs!Итак, есть ли способ выполнить автоматическое приведение и зарегистрировать мой метод с точными «Аргументами события»?

Ответы [ 3 ]

1 голос
/ 10 декабря 2010

C ++ шаблон может решить эту проблему. Используйте это:

struct Control
{
    //Note this change!
    template<typename TEventHandler>
    void AddHandler(int eventId, TEventHandler handler, void* data);
};

struct SubControl
{
    static void mousemove_cb(EventObject* sender, MouseEventArgs* calldata, void* closure);
    SubControl()
    {
        Control control;
        control.AddHandler(0, mousemove_cb, 0);
    }
};
1 голос
/ 10 декабря 2010

Вы получаете ошибку, потому что это фактически запрещено языком.Если бы это было возможно, это открыло бы дыру в системе типов.Рассмотрим этот код:

struct EventArgs {};

void f(EventHandler handler)
{
    EventArgs args;
    handler(0, &args, 0);
}

struct MouseEventArgs : EventArgs { void GetMousePosition(); };

void g(EventObject* sender, MouseEventArgs* args, void* closure)
{
    args->GetMousePosition(); 
}

f(g); // oops... g calls GetMousePosition on EventArgs

К счастью, компилятор ловит эту ошибку.

0 голосов
/ 10 декабря 2010

Нет, автоматического приведения нет.Типы должны совпадать.Вы можете изменить подпись на AddHandler двумя различными способами:

  1. Установите ее для принятия void* и затем принудительно преобразуйте указатель на тип функции.
  2. Преобразуйте AddHandler в шаблон, который принимает тип T, чтобы его можно было вызывать с правильными параметрами t(sender, args,...), где второй параметр - это аргументы.Однако вызов должен сначала преобразовать args в правильный тип (например, если это событие мыши, перед вызовом t.
преобразуйте его в MouseEventArgs вручную.
...