C++设计模式--单例模式(Singleton)及单例通用模板

概述

C++中的单例模式应该是设计模式中最简单的了,在编码中常见到。那么,简单的总结下 C++中的单例模式写法,以及根据单例模式扩展后的一些写法,最后还有单例的通用模板,可用于快捷创建一个单例类。

单例类

创建一个单例模式的关键是防止他人获得任何控制其对象生存期的权利,也就是说不要让别人可以随便创建类对象,单例类在整个程序生存周期中至始至终就只有一个对象,为了做到这一点,必须要先把构造函数声明为私有,并且防止编译器隐式生成任何构造函数。
注意:拷贝构造函数和赋值操作符无需实现,因为根本就不会在单例中被调用

然后为了只实现只保留一个对象,需要将对象通过静态创建来实现,并且可以在调用的时候再进行创建,这种方式叫惰性初始化。

接下来看一下单例的通用写法:

#include 

using namespace std;

class Singleton
{
public:
    static Singleton & instance(){
        return s;
    }
    int getValue(){return i;}
    void setValue(int x){i = x;}

private:
    static Singleton s;
    int i;
    Singleton(int x):i(x){}
};

Singleton Singleton::s(47);

int main()
{
    Singleton & s = Singleton::instance();
    cout<< s.getValue() << endl;
    Singleton &s2 = Singleton::instance();
    s2.setValue(4);
    cout<< s.getValue() << endl;
    return 0;
}

输出结果:

47
4

代码很简单,调用静态函数 instance()返回的是引用而不是指针,如果是指针的话用户可能会不小心删除此指针,因此上面这种写法被认为是最安全的。

当然,这种方法并没有限制只创建一个对象,也可以通过这种方式创建有限个对象的对象池,但是这种情况下可能遇到池中共享对象的问题,需要创建一个对共享对象进出对象池登记的方法啦解决。不过通常我们写单例类都只创建一个对象, 那么就不用考虑啦。

以上程序还可以做得更加简单,我们可以将在一个成员函数内部的静态对象的创建与单例类结合在一起,如下:

#include 

using namespace std;

class Singleton
{
public:
    static Singleton & instance(){
//        return s;
        static Singleton s(47);
        return s;
    }
    int getValue(){return i;}
    void setValue(int x){i = x;}

private:
    static Singleton s;
    int i;
    Singleton(int x):i(x){}
    Singleton & operator =(Singleton&); //赋值操作符 不会调用
    Singleton(const Singleton&);//拷贝构造函数  不会调用
};

//Singleton Singleton::s(47);

int main()
{
    Singleton & s = Singleton::instance();
    cout<< s.getValue() << endl;
    Singleton &s2 = Singleton::instance();
    s2.setValue(4);
    cout<< s.getValue() << endl;
    return 0;
}

只对第一个程序做了简单的修改,可以看到,在调用instance函数的时候才去创建静态对象。这种写法更简单一些。

单例类通用模板

根据单例类的特征,我们可以写一个通用模板,如下:

#include 

using namespace std;

template
class Singleton
{
public:
    static T& instance(){
        static T theInstance;
        return theInstance;
    }

protected:
    Singleton(){}
    virtual ~Singleton(){}

private:
//    Singleton(const Singleton&);
//    Singleton& operator =(const Singleton&);

};

//单例类
class MyClass : public Singleton
{
public:
    void setValue(int n){x = n;}
    int getValue(){return x;}

protected:
    friend class Singleton;
    MyClass(){x = 0;}

private:
    ~MyClass();
    int x;
};

int main()
{
    MyClass& m = MyClass::instance();
    cout << m.getValue() << endl;
    m.setValue(1);
    cout << m.getValue() << endl;
    return 0;
}

以上可以看到,MyClass 类可以通过继承模板来快速实现一个单例模式。通过下面三个步骤来实现:

  • 1.声明其构造函数为私有或保护
  • 2.声明类Singleton为友元
  • 3.从Singleton派生出 MyClass

第三点可能不太容易理解,这里只是对模板 Singleton 中模板参数的静态依赖。换句话说,类 Singleton的代码之所以能够被编译器实例化,是因为它不依赖于类 MyClass 的大小,当函数Singleton::instance()第一次被调用时,才需要类 MyClass 的大小,而此时编译器已经知道类 MyClass 的大小。

参考资料:《C++编程思想》

你可能感兴趣的:(C++,And,C)