いくつかのサブクラスを持つ C++ の抽象クラスがあります。
どういうわけか、マクロまたはテンプレートのメタプログラミングによって、そのようなことを行うことができますか:
foreach subclass of Base:
mymap[subclass::SOME_CONSTANT] = new subclass();
いくつかのサブクラスを持つ C++ の抽象クラスがあります。
どういうわけか、マクロまたはテンプレートのメタプログラミングによって、そのようなことを行うことができますか:
foreach subclass of Base:
mymap[subclass::SOME_CONSTANT] = new subclass();
いいえ、あなたがすることはできません。
どうやら、あなたが望むのはFactory
(またはおそらくAbstract Factory
) です。
C++ では、Factory クラスをセットアップし、ビルダーを登録します。
class FooFactory
{
public:
typedef std::function<Foo*()> Builder;
/// returns true if the registration succeeded, false otherwise
bool Register(std::string const& key, Builder const& builder) {
return map.insert(std::make_pair(key, builder)).second;
}
/// returns a pointer to a new instance of Foo (or a derived class)
/// if the key was found, 0 otherwise
Foo* Build(std::string const& key) const {
auto it = _map.find(key);
if (it == _map.end()) { return 0; } // no such key
return (it->second)();
}
private:
std::map<std::string, Builder> _map;
};
このファクトリのシングルトンを作成して、ライブラリのロード中に派生クラスを登録できます。これは、プラグインのようなアーキテクチャに便利です。
FooFactory& GetFooFactory() { static FooFactory F; return F; }
また、便利なビルダーを準備できます。
template <typename Derived>
Foo* fooBuilder() { return new Derived(); }
次に、派生クラスをファクトリに登録することが期待されます。
static const bool registeredBar =
GetFooFactory().Register("Bar", fooBuilder<Bar>);
注: ファクトリがシングルトンであることは必須ではありませんが、ライブラリのロードが終了すると一定であるため、ここではそれほど悪くはありません。
注: 適切なプラグイン アーキテクチャでは、ライブラリのアンロード時に登録解除を処理するために、(bool の代わりに) RAII を使用する必要があります。しかし、それははるかにまれです。
C++ では、型の反復処理は許可されていません。また、列挙メンバーの列挙はできません。これを参照してください:
enum Color
{
red,
green,
blue=5,
yellow
};
さらに、C++ コンパイラはコンパイル ユニットを独立してコンパイルします。基本クラスの実装をコンパイルするときに、クラスが継承される場合があることを認識できないことがイメージできます。