我喜欢使用一种模式来实现工厂类,如下所示(取自我对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也不起作用。
答案 0 :(得分:3)
继承CRTPFactory<AFactory,A>
会导致类的隐式实例化,但不会导致其成员的定义。
[temp.inst]
类模板特化的隐式实例化会导致类成员函数,成员类,静态数据成员和成员模板的声明的隐式实例化,而不是定义或默认参数的实例化;
您可以简单地显式实例化CRTPFactory<AFactory,A>
成员,而不是继承自m_temp
。
template bool CRTPFactory<AFactory,A>::m_temp;
作为参考,这里是修改后的例子(以编译的形式):
#include <map>
class Factory
{
public:
template<class DerivedType, class CreatedType>
CreatedType *createType()
{
CreatedType *r = (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
{
public:
static bool register_()
{
Factory::m_creators.insert(std::make_pair(Derived::id,Derived::create));
return true;
}
static bool m_temp;
};
template<class Derived, class CreatedType>
bool CRTPFactory<Derived, CreatedType>::m_temp = CRTPFactory<Derived, CreatedType>::register_();
struct A
{
};
class AFactory
{
public:
static void *create()
{
//do all initialization stuff here
return new A;
}
public:
static const int id = 0;
};
template bool CRTPFactory<AFactory,A>::m_temp;
答案 1 :(得分:1)
应该在某处显式创建静态类成员。
在你选择的cpp文件中做这样的事情应该有效:
int AFactory::id = 0
答案 2 :(得分:1)
你的假设是错的。 class AFactory
肯定是编译的。可能有很多次,因为它在标题中。
您真正的问题可能是class AFactory
未已注册。为什么会这样?哪个陈述会导致它?每个语句最终都来自main()
或来自全局变量的初始值设定项。