【发布时间】:2013-07-04 09:16:47
【问题描述】:
我喜欢使用一种模式来实现工厂类,如下所示(摘自我对this 问题的回答):
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 的答案也很好)编译 AFactory 而无需显式创建它的实例? 我在 VS 中使用的一个解决方案是 dllexport AFactory,这样编译器就会编译该类,即使它不知道有人实例化它。这是因为它假定其他一些 dll 可能会实例化它。这个解决方案的问题是工厂类必须像其他代码一样在单独的 dll 中实现。而且这在 GCC 上也不起作用。
【问题讨论】:
-
对不起,我重命名了很多变量,所以在这里看起来不错。我忘了那个。
-
这种技术还有一个问题,那就是它要求
CRTPFactory的所有特化在同一个翻译单元(又名 cpp 文件)中实例化,以保证它们在Factory::m_creators的初始化。我建议使用不依赖于静态成员构造函数的执行顺序的技术。
标签: c++ templates design-patterns compiler-construction