如何在C ++ 11代码中实现Singleton Pattern和Factory Pattern

时间:2014-01-05 02:43:09

标签: c++ design-patterns singleton

我正在尝试同时实现Singleton Pattern和Factory Pattern。 在我看来,每种工厂只能有一个基于抽象类的工厂,并使用工厂生成相应的shape对象。

但我收到了一个错误:

  

错误LNK2001:未解析的外部符号“private:static class TriangleFactory * TriangleFactory :: instance”(?instance @ TriangleFactory @@ 0PAV1 @ A)

我不知道为什么会这样。你能告诉我如何解决这个问题吗? 代码如下。

#include<type_traits>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<memory>
#include<time.h>
using namespace std;

class Shape
{
public:
    virtual void display();
protected:
    int x, y;
};

class MyTriangle:public Shape
{
public:
    MyTriangle(int _x, int _y)
    {
        x = _x;
        y = _y;
    }
    MyTriangle()
    {
        x = rand() % 200;
        y = rand() % 200;
    }
    void display()
    {
        printf("%d %d\n",x,y);
    }
};

class SuperFactory
{
public:
    virtual Shape* Execute() = 0;
};

class TriangleFactory :public SuperFactory
{
public:
    Shape* Execute()
    {
        Shape *p = new MyTriangle;
        return p;
    }
    static SuperFactory* GetFactory()
    {
        return instance;
    }
private:
    TriangleFactory()
    {
        instance = nullptr;
        instance = new TriangleFactory;
    }
    ~TriangleFactory(){}
    static TriangleFactory* instance;
};

int main()
{
    MyTriangle *p = dynamic_cast<MyTriangle*>(TriangleFactory::GetFactory()->Execute());
    p->display();
    return 0;
}

非常感谢您的回答:)

4 个答案:

答案 0 :(得分:4)

我的批评:

  1. 您不需要所有这些#include。您只能使用<iostream>

  2. 您的构造函数和解构函数是私有的。我建议你:a。)使它们受到保护,而b。)只使构造函数成为私有的。解构器应该是公共的和虚拟的。

  3. 函数Shape::display应声明为纯SuperFactory::Execute的虚函数。将其更改为:virtual void display() = 0;

  4. 其他答案的主要问题 - 只需在TriangleFactory* TriangleFactory::instance;函数之前写main()就是这样:你会发现自己面临一个可爱的空指针错误。解决方案需要改变你的单身人士。因为您在构造函数中初始化instance,并且在您发布的代码中没有创建类型TriangleFactory的对象,所以永远不会调用构造函数,并且永远不会初始化instance

  5. 我的解决方案:

    继续使用TriangleFactory* TriangleFactory::instance;功能之前的main(),但将其值设置为null,如TriangleFactory* TriangleFactory::instance = nullptr;。这样做可以避免与过去的内存泄漏有关的错误。

    不要在构造函数中初始化instance,而是将构造函数保留为空并将GetFactory函数更改为:

    static SuperFactory *GetFactory()
    {
        if(!instance)
        {
            instance = new TriangleFactory();
            return instance;
        }
        else
        {   
            return instance;
        }
    }
    

    现在,为什么我会在TriangleFactory *TriangleFactory::instance = new TriangleFactory(); main()之前改变所有这一切 - 我怀疑你做了 - 工作得很好?好吧,初始化函数之外的任何数据都是有风险的。这些对象在运行时以任意顺序创建 - 当您开始创建依赖于其他类的类时,TriangleFactory *TriangleFactory::instance = new TriangleFactory();会在您的脸上爆炸。不要在你的脸上炸掉东西。 Get rid of cable and upgrade to DirecTV。没有xD开玩笑,但绝对TriangleFactory *TriangleFactory::instance = new TriangleFactory();

答案 1 :(得分:1)

该行:

static TriangleFactory* instance; 

声明实例。没有定义。添加:

TriangleFactory* TriangleFactory::instance;

这将定义链接器的符号。

答案 2 :(得分:1)

您需要输入以下行。

TriangleFactory* TriangleFactory::instance;

错误消息告诉您编译器找不到定义实例。当您将其用作类成员变量时,需要初始化静态成员变量 instance

答案 3 :(得分:1)

在c ++中正确启动单例的方法是使用静态实例,而不是静态指针。这样,对象将在程序退出时被正确销毁。

因此GetFactory()的正确外观将是:

static SuperFactory * GetFactory(){

    static TriangleFactory factory;
    return &factory;
}

factory实例将在首次使用GetFactory()时创建,并在程序退出时销毁。没有内存泄漏和最简单的解决方案。