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

【C++高阶(八)】单例模式特殊类的设计

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

单例模式

  • 1. 前言
  • 2. 设计一个不能被拷贝/继承的类
  • 3. 只能在堆上创建对象的类
  • 4. 只能在栈上创建对象的类
  • 5. 只能实例化一个对象的类的介绍
  • 6. 饿汉模式的具体实现
  • 7. 懒汉模式的具体实现
  • 8. 总结以及拓展

1. 前言

在实际场景中,总会遇见一些特殊情况,
比如设计一个类,只能在堆上开辟空间,
亦或者是设计一个类只能实例化一个对象
在实际需求的场景下,来学习这节实用课

本章重点:

本篇文章着重讲解如何设计一些特殊
的类,包括不能被拷贝,只能在栈/堆上
创建对象以及此类只能实例化一个对象,
这也就是题目中的单例模式,单例模式又
包含饿汉和懒汉模式,文章都是干货
请同学们耐心学习!


2. 设计一个不能被拷贝/继承的类

  1. 设计一个不能被拷贝的类

C++11中引入的关键字delete
就能很好的解决这个问题,并且
不仅仅要禁用拷贝,还有赋值!

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

在C+98中,也有方法能够解决,
那就是显示将拷贝构造函数和
赋值运算符重载函数私有化!

class CopyBan
{
private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);
};
  1. 设计一个不能被继承的类

使用关键字final就能解决问题

class A  final
{// ....
};

在C++98中,将构造函数私有化也能
达到目的,因为子类的构造会调用基类
的构造,如果私有了基类的构造就会报错!

class NonInherit
{
private:NonInherit(){}
};

3. 只能在堆上创建对象的类

只能在堆上创建对象的含义就是
必须使用new来创建对象.

本篇文章是实用性的,就直接讲方法了:

  1. 将析构函数私有化

将析构函数私有化后,由于对象析构时并不能调用到析构函数,所以不管是在堆上还是栈上创建对象都会报错!但是我们可以特殊处理,在共有域定义一个函数,此函数显示调用析构!

//思路一,封析构函数
class HeapOnly
{
public:void destory(){delete this;}
private:~HeapOnly(){cout<<"调用析构成功!"<<endl;}
};

能否达到目的大家可以自行测试!

  1. 将构造函数私有化

将构造函数设置为私有后,不管是在堆上还是栈上都不能创建对象,但是我们可以在共有域写一个函数显示去调用构造函数,注意,这里的共有域函数必须设置为static类型,因为必须有了对象后才能调用函数,但是要调用了此函数才能创建对象,就会出现先有鸡还是先有蛋的问题,所以设置为static后,可以用类域调用!

//思路二,封构造函数
class HeapOnly
{
public:static HeapOnly* CreateObject(int x = 0){return new HeapOnly(x);}
private:HeapOnly(int x = 0):_x(x){}int _x;
};
  1. 以上两种方案真的就ok了吗?

事实上并不够ok,因为即使封掉了析构
或者是构造,人们也能用拷贝构造或
赋值来在栈上开辟空间,比如在方法二
中,我们可以这样打破规则:

HeapOnly* ho1 = HeapOnly::CreateObject(10);
HeapOnly ho(*ho1);

所以在上面两种方案的基础上
要禁用拷贝构造和赋值重载两个函数!


4. 只能在栈上创建对象的类

有了前面的思想,解决这个类型
的问题就显示很小儿科了!

同上将构造函数私有化然后设计
静态方法创建对象返回对象即可

class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉
// StackOnly obj = StackOnly::CreateObj();
// StackOnly* ptr3 = new StackOnly(obj);void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly()  :_a(0){}private:int _a;
};

5. 只能实例化一个对象的类的介绍

一个类只能实例化一个对象
这就是大名鼎鼎的"单例模式"

谈单例模式前,先谈设计模式:

在这里插入图片描述

单例模式就是设计模式中的一种:

在这里插入图片描述

单例模式在实际场景下使用非常广泛
如果你恰好在读我的并发内存池项目
亦或者是你学过线程池(thread pool),
这里都能看见单例模式的影子,并且,
单例模式有两种实现模式:

  • 饿汉模式:就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象
  • 懒汉模式:第一次使用时才创建一个唯一的实例对象

6. 饿汉模式的具体实现

注意,这里实现的是样例(demo)代码,在
不同的工程场景下需要大家做灵活的变换

// 饿汉模式
// 优点:简单
// 缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。
class Singleton
{
public:static Singleton* GetInstance(){return _ins;}
private://限制类外随意创建对象Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;Singleton(){}
private:static Singleton* _ins;
};
Singleton* Singleton::_ins = new Singleton;

单例模式的饿汉模式中,程序一启动就会
把_ins,也就是唯一的实例对象给初始化,
并且由于构造函数被私有了,只能调用共
有的GetInstance()函数获取_ins对象,又
由于这个对象是static类型的,所以不管你
调用多少次GetInstance()都获取的是同
一个对象,也就是_ins


7. 懒汉模式的具体实现

在这里插入图片描述

//懒汉模式
class Singleton
{
public:static Singleton* GetInstance(){if (_ins == nullptr)//双检查加锁,只有第一次进来时需要加锁,其他情况不用加锁{imtx.lock();if (_ins == nullptr)//第一次调用才创建实例!{_ins = new Singleton;}imtx.unlock();}return _ins;}void DelInstance(){imtx.lock();if (_ins != nullptr){cout << "over!!!" << endl;delete _ins;_ins = nullptr;}imtx.unlock();}
private://限制类外随意创建对象Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;Singleton(){}
private:static Singleton* _ins;static mutex imtx;
};
Singleton* Singleton::_ins = nullptr;
mutex Singleton::imtx;

与饿函数模式不同的是,懒汉模式在多线程
情况下有线程安全问题,所以在第一次拿唯
一的对象前需要加锁,并且对象在程序启动
时被置空了,只有调用了GetInstance()才会
真正的分配空间

当然,这两个模式都是样例代码,大家要随机应变


8. 总结以及拓展

特殊类的设计这块儿,大家需要在写某些
项目的时候真正运用到它才能体会出它
的作用和奥妙之处,总的来说单例模式是
使用很广泛并且很有用的一种设计模式!

对设计模式的拓展:

常见的设计模式不仅仅有单例模式,还有工厂模式、抽象工厂模式、适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式、观察者模式和命令模式等,如果大家有兴趣的话可以阅读这篇文章拓展自己的知识

C++常见的11种设计模式


🔎 下期预告:C++类型转换以及IO流🔍

相关文章:

【C++高阶(八)】单例模式特殊类的设计

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C从入门到精通⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习C   &#x1f51d;&#x1f51d; 单例模式 1. 前言2. 设计一个不能被拷贝/继承的…...

Linux之进程(五)(进程控制)

目录 一、进程创建 1、fork函数创建进程 2、fork函数的返回值 3、fork常规用法 4、fork调用失败的原因 二、进程终止 1、进程终止的方式 2、进程退出码 3、进程的退出方法 三、进程等待 1、进程等待的必要性 2、wait函数 3、waitpid函数 四、进程程序替换 1、概念…...

63. 不同路径 II 23.12.21(二)

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

【线性代数】两个向量组等价,其中一个向量组线性无关,另一个向量组也是线性无关吗?

一、问题 两个向量组等价,其中一个向量组线性无关,另一个向量组也是线性无关吗? 二、答案 不一定,当两个向量组中的向量个数也相同时,结论才成立.若向量个数不相同,结论不成立. 例如&#xff1a; 向量组一&#xff1a;(1,0),(0,1) 向量组二&#xff1a;(1,0),(0,1),(1,1) 两…...

c语言:指针作为参数传递

探究实参与形参它们相互独立 由于主调函数的变量a&#xff0c;b与被调函数的形参x&#xff0c;y它们相互独立。函数 swap 可以修改变量x&#xff0c;y&#xff0c;但是却无法影响到主调函数中的a&#xff0c;b。 现在利用取地址运算符&#xff0c;分别打印它们的首地址&#x…...

YOLOv5性能评估指标->mAP、Precision、Recall、FPS、Confienc (讲解论文关注的主要指标)

简介 这篇博客&#xff0c;主要给大家讲解我们在训练yolov5时生成的结果文件中各个图片及其中指标的含义&#xff0c;帮助大家更深入的理解&#xff0c;以及我们在评估模型时和发表论文时主要关注的参数有那些。本文通过举例训练过程中的某一时间的结果来帮助大家理解&#xf…...

陶建辉在 CIAS 2023 谈“新能源汽车的数字化”

近年&#xff0c;中国的新能源汽车发展迅猛&#xff0c;在全球竞争中表现出色&#xff0c;已经连续 8 年保持全球销量第一。在新兴技术的推动下&#xff0c;新能源汽车的数字化转型也正在加速进行&#xff0c;从汽车制造到能源利用、人机交互&#xff0c;各个环节都在进行数字化…...

PSP - 结构生物学中的机器学习 (NIPS MLSB Workshop 2023.12)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135120094 Machine Learning in Structural Biology (机器学习在结构生物学中) 网址&#xff1a;https://www.mlsb.io/ Workshop at the 37th Co…...

某领先的集成电路研发中心:建立跨网交换平台 杜绝数据泄露风险

1、客户介绍 某技术领先的集成电路研发中心&#xff0c;是产学研合作的国家级集成电路研发中心&#xff0c;致力于解决重大共性技术的研发及服务支撑问题。该中心积极探索国际化道路&#xff0c;不断提升国际影响力&#xff0c;与多家国际著名集成电路企业和研发机构建立技术合…...

map|动态规划|单调栈|LeetCode975:奇偶跳

作者推荐 【贪心算法】【中位贪心】.执行操作使频率分数最大 涉及知识点 单调栈 动态规划 map 题目 给定一个整数数组 A&#xff0c;你可以从某一起始索引出发&#xff0c;跳跃一定次数。在你跳跃的过程中&#xff0c;第 1、3、5… 次跳跃称为奇数跳跃&#xff0c;而第 2、…...

从安全性角度,看“可信数字底座”有何价值

文章目录 每日一句正能量前言概念对比安全技术对比思考与建议 每日一句正能量 不管现在有多么艰辛&#xff0c;我们也要做个生活的舞者。 前言 万向区块链此前提出“可信数字底座”这一概念和技术&#xff0c;即将区块链与物联网、人工智能、隐私计算等数字化技术相融合&#…...

软件设计模式:UML类图

文章目录 前言一、&#x1f4d6;设计模式概述1.软件设计模式的产生背景2.软件设计模式3.设计模式分类 二、&#x1f4e3;UML图1.类图概述2.类的表示法3.类与类之间的关系关联关系&#xff08;1&#xff09;单向关联&#xff08;2&#xff09;双向关联&#xff08;3&#xff09;…...

力扣题目学习笔记(OC + Swift)15. 三数之和

15. 三数之和 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请 你返回所有和为 0 且不重复的三元组。 注意&#xff1a;答案中不可以包含重复的三元…...

想将电脑屏幕共享到iPhone上,但电脑是Linux系统,可行吗?

常见Windows系统或macOS系统的电脑投屏到手机&#xff0c;难道Linux系统的电脑要投屏就是个难题吗&#xff1f; 想要将Linux系统投屏到iPhone、iPad、安卓设备、鸿蒙设备&#xff0c;其实你可以利用软件AirDroid Cast和Chrome浏览器&#xff01;连接同一网络就可以直接投屏。 第…...

大华 DSS 城市安防数字监控系统 SQL 注入漏洞

漏洞简介 大华DSS数字监控系统itcBulletin接口对传入的数据没有预编译和充足的校验&#xff0c;导致该接口存在SQL注入漏洞&#xff0c;可通过注入漏洞获取数据库敏感信息。 资产测绘 app“dahua-DSS” 漏洞复现 POC: POST /portal/services/itcBulletin?wsdl HTTP/1.1 H…...

vue中的侦听器和组件之间的通信

目录 一、侦听器 监听基本数据类型&#xff1a; 监听引用数据类型&#xff1a; 计算属性和watch区别&#xff1f; 二、组件通信/传值方式 1.父子组件传值 父组件给子组件传值&#xff1a; &#xff08;1&#xff09;props &#xff08;2&#xff09;provide inject &…...

maven-shade-plugin有什么用

maven-shade-plugin 是 Maven 的一个插件&#xff0c;用于创建可执行的 JAR 文件&#xff0c;并且可以将所有依赖项打包到一个 JAR 文件中。 该插件的主要用途是创建包含所有依赖项的“fat” JAR&#xff08;也称为“uber” JAR&#xff09;&#xff0c;使得应用程序可以作为一…...

本地部署 OpenVoice

本地部署 OpenVoice OpenVoice 介绍Qwen-Audio Github 地址部署 OpenVoice克隆代码库创建虚拟环境使用 pip 安装 pytorch使用 pip 安装依赖下载 checkpoint运行 Web UI OpenVoice 介绍 通过 MyShell 进行即时语音克隆。 Qwen-Audio Github 地址 https://github.com/myshell-…...

【模式识别】解锁降维奥秘:深度剖析PCA人脸识别技术

​&#x1f308;个人主页&#xff1a;Sarapines Programmer&#x1f525; 系列专栏&#xff1a;《模式之谜 | 数据奇迹解码》⏰诗赋清音&#xff1a;云生高巅梦远游&#xff0c; 星光点缀碧海愁。 山川深邃情难晤&#xff0c; 剑气凌云志自修。 目录 &#x1f30c;1 初识模式识…...

大模型赋能“AI+电商”,景联文科技提供高质量电商场景数据

据新闻报道&#xff0c;阿里巴巴旗下淘天集团和国际数字商业集团都已建立完整的AI团队。 淘天集团已经推出模特图智能生成、官方客服机器人、万相台无界版等AI工具&#xff0c;训练出了自己的大模型产品 “星辰”&#xff1b; 阿里国际商业集团已成立AI Business&#xff0c;…...

VSCode界面突然变英文了?别慌,一分钟教你切回中文(附快捷键和常见问题解决)

VSCode界面突然变英文了&#xff1f;别慌&#xff0c;一分钟教你切回中文&#xff08;附快捷键和常见问题解决&#xff09; 早上打开VSCode准备写代码&#xff0c;突然发现所有菜单和按钮都变成了英文&#xff1f;这种突如其来的"国际化"体验确实让人措手不及。别担…...

5分钟快速上手:如何用Video2X免费AI工具让老旧视频焕发4K新生

5分钟快速上手&#xff1a;如何用Video2X免费AI工具让老旧视频焕发4K新生 【免费下载链接】video2x A machine learning-based video super resolution and frame interpolation framework. Est. Hack the Valley II, 2018. 项目地址: https://gitcode.com/GitHub_Trending/v…...

AI工具导航与实战指南:从分类体系到选型策略

1. 项目概述&#xff1a;AI-Infinity&#xff0c;一个前沿AI工具的探索者指南如果你和我一样&#xff0c;对AI领域层出不穷的新工具感到既兴奋又头疼&#xff0c;那么这个项目绝对值得你花时间深入了解。AI-Infinity&#xff0c;这个由开发者meetpateltech维护的GitHub仓库&…...

移动通信浪潮如何重塑半导体产业格局:从高通与英特尔市值对比说起

1. 从市场估值看产业浪潮&#xff1a;移动通信如何重塑半导体格局2013年春天&#xff0c;一则消息在半导体和投资圈内引发了不小的震动&#xff1a;无线通信芯片巨头高通&#xff08;Qualcomm&#xff09;的市值&#xff0c;悄然与行业传统霸主英特尔&#xff08;Intel&#xf…...

绩效考核的量化迷思:如何衡量不可直接测量的技术贡献

一、量化绩效考核的困境&#xff1a;软件测试的“隐形”价值在软件行业的绩效考核体系中&#xff0c;量化指标似乎成了“公平”与“高效”的代名词。代码行数、Bug数量、测试用例覆盖率……这些清晰可统计的数字&#xff0c;被当作衡量技术人员贡献的核心标尺。然而&#xff0c…...

90%的程序员都不知道,转大模型根本不用从头学深度学习

文章目录前言一、大模型时代&#xff0c;传统深度学习的学习路径已经彻底过时了1.1 以前做AI&#xff0c;确实得先学深度学习1.2 现在做AI&#xff0c;更像是开汽车1.3 90%的大模型岗位&#xff0c;根本不需要深度学习底层知识二、90%的大模型开发工作&#xff0c;到底在做什么…...

Docker Hub命令行工具hub-tool:镜像仓库自动化管理的终极利器

1. 项目概述&#xff1a;一个被低估的Docker Hub命令行利器 如果你日常工作中需要和Docker Hub打交道&#xff0c;无论是管理个人镜像、处理团队仓库&#xff0c;还是需要自动化镜像的推送、拉取和清理&#xff0c;那么你很可能已经受够了在浏览器和命令行之间反复横跳的繁琐。…...

深入解析:parseInt 到底有几个参数?

&#x1f522; 深入解析&#xff1a;parseInt 到底有几个参数&#xff1f; &#x1f914; parseInt 的签名 parseInt 函数接收 两个 参数&#xff1a; parseInt(string, radix)string (必填)&#xff1a;要被解析的值。如果参数不是字符串&#xff0c;会先转换为字符串。rad…...

Windows 11终极优化指南:一键清理系统臃肿,免费提升51%性能

Windows 11终极优化指南&#xff1a;一键清理系统臃肿&#xff0c;免费提升51%性能 【免费下载链接】Win11Debloat A simple, lightweight PowerShell script that allows you to remove pre-installed apps, disable telemetry, as well as perform various other changes to …...

AI建站工具推荐:能建站只是开始,实测“全链路变现”才是关键

AI建站工具推荐&#xff1a;能建站只是开始&#xff0c;实测“全链路变现”才是关键 【引言&#xff1a;95%的建站工具都搞错了一件事】 最近我们拆解了市面上17款AI建站工具&#xff0c;发现一个扎心的数据&#xff1a; 超过80%的外贸网站&#xff0c;在上线3个月后依然没有…...