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次の2 つの方法で署名を に変更できます。

  1. aを受け入れるように設定してから、void*関数型への正確なポインターへの変換を強制します。
  2. AddHandlerを型を受け入れるテンプレートに変換しTて、正しいパラメーター で呼び出すことができるようにしますt(sender, args,...)。ここで、2 番目のパラメーターは引数です。ただし、この呼び出しでは、最初にargsを正しいタイプに変換する必要があります (たとえば、マウス イベントの場合は、 をMouseEventArgs呼び出す前に手動で変換しtます。
于 2010-12-10T11:11:12.240 に答える