我试图从本网站的其他问题了解我的情况,但我还没有找到一个好的答案。我尝试了大多数我发现的建议,但仍然得到同样的错误。
我正在尝试基于单例和CRTP实现工厂。所以我有一个Singleton类,在Singleton.h中定义:
template<class T>
class Singleton
{
public:
static T &instance()
{
static T one;
return one;
}
Singleton(const Singleton &) = delete;
Singleton(Singleton &&) = delete;
Singleton &operator=(const Singleton &) = delete;
protected:
Singleton() = default;
};
我还有一个Factory类,在Factory.h中定义和实现。出于此问题的目的,工厂创建层次结构的对象,其基类是Object
。这些对象都有一个构造函数接受double
。
class Factory : public Singleton<Factory>
{
friend class Singleton<Factory>; // to access constructor
public:
using createFunction = Object *(*)(double);
void registerObject(const std::string &, createFunction);
Object *createObject(const std::string &, double) const;
private:
Factory() = default;
std::map<std::string, createFunction> theCreatorFunctions;
};
void Factory::registerObject(
const std::string &ObjectId,
createFunction creatorFunction)
{
theCreatorFunctions.insert(
std::pair<std::string, createFunction>(
ObjectId, creatorFunction));
}
Object *Factory::createObject(
const std::string &ObjectId, double a) const
{
auto it = theCreatorFunctions.find(ObjectId);
if (it == theCreatorFunctions.end())
{
std::cout << ObjectId << " is an unknown object."
<< std::endl;
return nullptr;
}
return (it->second)(a);
}
最后,我有一个“帮助器”类,它将新类型的对象注册到工厂中。每次创建新的继承对象时,比如ObjectDerived
,我添加(在.cpp文件中实现ObjectDerived
):
FactoryHelper<ObjectDerived> registerObjectDerived("ObjectDerived");
这将创建一个FactoryHelper<ObjectDerived>
类型的对象,其构造函数处理工厂中的注册。 FactoryHelper
中定义(并实施)FactoryHelper.h
:
template<class T>
class FactoryHelper
{
public:
FactoryHelper(const std::string &);
static Object *create(double);
};
template<class T>
FactoryHelper<T>::FactoryHelper(const std::string &ObjectId)
{
Factory &theFactory = Factory::instance(); // the one and only!
// if it doesn't exist at this point, it is created.
theFactory.registerObject(ObjectId, FactoryHelper<T>::create);
}
template<class T>
Object *FactoryHelper<T>::create(double a)
{
return new T(a);
}
所以我遇到的问题是我得到了一堆未定义的Factory::instance()
引用,基本上是对于层次结构中每种类型的对象。
如果我将all放在同一个main.cpp文件中,它可以工作,但这不是我想要的解决方案。
答案 0 :(得分:2)
由于当您的所有代码都在一个文件中时没有编译错误,并且您没有使用可能导致多个文件出现问题的任何外部全局对象,我怀疑您的编译/链接存在问题脚本。
为了记录,我可以确认您在代码中没有内在问题。添加层次结构
class Object
{
public:
Object(double _value) : value(_value) {}
virtual double getVal() { return value; }
private:
double value;
};
class SpecialObject : public Object
{
public:
SpecialObject(double _value) : Object(_value) {}
virtual double getVal() { double val = Object::getVal(); return val*val; }
};
简单的主程序
int main(int argc, char *argv[]) {
FactoryHelper<Object> baseMaker("Object");
FactoryHelper<SpecialObject> derivedMaker("SpecialObject");
Factory& factory = Factory::instance();
Object* a1 = factory.createObject("Object",4);
std::cout << a1->getVal() << std::endl;
Object* b1 = factory.createObject("SpecialObject",4);
std::cout << b1->getVal() << std::endl;
Object* c1 = factory.createObject("NonexistentObject",4);
return 0;
}
有预期的输出:
4
16
NonexistentObject is an unknown object.
顺便说一下,意见问题:你的FactoryHelper<T>
类没有取得多大成就,本质上是作为使用默认分配器/构造函数注册对象的捷径。在某些时候,新的类停止实际上节省了很多代码。如果你可以使用C ++ 11,那么编写
factory.registerObject("SpecialObject", [] (double a) -> Object* { return new SpecialObject(a); });
如果您愿意,可以将快捷方式添加到Factory
本身:
// definition
template <class T>
void registerObject(const std::string &);
// implementation
template<class T>
void Factory::registerObject(const std::string &ObjectId)
{
registerObject(ObjectId, [] (double a) -> Object* { return new T(a); });
};
通过这个,FactoryHelper
类可以被删除,而之前的等效main
例程是
using namespace std;
int main(int argc, char *argv[]) {
Factory& factory = Factory::instance();
factory.registerObject<Object>("Object");
factory.registerObject<SpecialObject>("SpecialObject");
Object* a1 = factory.createObject("Object",4);
std::cout << a1->getVal() << std::endl;
Object* b1 = factory.createObject("SpecialObject",4);
std::cout << b1->getVal() << std::endl;
Object* c1 = factory.createObject("NonexistentObject",4);
return 0;
}
同样,如果你能够使用C ++ 11,你总是可以让createObject
将原始Object*
指针包装在一个智能指针中(你可能知道,也许你有好处)已经没有这样做的理由)。