首页 > 解决方案 > 是否可以强制仅通过单例实例化一个类

问题描述

当我使用 C++11 进行编码时,我通常使用设计模式 Singleton。这是我设计单身人士的方式:

template<typename T>
class Singleton {
private:
    Singleton() = default;
    ~Singleton() = default;
public:
    static T * GetInstance() {
        static T t;
        return &t;
    }
    Singleton(const Singleton &) = delete;
    Singleton(Singleton &&) = delete;
    Singleton & operator=(const Singleton &) = delete;
    Singleton & operator=(Singleton &&) = delete;
};

然后,我们可以定义我们想要的任何类,例如class Test{};Singleton<Test>::GetInstance();并将生成一个对象。

一切正常。

但是,今天我认为这class Test{};可以摆脱限制。我的意思是,即使我定义了 class Singletion<T>,但其他开发人员可以定义他们的类,例如Test,并且不要使用Singleton,因此他们可以根据需要生成许多对象。但我想要的是,如果你决定定义一个应该是单例的类,你不能通过调用构造函数来生成对象,而只能通过调用Singleton<Test>::GetInstance().

总之,我想得到这个:

Test t;  // compile error
Test *p = Singleton<Test>::GetInstance(); // OK

为此,我尝试了一些棘手的方法,例如,我让类Test继承Singleton<Test>

class Test : public Singleton<Test> {
public:
    Test() : Singleton<Test>() {}
};

因此,如果您正在定义一个应该是单例的类,则继承该类Singleton,现在您的类无法通过调用构造函数生成任何其他对象。但它不起作用,因为它的构造函数Singleton是私有的。但是如果我friend T;在课堂上写SingletonTest t;就会变得合法......

看来我不能强制类用户仅通过 Singleton 来构造对象。

有人能帮我吗?或者告诉我我正在做一些不可能的事情......

标签: c++singleton

解决方案


您可以使用 CRTP 模式来实现这一点

template <class T>
class Singleton {
public:
    Singleton& operator = (const Singleton&) = delete;
    Singleton& operator = (Singleton&&)      = delete;

    static T& get_instance() {
        if(!instance)
            instance = new T_Instance;
        return *instance;
    }

protected:
    Singleton() {}

private:
    struct T_Instance : public T {
        T_Instance() : T() {}
    };

    static inline T* instance = nullptr;
};

class Example : public Singleton<Example> {
protected:
    Example() {}
};

int main()
{
    auto& test = Example::get_instance();
    Example e; // this will give you error
}

推荐阅读