C++中特殊类的设计与单例模式的简易实现

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

对于这种特殊类的设计我们一般都是优先考虑私有构造函数。然后对于一些特殊要求就直接通过静态成员函数的实现来完成。

class A//构造函数私有(也可以析构函数私有)
{
public:
	static A* creat()
	{
		return new A;
	}
private:
	A()
	{}
	A(const A&) = delete;
	A operator=(const A&) = delete;
	int _a;
};

 这里选择禁掉拷贝构造函数和拷贝函数是为了防止将已创建的对象去拷贝构造新的对象。

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

class B
{
public:
	static B creat()
	{
        B tmp;
		return tmp;
	}
	//直接禁掉new和delete
	//全局也有,类中也有,会优先调用类中的operator new(类中专属的)
	void* operator new(size_t size) = delete;
	void operator delete(void* p) = delete;
private:
	B()
	{}
	int _b;
};

 这里如果没有禁掉operator new和operator delete的话就会导致以下情况是在栈上创建对象

B* pb = new B(B::creat());//会调用拷贝构造

对于这种new一个对象的情况下是会调用拷贝构造函数的 ,而且我们是不能直接禁掉拷贝构造函数的,因为我们创建的对象必须通过调用拷贝构造函数来接受,所以就有了禁掉operator new和operator delete的方式。

对于在类中禁掉这两个函数,我们需要了解:当我们类中实现了operator new和operator delete这两个函数的话,在我们new该类对象或delete该类对象的话就会调用该类的operator new和operator delete函数,而不会选择调用全局的operator new和operator delete函数。

设计一个不能被继承的类

class D final
{
	D()//私有构造也可以
	{}
};

这里需要认识一个关键词final,该关键词修饰得类会不允许被继承。 

而且还有一点,我们知道继承一个类之后,子类创建对象会调用父类的构造函数,如果父类没有默认的构造函数的话,子类必须要显示的调用父类的构造函数。

设计一个只能创建一个对象的类(单例模式)

单例模式:一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
单例模式有以下两种实现方式:

饿汉模式

饿汉模式就是不管你用不用该实例,系统在启动程序时就会直接创建一个唯一的实例。

class A
{
	A(const A& tmp) = delete;//禁掉拷贝构造,防止再次创建对象
	A& operator=(const A& tmp) = delete;

public:
	static A& getinstance()//通过成员函数得到该对象
	{
		return sigle;
	}
	void Add(string s1, string s2)
	{
		_dict[s1] = s2;
	}
	void Print()
	{
		for (auto tmp : _dict)
		{
			cout << tmp.first << ":" << tmp.second << endl;
		}
	}

private:
	A()//只能创建一个对象,构造私有
	{
		cout << "构造完成" << endl;
	}

	map<string, string> _dict;
	static A sigle;//声明 类里面静态成员可以直接调用私有函数
};
A A::sigle;//定义(此时已经调用好了构造函数)

对于单例模式一般就是在类中提前声明好该静态对象 所以在定义自定义类型的的时候就会直接调用构造函数。而这sigle对象就是我们所创建的唯一实例。 

懒汉模式

懒汉模式就是在你开始调用的时候才会创建对象。

class B
{
	B(const B& tmp) = delete;//禁掉拷贝构造,防止再次创建对象
	B& operator=(const B& tmp) = delete;
public:
	static B* getinstance()
	{
		if (sigle == nullptr)//只有为空才创建
			sigle = new B;//一般不需要释放,进程结束的时候会释放
		return sigle;
	}
	static void del()
	{
		delete sigle;//为空就不会再调用析构函数
		sigle = nullptr;
	}
	void Add(string s1, string s2)
	{
		_dict[s1] = s2;
	}
	void Print()
	{
		for (auto tmp : _dict)
		{
			cout << tmp.first << ":" << tmp.second << endl;
		}
	}
private:
	B()//只能创建一个对象,构造私有
	{
		cout << "构造完成" << endl;
	}
	
	~B()
	{
		//持久化:要求数据写到文件中
		cout << "数据录入文件中 并析构" << endl;
	}
	map<string, string> _dict;
	static B* sigle;

	//内部类是外部类的友元
	class gc//类似智能指针,程序结束前调用析构
	{
	public:
		gc()
		{
			cout << "gc()" << endl;
		}
		~gc()
		{
			del();
		}
	};
	static gc _gc;//声明  创建静态成员,属于一个类,不会创建多份
	//程序结束前就会自动调用gc析构函数
	
};
B* B::sigle = nullptr;//初始化为空
B::gc B::_gc;//定义  main结束会调用构造

对于懒汉模式和饿汉模式本质区别就是对象和指针的转变,饿汉模式的唯一实例是一个静态的类指针,但是该指针的释放就会有点困难,需要我们手动去delete,其实进程结束也是会释放内存的,但是对于一些需要持久化的将数据写到文件的情况时就会采用内部类gc来解决(内部类是外部类的友元,可以访问外部类的所有成员)而同样在外部类中创建静态成员,类外进行定义(调用构造),所以当main函数结束前,对于自定义的该成员就会自动调用析构函数,此时就可以进行持久化处理。

对于以上代码如果_gc不设为外部类的静态成员而是一般成员的话,就会陷入循环析构,因为对于外部类来说_gc属于类的自定义成员,所以当调用外部类的析构时就会先调用自生的析构函数再调用自定义成员_gc的析构函数,此时就会造成循环析构的情况。

int main()
{
	B::getinstance()->Add("sort", "排序");
	B::getinstance()->Add("left", "左边");
	B::getinstance()->Print();
	//B::del();

	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

VsCode + CMake构建项目 C/C++连接Mysql数据库 | 数据库增删改查C++封装 | 信息管理系统通用代码 ---- 课程笔记

这个是B站Up主&#xff1a;程序员程子青的视频 C封装Mysql增删改查操作_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1m24y1a79o/?p6&spm_id_frompageDriver&vd_sourcea934d7fc6f47698a29dac90a922ba5a3安装mysql:mysql 下载和安装和修改MYSQL8.0 数据库存储…

2023 年,我患上了 AI 焦虑症!

【作者有话说】2023 年对我来说是神奇的一年&#xff0c;我意外地从一个程序员变成了一个 AI 资讯届的“网红”&#xff0c;到年底时我在 X 平台的阅读量超过 1 亿&#xff0c;微博上的阅读量则超过 10 亿&#xff0c;很多人通过我的微博或者 X 了解最新的 AI 资讯、教程和 Pro…

C#,字符串匹配(模式搜索)Sunday算法的源代码

Sunday算法是Daniel M.Sunday于1990年提出的一种字符串模式匹配算法。 核心思想&#xff1a;在匹配过程中&#xff0c;模式串并不被要求一定要按从左向右进行比较还是从右向左进行比较&#xff0c;它在发现不匹配时&#xff0c;算法能跳过尽可能多的字符以进行下一步的匹配&…

多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现CNN-BiLSTM-Mutilhead-Attention卷积双向长短期记忆神经网络融合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计…

scipy测试数据

文章目录 图像心电图 图像 scipy的datasets中提供了几组在图像和信号处理中可能会用到的数据&#xff0c;但是&#xff0c;如果想顺利使用&#xff0c;还需要安装一个scipy的依赖模块pooch pip install pooch然后就可以加载这几种数据了 from scipy.datasets import ascent,…

云服务器搭建coturn出现Not reachable?

文章目录 问题复现解决方案1. 云服务器端口开放问题2. 检查配置文件3. 浏览器 问题解决 问题复现 使用云服务器搭建coturn服务时&#xff0c;出现not reachable报错 ICE Server配置是正确的 但测试relay时却报错&#xff1a;not reachable? 并且服务器也没输出相应日志。 …

Windows命令大全

文章目录 1. 文件和目录管理2. 系统信息查询3. 系统维护与修复4. 网络相关5. PowerShell 命令6. 用户管理7. 进程和服务管理8. 文件搜索与查找9. 时间和日期操作10. 注册表操作 Windows系统命令非常丰富&#xff0c;涵盖了操作系统管理、文件操作、网络配置、系统维护等诸多方面…

Java网络编程——UDP通信原理

一、TCP和UDP概述 传输层通常以TCP和UDP协议来控制端点与端点的通信 TCPUDP协议名称传输控制协议用户数据包协议是否连接面向连接的协议。数据必须要建立连接无连接的协议&#xff0c;每个数据报中都给出完整的地址信息&#xff0c;因此不需要事先建立发送方和接受方的连接是…

FPGA 多路分频器实验

1 概述 在 FPGA 中&#xff0c;时钟分频是经常用到的。本节课讲解 2 分频、3 分频、4 分频和 8 分频的 Verilog 实现并且学习 generate 语法功能的应。 2 程序设计思路 1&#xff09;整数倍分频&#xff0c;为 2、4、8&#xff0c;这种 2^n 次方倍数倍数关系的…

记一次DateTimeFormat注解的坑

记一次DateTimeFormat注解的坑 背景&#xff1a;在用Echarts做图表时&#xff0c;前端传两个日期参数&#xff0c;获取日期区间的图表数据。想遵循RESTful风格&#xff0c;所以使用get请求获取date参数。前端读取当前日期&#xff0c;将七天前日期和当前日期作为参数传给后端&…

享元模式介绍

目录 一、享元模式介绍 1.1 享元模式定义 1.2 享元模式原理 1.2.1 享元模式类图 1.2.2 模式角色说明 1.2.3 示例代码 二、享元模式的应用 2.1 需求说明 2.2 需求实现 2.2.1 类图 2.2.2 具体实现 2.2.2.1 抽象享元类 2.2.2.2 共享享元类-白色棋子 2.2.2.3 共享享元…

JAVA SECS发送Report C#处理SECS Report SECS发送事件资料大全 S6F11 建立通讯S1F13

发送S6F11非常简单&#xff0c;只需5~6行代码&#xff0c;最核心是代码清晰易懂。 任何人都可以一看就能上手&#xff0c;如果说用代码可读性作为不可替代性的壁垒就无话可说了。 private void buttonS6F11_Click(object sender, EventArgs e) {int nTransaction 0;// 数据部…

Rust之旅 - Rust概念、Windows安装、环境配置

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列专栏目录 [Java项目…

【SpringBoot】SpringBoot 项目初始化方法

github 搜索 springboot 模板 github 搜索 springboot 模板&#xff0c;拉取现成代码。 SpringBoot 官方的模板生成器 SpringBoot 官方的模板生成器&#xff08;https://start.spring.io/&#xff09; 在 IDEA 开发工具中生成 这里我修改成阿里的镜像主要是要使用 Java8。 …

制作一个Python聊天机器人

我们学习一下如何使用 ChatterBot 库在 Python 中创建聊天机器人&#xff0c;该库实现了各种机器学习算法来生成响应对话&#xff0c;还是挺不错的 什么是聊天机器人 聊天机器人也称为聊天机器人、机器人、人工代理等&#xff0c;基本上是由人工智能驱动的软件程序&#xff0…

最多购买宝石数目 - 华为OD统一考试

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 橱窗里有一排宝石&#xff0c;不同的宝石对应不同的价格&#xff0c;宝石的价格标记为 gems[i],0<i<n, n gems.length 宝石可同时出售0个或多个&#xff…

test2测试

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 磁盘满的本质分析 专栏&#xff1a;《Linux从小白到大神》 | 系统学习Linux开发、VIM/GCC/GDB/Make工具…

如何发挥 Sketch在UI和UX设计中的作用

Sketch是一款专业的矢量图形设计软件&#xff0c;主要应用于UI设计、移动应用设计、Web设计等领域。假如你是一个交互设计师或UI设计师&#xff0c;那么你一定知道Sketch这一强大的矢量设计软件&#xff1b;如果你使用了Photoshop&#xff0c;那么在你接触到Sketch之后&#xf…

物联网协议Coap之C#基于Mozi的CoapServer实现解析

目录 前言 一、C#的Coap Server实现 1、CoapServer相关类 2、主要类解析 3、资源控制器定义 4、ResourceManager管理器 二、CoapServer生命周期 1、Server创建代码 2、服务端创建 3、绑定endpoint 4、准备接收请求 总结 前言 在之前的关于物联网协议的介绍中&#…

汽车连接器接线端子和多芯线束连接界面

冷压接的开式压接和闭式压接以及热压接的超声波焊接对汽车连接器接线端子和多芯线束连接界面 连接器接线端子和多芯线束的连接是电子线束行业&#xff0c;特别是汽车行业常用的导线连接方式。汽车整车线束又由许多分支线束组成&#xff0c;而分支线束必须通过连接器实现连接&am…