C++——特殊类设计

目录

前言

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

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

2.1 思路一:构造函数私有

2.2 思路二,析构函数私有

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

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

4.1 关于设计模式

4.2 单例模式

4.3 饿汉模式

4.4 懒汉模式


前言

C++的类是C++这门面向对象语言的精华所在,C++的类设计在众多OO语言中也是非常具有代表性的存在。所以,原本的类功能已经可以满足我们大部分的需求,但是随着编程语言的不断发展和实际应用的持续复杂,类原本的功能可能会有一部分失效或缺陷。

所以就有了特殊类设计,通过设计特殊的类来应对特殊的各种情况。正所谓对症下药。下面给出了部分特殊类设计

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

不能被拷贝的类我们在智能指针的unique_ptr已经初步认识过了,要想一个类不能被拷贝,只要想办法把它的拷贝构造和赋值重载干掉即可,如下代码:C++98和C++11的处理方式不同

class BanCopy
{

	//C++98的处理方式
private:
	/*BanCopy(const BanCopy&);
	BanCopy& operator=(const BanCopy&);*/
public:
	BanCopy(int a = 0)
		:_a(a)
	{
		cout << "BanCopy()" << endl;
	}
	~BanCopy()
	{
		cout << "~BanCopy" << endl;
	}
	//C++11的处理方式
	BanCopy(const BanCopy&) = delete;
	BanCopy& operator=(const BanCopy&) = delete;
private:
	int _a;
};

int main()
{
	BanCopy a(1);
	BanCopy b(a);
}

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

2.1 思路一:构造函数私有

class HeapOnly
{
public:
	//提供一个公有的获取对象的方式,对象控制是new出来的
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}

	//防拷贝
	HeapOnly(const HeapOnly& hp) = delete;
	HeapOnly& operator=(const HeapOnly& hp) = delete;
private:
	HeapOnly()
		:_a(0)
	{}
private:
	int _a;
};
//构造函数私有
void main3()
{
	/*HeapOnly hp1;
	static HeapOnly hp2;*/

	//HeapOnly* hp3 = CreateObj();
    //上面这一条语句是先有鸡还是先有蛋的问题,我们可以通过CreateObj来创建对象,但是我们只有先创建对象才能调用CreateObj
	//把CreateObj定义成static就可以了
	HeapOnly* hp3 = HeapOnly::CreateObj();
	delete hp3;

	//HeapOnly* copy(hp3);
}

2.2 思路二,析构函数私有

class HeapOnly
{
public:
	/*static void Delete(HeapOnly* ptr)
	{
		delete ptr;
	}*/
    //两种方式都可以
	void Delete()
	{
		delete this;
	}
private:
	~HeapOnly()
	{
		cout << "~HeapOnly" << endl;
	}
private:
	int _a;
};

//析构函数私有
void main()
{
	/*HeapOnly hp1;
	static HeapOnly hp2;*/

	HeapOnly* ptr = new HeapOnly;
	//HeapOnly::Delete(ptr);
	ptr->Delete();
}

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

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

	// 不能防拷贝
	//StackOnly(const StackOnly& st) = delete;
	//StackOnly& operator=(const StackOnly& st) = delete;
	void* operator new(size_t n) = delete;
private:
	// 构造函数私有
	StackOnly()
		:_a(0)
	{}
private:
	int _a;
};

void main4()
{
	StackOnly st1 = StackOnly::CreateObj();

	//拷贝构造
	static StackOnly copy2(st1);//本来不能拷贝的,用防拷贝,但是这样又会限制上面的CreateObj,不好处理,算是一个小缺陷
	//StackOnly* copy = new StackOnly(st1); 要防止栈上的数据拷贝到堆上可以把new禁掉
}

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

4.1 关于设计模式

设计模式(Design Pattern)是一套被反复使用,多数人知晓的,经过分类的,代码设计经验的总结。而它产生的原因就好比我们中国古代兵法的产生,最开始各部落之间打仗就是拼人数,无技术含量的对砍,后来春秋战国后,各国也经常打仗,后来发现打仗也是有套路的,后来就有了《孙子兵法》

而使用设计模式的目的:提高代码可重用性,和可理解性,保证代码可靠性。设计模式使代码真正工程化,是软件工程的基石。

4.2 单例模式

一个类只能创建一个对象,即单例模式。该模式保证系统中该类只有一个实例化对象,并提供一个访问它的全局访问点,并且该实例被所有程序模块共享。

简单来说:保证一些数据(一个进程中)全局只有唯一一份,并且方便访问
①把这些数据放进一个类里面,把这个类设计出单例类
②封死构造和拷贝,提供一个static公有获取单例对象地函数
③如何创建单例对象,饿汉和懒汉

单例new对象释放问题:
①一般情况下,单例对象不需要释放的。因为一般整个程序运行期间都可能会用它。
单例对象在进程正常结束后,也会资源释放。
②有些特殊场景需要释放

4.3 饿汉模式

在main函数开始之前就创建出唯一对象

优点:代码简单,并且无线程安全问题,因为是在main函数之前创建的

缺点:

①一个程序中如果有多个单例需要被创建,并且这多个单例有创建顺序时,饿汉无法控制创建顺序

②饿汉单例类如果初始化任务多,会影响程序启动速度

class Singleton1
{
public:
	//要保证每次获取的对象都是同一个对象,自己定义一个静态的自己类型的对象或指针
	static Singleton1* GetInstance()
	{
		return _pinst;
	}

	void Add(const string& str)
	{
		_mtx.lock();
		_v.push_back(str);
		_mtx.unlock();
	}

	void Print()
	{
		_mtx.lock();
		for (auto& e : _v)
		{
			cout << e << endl;;
		}
		cout << endl;
		_mtx.unlock();
	}
private:
	//构造函数私有化,是为了限制在类外面随意创建对象
	Singleton1(){}
	Singleton1(const Singleton1& s) = delete;
	Singleton1& operator=(const Singleton1& s) = delete;
private:
	mutex _mtx;
	vector<string> _v;

	//static Singleton _inst;//声明
	static Singleton1* _pinst; // 声明
};

//静态的必须在类外面初始化
//Singleton1 Singleton1::_inst = new Singleton1;
Singleton1* Singleton1::_pinst = new Singleton1;

//线程安全地往里面添加数据
void main()
{
	srand(time(0));
	int n = 100;
	thread t1([n]() {
		for (size_t i = 0; i < n; i++)
		{
			Singleton1::GetInstance()->Add("t1线程:" + to_string(rand()));
		}
	});

	thread t2([n]() {
		for (size_t i = 0; i < n; i++)
		{
			Singleton1::GetInstance()->Add("t2线程:" + to_string(rand()));
		}
		});
	t1.join();
	t2.join();
	Singleton1::GetInstance()->Print();
}

4.4 懒汉模式

饿汉模式有程序启动时间增长的问题,所以我们可以用懒汉模式,它表示当我们第一次要使用对象时再创建实例对象

优点:①不需要控制创建顺序  ②不影响启动速度

缺点:①代码实现相比饿汉更复杂,这个在下面的代码中会深有体会  ②线程安全问题要处理好,因为如果不对临界区做保护会造成很严重的后果

class Singleton2
{
public:
	static Singleton2* GetInstance()
	{
		//每次获取对象都要加锁解锁,但是我们只需要第一次new地时候加锁解锁
		//双检查加锁
		if (_pinst == nullptr) //这个时为了提供效率,不需要每次获取单例都加锁解锁
		{
			_imtx.lock();
			if (_pinst == nullptr) //这个才是保证线程安全和只new一次
			{
				_pinst = new Singleton2;
			}
			_imtx.unlock();
		}
		
		return _pinst;
	}

	void Add(const string& str)
	{
		//添加数据时要保证线程安全
		_vmtx.lock();
		_v.push_back(str);
		_vmtx.unlock();
	}

	void Print()
	{
		_vmtx.lock();
		for (auto& e : _v)
		{
			cout << e << endl;;
		}
		cout << endl;
		_vmtx.unlock();
	}

	class CGarbo
	{
	public:
		~CGarbo()
		{
			if (_pinst)
			{
				delete _pinst;
				_pinst = nullptr;
			}
		}
	};

	//上面那个是自动释放,我们也可以显示手动释放
	static void DelInstance()
	{
		_imtx.lock();
		if (_pinst)
		{
			delete _pinst;
			_pinst = nullptr;
		}
		_imtx.unlock();
	}

private:
	//构造函数私有化,还有防拷贝
	Singleton2(){}
	Singleton2(const Singleton2& s) = delete;
	Singleton2& operator=(const Singleton2& s) = delete;
private:
	mutex _vmtx;
	vector<string> _v;
	static Singleton2* _pinst;//声明
	static mutex _imtx;
};

//定义
Singleton2* Singleton2::_pinst = nullptr;
mutex Singleton2::_imtx;

//回收对象,main函数结构后,他会调用析构函数,就会释放单例对象
static Singleton2::CGarbo gc;

void main6()
{
	srand(time(0));
	int n = 100;
	thread t1([n]() {
		for (size_t i = 0; i < n; i++)
		{
			Singleton2::GetInstance()->Add("t1线程:" + to_string(rand()));
		}
		});

	thread t2([n]() {
		for (size_t i = 0; i < n; i++)
		{
			Singleton2::GetInstance()->Add("t2线程:" + to_string(rand()));
		}
		});
	t1.join();
	t2.join();
	Singleton2::GetInstance()->Print();
}

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

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

相关文章

练习14 Web [极客大挑战 2019]Upload

phtml格式绕过&#xff0c;burp修改content-type绕过&#xff0c;常见的文件上传存放目录名 题目就叫upload&#xff0c;打开靶机 直接上传一个图片格式的一句话木马&#xff0c;返回如下&#xff1a; 提交练习5和9中的两种可以执行图片格式php代码的文件&#xff0c;修改con…

Netty的线程模型

文章目录 前言NIO的三种reactor模式Netty对3种Reactor模式的支持Netty内部如何实现Reactor线程模型在事件分发过程中&#xff0c;Netty如何避免竞争条件 前言 Netty的线程模型采用了Reactor模式&#xff0c;这是一种高性能的IO设计模式&#xff0c;它基于NIO多路复用。Netty支…

226.翻转二叉树

226.翻转二叉树 力扣题目链接(opens new window) 翻转一棵二叉树。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNo…

Linux操作系统之防火墙、redis安装

目录 一、防火墙 1、防火墙的类别 2、安装iptables(四表五链&#xff09; 一、防火墙 1、防火墙的类别 安全产品 杀毒 针对病毒&#xff0c;特征篡改系统中文件杀毒软件针对处理病毒程序 防火墙 针对木马&#xff0c;特征系统窃密 防火墙针对处理木马 防火墙分为两种 硬件…

MySql 实战大数据查询-(表分区实现)

一 mysql分区&#xff1a; 分区是将单个表按照某种规则划分成多个子集&#xff0c;每个子集称为一个分区。常见的分区策略包括按照时间范围、范围值、列表等进行分区。 优点&#xff1a; 查询性能更好&#xff0c;涉及分区键的查询&#xff0c;数据库引擎可以只扫描特定分区&…

【MySQL】聚合函数和分组聚合

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习计网、mysql和算法 ✈️专栏&#xff1a;MySQL学习 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac…

Qt+OpenGL_part1

OpenGL&#xff0c;Qt实现&#xff1a;1入门篇(已更完)_哔哩哔哩_bilibili OpenGL3.3以上是现代模式&#xff08;可编程管线&#xff09;&#xff1a; 状态机 状态设置函数&#xff08;State-changing Function) 状态应用函数 &#xff08;State-using Function) OpenGL的状态…

人脸表情识别——数据集分享(内含处理过的AffectNet数据集)

前言&#xff1a; 最近终于是把第一篇论文发出去了&#xff0c;半年前我还挣扎在复现不出来论文的精度之中&#xff0c;这里指的是AffectNet和FERPlus这俩个数据集精度复现不出来&#xff0c;Raf-db数据集是可以复现出精度的。 接下来说重点&#xff1a;之前之所以另外两个数据…

【动手学深度学习】深入浅出深度学习之RMSProp算法的设计与实现

目录 &#x1f31e;一、实验目的 &#x1f31e;二、实验准备 &#x1f31e;三、实验内容 &#x1f33c;1. 认识RMSProp算法 &#x1f33c;2. 在optimizer_compare_naive.py中加入RMSProp &#x1f33c;3. 在optimizer_compare_mnist.py中加入RMSProp &#x1f33c;4. 问…

MacOS - brew 和 brew cask 有什么区别?

brew 是 ruby 的包管理&#xff0c;后来看 yangzhiping 的博客介绍了 brew cask&#xff0c;感觉 cask 是更好的关联关系管理&#xff0c;但是&#xff0c;我后来使用过程中&#xff0c;发现很多软件 brew cask 里没有&#xff0c;但是 brew 里面倒是挺多&#xff01;今天来给说…

电梯轿厢内电动车数据集,VOC标签格式已标注(数据集+训练好的权重)

本数据集用于电梯禁入电动车项目的目标检测算法模型训练任务。 共有4000张左右图片&#xff0c;全部为电梯监控真实照片&#xff0c;没有网络爬虫滥竽充数的图片&#xff0c;并已经分好数据集和验证集&#xff0c;可直接用来训练。以上图片均一一手工标注&#xff0c;标签格式为…

深入浅出 -- 系统架构之分布式架构

​​​​​​分布式架构&#xff1a; 根据业务功能对系统做拆分&#xff0c;每个业务功能模块作为独立项目开发&#xff0c;称为一个服务。 当垂直应用越来越多时&#xff0c;应用之间的交互不可避免&#xff0c;可将共用的基础服务或核心模块抽取出来作为独立服务&#xff0c…

golang 和java对比的优劣势

Golang&#xff08;或称Go&#xff09;和Java都是非常流行的编程语言&#xff0c;被广泛应用于各种领域的软件开发。尽管它们都是高级编程语言&#xff0c;但它们具有许多不同的特性和适用场景。本文将重点比较Golang和Java&#xff0c;探讨它们的优势和劣势。 性能方面&#…

java数据结构与算法刷题-----LeetCode504. 七进制数

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 倒退迭代&#xff08;除基取余法&#xff09;2. 省略掉反转操…

基于java+SpringBoot+Vue的房屋租赁系统设计与实现

基于javaSpringBootVue的房屋租赁系统设计与实现 开发语言: Java 数据库: MySQL技术: Spring Boot JSP工具: IDEA/Eclipse、Navicat、Maven 系统展示 前台展示 房源浏览模块&#xff1a;展示可租赁的房源信息&#xff0c;用户可以根据条件筛选房源。 预约看房模块&#…

武汉星起航电子商务有限公司挂牌展示,为合作伙伴提供全方位支持

随着跨境电商领域市场竞争愈演愈烈&#xff0c;武汉星起航亚马逊一站式孵化平台悄然崭露头角。从2017年起&#xff0c;武汉星起航便立足亚马逊自营店铺&#xff0c;积累了丰富的实战运营经验。2020年正式成立后&#xff0c;公司以跨境电商为核心&#xff0c;凭借专业的运营团队…

STM32CubeIDE基础学习-定时器PWM实验

STM32CubeIDE基础学习-定时器PWM实验 文章目录 STM32CubeIDE基础学习-定时器PWM实验前言第1章 硬件介绍第2章 工程配置2.1 基础工程配置部分2.2 生成工程代码部分 第3章 代码编写3.1 查看PWM波3.2 设置单个比较值3.3 呼吸灯 第4章 实验现象总结 前言 在平时单片机开发时&#…

Midjourney艺术家分享|By Moebius

Moebius&#xff0c;本名让吉拉德&#xff08;Jean Giraud&#xff09;&#xff0c;是一位极具影响力的法国漫画家和插画师&#xff0c;以其独特的科幻和幻想风格而闻名于世。他的艺术作品不仅在漫画领域内受到高度评价&#xff0c;也为电影、时尚和广告等多个领域提供了灵感。…

MATLAB多级分组绘图及图例等细节处理 ; MATLAB画图横轴时间纵轴数值按照不同sensorCode分组画不同sensorCode的曲线

平时研究需要大量的绘图Excel有时候又臃肿且麻烦 尤其是当处理大量数据时可能会拖死Windows 示例代码及数据量展示 因为数据量是万级别的折线图也变成"柱状图"了, 不过还能看出大致趋势! 横轴是时间纵轴是传感器数值图例是传感器所在深度 % data readtable(C:\U…

Vue依赖注入,详细解析

Prop 逐级透传问题​ 通常情况下&#xff0c;当我们需要从父组件向子组件传递数据时&#xff0c;会使用 props。想象一下这样的结构&#xff1a;有一些多层级嵌套的组件&#xff0c;形成了一颗巨大的组件树&#xff0c;而某个深层的子组件需要一个较远的祖先组件中的部分数据。…