部分代码
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的子类!那么,有没有办法进行自动投射并使用精确的“事件参数”注册我的方法?
答案 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
:
void*
,然后强制转换为功能类型的确切指针。AddHandler
转换为接受类型T
的模板,以便可以使用正确的参数t(sender, args,...)
调用它,其中第二个参数是参数。但是,调用必须首先将args
转换为正确的类型(例如,如果是鼠标事件,请在调用MouseEventArgs
之前手动将其转换为t
。