c++ - 工厂和单例模式 : undefined reference

标签 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(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 ,我添加(在实现 ObjectDerived 的 .cpp 文件中):

FactoryHelper<ObjectDerived> registerObjectDerived("ObjectDerived");

这将创建一个 FactoryHelper<ObjectDerived> 类型的对象,其构造函数处理工厂中的注册。 FactoryHelperFactoryHelper.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() 的 undefined reference ,基本上对应于层次结构中的每种类型的对象。

如果我将所有内容都放在同一个 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;
}

有预期的输出:

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可以消除class,相当于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*智能指针中的指针(您可能很清楚,也许您已经有充分的理由不这样做)。

关于c++ - 工厂和单例模式 : undefined reference,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43232759/

相关文章:

c++ - 在 C++ 中的 3 个数组中找到所有可能的解决方案而不重复

c++ - 如何在没有默认构造函数的情况下在另一个类中创建模板类

c++ - 引用作为参数的模板参数推导

c++ - 静态多态性的 CRTP 与名称隐藏

c++ - 将类型名称和值与模板包扩展混合

c++ - 如何更改初始化的变量取决于虚函数

linq-to-sql - 使用 Linq to 查询分层表/复合模式中的终端/叶节点

c++ - QTextEdit中的 "selection"和 "cursor"有什么区别?

c++ - 具有两个目标和两种语言的 Makefile

oop - 工厂方法 (1) vs factory(2) vs Builder (3) 模式