2

一些代码

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 的子类!那么,有没有办法进行自动转换并使用精确的“事件参数”注册我的方法?

4

3 回答 3

1

您收到错误是因为它实际上被语言禁止。如果可能的话,这将在类型系统中打开一个漏洞。考虑这段代码:

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

幸运的是,编译器捕捉到了这个错误。

于 2010-12-10T10:47:10.187 回答
1

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);
    }
};
于 2010-12-10T11:37:19.290 回答
0

不,没有自动投射。类型必须一致。AddHandler您可以通过两种不同的方式将签名更改为:

  1. 将其设置为接受 avoid*然后强制转换为指向函数类型的确切指针。
  2. 将 转换AddHandler为接受类型的模板,T以便可以使用正确的参数调用它t(sender, args,...),其中第二个参数是实参。但是,调用必须首先将 转换args为正确的类型(例如,如果是鼠标事件,则MouseEventArgs在调用t.
于 2010-12-10T11:11:12.240 回答