当前位置: 首页 > 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;是计算机系统中用于管理和控制设备与主…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

AtCoder 第409​场初级竞赛 A~E题解

A Conflict 【题目链接】 原题链接&#xff1a;A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串&#xff0c;只有在同时为 o 时输出 Yes 并结束程序&#xff0c;否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

CocosCreator 之 JavaScript/TypeScript和Java的相互交互

引擎版本&#xff1a; 3.8.1 语言&#xff1a; JavaScript/TypeScript、C、Java 环境&#xff1a;Window 参考&#xff1a;Java原生反射机制 您好&#xff0c;我是鹤九日&#xff01; 回顾 在上篇文章中&#xff1a;CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

AI语音助手的Python实现

引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...