次のようなファクトリ クラスの実装に使用するのが好きなパターンがあります (この質問に対する私の回答から抜粋)。
class Factory
{
public:
template<class DerivedType>
DerivedType::CreatedType *createType()
{
DerivedType::CreatedType *r = (DerivedType::CreatedType) (*(m_creators[DerivedType::id]))();
return r;
}
protected:
static std::map<int,void *(*)()> m_creators;
};
std::map<int,void *(*)()> Factory::m_creators = std::map<int,void*(*)()>();
template<class Derived, class CreatedType>
class CRTPFactory : public Factory
{
typedef typename CreatedType CreatedType;
public:
static bool register()
{
Factory::m_creators.push_back(std::make_pair(Derived::id,Derived::create);
return true;
}
private:
static bool m_temp;
};
template<class Derived>
bool CRTPFactory<Derived>::m_temp = CRTPFactory<Derived>::register();
class AFactory : public CRTPFactory<AFactory,A>
{
private:
static A *create()
{
//do all initialization stuff here
return new A;
}
public:
static const int id = 0;
};
これにより、ファクトリ クラスを変更することなく、新しい型のファクトリを拡張できます。また、ファクトリ クラスを変更せずに、さまざまな型の特定の作成アルゴリズムを実装することもできます。ただし、このパターンには大きな問題があります。クラス AFactory が明示的に使用されることはありません。CRTPFactory のメンバー temp を使用して、ロード時に作成者関数を登録します。これを理解するのは少し複雑かもしれませんが、使い方はとても簡単です。問題は、AFactory がコンパイルされていないため、読み込み時に静的パラメーターが初期化されないことです。私の質問は、明示的にインスタンスを作成せずにコンパイラ (私は VS 2012 を使用していますが、GCC の回答も良い) を強制的にコンパイルすることは可能ですか? 私が VS で使用する解決策は、AFactory を dllexport することです。そうすれば、コンパイラはクラスをインスタンス化していることを知らなくても、クラスをコンパイルします。これは、他の dll がそれをインスタンス化する可能性があると想定しているためです。このソリューションの問題点は、ファクトリ クラスを残りのコードとは別の dll に実装する必要があることです。また、これは GCC では機能しません。