2

GUIウィンドウのコールバッククラスを作成しようとしています。(うまくいけば)それを達成するために、私はデリゲートを使用しています。

typedef srutil::delegate2<void,DWORD,DWORD> CallbackMethod;
typedef std::map<MESSAGE_TYPE,std::vector<CallbackMethod>> CallbackMap;

MESSAGE_TYPEは列挙型です。

私が必要としているのは、クラスデストラクタの変更に依存しない、ある種の永続的/一定のインデックスを介して、オブジェクトが破棄されたときにマップからオブジェクトの登録を自動的に解除する何らかの方法です。

つまり、特定の署名に一致するようにコールバックを指定するため、私の計画はゼロから欠陥がある可能性があります(これらの高度なものではまだハーフブラインドでコーディングしています)。したがって、本質的に、この機能を使用するクラスにはいくつかが必要です。それに一致するメソッド、したがって、すでにそれらのルール(クラスに結合されている)に従うことを強制されています。

だから私はそれらの中に地図への参照を置くかもしれません。ただし、それだけでも、マップ内のすべてのエントリを繰り返し処理し、破棄されるオブジェクトに一致するエントリを削除する必要があります。

ですから、私が必要としているのは、ある種の自己認識定数参照ポインターインデックスのものだと思います。

そのようなものは存在しますか?それは一般的な問題であるはずだと私には感じます...

4

1 に答える 1

2

頭のてっぺんから推測します...いいえ、存在しません(少なくとも、C ++の場合はそうではありません)。

あなたの提案は複雑な状況を暗示しています(コールバックを使用していなかったとしても)。あなたは、それ自体が破壊されると、それを参照するデータ構造から(潜在的に)それ自体の参照を削除する処理を行う何かを求めています。これはかなり難しい注文であり、特にSTLが意図したことではありません。


あなたが本当にこれをしたいのなら(そして私はあなたがそうすると確信しています)、それからここに私の最初の考えがあります。オブジェクトがデータ構造に追加されるたびに、たとえば。のようなメソッドを使用して、データ構造がオブジェクトに登録されていることを要求できますObject::Register(const std::vector<Object> &v)。次に、への参照(実際には、おそらくポインタをキャプチャします)を保存できるので、破棄時にオブジェクトを削除するvectorように指示できます。vectorもちろん、これには2つの問題があります。

  1. それはまだ非常に複雑です(特に、単なるベクトルよりも多くの構造をサポートしたい場合、そして完全に一般的なソリューションを探している場合はさらにそうです)。
  2. オブジェクトが構造に追加されるすべての場所で、他のコーダーがこのスタイルに従う必要があります
  3. おそらく、のデストラクタを編集する必要がObjectありますが、これは行うべきではないと明示的に指示しました。

だから、ええ、そこではあまり助けにはなりません。


個人的には、イベント(具体的には、c#で使用するようなデリゲートベースのイベント)を中心に展開する、はるかに好ましいソリューションがあります。これらがどのように機能するかをよく知らない場合は、このプログラミングガイドをお読みください。繰り返しになりますが、c#ではなくc ++を使用しているため、また、ほとんど自分で説明するため、そうではないかもしれません。

イベントのアイデアが気に入った理由の1つは、すでにコールバックを使用していることです。デリゲート(c#デリゲートのように)は、コールバックの単なる拡張です。vector<Callback>これらは基本的に、動作をDelegateクラスにカプセル化します。このDelegateクラスでは、関数呼び出し演算子をオーバーロードすると、これらすべてのメソッドを1回の操作で呼び出すことができます。また、delegateすでに使用しているように、パラメータ化されたタイプである可能性があります。(実際、C++0xすぐに使えるようになると、可変個引数テンプレートも非常に役立ちます)。

Delegateとにかく、このすべてのポイントは、任意のクラスのメンバー変数などを持つことができるということです。

class Object
{
    public:
    ... // whatever constructors, etc. you might need
    Delegate<void, Collection, EventArgs> destroyHandler;
    ... // and number of event handlers can be used.
};

これで、どのデータ構造クラスでも、次のような方法でコールバックを登録できます。

obj.destroyHandler += myDelegate;

ここmyDelegateで、必要なタイプの関数はどこにありますか。

ただし、このアプローチにはさらに多くの問題があります。具体的には、イベントモデルを認識するデータ構造で満たされたまったく新しいライブラリが必要です。既存のSTLコンテナは単純にラップできるため、これはそれほど難しいことではありません。それは大変な作業であり、誰もがあなたの新しいライブラリを使用することを決定しなければならないでしょう。

別の落とし穴が行にありDelegate<void, Collection, EventArgs> destroyHandler;ます。これらのタイプパラメータのそれぞれはどういう意味ですか?まあ、voidかなり明確にする必要があります:それはメソッドの単なるreturnタイプです。また、EventArgs単純です。コールバックに渡す必要のあるデータをラップするだけです。タイプは最もCollection奇妙です-使用されるタイプコレクションをパラメータ化するのはなぜですか?

これは、C++でメンバー関数へのポインターを使用する際の厄介な問題を回避するためです。このようなポインターは可能ですが、使用するのはひどいものであり、(私が知る限り)複数の型からメンバー関数へのポインターを取得して単一のコレクションに格納する方法はありません。

代わりに、私が過去に試したことは(私は実際にはアイデアを完成させていませんでしたが)次のようなものでした

class MyVector
{

    static void DestructionHandler( MyVector & v, EventArgs & args )
    {
        // ... Handler code goes here
    }

};

注意すべきことはパラメータMyVector & vです:それは通常のthisポインタを置き換えます。また、メソッドは次のとおりであることに注意してください。staticこれにより、通常の古いCスタイルの関数ポインターとして使用できるようになります。

とにかく、私は少し夢中になっているかもしれませんが、これらすべてをまとめると、他のOOP言語で非常に人気のあるかなりまともなイベントベースのシステムを手に入れることができます。それに、大変な注文だったと言いました!

于 2011-06-20T02:57:55.577 に答える