C++单态模板类

13 篇文章 0 订阅

单态模式作为一个经典的设计模式,使用非常广泛,最近用qt写一个应用,其中有多个类决定按单态模式实现,写的过程中感觉大体上的结构都是类似的,每个写一遍太啰嗦了,就想能不能实现一个模板类作为基类,需要使用单态模式的类只需继承这个类即可,方便使用也能保证质量,避免某次编码过程漏写东西。

先再网上找了一下有没有别人已经实现的C++单态模板基类,但是网上大部分的代码都是按照单个类的模式实现的,按基类模式写的也都不够完善,或者用的时候还是有点儿麻烦,综合了几种实现方案后,实现了第一版

模板基类

#ifndef QCSINGLETONBASE_H
#define QCSINGLETONBASE_H

#include <QDebug>
#include <QMutex>
#include <QMutexLocker>

template<class T>
class QcSingletonBase
{
public:
    static T *instance()
    {
        if (s_instance != nullptr)
            return s_instance;

        QMutexLocker locker(s_mutex);
        if (s_instance == nullptr)
            s_instance = new T();

        return s_instance;
    }

    virtual ~QcSingletonBase(){};

private:
    static T* s_instance;
    static QMutex *s_mutex;

public:
    class QcGarbo
    {
    public:
        ~QcGarbo()
        {
            delete QcSingletonBase<T>::s_instance;
            QcSingletonBase<T>::s_instance = nullptr;

            delete QcSingletonBase<T>::s_mutex;
            QcSingletonBase<T>::s_mutex = nullptr;
        }
    };
};

template<class T>
T *QcSingletonBase<T>::s_instance = nullptr;

template<class T>
QMutex *QcSingletonBase<T>::s_mutex = new QMutex;

#define QC_SINGLETON_GARBO(T) QcSingletonBase<T>::QcGarbo s_garbo;

#define QC_FRIEND_SINGLETON_BASE(T) friend class QcSingletonBase<T>;

#endif // QCSINGLETONBASE_H

具体单态类使用头文件

#ifndef TESTSINGLETON_H
#define TESTSINGLETON_H

#include "qcsingletonbase.h"
#include <QObject>

class TestSingleton : public QObject, public QcSingletonBase<TestSingleton>
{
    Q_OBJECT

public:
    void output();

private:
    TestSingleton();
    
    Q_DISABLE_COPY(TestSingleton)

    QC_FRIEND_SINGLETON_BASE(TestSingleton);
};

#endif // TESTSINGLETON_H

具体单态类cpp文件

#include "testsingleton.h"

#include <QDebug>

QC_SINGLETON_GARBO(TestSingleton)

TestSingleton::~TestSingleton()
{
    qDebug() << "test singleton destroyed";
}

void TestSingleton::output()
{
    qDebug() << "ssssssssssssssssssss";
}

TestSingleton::TestSingleton()
{
    qDebug() << "test singleton created";
}

该写法需要另外声明一个全局的garbo变量,否则不能自动析构单态对象,且析构函数是公有的,可以在任意位置对单态类对象调用delete,这就只能通过约定,在外面不调用delete来保证不会错误释放对象。

考虑到单态类的的另一种写法是将静态对象声明为局部静态变量,想到此处也可以通过局部静态变量的形式减少额外声明静态变量的麻烦,意外析构的问题可通过将析构函数声明为private解决,由此得到第二版写法。

 

模板基类

#ifndef QCSINGLETONBASE_H
#define QCSINGLETONBASE_H

#include <QDebug>
#include <QMutex>
#include <QMutexLocker>

template<class T>
class QcSingletonBase
{
public:
    static T *instance()
    {
        if (s_instance != nullptr)
            return s_instance;

        QMutexLocker locker(s_mutex);
        if (s_instance == nullptr)
            s_instance = new T();

        return s_instance;
    }

protected:
    QcSingletonBase() { static QcGarbo garbo; }

    virtual ~QcSingletonBase(){};

private:
    static T* s_instance;
    static QMutex *s_mutex;

private:
    class QcGarbo
    {
    public:
        ~QcGarbo()
        {
            delete QcSingletonBase<T>::s_instance;
            QcSingletonBase<T>::s_instance = nullptr;

            delete QcSingletonBase<T>::s_mutex;
            QcSingletonBase<T>::s_mutex = nullptr;
        }
    };
};

template<class T>
T *QcSingletonBase<T>::s_instance = nullptr;

template<class T>
QMutex *QcSingletonBase<T>::s_mutex = new QMutex;

#define QC_FRIEND_SINGLETON_BASE(T) friend class QcSingletonBase<T>;

#endif // QCSINGLETONBASE_H

具体单体类头文件

#ifndef TESTSINGLETON_H
#define TESTSINGLETON_H

#include "qcsingletonbase.h"
#include <QObject>

class TestSingleton : public QObject, public QcSingletonBase<TestSingleton>
{
    Q_OBJECT

public:
    void output();

private:
    TestSingleton();
    ~TestSingleton();

    Q_DISABLE_COPY(TestSingleton)

    QC_FRIEND_SINGLETON_BASE(TestSingleton);
};

#endif // TESTSINGLETON_H

现在通过在模板基类的构造函数中声明局部静态变量的方式解决garbo变量声明的问题,无需再每次都声明一个garbo变量,使用时需要做的就是继承单态模板基类,将构造函数和析构函数都声明为private的,禁用拷贝构造函数和赋值操作符,将模板基类声明为单态类的友元类

这应该是写一个单态类的最小化编码方案了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值