C++ 特殊类的实现

news2024/11/27 10:44:25

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

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

 在C++98中:将拷贝构造函数与赋值运算符重载只声明不定义,并且将其访问权限设置为私有即可禁止拷贝。

原因:

  1. 设置成私有:如果声明了但是没有设置成private,用户就可以在类外面进行定义,就不能禁止拷贝了。
  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了,但一定要声明,不然会默认生成。

代码示例:

class CopyBan
{
	// ...
private:
	CopyBan(const CopyBan& cb);
	CopyBan& operator=(const CopyBan& cb);
	//...
};

 C++11做法C++11扩展delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。

  代码示例:

class CopyBan
{
public:
    CopyBan(int x = 1)
        :_x(x)
    {}
    CopyBan(const CopyBan&) = delete;
    CopyBan& operator=(const CopyBan&) = delete;

private:
    int _x;
};

int main() {
    CopyBan a(1);
    CopyBan b(a);
    CopyBan b=a;
	return 0;
}

显示函数被删除:

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

实现方式一:析构函数私有化

原因:

   因为在栈上和静态区的对象需要自动调用析构函数,而析构函数无法调用了,就会导致我们程序出现问题,编译器检测出来这个问题,使我们无法在栈上和静态区创建对象。

 因为堆上的对象是需要我们手动的创建和删除的,所以在堆上创建对象只先调用构造函数; 如果我们需要对堆上创建的对象进行销毁,我们可以提供一个公有函数接口,用这个函数接口调用私有函数。

代码如下:
 

class HeapOnly
{
public:

	void Destroy()
	{
		delete this;
	}
private:
	~HeapOnly()
	{
		cout << "~HeapOnly()" << endl;
	}
};

方案二:构造函数私有化

实现方式:

  1. 将类的构造函数私有,拷贝构造声明成私有或delete,防止别人调用拷贝在栈上生成对象
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
class HeapOnly
{
public:
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}

private:

	//C++98
	//HeapOnly(const HeapOnly& hp);
	
	//C++11
	HeapOnly(const HeapOnly& hp) = delete;

	HeapOnly()
	{
		cout << "HeapOnly()" << endl;
	}
};

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

 实现方式:将构造函数私有化,然后设计静态方法创建对象返回。

class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		StackOnly obj;
		return obj;
	}

	void* operator new(size_t size) = delete;

	// 实现类专属的operator new
	// new这个类对象时,operator new就会调用这个,不会调全局的

private:
	StackOnly()
	{
		cout << "StackOnly()" << endl;
	}
};

四、请设计一个类,不能被继承

C++98:构造函数私有化,派生类中调不到基类的构造函数,则无法继承

class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{}
};

C++11:final关键字,final修饰类,表示该类不能被继承

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

五、设计模式的引出

设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。


为什么会产生设计模式这样的东西呢?


就像人类历史发展会产生兵法,最开始部落之间打仗时都是人拼人的对砍,后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》,写代码也是类似,也有套路。

使用设计模式的目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。设计模式使代码编写真正工程化,设计模式是软件工程的基石脉络,如同大厦的结构一样 。(类似于一个模板,

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

单例模式的定义

单例模式的类需要保证系统中该类只有一个实例并提供一个用于访问它的全局访问点,而且该实例需要被所有程序模块共享。

单例模式有以下特征:

因为全局只允许存在单个对象,所以单例对象常放在静态区或者堆区(只创建一次)。
为了防止在其他位置创建该对象,构造函数必须私有。
为了防止拷贝,需要禁用拷贝构造和赋值运算符重载函数。


单例模式有两种实现方式:饿汉模式和懒汉模式。

一 饿汉模式

饿汉模式
优点:简单
缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定

// 饿汉模式:提前(main函数启动时)创建好实例对象
// 优点:实现简单
// 缺点:1、可能会导致进程启动慢、2、如果两个单例有启动先后顺序,那么饿汉无法控制
class A
{
public:
	static A* GetInstance()
	{
		return &_inst;
	}

	void Add(const string& key, const string& value)
	{
		_dict[key] = value;
	}

	void Print()
	{
		for (auto& kv : _dict)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}
private:
	A()
	{}

	A(const A& aa) = delete;
	A& operator=(const A& aa) = delete;

	map<string, string> _dict;
	int _n = 0;

	static A _inst;
};

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好

二 懒汉模式

懒汉模式
优点:第一次使用实例对象时创建对象,进程启动无负载,多个单例实例启动顺序自由控制
缺点:复杂

// 懒汉模式:第一次用的时候再创建(现吃现做)
// todo:线程安全问题
// new的懒汉对象一般不需要释放,进程正常结束会释放资源
// 如果需要做一些动作,比如持久化,那么可以利用gc类static对象搞定
class B
{
public:
	static B* GetInstance()
	{
		if (_inst == nullptr)
		{
			_inst = new B;
		}

		return _inst;
	}

	void Add(const string& key, const string& value)
	{
		_dict[key] = value;
	}

	void Print()
	{
		for (auto& kv : _dict)
		{
			cout << kv.first << ":" << kv.second << endl;
		}
		cout << endl;
	}

	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;

此处需要注意的是由于懒汉模式的单例对象是new出来的,大部分情况下这个单例对象是不需要回收的,由于进程使用的是虚拟地址,由页表映射到物理地址,所以等进程结束时,会发生解页表操作,此时动态分配的空间在系统的层面上被回收了

但如果我们还是希望能够自主控制这个单例何时释放空间或者当main函数结束的时候单例能够自动回收空间的话,可以实现一个内部类,进行回收操作

理由:我们不能把new出来的单例对象放在单例的析构函数中delete,因为如果这样会发生无限递归函数的情况,导致栈溢出,所以我们需要额外写一个函数接口能够自主将new出的单例对象空间释放,同时我们希望main函数结束的时候,如果该空间未释放,能够做到自动回收这份new出来的空间,此时内部类的回收机制就完全符合了我们的要求,也就是说内部类是解决问题的最优解

如果单例对象构造十分耗时或者占用很多资源,比如加载插件, 初始化网络连接,读取文件等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的慢,所以这种情况使用懒汉模式(延迟加载)更好

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

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

相关文章

【Java记】数据类型与变量

一、数据类型 在Java中数据类型主要分为两类&#xff1a;基本数据类型和引用数据类型。基本数据类型有四类八种&#xff1a; 四类&#xff1a;整型、浮点型、字符型以及布尔型八种&#xff1a; 数据类型 关键字 内存占用 范围 字节型 byte 1 字节 -128~ 127 短整型 …

【C语言】数据结构#实现堆

目录 &#xff08;一&#xff09;堆 &#xff08;1&#xff09;堆区与数据结构的堆 &#xff08;二&#xff09;头文件 &#xff08;三&#xff09;功能实现 &#xff08;1&#xff09;堆的初始化 &#xff08;2&#xff09;堆的销毁 &#xff08;3&#xff09;插入数据 …

Vue3+Vite+TS+Pinia+ElementPlus+Router+Axios创建项目

目录 初始项目组成1. 创建项目1.1 下载项目依赖1.2 项目自动启动1.3 src 别名设置vite.config.ts配置文件tsconfig.json配置若新创项目ts提示1.4 运行测试2. 清除默认样式2.1 样式清除代码下载2.2 src下创建公共样式文件夹`style`2.3 main.js中引入样式2.4 安装`sass`解析插件2…

SpringCloud之Eureka注册中心和负载均衡

SpringCloud之Eureka注册中心和负载均衡 微服务技术栈认识微服务单体架构分布式架构微服务 微服务拆分及远程调用微服务拆分注意事项 Eureka注册中心提供者与消费者原理分析服务调用出现的问题Eureka的作用 使用流程1、搭建EurekaServer2、注册user-service3、在order-service完…

代码随想录算法训练营第三十一天 |基础知识,455.分发饼干,376.摆动序列,53.最大子序和(已补充)

基础知识&#xff1a; 题目分类大纲如下&#xff1a; #算法公开课 《代码随想录》算法视频公开课(opens new window)&#xff1a;贪心算法理论基础&#xff01;(opens new window),相信结合视频再看本篇题解&#xff0c;更有助于大家对本题的理解。 #什么是贪心 贪心的本质…

《区块链公链数据分析简易速速上手小册》第4章:交易数据分析(2024 最新版)

文章目录 4.1 解析交易输入和输出4.1.1 基础知识4.1.2 重点案例&#xff1a;追踪比特币交易4.1.3 拓展案例 1&#xff1a;以太坊交易的输入输出解析拓展案例1&#xff1a;以太坊交易的输入输出解析步骤1: 连接到以太坊网络步骤2: 获取交易数据步骤3: 解析交易输入结论 4.1.4 拓…

PyQt Python 使用 VTK ITK 进行分割 三维重建 医学图像可视化系统 流程

效果&#xff1a; 重建流程&#xff1a; 1. 输入 可以读取DICOM &#xff0c;nii nrrd 等数据 设置读取器以加载 DICOM 图像系列。 使用 itk::GDCMImageIO 作为 DICOM 图像的输入输出接口。 使用 itk::GDCMSeriesFileNames 获取指定路径下的所有 DICOM 文件名。 使…

Zabbix图形中文乱码问题(显示口口)解决办法

一 切换到zabbix安装目录assets/fonts下&#xff0c;下载字体 这里使用是nginxphp作为zabbix-web展示&#xff0c;使用find 命令查找 进入目录下&#xff0c;将原有字体备份&#xff0c;下载msyh字体 wget https://www.xxshell.com/download/sh/zabbix/ttf/msyh.ttf 二 修改配…

AI换脸(视频换脸)讲解-1

AI换脸是一种人工智能技术&#xff0c;它可以将一个人的面部表情和特征应用到另一个人的脸部上&#xff0c;以创建逼真的视频和图像。 首先&#xff0c;AI换脸技术需要大量的训练数据。这些数据通常是由多个人以不同的表情、姿态、光照条件下的照片或视频组成。通过使用人工智…

DolphinScheduler安装与配置

DolphinScheduler概述 Apache DolphinScheduler是一个分布式、易扩展的可视化DAG工作流任务调度平台。致力于解决数据处理流程中错综复杂的依赖关系&#xff0c;使调度系统在数据处理流程中开箱即用。 DolphinScheduler的主要角色如下&#xff1a; MasterServer采用分布式无…

Linux第46步_通过“添加自定义菜单”来学习menuconfig图形化配置原理

通过“添加自定义菜单”来学习menuconfig图形化配置原理&#xff0c;将来移植linux要用到。 自定义菜单要求如下: ①、在主界面中添加一个名为“My test menu”&#xff0c;此菜单内部有一个配置项。 ②、配置项为“MY TESTCONFIG”&#xff0c;此配置项处于菜单“My test m…

C# winfrom实例:四路激光测距雷达数据采集和波形图绘制

1.所述产品 产品型号&#xff1a;TFmini Plus 相关资料下载地址&#xff1a;http://www.benewake.com/download 产品名称&#xff1a;TFmini Plus激光雷达模组制造商公司&#xff1a;北醒&#xff08;北京&#xff09;光子科技有限公司 2.产品功能&#xff1a;TFmini Plus是基…

编辑器的新选择(基本不用配置)

Cline 不用看网上那些教程Cline几乎不用配置。 点击设置直接选择Chinese, C直接在选择就行了。 Cline是一个很好的编辑器&#xff0c;有很多懒人必备的功能。 Lightly 这是一个根本不用配置的C编辑器。 旁边有目录&#xff0c;而且配色也很好&#xff0c;语言标准可以自己…

vue 获取 form表格 的值 的方法

vue 获取 form表格 的值 代码 let discountLastMoney this.form.getFieldValue(discountLastMoney)-0

tee漏洞学习-翻译-3:TrustZone exploit for MSM8974

原文&#xff1a;http://bits-please.blogspot.com/2015/08/full-trustzone-exploit-for-msm8974.html 在这篇博文中&#xff0c;我们将介绍利用上一篇文章中描述的 TrustZone 漏洞的完整过程。 在开发此漏洞时&#xff0c;我只使用了我值得信赖的&#xff08;个人&#xff0…

Linux环境中的git

目录 1.要使用git&#xff0c;首先要安装git 2.首次使用git需要做的操作 3.git操作 1.要使用git&#xff0c;首先要安装git 指令&#xff1a;sudo yum install -y git 2.首次使用git需要做的操作 在gitee网页&#xff0c;在你的仓库中找到&#xff1a; 先将下面两行代码分别…

第12讲创建图文投票实现

创建图文投票实现 图文投票和文字投票基本一样&#xff0c;就是在投票选项里面&#xff0c;多了一个选项图片&#xff1b; <view class"option_item" v-for"(item,index) in options" :key"item.id"><view class"option_input&qu…

如何用 ChatGPT 做项目管理?

ChatGPT 可以通过创建和维护跨团队项目协作计划&#xff0c;让员工更容易理解他们的角色和职责。 这个协作计划里面会包括每个团队或个人要执行的具体任务&#xff0c;每个任务最后期限和任何事情之 间的依赖关系。 该场景对应的关键词库:(24 个) 项目管理、项目协作计划、跨…

蓝桥杯电子类单片机提升一——超声波测距

前言 单片机资源数据包_2023 一、超声波测距原理 二、超声波测距的应用 1.超声波的发射 2.单片机知识补充&#xff1a;定时器 3.超声波的接收与计时 4.距离的计算 1&#xff09;定时器1为16位自动重载&#xff0b;1T11.0592MHz 2&#xff09;定时器1为16位自动重载&am…

express 定时删除 oss 垃圾图片

一&#xff1a; 删除垃圾图片 思路&#xff1a; 获取 oss 中存储的所有图片文件&#xff1b;获取数据库中存储的图片文件数据&#xff1b;对比差异&#xff0c;不在数据库中的 oss 图片文件即为要删除的垃圾图片。 实现&#xff1a; 1、获取所有 oss 文件 import OSS from…