当前位置: 首页 > news >正文

C++单例模板类,继承及使用

前言:

单例模式可以参考如下文章:

我的设计模式,单例模式的设计和实现

c++ 单例模式的模板类 - 川野散人 - 博客园

1.为什么需要单例模板类?

场景问题:

如果需要100个单例类就需要设计100个单例模式,代码重复且冗余,不利于扩展。

单例模板类可以实现单例模式的基础功能,普通类继承它之后,就拥有单例的特性。

2.单例模板类需要具备哪些特质?如何设计?

单例模板类需要具备哪些特质?

  • 单例模板类的构造函数应该是protected的?(子类要拥有创建父类的权限,但是不能是pubic,如果是public就丧失单例特性)
  • 单例模板类的析构函数应该是protected的?(子类要拥有析构父类的权限,但是不能是pubic,会重复析构)
  • 单例模板不能使用拷贝构造
  • 单例模板不能使用拷贝赋值
  • 单例模板应提供实例的public方法

设计代码如下:

template<typename T>
class Singleton
{
protected:
    Singleton(){std::cout << "Singleton()!" << std::endl;}
    ~Singleton(){std::cout << "~Singleton()!" << std::endl;}
public:
    static T& getInstance()
    {
        static std::mutex mtx;
        static std::unique_ptr<T> uniPtr;
        if (uniPtr == nullptr)
        {
            mtx.lock();
            if (uniPtr == nullptr)
            {
                uniPtr.reset(new T());
            }
            mtx.unlock();
        }
        return *uniPtr;
    }
private:
    Singleton(const Singleton& s) = delete;
    Singleton& operator = (const Singleton& s) = delete;
};

继承者应注意哪些?

  • 继承者的构造函数应设为私有
  • 继承者应设置单例模板类为友元(父类可以调用继承者私有构造函数)
class MySingleton :public Singleton<MySingleton>
{
    friend class Singleton<MySingleton>;
private:
    MySingleton() {std::cout << "MySingleton()!" << std::endl;}
public:
    //unique_ptr需要权限销毁管理的对象
    ~MySingleton() {std::cout << "~MySingleton()!" << std::endl;}
public:
    void MySingletonSay(){std::cout << "MySingletonSay : Hello World!" << std::endl;}
};

3.测试代码

int main()
{
    {
        MySingleton::getInstance().getInstance().MySingletonSay();
    }
    {
        MySingleton::getInstance().MySingletonSay();
    }
}

输出:

Singleton()!
MySingleton()!
MySingletonSay : Hello World!
MySingletonSay : Hello World!
~MySingleton()!
~Singleton()!

4.当我设置继承者析构函数为私有时,编译unique_ptr报错

class MySingleton :public Singleton<MySingleton>
{
    friend class Singleton<MySingleton>;
private:
    MySingleton() {std::cout << "MySingleton()!" << std::endl;}
    ~MySingleton() {std::cout << "~MySingleton()!" << std::endl;}
public:
    void MySingletonSay(){std::cout << "MySingletonSay : Hello World!" << std::endl;}
};

5.继承者析构函数不显式声明,编译unique_ptr不报错,但析构不完全

class MySingleton :public Singleton<MySingleton>
{
    friend class Singleton<MySingleton>;
private:
    MySingleton() {std::cout << "MySingleton()!" << std::endl;}
public:
    void MySingletonSay(){std::cout << "MySingletonSay : Hello World!" << std::endl;}
};
  • 输出
Singleton()!
MySingleton()!
MySingletonSay : Hello World!
MySingletonSay : Hello World!
~Singleton()!

6.继承者析构函数声明为public可能出现的问题举例

#include <iostream>
#include <memory>
#include <mutex>

template<typename T>
class Singleton
{
protected:
    Singleton(){std::cout << "Singleton()!" << std::endl;}
    ~Singleton(){std::cout << "~Singleton()!" << std::endl;}
public:
    static T& getInstance()
    {
        static std::mutex mtx;
        static std::unique_ptr<T> uniPtr;
        if (uniPtr == nullptr)
        {
            mtx.lock();
            if (uniPtr == nullptr)
            {
                uniPtr.reset(new T());
            }
            mtx.unlock();
        }
        return *uniPtr;
    }
private:
    Singleton(const Singleton& s) = delete;
    Singleton& operator = (const Singleton& s) = delete;
};

class MySingleton :public Singleton<MySingleton>
{
    friend class Singleton<MySingleton>;
private:
    MySingleton() {std::cout << "MySingleton()!" << std::endl;}
public:
    //unique_ptr需要权限销毁管理的对象
    ~MySingleton() {std::cout << "~MySingleton()!" << std::endl;}
public:
    void MySingletonSay(){std::cout << "MySingletonSay : Hello World!" << std::endl;}
};


int main()
{
    {
        MySingleton::getInstance().MySingletonSay();

        delete &MySingleton::getInstance();
    }
    std::cout << "end...................." << std::endl;
}

  • 输出:出现了重复析构sos
Singleton()!
MySingleton()!
MySingletonSay : Hello World!
~MySingleton()!
~Singleton()!
end....................
~MySingleton()!
~Singleton()!

7.如上的问题怎么解决呢?欢迎观众大佬们留言

相关文章:

  • C语言宏定义的底层应用
  • 【SpringMVC】概述 SSM:Spring + SpringMVC + Mybats
  • 在CentOS安装Docker
  • Redis常用数据类型及其应用案例
  • 机器学习数学基础:30.Pearson相关系数及t检验教程
  • 信息安全实战04_ECC椭圆曲线加密算法原理详解
  • 蓝桥杯试题:区间次方和(前缀和)
  • Gin从入门到精通 (四)请求参数
  • 网络运维学习笔记 022 HCIA-Datacom新增知识点03园区网典型组网架构及案例实战
  • 第一届网谷杯
  • 力扣每日一题【算法学习day.133】
  • 敏捷开发08:如何高效开每日站会(Daily Stand-up Meeting)
  • LEARNING ON LARGE-SCALE TEXT-ATTRIBUTED GRAPHS VIA VARIATIONAL INFERENCE
  • Go语言中使用viper绑定结构体和yaml文件信息时,标签的使用
  • NIO-Reactor模型梳理与demo实现
  • Linux 第三次脚本作业
  • 如何使用智能指针来管理动态分配的内存
  • 函数中的形参和实参(吐槽)
  • R 语言科研绘图 --- 散点图-汇总
  • 记录 idea 启动 tomcat 控制台输出乱码问题解决
  • 中国证券监督管理委员会党委委员、副主席王建军接受审查调查
  • 秦洪看盘|资金切换主线,重构市场风格
  • 人物|德国新外长关键词:总理忠实盟友、外交防务专家、大西洋主义者
  • 马克思主义理论研究教学名师系列访谈|杜玉华:马克思主义是“认识世界”和“改变世界”的思维工具
  • 魔都眼|静安光影派对五一启幕:苏河湾看徐悲鸿艺术画作
  • 狄威已任国铁集团副总经理