【C++】 单例设计模式的讲解

前言
在我们的学习中不免会遇到一些要设计一些特殊的类,要求这些类只能在内存中特定的位置创建对象,这就需要我们对类进行一些特殊的处理,那我们该如何解决呢?

目录

    • 1. 特殊类的设计
      • 1.1 设计一个类,不能被拷贝:
      • 1.2设计一个类,只能在堆上创建对象
        • 方法二:
      • 1.3 设计一个类,只能在栈上创建对象
      • 1.4 请设计一个类,不能被继承:
    • 2 单例模式:
      • 2.1 饿汉模式:
      • 2.2 懒汉模式:
      • 2.3 特殊情况下,单例类的释放

1. 特殊类的设计

1.1 设计一个类,不能被拷贝:

  • 拷贝构造函数以及赋值运算符重载
  • 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可

C++98的处理方式:

  • 让拷贝构造和赋值重载设成私有即可

  • 只声明不定义。

  • C++11扩展delete的用法,delete除了释放new申请的资源外

  • 如果在默认成员函数后跟上 = delete,表示让编译器删除掉该默认成员函数。

class CopyBan
{// ...CopyBan(const CopyBan&) = delete;CopyBan& operator=(const CopyBan&) = delete;// ...
};

1.2设计一个类,只能在堆上创建对象

C++98的设计的方法:

  • 就直接将构造函数私有化

  • 只声明不定义。

    C++11的做法:

class HeapOnly
{
public:static HeapOnly* CreateObj(){//这里new直接去调用构造函数去了,类里面直接调用没限制return new HeapOnly;}//防拷贝,不让拷贝(形参可写可不写)HeapOnly(const HeapOnly&) = delete;//赋值并不会影响创建的对象跑到其他的地方去了,赋值不是创建对象的//拷贝构造反而是用来创建对象的private://构造函数私有 -- 将构造函数封起来(三条路都封死)HeapOnly(){}
};

问题:

  1. 那我们在类外调用CreateObj()来创建对象的时候,会有个问题
  2. 那就是著名的先有鸡还是先有蛋的问题
  3. 调用成员函数,就要有对象,要有对象,要有对象,就需要先构造
  4. 我们要解决这个问题就必须打破这个循环死穴 我们将CreateObj()函数设成静态函数

补充:

  • 普通的非静态的构造函数都需要对象去调用
  • 而构造函数不需要

此时还有个问题就是,拷贝构造也是会在栈上创建对象,我们可以将拷贝构造设成私有,或者C++11中直接将拷贝构造给删除掉。

方法二:

相比于上一种方法(将构造函数和拷贝构造私有或者删除),方法二显得更加牵强一点,将析构函数设成私有的,这样当对象生命周期结束时自动调用析构函数时会调用不到。

  • 这种方式的缺陷是:new的时候确实能创建出来,但是在delete释放的时候会报错

解决办法:类外调用不了私有的析构函数,但是类内可以调用,所以我们可以提供一个接口

class HeapOnly
{
public:static void DelObj(HeapOnly* ptr){delete ptr;}//比较花的玩法 -- 这样还不用传参了/*void DelObj(){delete this; }*/private://析构函数私有~HeapOnly(){}
};int main()
{//HeapOnly h1;//static HeapOnly h2;HeapOnly* ph3 = new HeapOnly;//delete ph3;//方法一:要传参ph3->DelObj(ph3);//方法二:不用传参//ph3->DelObj();return 0;
}

1.3 设计一个类,只能在栈上创建对象

类似于上一个问题中的方法,我们先将三条路封死,然后单独给在栈上创建对象开条出路。

思路如下:

  • 先将构造函数私有化
  • 然后在类内写一个函数专门用来创建对象并负责将其传出来
  • 注意:此时传返回值只能是传值返回,不能传指针,也不能传引用
  • 因为是在栈上创建对象,是个局部变量,出了作用域就销毁掉了
class StackOnly
{
public:static StackOnly CreateObj(){//局部对象,不能用指针返回,也不能用引用返回,只能传值返回//传值返回必然会有一个拷贝构造发生return StackOnly();}void Print(){cout << "Stack Only" << endl;}
private://构造函数私有StackOnly(){}
};int main()
{StackOnly h1 = StackOnly::CreateObj();//不用对象去接受StackOnly::CreateObj().Print();//static StackOnly h2;//禁掉下面的玩法//StackOnly* ph3 = new StackOnly;return 0;
}

注意:

这里不能将拷贝构造给禁掉,因为CreateObj()是传值返回,传值返回必然会有一个拷贝构造(不考虑编译器优化的问题)。

1.4 请设计一个类,不能被继承:

  • 构造函数私有
  • 只声明不定义
class A
{
private:A(){}
};class B : public A
{};int main()
{B b;return 0;
}
  • 父类A的构造函数私有化以后,B就无法构造对象
  • 因为规定了子类的成员必须调用父类的构造函数初始化

这时又有一个问题 —— 先有鸡还是先有蛋的问题:

  • 调用成员函数需要对象,对象创建需要调用成员函数,调用成员函数需要对象…
    在这里插入图片描述

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错。
在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

2 单例模式:

概念:

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,一个进程只能有一个对象,并提供一个访问它的全局访问点,该实例被所有程序模块共享.

2.1 饿汉模式:

  • 这种模式是不管你将来用不用这个类的对象,程序启动时就创建一个唯一的实例对象。
  • 创建多线程都是在main函数之后创建的。(main函数之前没有多线程)。
%饿汉模式--一开始(main函数之前)就创建出对象
%优点:简单、没有线程安全问题
%缺点:1,一个程序中,多个单例,并且有先后创建初始化顺序要求时,饿汉无法控制比如程序中两个单例类A和B,假设要求A先创建初始化,B再创建初始化,2.饿汉单例类,初始化时任务多,会影响程序启动速度。class MemoryPool
{
public:static MemoryPool* GetInstance(){cout << _spInst << endl;return _spInst;}void Print();
private://构造函数私有化MemoryPool(){}//防不住拷贝,直接将其删除MemoryPool(const MemoryPool&) = delete;MemoryPool & operator=(MemoryPool const&) = deletechar*  _ptr=nullptr; //声明static MemoryPool* _spInst; //声明
};void MemoryPool::Print()
{cout << *_ptr<< endl;
}MemoryPool* MemoryPool::_spInst = new MemoryPool; //定义int main()
{//GetInstance() 可以或者这个Singleton类的单例对象MemoryPool::GetInstance()->Print();//在外面就定义不出来对象了//MemoryPoolst1;//MemoryPool* st2 = new MemoryPool;//拷贝删除掉//MemoryPool copy(*MemoryPool::GetInstance());return 0;
}

2.2 懒汉模式:

  • 开始不创建对象,在第一调用GetInstance()的时候再创建对象。

优点:

  • 1.控制顺序
  • 2.不影响启动速度。

缺点:

  • 1.相对复杂(线程安全问题没讲)
  • 2.线程安全问题要处理好
class Singleton
{
public:static Singleton* GetInstance() {**/ 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全**%一定要用双把锁if (nullptr == m_pInstance) {m_mtx.lock();if (nullptr == m_pInstance){m_pInstance = new Singleton();}m_mtx.unlock();}return m_pInstance;
}private:// 构造函数私有Singleton(){};// 防拷贝Singleton(Singleton const&);Singleton& operator=(Singleton const&);static Singleton* m_pInstance; // 单例对象指针static mutex m_mtx; //互斥锁
};Singleton* Singleton::m_pInstance = nullptr;
mutex Singleton::m_mtx
  • 与饿汉模式不同的是, 懒汉是模式则是一开始不创建对象,而是一开始先给一个指针,这样就避免了程序启动起来很慢的问题。

思路:

  • 将构造函数私有化
  • 一开始不构建对象,只是给一个空指针
  • 在需要的时候再调用其构造函数构造

补充:

  • 懒汉是一种延迟加载,饿汉是一开始就加载

2.3 特殊情况下,单例类的释放

在这里插入图片描述

解决方案:

  • 设计一个内部类
    在这里插入图片描述

尾声
看到这里,相信大家对这个C++有了解了。
如果你感觉这篇博客对你有帮助,不要忘了一键三连哦

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/13600.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Studio 与 Gradle 及插件版本兼容性

Android Studio 开始新项目时&#xff0c;会自动创建其中部分文件&#xff0c;并为其填充合理的默认值。 项目文件结构布局&#xff1a; 一、Android Gradle 及插件作用&#xff1a; Android Studio 构建系统以 Gradle 为基础&#xff0c;并且 Android Gradle 插件 (AGP) 添加…

代码随想录阅读笔记-动态规划【不同路径 II】

题目 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为“Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为“Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到右…

全球视频会议软件巨头Zoom,率先引入后量子端到端加密

5月21日&#xff0c;Zoom Video Communications公司宣布&#xff0c;后量子端到端加密&#xff08;E2EE&#xff09;现已面向全球推出&#xff0c;适用于Zoom Workplace。目前&#xff0c;Zoom已将该功能加入Zoom Meetings&#xff0c;稍后将扩展至Zoom Phone和Zoom Rooms。 图…

视频批量裁剪助手:一键式高效缩小视频尺寸,极速提升工作效率的必备神器!

视频已经成为我们日常生活和工作中不可或缺的一部分。无论是个人vlog、企业宣传片&#xff0c;还是教学视频、广告素材&#xff0c;视频都承载着大量的信息和情感。然而&#xff0c;很多时候&#xff0c;我们手中的视频尺寸并不符合我们的需求&#xff0c;这时&#xff0c;一款…

He3DB MySQL计算下推优化设计

前言 计算下推是数据库优化器优化查询性能的一种常见手段&#xff0c;早期的数据库系统提及的计算下推一般是指谓词下推&#xff0c;其 理论源自关系代数理论。 2000 年以后&#xff0c;随着 Oracle RAC 的盛行以及一众开源分布式数据库的崛起&#xff0c;存算分离的概 念逐步…

k8s 声明式资源管理

一、资源配置清单的管理 1.1 查看资源配置清单 声明式管理方法&#xff1a; 1.适合于对资源的修改操作 2.声明式资源管理方法依赖于资源配置清单文件对资源进行管理 资源配置清单文件有两种格式&#xff1a;yaml&#xff08;人性化&#xff0c;易读&#xff09;&#xff0c;j…

Flink 调度源码分析4:Physical Slot 分配过程

Flink 调度源码分析1&#xff1a;拓扑图创建与提交过程 Flink 调度源码分析2&#xff1a;调度过程 Flink 调度源码分析3&#xff1a;Shared Slot 分配策略 Flink 调度源码分析4&#xff1a;Physical Slot 分配过程 1 整体过程 在 SlotSharingExecutionSlotAllocator.allocate…

【EXCEL_VBA_实战】两组数据比对是否一致(字符串数组)

工作背景&#xff1a;比对两组数据是否一致&#xff08;位置非一一对应&#xff09; 思路构建&#xff1a;两组数据转换为两组字符串数组&#xff0c;比对所包含元素是否相同 问题点&#xff1a;A数组的第一个元素不一定与B数组的第一个元素对应&#xff0c;此时无法通过公式…

es数据备份和迁移Elasticsearch

Elasticsearch数据备份与恢复 前提 # 注意&#xff1a; 1.在进行本地备份时使用--type需要备份索引和数据&#xff08;mapping,data&#xff09; 2.在将数据备份到另外一台ES节点时需要比本地备份多备份一种数据类型&#xff08;analyzer,mapping,data,template&#xff09; …

岛屿问题刷题

200. 岛屿数量 - 力扣&#xff08;LeetCode&#xff09; class Solution {public int numIslands(char[][] grid) {int n grid.length;//grid行数int m grid[0].length;//grid列数int res 0;for(int r 0;r<n;r){for(int c0;c<m;c){if(grid[r][c]1){dfs(grid,r,c);res…

分布式异步框架celery + Redis 安装配置

引入 这里不对web框架做过多说明&#xff0c;到时候在总结一篇 python的常见web框架 django、flask、tornado、sanic、fastapi..各框架区别 - 内部集成功能的多少 django&#xff0c;内部提供了很多组件。 【相对大】flask、tornado、sanic、fastapi… 本身自己功能很少第…

java集合类详解

目录 1、数组导入&#xff1a; 2、单列集合 List接口 1、ArrayList&#xff1a;数组列表 ArrayList类中的方法 2、LinkedList&#xff1a;链表列表 3、Vector&#xff1a;数组列表 4、list集合的遍历 1、for循环遍历 2、增强for循环 3、迭代器遍历 Set接口 1、Has…

data studio连接到虚拟机上的openGauss

参考&#xff1a;使用DataStudio连接本地虚拟机中的opengauss数据库_big data_白日梦想家_胖七七-华为云开发者联盟 本实验虚拟机安装的是CentOS7 数据库版本是&#xff1a;openGauss-5.0.2-CentOS-64bit-all.tar.gz 1.配置pg_hba.conf 首先使用su - omm登录到omm用户&…

MySQL数据库,创建表及其插入数据和查询数据

首先&#xff0c;由上图创建表 mysql> create table worker( -> dept_id int(11) not null, -> emp_id int (11) not null, -> work_time date not null, -> salary float(8,2) not null, -> poli_face varchar(10) not null default 群众, -> name…

华为设备WLAN基础配置

WLAN基础配置之AP上线 配置WLAN无线网络的第一阶段&#xff0c;AP上线技术&#xff1a; 实验目标&#xff1a;使得AP能够获得来自AC的DHCP地址服务的地址&#xff0c;且是该网段地址池中的IP。 实验步骤&#xff1a; 1.把AC当作三层交换机配置虚拟网关 sys Enter system view…

安卓CardView使用

目录 前言一、基础使用1.1 依赖导入1.2 CardView的常用属性1.3 CardView继承关系 二、关于Z轴的概念三、CardView效果3.1 圆角 CardView3.2 阴影 CardView3.3 设置卡片背景3.4 设置卡片背景&#xff08;内部颜色&#xff09;3.5 同时设置背景颜色 前言 CardView是Android支持库…

WXML模板语法-数据绑定

1.数据绑定的基本原则 (1)在data中定义数据 (2)在WXML中使用数据 2.在data页面中定义数据&#xff1a;在页面对应的.js文件中&#xff0c;把数据定义在data对象中即可 &#xff08;这里打错了 应该是数组类型的数据... 报意思啊&#xff09; 3.Mustache语法的格式 把data中的…

低代码开发平台:开启企业数字化转型的快捷通道

低代码开发平台&#xff08;Low-Code Development Platform&#xff09;是近年来企业数字化转型中备受瞩目的技术工具&#xff0c;其被誉为加速业务上线的利器。随着信息技术的迅猛发展&#xff0c;企业对于数字化的需求与日俱增&#xff0c;但传统的软件研发流程往往耗时耗力&…

MATLAB|【免费】融合正余弦和柯西变异的麻雀优化算法SCSSA-CNN-BiLSTM双向长短期记忆网络预测模型

目录 主要内容 部分代码 部分结果一览 下载链接 主要内容 该程序实现多输入单输出预测&#xff0c;通过融合正余弦和柯西变异改进麻雀搜索算法&#xff0c;对CNN-BiLSTM的学习率、正则化参数以及BiLSTM隐含层神经元个数等进行优化&#xff0c;并对比了该改进算法…

摄像头应用测试

作者简介&#xff1a; 一个平凡而乐于分享的小比特&#xff0c;中南民族大学通信工程专业研究生在读&#xff0c;研究方向无线联邦学习 擅长领域&#xff1a;驱动开发&#xff0c;嵌入式软件开发&#xff0c;BSP开发 作者主页&#xff1a;一个平凡而乐于分享的小比特的个人主页…