-
19-08-2019 - |
質問
typedef void (FunctionSet::* Function)();
class MyFunctionSet : public FunctionSet
{
protected:
void addFunctions()
{
addFunction(Function(&MyFunctionSet::function1));
}
void function1()
{
// Do something.
}
};
のaddFunction方法の追加の機能リストの基底クラス
できる列挙への通話に。
その簡素化(タイピング)の追加の機能は?
解決
のように見えますが割り当てのメンバー関数へのポインタ機能の派生クラスへの会員機能を指すポインタ機能の基底クラスです。でも、それを禁ず開けていますので、穴のあいさつに行くだけ。で驚きの少なくとも私にとって初めてと聞いています。読む この答え のためにいかがでしょうか。
お答えし実際の質問のよう addFunction
テンプレート:
void addFunctions() {
addFunction(&MyFunctionSet::function1);
}
変化 addFunction
基底クラスのす:
template<typename Derived>
void addFunction(void(Derived::*f)()) {
myFunctions.push_back(static_cast<Function>(f));
}
より良い活用 static_cast
, でいる場合 Derived
なんら FunctionSet
.
他のヒント
これを行うことで達成しようとしていることを説明できますか?
これはかなり悪いデザインのようです。<!> quot; Computable <!> quot;のような抽象クラス(<!> quot; c ++ interface <!> quot;)を使用することはできません。純粋な仮想function1、各実装のサブクラスComputableを持ち、MyFunctionSetにComputableのセットを保持させますか?
関数ポインタを使用している特定の理由はありますか?
だから、私はウリに多少反対する傾向があります。
Observerパターンを実装している場合は、次のように言うことができます。
<!> quot;オブジェクトXがYを実行するとき、コードZ <!> quot;を実行したい。
純粋に抽象クラスに基づいたアプローチを採用することは、そのための最良の方法ではありません。すべてのイベントハンドラーに個別のクラス(特にC ++)を要求するのはやり過ぎです。 Javaから来た場合、それがすべての方法です。ただし、Javaには2つの機能がありますが、これらはわずかに迷惑です。匿名クラスと<!> quot; instance <!> quot;メンバークラス。これにより、同じクラスの複数のイベントに対して複数のハンドラーを定義できます。メソッドの前に<!> quot; class {<!> quot;を付ける必要がありますが、できます。
C ++には匿名クラスも<!> quot; instance <!> quotもありません。メンバークラス。これにより、状態を共有する必要がある複数のハンドラーがある場合、イベントに抽象クラスを使用するのがはるかに面倒になります。クロージャーの生成と同等の操作を手動で行う必要があります。これにより、かなり迅速にイライラする可能性があります。
.NETはイベント処理にデリゲートを使用します。デリゲートは基本的にタイプセーフな関数ポインターです。イベントを処理するためのコードは非常に単純です。ただし、C ++の関数ポインターとは異なり、デリゲートはメンバー関数ポインターと静的関数ポインターを統合します。基本的に、<!> quot; this <!> quot;静的関数ポインターのように見える関数ポインターを残して、任意のメンバー関数のパラメーター。これは、イベントを処理するオブジェクトのタイプがイベント<!> quot; interface <!> quot;の一部ではないことを意味します。これにより、非常に柔軟になります。
<!> quot; this <!> quot;は、C ++メンバー関数ポインタを使用して直接実行することはできません。 typeは最終的に関数ポインター型の一部になるため、ハンドラーは現在のクラス内にのみ表示されるように制限されます。
C ++の最適なソリューションは、2つのハイブリッドです。必要なのは、次のような汎用インターフェイスです:
class EventHandler
{
public:
virtual void Handle() = 0;
};
そして、このようなメンバー関数の実装
template <class T>
class MemberFuncEventHandler : public EventHandler
{
public:
MemberFuncEventHandler(T * pThis, void (T::*pFunc)()) : m_pThis(pThis), m_pFunc(pFunc)
{
}
void Handle()
{
(m_pThis->*m_pFunc)();
}
private:
T* m_pThis;
void (T::*m_pFunc)();
};
template <class T>
EventHandler * Handler(T * pThis, void (T::*pFunc)())
{
return new MemberFuncEventHandler<T>(pThis, pFunc);
}
同様に、静的メソッドのハンドラクラスを定義することもできます。その後、次のようなことを行うことができます。
Handlers += Handler(obj, &(c1::foo));
Handlers += Handler(obj, &(c2::bar));
Handlers += Handler(blaa); // for static methods...
加算演算子をオーバーロードできると思います。
コールバックシステムなどを作成しようとしている場合は、Boost.Signalsライブラリをお勧めします。基本的に、関数を集約し、コマンドで関数グループを呼び出します(他の信号ライブラリと同様)が、素晴らしいBoost.BindおよびBoost.Functionで動作するようにも設計されています。
例:
using boost::function
using boost::bind
using boost::signal
void some_other_func();
Foo a;
Bar b;
signal<void()> sig;
sig.connect(bind(&Foo::foo,&a));
sig.connect(bind(&Bar::bar,&b));
sig.connect(some_other_func);
sig(); // calls -> a.foo(), b.bar(), some_other_func()
また、ブロッキング、高度な接続管理、その他の洗練された機能もサポートしています。