方法处理程序的隐式转换?

时间:2010-12-10 10:37:25

标签: c++ methods casting handlers

部分代码

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 个答案:

答案 0 :(得分: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

幸运的是编译器捕获了这个错误。

答案 1 :(得分: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);
    }
};

答案 2 :(得分:0)

不,没有自动演员。类型必须重合。您可以通过两种不同的方式将签名更改为AddHandler

  1. 将其设置为接受void*,然后强制转换为功能类型的确切指针。
  2. AddHandler转换为接受类型T的模板,以便可以使用正确的参数t(sender, args,...)调用它,其中第二个参数是参数。但是,调用必须首先将args转换为正确的类型(例如,如果是鼠标事件,请在调用MouseEventArgs之前手动将其转换为t