型消去を使用する:
class BarBase {
virtual void invoke() = 0;
};
template<typename TypeName>
class Bar final : public BarBase {
void(TypeName::*action)();
TypeName* objPtr;
virtual void invoke() override { (objPtr->*action)(); }
};
class Foo {
std::vector<std::unique_ptr<BarBase>> myBars;
/* ... */
};
template <typename TypeName>
void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr)
{
auto bar = new Bar<TypeName>();
bar->action = action;
bar->objPtr = objPtr;
myBars.emplace_back(bar);
};
次に、単に電話しますmyBars[x]->invoke();
コメントで質問に答えるため。
どうしたのoverride
?基本クラスから仮想関数をオーバーライドすると明示的に言います。これはここでは実際には必要ありませんが、良い習慣と考えられています。詳細については、ウィキペディアの記事を参照してください。
C ++ 11の新機能であり、一部のコンパイラはこの機能を長い間何らかの形でサポートしていましたが、現在は標準化されています。GCCはバージョン4.7からこの機能をサポートする必要があります-コマンドラインパラメータを使用する必要があります-std=c++0x
。
どうしたのunique_ptr
?それは人生を楽にします。を割り当てるときnew Bar<XXX>()
は、ある時点でdelete
そのメモリを解放するように指示する必要があります。のようなリソース管理オブジェクトにポインタを置くと、unique_ptr
それを削除することを心配する必要がなくなります。すると、次のようなことをvector<BarBase*>
行うデストラクタを宣言する必要があります。Foo
for each element in myBars
delete element
を使用する場合はvector<unique_ptr<BarBase>>
、何も削除する必要はありません。が寿命のvector
終わりに破壊されると、その要素が破壊され、自身のデストラクタに含まれているメモリが削除されます。Foo
unique_ptr
これはC++11の機能でもあります-標準ライブラリへの追加です。使用する必要はありません(ただし、最後にすべてを削除してください)。
どうしたのauto
?同じ型を2回繰り返す代わりに(Bar<Type> * bar = new Bar<Type>();
)、1回使用するだけで、コンパイラーに初期化子の型に基づいて変数の正しい型を推測させます。動作はまったく同じで、タイピングが少なく、見栄えも良くなります:)
また、C ++ 11機能、v4.4以降のGCCでサポートされています。
なぜmyBars[x]->invoke()
正しいことですか?invoke
で仮想として宣言されているためBarBase
。これは、実行されるメソッドが、静的タイプではなく、の動的タイプ(実行中の実際のタイプ)に基づいて選択されることを意味しmyBars[x]
ます。詳細な説明については、Wikiを参照してください。このメカニズムには実行時のオーバーヘッドがわずかにありますが、動的型を処理する場合は役に立ちません。