【C++】特殊类实现——设计一个类、不能被拷贝、只能在堆上创建对象、只能在栈上创建对象、不能被继承、单例模式、饿汉模式、懒汉模式

文章目录

  • C++
  • 特殊类实现
    • 1.设计一个类、不能被拷贝
    • 2.设计一个类、只能在堆上创建对象
    • 3.设计一个类、只能在栈上创建对象
    • 4.设计一个类、不能被继承
    • 5.设计一个类,只能创建一个对象(单例模式)
    • 5.1饿汉模式
    • 5.2懒汉模式

C++

在这里插入图片描述

特殊类实现

1.设计一个类、不能被拷贝

  在C++中,拷贝构造函数和拷贝赋值运算符是两种可以用于创建新对象或为现有对象赋值的方法。

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

  以下是一个示例,展示如何创建一个不能被拷贝的类:

  C++98做法:

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

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

  原因:

  (1)只声明不定义:因为没有定义,所以该函数根本不会进行任何操作,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

  (2)同时设置成私有:这样可以防止直接使用它们, 如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了。

  

  C++11做法:

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

class CopyBan
{
    // ...
    CopyBan(const CopyBan&)=delete;
    CopyBan& operator=(const CopyBan&)=delete;
    //...
};

            

2.设计一个类、只能在堆上创建对象

  实现方式:

  1.将类的析构函数私有;或者将类的构造函数私有,拷贝构造声明成私有。

  2.提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建(单例模式)。

  

  1.1析构函数私有化:

//析构函数私有化,因为堆要手动释放对象
class HeapOnly
{
public:
	void Destroy()
	{
		delete this;
	}

private:
	~HeapOnly()
	{
		//...
	}
};

int main()
{
	//HeapOnly hp1;
	//static HeapOnly hp2;
	HeapOnly* hp3 = new HeapOnly;
	hp3->Destroy();

	return 0;
}

  原因:

  我们可以将析构函数私有化,因为在栈上和静态区的对象需要自动调用析构函数,而析构函数无法显示调用了,就会导致我们无法在栈上和静态区创建对象。

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

在这里插入图片描述

  

  1.12构造函数私有化:

//2、设计一个类只能在堆上创建对象
//构造函数私有化
class HeapOnly
{
public:
	static HeapOnly* CreateObj()
	{
		return new HeapOnly;
	}

private:
	HeapOnly()
	{
		//...
	}

	//防止拷贝构造
	HeapOnly(const HeapOnly& hp) = delete;
	HeapOnly& operator=(const HeapOnly& hp) = delete;
};

int main()
{
	//HeapOnly hp1;
	//static HeapOnly hp2;
	//HeapOnly* hp3 = new HeapOnly;
	HeapOnly* hp3 = HeapOnly::CreateObj();
	//HeapOnly copy(*hp3);//拷贝构造在栈上
	return 0;
}

  原因:

  我们将构造函数私有,禁止任何方式创建示例。但是提供一个可以在堆上创建对象的公有函数,这样我们就可以通过公有函数来调用私有的构造函数。

  注意:这里的要创建对象的公有函数应该是static修饰的,因为如果要调用公有函数,需要有一个对象示例,而我们要用公有函数创建一个示例,而我们现在没有对象示例,需要调用公有函数(类似鸡生蛋,蛋生鸡)…如果函数在静态区,就可以直接调用了。

  同时,为了防止我们创建的对象示例被拷贝构造或者赋值,所以我们还需要将拷贝构造函数和赋值运算符重载函数封死。

在这里插入图片描述

            

3.设计一个类、只能在栈上创建对象

  实现方法:

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

//3、设计一个只能在栈上的类
//构造函数私有
class StackOnly
{
public:
	static StackOnly CreateObj()
	{
		StackOnly st;
		return st;
	}
	
private:
	StackOnly()
	{
		//...
	}

	//对一个类实现专属的operator new
	void* operator new(size_t size) = delete;
};

int main()
{
	//StackOnly hp1;
	//static StackOnly hp2;
	//StackOnly* hp3 = new StackOnly;
	StackOnly hp3 = StackOnly::CreateObj();
	StackOnly copy(hp3);

	//new  operator new  +  构造
	//StackOnly* hp4 = new StackOnly(hp3);

	return 0;
}

  原因:

  和上面的实现一样,我们将构造函数私有化,提供一个只能在栈上创建对象的公有函数,static修饰。但是如果我们封死拷贝构造,CreateObj返回的临时对象就无法拷贝给我们的hp3,为了解决我们可以提供一个移动构造

  但是事实上也无法很有效的防止静态区创建对象,所以对于只在栈上创建对象的实现,这样就可以了。

在这里插入图片描述
            

4.设计一个类、不能被继承

  C++98方法:

  我们将构造函数私有化,派生类中调不到基类的构造函数,则无法继承。

//C++98  私有构造函数
class NonInherit
{
public:
	static NonInherit GetInstance()
	{
		return NonInherit();
	}
private:
	NonInherit()
	{
		//...
	}
}

  

  C++11方法:

  final关键字,final修饰类,表示该类不能被继承。

//C++11  final
class A final
{
	//...
};

            

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

  单例模式:

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

5.1饿汉模式

  饿汉模式:

  就是说不管你将来用不用,程序启动时(main函数之前创建)就创建一个唯一的实例对象;

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

  优点:简单;

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

// 饿汉模式:一开始(main函数之前)就创建单例对象
// 1、如果单例对象初始化内容很多,影响启动速度
// 2、如果两个单例类,互相有依赖关系。 
// 假设有A B两个单例类,要求A先创建,B再创建,B的初始化创建依赖A
namespace hungry
{
	class Singleton
	{
	public:
		// 2、提供获取单例对象的接口函数
		static Singleton& GetInstance()
		{
			return _sinst;
		}

		void func();

		void Add(const pair<string, string>& kv)
		{
			_dict[kv.first] = kv.second;
		}

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

	private:
		// 1、构造函数私有
		Singleton()
		{
			// ...
		}

		// 3、防拷贝
		Singleton(const Singleton& s) = delete;
		Singleton& operator=(const Singleton& s) = delete;

		map<string, string> _dict;
		// ...

		static Singleton _sinst;
	};

	Singleton Singleton::_sinst;

	void Singleton::func()
	{
		// 
		_dict["xxx"] = "1111";
	}
}

  

5.2懒汉模式

  懒汉模式:

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

  优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制;

  缺点:复杂。

namespace lazy
{
	class Singleton
	{
	public:
		// 2、提供获取单例对象的接口函数
		static Singleton& GetInstance()
		{
			if (_psinst == nullptr)
			{
				// 第一次调用GetInstance的时候创建单例对象
				_psinst = new Singleton;
			}

			return *_psinst;
		}

		// 一般单例不用释放。
		// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)
		static void DelInstance()
		{
			if (_psinst)
			{
				delete _psinst;
				_psinst = nullptr;
			}
		}

		void Add(const pair<string, string>& kv)
		{
			_dict[kv.first] = kv.second;
		}

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

		class GC
		{
		public:
			~GC()
			{
				lazy::Singleton::DelInstance();
			}
		};

	private:
		// 1、构造函数私有
		Singleton()
		{
			// ...
		}

		~Singleton()
		{
			cout << "~Singleton()" << endl;

			// map数据写到文件中
			FILE* fin = fopen("map.txt", "w");
			for (auto& e : _dict)
			{
				fputs(e.first.c_str(), fin);
				fputs(":", fin);
				fputs(e.second.c_str(), fin);
				fputs("\n", fin);
			}
		}

		// 3、防拷贝
		Singleton(const Singleton& s) = delete;
		Singleton& operator=(const Singleton& s) = delete;

		map<string, string> _dict;
		// ...

		static Singleton* _psinst;
		static GC _gc;
	};

	Singleton* Singleton::_psinst = nullptr;
	Singleton::GC Singleton::_gc;
}

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

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

相关文章

谷歌桌面布局修改

前言 近期接到一个关于谷歌EDLA认证的需求&#xff0c;我负责的是谷歌原生桌面布局的修改&#xff0c;通过研究源码&#xff0c;将涉及到了一些修改思路发出来&#xff0c;大家可以参考一下有没有对你有用的信息。主要修改内容有&#xff1a; 1、搜索栏、底部导航栏未居中 2、…

STK 根据六根数文件导出星下点(二)

利用给定的六根数数据&#xff0c;生成星下点数据 首先在STK中建立卫星对象 建立成功后&#xff0c;在Satellite1中设置Properties ,输入六根数数据 使用如下参数&#xff1a; propagator&#xff08;轨道&#xff09;&#xff1a;TwoBody&#xff08;开普勒&#xff09; st…

前端食堂技术周刊第 103 期:10 月登陆 Web 平台的新功能、TS 5.3 RC、React 2023 状态、高并发的哲学原理、Web 资源加载优先级

美味值&#xff1a;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f;&#x1f31f; 口味&#xff1a;夏梦玫珑 食堂技术周刊仓库地址&#xff1a;https://github.com/Geekhyt/weekly 大家好&#xff0c;我是童欧巴。欢迎来到前端食堂技术周刊&#xff0c;我们先来看下…

如何在CPU上进行高效大语言模型推理

大语言模型&#xff08;LLMs&#xff09;已经在广泛的任务中展示出了令人瞩目的表现和巨大的发展潜力。然而&#xff0c;由于这些模型的参数量异常庞大&#xff0c;使得它们的部署变得相当具有挑战性&#xff0c;这不仅需要有足够大的内存空间&#xff0c;还需要有高速的内存传…

Stable Diffusion webui 源码调试(二)

Stable Diffusion webui 源码调试&#xff08;二&#xff09; 个人模型主页&#xff1a;LibLibai stable-diffusion-webui 版本&#xff1a;v1.4.1 内容更新随机&#xff0c;看心情调试代码~ 分析StableDiffusionProcessingTxt2Img类中的sample函数 Sampler /work/stable-d…

threejs(11)-精通着色器编程(难点)1

一、初识着色器语言 GLSL 代表 openGL Shading Language&#xff0c;它是着色器程序的特定标准&#xff0c;您将在接下来的章节中看到。根据硬件和操作系统&#xff0c;还有其他类型的着色器。在这里&#xff0c;我们将使用由Khronos Group监管的 openGL 规范。了解 OpenGL 的…

百度上线“文心一言”付费版本,AI聊天机器人市场竞争加剧

原创 | 文 BFT机器人 百度不愧是我国AI技术领域的先行者&#xff0c;每年致力于人工智能领域取得技术产品的突破和创新。据爆料称&#xff0c;百度的文心一言有突破了新境界&#xff0c;开创了文心大模型4.0会员版本。从线上的to C产品到试水商业化&#xff0c;百度都是争先走…

JavaEE平台技术——MyBatis

JavaEE平台技术——MyBatis 1. 对象关系映射框架——Hibernate、MyBatis2. 对象关系模型映射3. MyBatis的实现机制4. MyBatis的XML定义5. Spring事务 在观看这个之前&#xff0c;大家请查阅前序内容。 &#x1f600;JavaEE的渊源 &#x1f600;&#x1f600;JavaEE平台技术——…

互联网金融P2P主业务场景自动化测试

互联网金融P2P行业&#xff0c;近三年来发展迅速&#xff0c;如火如荼。 据不完全统计&#xff0c;全国有3000的企业。 “互联网”企业&#xff0c;几乎每天都会碰到一些奇奇怪怪的bug&#xff0c;作为在互联网企业工作的测试人员&#xff0c;风险和压力都巨大。那么我们如何降…

数据的读取和保存-MATLAB

1 序言 在进行数据处理时&#xff0c;经常需要写代码对保存在文件中的数据进行读取→处理→保存的操作&#xff0c;流程图如下&#xff1a; 笔者每次在进行上述操作时&#xff0c;都需要百度如何“选中目标文件”以及如何“将处理好的数据保存到目标文件中”&#xff0c;对这一…

渗透测试学习day3

文章目录 靶机&#xff1a;DancingTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8 靶机&#xff1a;RedeemerTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9Task 10Task 11 靶机&#xff1a;AppointmentTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9T…

AI:62-基于深度学习的人体CT影像肺癌的识别与分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

java--String

1.String创建对象封装字符串数据的方式 ①方式一&#xff1a;java程序中的所有字符串文字(例如"abc")都为此类的对象 ②方式二&#xff1a;调用String类的构造器初始化字符串对象。 2.String提供的操作字符串数据的常用方法

[Vue warn]: Missing required prop: “action“

控制台显示错误信息 vue.runtime.esm.js:4605 [Vue warn]: Missing required prop: "action" found in ---> <ElUpload> at packages/upload/src/index.vue <ElTableRow> <ElTableBody> <ElTable> at pack…

maven中的install 和 clean命令,以及compile、、package、test等操作介绍

maven中的install命令 主要就是谁要被其他模块依赖就install谁 Maven工具可以进行clean、compile、install、package、test等操作&#xff0c;但是这些操作有什么用呢&#xff0c;以下面的p2p-exterface为例说明一下&#xff0c;pwp-exterface工程目录如下&#xff1a; com…

缓存-基础理论和Guava Cache介绍

缓存-基础理论和Guava Cache介绍 缓存基础理论 缓存的容量和扩容 缓存初始容量、最大容量&#xff0c;扩容阈值以及相应的扩容实现。 缓存分类 本地缓存&#xff1a;运行于本进程中的缓存&#xff0c; 如Java的 concurrentHashMap, Ehcache&#xff0c;Guava Cache。 分布式缓…

12 tcp协议详解

1、tcp的本性 tcp是一个悲观者&#xff0c;生下来就不信任网络&#xff0c;任务会发生丢包等&#xff0c;所以要从算法层面来保证可靠性。 2、TCP 包头格式 tcp的包头格式比UDP要复杂的多。 1.源端口号和目标端口号是不可少的&#xff0c;这一点和 UDP 是一样的。如果没有…

星岛专栏|从Web3发展看金融与科技的融合之道

11月起&#xff0c;欧科云链与香港主流媒体星岛集团开设Web3.0安全技术专栏&#xff0c;该专栏主要面向香港从业者、交易机构、监管机构输出专业性的安全合规建议&#xff0c;旨在促进香港Web3.0行业向安全与合规发展。 出品&#xff5c;欧科云链研究院 自2016年首届香港金融…

轻松与任何 SQL 数据库集成:Directus 助你无代码开发 | 开源日报 No.69

Ebazhanov/linkedin-skill-assessments-quizzes Stars: 26.5k License: AGPL-3.0 这个项目是一个 LinkedIn 技能评估答案的存储库。它提供了各种领域和主题的问题和答案&#xff0c;以帮助用户更好地学习新概念并准备相关考试。该项目具有以下核心优势&#xff1a; 提供多语…

计算机毕业设计 基于SpringBoot的养老院管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…