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

C++特殊类设计(单例模式等)

目录

引言

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

2. 请设计一个类,只能在堆上创建对象

为什么设置实例的方法为静态成员呢

3. 请设计一个类,只能在栈上创建对象

4. 请设计一个类,不能被继承

5. 请设计一个类,只能创建一个对象(单例模式)

饿汉模式

懒汉模式

单例对象一般不考虑析构

为什么私有析构呢?


引言

在当今的软件开发实践中,特殊类设计模式扮演着至关重要的角色,它们不仅提高了代码的可维护性和可扩展性,还确保了系统的稳定性和性能。其中,单例模式作为最常用的设计模式之一,以其独特的实例管理方式,成为了许多场景下的首选解决方案。本文旨在探讨C++中单例模式及其他特殊类设计的精髓,通过分析其背后的设计哲学和实现技巧,帮助读者掌握这些高级编程技巧,以提升其在软件开发过程中的设计能力和代码质量。

在我们设计一个特殊类的时候,一般要把构造、拷贝和赋值私有保护,防止被其他类拷贝或者产生不想要(意料之外)的错误。

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

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,

只需让该类不能调用拷贝构造函数以及赋值运算符重载即可
C++98
将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可。
class CopyBan
{// ...private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};

C++11

C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上
=delete,表示让编译器删除掉该默认成员函数。
class CopyBan
{// ...CopyBan(const CopyBan&)=delete;CopyBan& operator=(const CopyBan&)=delete;//...
};

同时我们还可以设置一个基类,让子类继承基类,让子类正常实现功能,设置基类不可被拷贝即可。

2. 请设计一个类,只能在堆上创建对象

实现方式:
1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
只能在堆上创建对象,即只能new对象,不允许在栈上创建临时变量。当然要禁用拷贝、构造、赋值函数(非单例)
class HeapOnly    
{     
public:     static HeapOnly* CreateObject()  {      return new HeapOnly;    }
private:    HeapOnly() {}// C++98// 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要// 2.声明成私有HeapOnly(const HeapOnly&);// or// C++11    HeapOnly(const HeapOnly&) = delete;
}

由于没有this指针,无法调用构造,而是只是去new这个镀锡,由系统去完成资源的申请


静态不能调用非静态就是因为没有this指针,缺少调用的参数

但是new和delete这种操作不需要this指针

那每次调的时候,返回的都是一个新的静态对象吗?--- NO!这个方法是静态的,但是返回的变量不是静态的

为什么设置实例的方法为静态成员呢

收线确定的是,一定是内部new创建的对象。

因为如果设置为非静态成员,那就只能通过对象去调用,但是我们不能去在栈区创建对象。

并且构造私有,外部一定不可以创建对象,只能用类调用,所以必须静态!

为什么禁用拷贝构造:比如A a1(a2);这样a1依然是在栈区!

3. 请设计一个类,只能在栈上创建对象

只能通过类型创建,禁止new对象

方法一:同上将构造函数私有化,然后设计静态方法创建对象返回即可
依然需要把构造私有,需要注意的是,不能把构造和拷贝工构造私有
class StackOnly
{
public:static StackOnly CreateObj(){StackOnly obj;return obj;}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly()  :_a(0){}
private:int _a;
};

1.设置为静态:

并且构造私有,外部一定不可以创建对象,只能用类调用,所以必须静态!

2.为什么不可以禁用拷贝构造:比如A a1(a2);这样a1依然是在栈区!符合要求,并且匿名对象的声明周期只在这一行!为了防止匿名对象周期太短,无法进行较好的连续性开发,所以需要赋值给另一个栈区的对象。

3.可以返回临时对象,只需要赋值给其他对象即可(栈区);也可以返回非匿名对象,也是采用赋值的方式进行连续性开发。

4.为了防止创建堆区对象,需要禁用new和delete(为了防止创建栈区对象时,需要禁用拷贝、赋值)

        

4. 请设计一个类,不能被继承

C++98方式

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};
C++11方法
final关键字, final修饰类,表示该类不能被继承。
class A  final
{// ....
};

5. 请设计一个类,只能创建一个对象(单例模式)

设计模式:
设计模式(Design Pattern)是一套 被反复使用、多数人知晓的、经过分类的、代码设计经验的
总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打
仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有 套路的,后
来孙子就总结出了《孙子兵法》。孙子兵法也是类似。
使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模
式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。
单例模式:
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个
访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置
信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再
通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有两种实现模式:

饿汉模式

饿汉模式:已经饿得不行了,要求立刻有东西吃,即在main函数之前就得创建好---全局

饿汉:设置为全局,提前创建。

既然是单例,一定先把构造私有。

在类的外部虽然不能创建全局的对象,但是在类的内部可以创建。----思路:类的内部声明静态成员,类的外部定义,这样就是一个全局的数据。

demo
// 懒汉模式:第一次用的时候再创建(现吃现做)
class A {
public:static A* GetInstance() {return _inst;}
private:A() {}map<string, string> _dict;int _n = 0;static A* _inst;
};

我们在类的内部创建对象的时候,当然不能

   class        A

        A   _a;

  }

这样属于嵌套定义。
但是也不能内部用静态成员方法去获取,因为函数需要在主函数内调用。
当我们在内部使用静态成员的时候,当然不是嵌套定义,因为静态不属于某个对象,而是属于整个类。并且,我们只能是在类内声明,并没有定义,需要在类的外部定义。
在类的外部定义的时候,只需要点名:类型 + 作用域即可,不需要再次声明静态,静态只需要声明一次即可,但是定义(实例化),必须使用类型。
当需要使用这个实例的时候,调用实例方法去获取即可。
总结:
1.类内声明静态,类外实例化静态(全局)
2.类内提供获取实例的犯法
同时删除拷贝构造和赋值

访问成员需要借助对象,这时候就需要调用GetInstance函数

优点:创建简单 

缺点:1.进程启动慢

           2.一旦存在两个全局单例,不能控制单例启动的先后顺序。

懒汉模式

现吃现做,不着急,main函数内创建。

  只需要把静态的对象换成指针即可,获取实例的时候,如果指针是nullptr,那么创建,如果不是,那么直接返回

线程不安全,两个线程同时进来,可能会new两个对象---加锁

单例对象一般不考虑析构

恶汉不存在释放的问题--全局,

懒汉对象也一般不需要释放---单例对象一般是生命周期伴随整个程序,对整个程序都起到至关重要的作用,进程结束时,会自动释放。

就算要释放,如果我们期望既可以手动释放(析构不能手动释放),也可以在main函数结束时自动释放

class B
{
public:static B* GetInstance(){if (_inst == nullptr){_inst = new B;}return _inst;}static void DelInstance(){if (_inst){delete _inst;_inst = nullptr;}}private:B(){}~B(){// 持久化:要求把数据写到文件cout << "数据写到文件" << endl;}B(const B& aa) = delete;B& operator=(const B& aa) = delete;map<string, string> _dict;int _n = 0;static B* _inst;class gc{public:~gc(){DelInstance();}};static gc _gc;
};B* B::_inst = nullptr;
B::gc B::_gc;

可以私有析构函数

提供一个调用析构函数的接口DelInstance,我们可以手动调用这个接口去进行析构。

我们新建一个内部类,这个内部类是外部类的友元,可以访问私有。等main函数结束的时候_gc调用析构,析构会调用DelInstance。

这样可以做到:1.显示释放(析构不允许显示调用,但是delete指针的时候,可以调用析构)

                        2.没有显示释放,等程序结束也会释放

为什么私有析构呢?

B* instance = B::GetInstance();
delete instance;

B* instance2 = B::GetInstance();

如果是public的话,每个人可以自己delete这个,那么就违背单例模式的原则了!

而这块放的这个DelInstance函数是意思万一情况下,不使用单例了,自己想释放的话,可以通过这个函数释放,但是一般也不会这样做的,一般gc就替咱们回收了

总之就是:不能让其他人去随便delete单例,所以私有;同时希望gc能够管理单例,等程序结束,gc清理的时候,gc会协助清理单例

相关文章:

C++特殊类设计(单例模式等)

目录 引言 1.请设计一个类&#xff0c;不能被拷贝 2. 请设计一个类&#xff0c;只能在堆上创建对象 为什么设置实例的方法为静态成员呢 3. 请设计一个类&#xff0c;只能在栈上创建对象 4. 请设计一个类&#xff0c;不能被继承 5. 请设计一个类&#xff0c;只能创建一个对…...

J8学习打卡笔记

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 Inception v1算法实战与解析 导入数据数据预处理划分数据集搭建模型训练模型正式训练结果可视化详细网络结构图个人总结 import os, PIL, random, pathlib imp…...

前端学习-操作元素内容(二十二)

目录 前言 目标 对象.innerText 属性 对象.innerHTML属性 案例 年会抽奖 需求 方法一 方法二 总结 前言 曾经沧海难为水&#xff0c;除却巫山不是云。 目标 能够修改元素的文本更换内容 DOM对象都是根据标签生成的,所以操作标签,本质上就是操作DOM对象&#xff0c;…...

【踩坑】pip离线+在线在虚拟环境中安装指定版本cudnn攻略

pip离线在线在虚拟环境中安装指定版本cudnn攻略 在线安装离线安装Windows环境&#xff1a;Linux环境&#xff1a; 清华源官方帮助文档 https://mirrors.tuna.tsinghua.edu.cn/help/pypi/ 标题的离线的意思是先下载whl文件再安装到虚拟环境&#xff0c;在线的意思是直接在当前虚…...

golang操作sqlite3加速本地结构化数据查询

目录 摘要Sqlite3SQLite 命令SQLite 语法SQLite 数据类型列亲和类型——优先选择机制 SQLite 创建数据库SQLite 附加数据库SQLite 分离数据库 SQLite 创建表SQLite 删除表 SQLite Insert 语句SQLite Select 语句SQLite 运算符SQLite 算术运算符SQLite 比较运算符SQLite 逻辑运算…...

vllm加速(以Qwen2.5-7B-instruction为例)与流式响应

1. vllm介绍 什么是vllm? vLLM 是一个高性能的大型语言模型推理引擎&#xff0c;采用创新的内存管理和执行架构&#xff0c;显著提升了大模型推理的速度和效率。它支持高度并发的请求处理&#xff0c;能够同时服务数千名用户&#xff0c;并且兼容多种深度学习框架&#xff0c;…...

WordPress弹窗公告插件-ts小陈

使用效果 使用后网站所有页面弹出窗口 插件特色功能 设置弹窗公告样式&#xff1a;这款插件可展示弹窗样式公告&#xff0c;用户点击完之后不再弹出&#xff0c;不会频繁打扰用户。可设置弹窗中间的logo图&#xff1a;这款插件针对公告图片进行独立设置&#xff0c;你可以在设…...

【ELK】容器化部署Elasticsearch1.14.3集群【亲测可用】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1. 部署1.1 单节点1.2 新节点加入集群1.3 docker-compose部署集群 1. 部署 按照官网流程进行部署 使用 Docker 安装 Elasticsearch |Elasticsearch 指南 [8.14] |…...

[SAP ABAP] ALV状态栏GUI STATUS的快速创建

使用事务码SE38进入到指定程序&#xff0c;点击"显示对象列表"按钮 鼠标右键&#xff0c;选择"GUI状态" 弹出【创建状态】窗口&#xff0c;填写状态以及短文本描述以后&#xff0c;点击按钮 点击"调整模板"&#xff0c;复制已有程序的状态栏 填…...

【Linux】NET9运行时移植到低版本GLIBC的Linux纯内核板卡上

背景介绍 自制了一块Linux板卡(基于全志T113i) 厂家给的SDK和根文件系统能够提供的GLIBC的版本比较低 V2.25/GCC 7.3.1 这个版本是无法运行dotnet以及dotnet生成的AOT应用的 我用另一块同Cortex-A7的板子运行dotnet的报错 版本不够&#xff0c;运行不了 而我的板子是根本就识…...

深入浅出支持向量机(SVM)

1. 引言 支持向量机&#xff08;SVM, Support Vector Machine&#xff09;是一种常见的监督学习算法&#xff0c;广泛应用于分类、回归和异常检测等任务。自1990年代初期由Vapnik等人提出以来&#xff0c;SVM已成为机器学习领域的核心方法之一&#xff0c;尤其在模式识别、文本…...

Vue脚手架相关记录

脚手架 安装与配置 安装node node -> 16.20.2 切换淘宝镜像 npm install -g cnpm -registryhttp://registry.npm.taobao.orgnpm config set registry http://registry.npm.taobao.org/使用了第二个,下一步才有用 安装vue npm install -g vue/clivscode中不给运行vue解…...

基于Docker的Minio分布式集群实践

目录 1. 说明 2. 配置表 3. 步骤 3.1 放行服务端口 3.2 docker-compose 编排 4. 入口反向代理与负载均衡配置 4.1 api入口 4.2 管理入口 5. 用例 6. 参考 1. 说明 以多节点的Docker容器方式实现minio存储集群&#xff0c;并配以nginx反向代理及负载均衡作为访问入口。…...

Scala 的迭代器

迭代器定义&#xff1a;迭代器不是一种集合&#xff0c;它是一种用于访问集合的方法。 迭代器需要通过集合对应的迭代器调用迭代器的方法来访问。 支持函数式编程风格&#xff0c;便于链式操作。 创建一个迭代器&#xff0c;相关代码如下&#xff1a; object Test {def mai…...

vue实现文件流形式的导出下载

文章目录 Vue 项目中下载返回的文件流操作步骤一、使用 Axios 请求文件流数据二、设置响应类型为 ‘blob’三、创建下载链接并触发下载四、在 Vue 组件中集成下载功能五、解释与实例说明1、使用 Axios 请求文件流数据&#xff1a;设置响应类型为 blob&#xff1a;创建下载链接并…...

【DIY飞控板PX4移植】深入理解NuttX下PX4串口配置:ttyS设备编号与USARTUART对应关系解析

深入理解NuttX下PX4串口配置&#xff1a;ttyS设备编号与USART&UART对应关系解析 引言问题描述原因分析结论 引言 在嵌入式系统开发中&#xff0c;串口&#xff08;USART/UART&#xff09;的配置是一个常见但关键的任务。对于使用 NuttX 作为底层操作系统的飞控系统&#x…...

【报错解决】vsvars32.bat 不是内部或外部命令,也不是可运行的程序或批处理文件

报错信息&#xff1a; 背景问题&#xff1a;Boost提示 “cl” 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件时&#xff0c;   按照这篇博客的方法【传送】添加了环境变量后&#xff0c;仍然报错&#xff1a; 报错原因&#xff1a; vsvars32.bat 的路径不正…...

CTFshow-文件上传(Web151-170)

CTFshow-文件上传(Web151-170) 参考了CTF show 文件上传篇&#xff08;web151-170&#xff0c;看这一篇就够啦&#xff09;-CSDN博客 Web151 要求png&#xff0c;然后上传带有一句话木马的a.png&#xff0c;burp抓包后改后缀为a.php&#xff0c;然后蚁剑连接&#xff0c;找fl…...

深度学习基础--将yolov5的backbone模块用于目标识别会出现怎么效果呢??

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 yolov5网络结构比较复杂&#xff0c;上次我们简要介绍了yolov5网络模块&#xff0c;并且复现了C3模块&#xff0c;深度学习基础–yolov5网络结构简介&a…...

操作系统(16)I/O软件

前言 操作系统I/O软件是负责管理和控制计算机系统与外围设备&#xff08;例如键盘、鼠标、打印机、存储设备等&#xff09;之间交互的软件。 一、I/O软件的定义与功能 定义&#xff1a;I/O软件&#xff0c;也称为输入/输出软件&#xff0c;是计算机系统中用于管理和控制设备与主…...

三维GIS开发cesium智慧地铁教程(5)Cesium相机控制

一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点&#xff1a; 路径验证&#xff1a;确保相对路径.…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计

随着大语言模型&#xff08;LLM&#xff09;参数规模的增长&#xff0c;推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长&#xff0c;而KV缓存的内存消耗可能高达数十GB&#xff08;例如Llama2-7B处理100K token时需50GB内存&a…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

【7色560页】职场可视化逻辑图高级数据分析PPT模版

7种色调职场工作汇报PPT&#xff0c;橙蓝、黑红、红蓝、蓝橙灰、浅蓝、浅绿、深蓝七种色调模版 【7色560页】职场可视化逻辑图高级数据分析PPT模版&#xff1a;职场可视化逻辑图分析PPT模版https://pan.quark.cn/s/78aeabbd92d1...

uniapp手机号一键登录保姆级教程(包含前端和后端)

目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号&#xff08;第三种&#xff09;后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

mcts蒙特卡洛模拟树思想

您这个观察非常敏锐&#xff0c;而且在很大程度上是正确的&#xff01;您已经洞察到了MCTS算法在不同阶段的两种不同行为模式。我们来把这个关系理得更清楚一些&#xff0c;您的理解其实离真相只有一步之遥。 您说的“select是在二次选择的时候起作用”&#xff0c;这个观察非…...

Qt学习及使用_第1部分_认识Qt---Qt开发基本流程

前言 学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面. 参考书:<Qt 6 C开发指南>(以下称"本书") 标识说明:概念用粗体倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字), 本书原话内容用深蓝色标识,比较重要的内容用加粗倾…...