2

C++ で小さな、限定されたスコープのクロスプラットフォーム UI ライブラリを作成しました。次のクラスを使用して UI コールバックを処理します。

// Base class for templated __Callback class to allow for passing __Callback
// objects as parameters, storing in containers, etc. (as Callback*)
class Callback
{
    public:
        virtual void execute() = 0;
        virtual ~Callback() { }

    protected:
        Callback() { }
};

コメントで説明されているように、これはコールバックの基本クラスです。これにより、コールバックを引数として渡し、適切なコールバックを実行できるように UI ウィジェット内に格納できます (たとえば、ユーザーがボタンをクリックしたとき)。

// C++ has no callbacks (in the sense of an action [method] of a
// target [object]), so we had to roll our own. This class can be used
// directly, but the NEW_CALLBACK macro is easier.
template <class __TargetType>
class __Callback : public Callback
{
    public:
        typedef __TargetType TargetType;
        typedef void (TargetType::*ActionType)(void);

        virtual void execute()
        {
            (this->__target->*this->__action)();
        }

        __Callback(TargetType* target_, ActionType action_) :
        Callback(), __target(target_), __action(action_) { }

        virtual ~__Callback() { }

    private:
        // target object for the callback
        TargetType* __target;

        // action (method) of the target that will be called
        ActionType __action;
};

このテンプレート化されたクラスは、コールバック パラダイムの要です。オブジェクトへのポインターとメンバー関数へのポインターを格納し、後でターゲット オブジェクトでメンバー関数を呼び出すことができるようにします。

#define NEW_CALLBACK(class_, obj_, act_) \
    new __Callback<class_>(obj_, &class_::act_)

このマクロは、テンプレート化されたオブジェクトの作成を少し簡単にし__Callbackます。

これは長い間うまく機能しています!コールバックを持つボタンは、次のようにインスタンス化できます。

MyClass* obj = new MyClass();
Button* btn = new Button("Title", NEW_CALLBACK(MyClass, obj, btnClicked));

これにより、後でウィンドウまたは他のコンテナーに配置されるボタンが作成され、クリックすると が呼び出されますobj->btnClicked()

さて、私の質問です(長いセットアップで申し訳ありません。これ以上削減できるとは思いません)。Callback*オブジェクトをコピーする必要があるケースが発生しました。もちろん、基本クラスへのポインタなので、テンプレート化された派生クラスの型を特定することはできません。

Callbackコピーが元のオブジェクトと同じターゲットとアクションを指している状態で、任意のオブジェクトをコピーするにはどうすればよいでしょうか? または、このコールバックの問題に対して、私が取るべきまったく異なるアプローチがありますか (あまり変更したくないのですが)?

皆さんありがとう!

4

2 に答える 2

3

より良いアプローチがあるかどうかはわかりませんが、これは clone メソッドの理想的な使い方のようです。

__Callback テンプレートでコピー コンストラクターを定義し、基本クラスで純粋な仮想 Clone メソッドを定義してから、テンプレートでその仮想メソッドを実装するだけです (作成したコピー コンストラクターを使用します)。

例えば:

class Callback
{
    public:
    ...
    virtual Callback* Clone()=0;
};

template <class __TargetType>
class __Callback : public Callback
{
public:
    ...
    __Callback(const __Callback& other) :
        __target(other.target_), __action(other.action_) { }

    virtual Callback* Clone()
    {
        return new __Callback(this);
    }
}
于 2012-05-12T00:34:47.860 に答える
1

仮想コンストラクターの代わりにcloneを使用します。これを実際に機能させる共変の戻り値の型に注意してください。例えば

struct Callback {
  virtual Callback* clone() const;
};

template<...>
struct Callback_impl {
  virtual Callback_impl* clone() const;
};

shared_ptrまた、生涯管理についても考えておく必要があります。これはすべて少し壊れやすいようです。

私には、std::functionが必要なようです。ポリモーフィックでタイプ セーフであり、 を介してメンバ関数へのポインタを操作しstd::mem_fnます。

于 2012-05-12T00:33:43.210 に答える