Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 工厂和单例模式:未定义的引用_C++_Templates_Design Patterns_Singleton_Factory - Fatal编程技术网

C++ 工厂和单例模式:未定义的引用

C++ 工厂和单例模式:未定义的引用,c++,templates,design-patterns,singleton,factory,C++,Templates,Design Patterns,Singleton,Factory,我试图从这个网站的其他问题中了解我的处境,但我并没有找到一个好的答案。我尝试了我发现的大多数建议,但仍然得到同样的错误 我正在尝试实现一个基于单例和CRTP的工厂。所以我有一个Singleton类,在Singleton中定义。h: template<class T> class Singleton { public: static T &instance() { static T one; return one; } Singleton(co

我试图从这个网站的其他问题中了解我的处境,但我并没有找到一个好的答案。我尝试了我发现的大多数建议,但仍然得到同样的错误

我正在尝试实现一个基于单例和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;
};
最后,我有一个“helper”类,它将新类型的对象注册到工厂中。每次创建新的继承对象时,例如
ObjectDerived
,我都会添加(在实现
ObjectDerived
的.cpp文件中):

FactoryHelper注册表对象派生(“对象派生”)

这将创建一个类型为
FactoryHelper
的对象,其构造函数处理工厂中的注册<代码>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);
}
模板
类FactoryHelper
{
公众:
FactoryHelper(const std::string&);
静态对象*创建(双);
};
模板
FactoryHelper::FactoryHelper(常量std::string和ObjectId)
{
Factory&theFactory=Factory::instance();//唯一的一个!
//如果此时不存在,则创建它。
registerObject(ObjectId,FactoryHelper::create);
}
模板
对象*FactoryHelper::创建(双a)
{
返回新的T(a);
}
所以我遇到的问题是,我得到了一堆对
Factory::instance()
的未定义引用,基本上层次结构中每种类型的对象都有一个引用


如果我将所有内容都放在同一个main.cpp文件中,它就可以工作,但这不是我想要的解决方案

由于当所有代码都在一个文件中时没有编译错误,并且您没有使用任何可能导致多个文件出现问题的外部全局对象,因此我怀疑您的编译/链接脚本中存在问题

作为记录,我可以确认代码中没有内在问题。添加层次结构

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;
}
顺便提一句,大家的看法是:您的
FactoryHelper
类并没有取得太大的成就,实际上是作为向默认分配器/构造函数注册对象的快捷方式。在某种程度上,创建新类实际上停止了节省大量代码。如果你能使用C++11,写起来就不会困难很多

factory.registerObject("SpecialObject", [] (double a) -> Object* { return new SpecialObject(a); });
如果需要,可以将快捷方式添加到
工厂
本身:

// 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); });
};

同样,如果您能够使用C++11,您可以始终使
createObject
将原始
Object*
指针包装在智能指针中(您可能很清楚,也许您已经有很好的理由不这样做)。

我无法重现您的错误。为了使代码完整,我在一个文件中添加了一个非常简单的对象类和main()函数。当然,我并没有创建从对象继承的类的层次结构。你能通过提供最小的基对象、派生类和主函数来创建MCVE来显示你的问题,并包括编译器错误吗?@jwimberley我实际上也这样做了,并且不得不编辑我的问题,因为显然我以前做了一些错误:将所有内容放在同一个cpp文件中不会产生错误。但这并不是一个理想的解决方案,真的。在这种情况下,这可能是编译/链接问题,而不是代码问题。老实说,我不知道发生了什么。在一次清理之后,它现在似乎也可以处理单独的文件。谢谢你给我的关于消除FactoryHelper的建议:)我真的遇到了新的麻烦。。我可以在主例程中使用您的方法注册对象,但理想情况下,我希望在我引入的每个新类(在其自己的.cpp中)上注册对象。行
Factory&Factory=Factory::instance();工厂注册对象(“对象”)如果对其中一个文件执行此操作,请为
工厂(在第二行中)提供一个“未知类型名称”错误。如果在main()上执行,则完全没有错误。嗯,您可以发布完整的错误吗?您以前是否有从FactoryHelper继承这些类的策略,例如,
WidgetObject:public FactoryHelper
?您需要更具体地说明将这些代码放在Object.cpp中的位置。它是类构造函数的一部分,还是它本身的一行?我希望后一种情况会失败(使用我的Factory建议或FactoryHelper),因为
Factory::registerObject(std::string&)
是一个函数调用,必须存在于main或main调用的某个函数中,原因很多。我明白了,把这个放进构造函数可能会有用。是的,它本身就是一条线,所以它失败是有道理的。我认为这是我使用FactoryHelper的主要原因,因为注册可以在构造函数中调用(这是我在没有考虑我正在做什么的情况下遵循的建议)。我不想把它放在对象的构造函数中,因为我希望即使不存在对象也能注册。
factory.registerObject("SpecialObject", [] (double a) -> Object* { return new SpecialObject(a); });
// 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); });
};
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;

}