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

news2024/11/18 20:40:13

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

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

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;
}

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

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

相关文章

【Flink-CDC】Flink CDC 介绍和原理概述

【Flink-CDC】Flink CDC 介绍和原理概述 1&#xff09;基于查询的 CDC 和基于日志的 CDC2&#xff09;Flink CDC3&#xff09;Flink CDC原理简述4&#xff09;基于 Flink SQL CDC 的数据同步方案实践4.1.案例 1 : Flink SQL CDC JDBC Connector4.2.案例 2 : CDC Streaming ETL…

【Redis】三种集群模式(主从复制、哨兵模式、Cluster)

前言 redis有三种集群模式&#xff0c;其中主从是最常见的模式。Sentinel 哨兵模式是为了弥补主从复制集群中主机宕机后&#xff0c;主备切换的复杂性而演变出来的。哨兵顾名思义&#xff0c;就是用来监控的&#xff0c;主要作用就是监控主从集群&#xff0c;自动切换主备&…

Excel表格的快速动态扩展与删除行

实例需求&#xff1a;工作表中的表格&#xff08;ListObject&#xff09;名称为Table1&#xff0c;表格列数不确定&#xff0c;需要实现如下功能&#xff1a; 当用户完成最后一行最后一列输入之后&#xff08;如果该单元格为空&#xff0c;则视为输入未完成&#xff09;&#…

Golang个人web框架开发-学习流程

Golang-个人web框架 github仓库创建github仓库 web框架学习开发周期第一阶段--了解第一阶段思考小结 第二阶段第三阶段 github仓库 github地址&#xff1a;ameamezhou/golang-web-frame 后续还将继续学习更新 创建github仓库 设置免密登录 ssh-keygen 一路回车就OK 上面有告…

x-www-form-urlencoded接收方式代码示例

数据回推方式是 “x-www-form-urlencoded”&#xff0c;可以选择使用 GET 或 POST 方法来接收数据回推。 使用 GET 方法接收数据回推时&#xff0c;您可以将数据作为查询参数附加在请求的 URL 中。例如&#xff1a; http://example.com/callback?param1value1&param2val…

Vue3使用

1、列表实现 <el-table :data"tableData" border style"width: 100%" selection-change"handleSelectionChange" :header-cell-style"{text-align:center}"><el-table-column type"selection" width"55"…

JAVA——数据类型与运算符

数据类型 注意事项&#xff1a;1.初始化操作是可选的, 但是建议创建变量的时候都显式初始化. 2.最后不要忘记分号, 否则会编译失败. 3.初始化设定的值为 10L , 表示一个长整型的数字. 10l 也可以. 4.float 类型在 Java 中占四个字节, 遵守 IEEE 754 标准. 由于表示的数据精度范…

广东金牌电缆:法大大电子合同助力业务风险管控

广东金牌电缆集团股份有限公司&#xff08;以下简称“广东金牌电缆”&#xff09;成立于2013年&#xff0c;现为广东省电线电缆重点生产企业、广东省守合同重信用单位、国家专精特新小巨人企业、国家高新技术企业&#xff0c;拥有自主商标“夺冠”&#xff0c;“夺冠”商标被评…

P4学习(五)实验二:Basic Tunneling

目录 一. 实验目的二. 实验过程1. Topo2. Parse3.Ingress 三. 实验结果1. 测试dst_addr 10.0.2.2的正常包2.测试走隧道的正常包3.发给h3但是带上隧道标签的包4.测试总结 四. 拓展1.table-entries里的匹配规则2.myTunnel_header.py 一. 实验目的 In this exercise, we will add…

“一键中日文件夹名转换 - 批量修改,轻松实现中文到日语的名称翻译“

在处理大量文件夹时&#xff0c;你是否曾为中日文件夹名称的转换而感到困扰&#xff1f;现在&#xff0c;有了我们的批量修改工具&#xff0c;这些烦恼全部消失&#xff01;只需简单几步&#xff0c;就能将中文名的文件夹名称翻译成日语&#xff0c;让你的文件管理更加高效。 …

最新企业数据实时同步软件推荐

实时同步软件能够帮助企业快速、准确地共享和更新数据&#xff0c;提高工作效率和决策质量。本文将介绍企业数据实时同步的概念、意义和应用场景&#xff0c;并推荐几款非常优秀的企业数据实时同步软件。 一、数据实时同步的意义 企业数据实时同步是指在企业内部或跨部门之间&…

13 STM32-随机数发生器 (RNG)

13.1 随机数发生器 (RNG)简介 RNG 处理器是一个以连续模拟噪声为基础的随机数发生器&#xff0c;在主机读数时提供一个 32 位的随机数. RNG 提供由模拟量发生器产生的 32 位随机数,两个连续随机数的间隔为 40 个 PLL48CLK 时钟信号周期 13.2 RNG框图 随机数发生器采用模拟电路…

多目标优化(Python):多目标粒子群优化算法(MOPSO)求解ZDT1、ZDT2、ZDT3、ZDT4、ZDT6(提供Python代码)

一、多目标粒子群优化算法 多目标粒子群优化算法&#xff08;MOPSO&#xff09;是一种用于解决多目标优化问题的进化算法。它基于粒子群优化算法&#xff08;PSO&#xff09;&#xff0c;通过引入多个目标函数和非支配排序来处理多目标问题。 MOPSO的基本思想是将问题转化为在…

React配置src根目录@

文章目录 1.打开webpack配置文件2.配置webpack 1.打开webpack配置文件 yarn eject or npm run eject 如果报错了记得提前 git commit一下 2.配置webpack 找到 webpack.config.js 文件在 webpack.config.js 文件中找到 alias 配置在alias里添加: path.resolve(src) , 或者 : pa…

文本按照标点符号切分符号丢掉问题

问题&#xff1a;文本按照标点符号切分符号丢掉问题 项目场景&#xff1a;需要对一个文字段落按照标点符号切分成一个个句子&#xff0c;使用正则切分的过程中发现标点符号丢了&#xff0c; 问题描述 文本按照标点符号切分符号丢掉问题 原始代码&#xff1a; public static v…

在分类任务中准确率(accuracy)、精确率(precision)、召回率(recall)和 F1 分数是常用的性能指标,如何在python中使用呢?

在机器学习和数据科学中&#xff0c;准确率&#xff08;accuracy&#xff09;、精确率&#xff08;precision&#xff09;、召回率&#xff08;recall&#xff09;和 F1 分数是常用的性能指标&#xff0c;用于评估分类模型的性能。 1. 准确率&#xff08;Accuracy&#xff09;…

ChatGPT Plus续费充值,到账延迟,如何申诉?

ChatGPT Plus充值总是到账延迟比较严重&#xff0c;一般多是通过充值链接代充值遇到&#xff0c;如果是账号登陆充值&#xff0c;是即时到账。但是有的客户不愿意提供账号密码&#xff0c;遇到延迟到账的情况如何解决呢&#xff1f;客户可按下面操作申诉&#xff0c;可快速到账…

大创项目推荐 深度学习花卉识别 - python 机器视觉 opencv

文章目录 0 前言1 项目背景2 花卉识别的基本原理3 算法实现3.1 预处理3.2 特征提取和选择3.3 分类器设计和决策3.4 卷积神经网络基本原理 4 算法实现4.1 花卉图像数据4.2 模块组成 5 项目执行结果6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &a…

Ansys Zemax | 如何使用光学制造全息图修正像差

附件下载 联系工作人员获取附件 本文介绍了利用光学全息图降低单透镜像差的方法。在描述了表示全息图构造光束的两个 ZMX 文件之后&#xff0c;本文演示了如何在重现文件中设置 OFH。然后解释了如何轻松地从重现文件中访问任何结构造光束变量&#xff0c;以实现衍射受限单透镜…

Git一台电脑 配置多个账号

Git一台电脑 配置多个账号 Git一台电脑 配置多个账号 常用的Git版本管理有 gitee github gitlab codeup &#xff0c;每个都有独立账号&#xff0c;经常需要在一个电脑上向多个代码仓提交后者更新代码&#xff0c;本文以ssh 方式为例配置 1 对应账号 公私钥生成 建议&#…