c++ - 特殊类设计

news2024/9/22 7:29:23

文章目录

    • 一、设计一个不允许拷贝的类
    • 二、设计一个只能在堆上实例对象的类
    • 三、设计一个只能在栈上创建对象的类
    • 四、设计一个不能被继承的类
    • 五、设计一个只能创建一个对象的类(单例模式)


一、设计一个不允许拷贝的类

1、方法一:将拷贝构造和赋值重载声明不定义并且放到私有域。
解释:

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

2、方法二:直接将拷贝构造和赋值重载删除。

3、演示

//防拷贝 - 不允许拷贝
class Base1
{
public:
	Base1(int a = 10):_a(a)
	{}

private:
	//c++98做法 -- 将函数声明不定义加不声明
	//Base1(const Base& b);
	//Base1& operator=(const Base& b);
	
	//c++11及以后做法 -- 将函数删除
	Base1(const Base1& b) = delete;
	Base1& operator=(const Base1& b) = delete;
	int _a = 0;
};

void test01()
{
	Base1 b1;
	//会报错
	//Base1 b2(b1);
}

在这里插入图片描述

二、设计一个只能在堆上实例对象的类

1、方法:将构造函数私有化并且将拷贝构造和赋值重载删除(或者声明不定义到私有域中),再在类内部提供一个静态成员函数。
解释:

(1)将构造函数私有化:这样就只允许在类内实例类对象了。
(2)拷贝构造和赋值重载删除:在其他位置拷贝。
(3)静态成员函数:用于在堆上申请对象,并返回。

2、演示

class Base2
{
public:
	//通过函数接口在堆上new一个对象出来
	static Base2& NewBase2()
	{
		Base2* b = new Base2;
		return *b;
	}

private:
	//将构造私有化
	Base2(int a = 10) :_a(a)
	{};

	//反拷贝

	//c++98做法 -- 将函数声明不定义加不声明
	//Base2(const Base& b);
	//Base2& operator=(const Base& b);
	 
	//c++11及以后做法 -- 将函数删除
	Base2(const Base2& b) = delete;
	Base2& operator=(const Base2& b) = delete;

	int _a = 0;
};

void test02()
{
	//在栈上不行
	//Base2 b;

	//通过函数接口
	Base2 &b = Base2::NewBase2();

	//不能拷贝
	//Base2 b1(b);
}

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

1、方法:将构造函数私有化并且将拷贝构造和赋值重载删除(或者声明不定义到私有域中),需要实现一个移动构造,再在类内部提供一个静态成员函数。
解释:

(1)将构造函数私有化:这样就只允许在类内实例类对象了。
(2)拷贝构造和赋值重载删除:在其他位置拷贝。
(3)静态成员函数:用于在栈上申请对象,并返回。
(4)实现移动构造:用于上述静态函数返回时使用。

2、演示

//只允许在栈上
class Base3
{
public:
	static Base3 StackBase3()
	{
		return Base3();
	}

	Base3(Base3&& b):_a(b._a)
	{

	}
private:
	//将构造私有化
	Base3(int a = 10) :_a(a)
	{};

	//反拷贝

	//c++98做法 -- 将函数声明不定义
	//Base3(const Base& b);
	//Base3& operator=(const Base& b);

	//c++11及以后做法 -- 将函数删除
	Base3(const Base3& b) = delete;
	Base3& operator=(const Base3& b) = delete;

	int _a = 0;
};

void test03()
{
	//不能new了
	//Base3* b = new Base3;

	//使用移动构造
	Base3 b = Base3::StackBase3();
	
	//防不了这种情况
//	Base3* b1 = new Base3(move(b));
}

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

1、方法一:将基类构造函数私有,这样派生类就调用不了基类的构造函数,这样就无法继承了。

class Base
{

private:
	Base() {}
};

class Derived:public Base
{
public:
	Derived() :Base()
	{

	}

}

在这里插入图片描述

2、方法二:final关键字,final修饰类,表示该类不能被继承

class Base final
{

private:
	Base() {}
};

class Derived:public Base
{
public:
};

在这里插入图片描述

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

1、单例模式

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

2、方法一:饿汉模式
(1)概念:就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。
(2)实现细节:

(1)在类内声明一个该类类型的静态成员变量,再到类外定义该静态成员变量。
(2)提供一个静态成员函数,返回该静态成员变量的引用。
(3)做防拷贝操作,并将该类构造函数私有化。

(3)优缺点

优点
(1)实现简单:饿汉模式在类加载时就完成了单例的初始化,这种方式简单直接,易于理解和实现。
(2)线程安全:由于单例对象在类加载时就已经创建,所以多线程环境下不会存在访问冲突,无需担心线程安全问题。
(3)执行效率高:在单例对象创建之后,所有对该单例的访问都直接返回已创建的对象,无需再进行创建或同步操作,因此在频繁访问的情况下具有较高的执行效率。
缺点
(1)资源浪费:无论是否需要使用单例对象,它都会在类加载时被创建,这可能导致在不需要使用单例对象时,系统资源被不必要地占用。特别是当单例对象占用资源较多或初始化时间较长时,这种资源浪费可能更为明显。
(2)灵活性不足:饿汉模式在类加载时就完成了单例的初始化,这意味着如果单例对象的创建依赖于某些外部条件或参数,那么这些条件或参数必须在类加载之前就已经确定或准备好,这限制了单例模式的灵活性。
(3)无法懒加载:与懒汉模式相比,饿汉模式无法实现单例对象的懒加载,即只有在真正需要时才创建单例对象。这可能会导致在某些情况下,程序启动时间较长或启动时需要加载较多的资源。

(4)演示

//饿汉模式
class Base4
{
public:
	//返回唯一的实例的静态类
	static Base4& RetuntB()
	{
		return b;
	}

	//输出信息
	void Printf()
	{
		cout << s << endl;
	}

private:
	Base4()
	{}
	Base4(const Base4& b) = delete;
	Base4& operator=(const Base4& b) = delete;

private:
	string s = "hello";	//假设这是储存的信息
	static Base4 b;

};

Base4 Base4::b;

void test04()
{
	Base4::RetuntB().Printf();

}

3、方法二:懒汉模式
(1)概念:在使用时再去实例化对象。
(2)实现细节:

(1)在类内声明一个该类类型的指针,再到类外定义为nullprt
(2)提供一个静态成员函数,返回该静态成员变量的引用(再使用时发现为空就向堆申请)。
(3)做防拷贝操作,并将该类构造函数私有化。
(4)通过实现一个静态的函数来清理这块空间,或者实现一个内部类,在内部类的析构函数进行清理。

(3)优缺点

优点
(1)资源利用率高:懒汉模式实现了单例的懒加载,即单例对象在第一次被使用时才创建,这可以确保在不需要使用单例对象时不会占用系统资源,从而提高了资源利用率。
(2)灵活性高:懒汉模式的单例对象创建时机是可控的,可以根据实际需要进行调整。例如,可以在单例对象创建时传入参数或依赖于外部条件,这增加了单例模式的灵活性。
适用于多种情况:由于懒汉模式可以根据需要创建单例对象,因此它适用于那些单例对象创建成本较高或初始化时间较长的情况。、
缺点
(1)线程安全问题:在多线程环境下,懒汉模式需要确保单例对象的唯一性。如果没有适当的同步机制,可能会出现多个线程同时创建单例对象的情况,导致单例模式失效。因此,需要加锁来确保线程安全,但这会增加性能开销。
(2)性能开销:为了实现线程安全,懒汉模式通常需要在访问单例对象时加锁。虽然这可以确保单例对象的唯一性,但频繁的加锁和解锁操作会降低程序的性能。特别是在高并发场景下,这种性能开销可能更加明显。
(3)双重检查锁定(Double-Checked Locking)的复杂性:为了解决懒汉模式的线程安全问题,同时减少性能开销,可以使用双重检查锁定技术。但这种技术实现起来较为复杂,且容易出错。如果实现不当,可能会导致单例模式失效或引入新的线程安全问题。

//懒汉模式
class Base5
{
public:

	//返回唯一的实例的静态类
	static Base5& RetuntP()
	{
		if (p == nullptr)
		{
			p = new Base5;
		}
		
		return *p;
	}

	//输出信息
	void Printf()
	{
		cout << s << endl;
	}

	//释放方法1 --- 实例一个内部类,当内部类释放了,p也会跟着释放
	class DeleteP
	{
	public:
		~DeleteP()
		{
			if (p != nullptr)
				delete p;
		}
	};

	释放方法二 --- 通过手动调用函数释放
	//void DeleteP()
	//{
	//	if (p != nullptr)
	//		delete p;
	//}

private:
	Base5()
	{}
	Base5(const Base5& b) = delete;
	Base5& operator=(const Base5& b) = delete;

private:
	string s = "hello";	//假设这是储存的信息
	static Base5* p;

};

//初始化
Base5* Base5::p = nullptr;

//实例一个内部类,当内部类生命周期结束后会释放 p
Base5::DeleteP del;

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

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

相关文章

在Windows上配置VSCode MinGW+CMake(包括C++多线程编程的两套API:posix和win32)

创建目录 首先&#xff0c;需要电脑上安装VSCode, 并且创建三个文件夹&#xff1a;cmake、MinGW-posix、MinGW-w32 文件下载 下载posix-seh posix和win32分别是c多线程变成的两套API,可根据不同需求安装&#xff0c;现在先下载配置环境需要的几个文件 百度搜索MinGW-64 点…

Django 链接MySQL数据库,报错Did you install mysqlclient?

据说是在python3里面&#xff0c;已经用pymysql替换了MySQLdb来进行数据库连接 所以&#xff0c;先安装pymysql pip install pymysql之后为了测试这个问题是否和mysql-connector-c有关系&#xff0c;我提前把这个应用给卸了。 之后在整个项目根目录的init文件内写入以下内容 im…

在docker中进行日志切割

先在Linux中安装docker&#xff0c;然后在docker中安装appnode面板&#xff0c;并进行docker网络端口映射。接着进入docker&#xff0c;进行nginx日志切割。 安装docker 第一步&#xff0c;卸载旧版本docker。 若系统中已安装旧版本docker&#xff0c;则需要卸载旧版本docke…

大模型在资源全生命周期的应用探索

资源全生命周期管理的传统价值 运营商的网络涉及接入网、数据网、承载网、核心网、传输网、无线网、光缆网、云专网、动力网、业务平台等十数类大专业。网络资源的全生命周期体现在以下六大生产活动环节&#xff1a;网络规划→网络设计→网络工程建设→网络资源的投入使用→网络…

数据安全防护措施有哪些?防数据泄露的10大措施丨让你一次性看够!

古时烽火传信&#xff0c;密语藏于竹简之间&#xff0c;以防外泄&#xff0c;保家国安宁。 今朝数字洪流&#xff0c;数据如织&#xff0c;信息安全之重&#xff0c;不亚于昔日之密信。 在信息爆炸的时代&#xff0c;数据安全防护犹如筑起铜墙铁壁&#xff0c;以防数据泄露之患…

想要数字人直播平台赚钱,前期源码部署要注意哪些要点?

随着人工智能时代的到来&#xff0c;数字人直播的应用频率不断升高&#xff0c;展现巨大收益潜力的同时&#xff0c;也让不少想要通过数字人源码厂商搭建数字人直播平台的创业者产生好奇&#xff0c;并开始从各方面打听数字人直播平台怎么赚钱等相关问题的答案。 本期&#xf…

开营啦!| 上海交通大学 AI for Bioengineering 暑期学校开营仪式圆满举行!

开营仪式 2024年8月12日 &#xff0c;“AI for Bioengineering暑期学校”在上海交通大学闵行校区理科群楼300号报告厅开幕。本次暑期学校吸引了来自国内外30余所高校&#xff08;包括芝加哥大学、曼彻斯特大学、哥伦比亚大学、爱丁堡大学、南加利福尼亚大学、北京大学、清华大…

element-plus的表单输入框有清除按钮的,文字输入前后宽度不一致怎么解决

输入内容之后多了一个可清除的图标&#xff0c;输入框的宽度也被撑开了 根据输入前后的dom对比发现&#xff0c;多了一个图标的span标签 :deep(.el-input__wrapper) {position: relative;.el-input__inner {padding-right: 18px;}.el-input__suffix {position: absolute;right:…

服务器重启后的端口占用分析及解决方案

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Android Studio报错 Failed to transform ‘...‘ using Jetifier. Reason null

Android Studio报错 Failed to transform ‘…‘ using Jetifier. Reason null 问题描述&#xff1a; AndroidX提示Failed to transform ‘/…/’ using Jetifier. Reason: null. 解决方案&#xff1a; 在gradle.properties中&#xff0c;将 android.enableJetifiertrue改为…

uniapp 对于scroll-view滑动和页面滑动的联动处理

需求 遇到一个需求 解决方案 这个时候可以做一个内页面滑动判断 <!-- scroll-y 做true或者false的判断是否滑动 --> <view class"u-menu-wrap" style"background-color: #fff;"><scroll-view :scroll-y"data.isGo" scroll-wit…

mongodb连表查询,postman使用

要实现与SQL类似的查询&#xff0c;你需要使用聚合框架&#xff08;Aggregation Framework&#xff09; SELECT b.name, a.* FROM user a LEFT JOIN order b ON a.id b.id WHERE b.name LIKE %acd%; 从MongoDB 3.2版本开始&#xff0c;引入了聚合框架中的$lookup阶段&#xf…

【JS】详解浏览器的5 种Observer: Mutation、Intersection、Performance、Resize、Reporting

文章目录 1、IntersectionObserver 交叉观察器用法使用场景 2、MutationObserver 变动观察器用法使用场景 3、ResizeObserver 尺寸变化观察器用法使用场景 4、PerformanceObserver 性能观察器用法使用场景 5、ReportingObserver用法使用场景 总结 网页开发中我们经常要处理用户…

第三方jar自带logback导致本地日志文件不生成

1.问题及解决 这是依赖的jar包&#xff0c;自己有logback&#xff0c;只打印到控制台&#xff0c;导致我们项目里配置的error级别日志不会生成到日志文件中去。ai给的答案是自己控制加载顺序&#xff0c;但很麻烦&#xff0c;--logging.config也不行&#xff0c;最好下了个7z压…

Grafana 可视化监控和告警

前言 在现代分布式系统和云原生环境中&#xff0c;为了确保复杂的分布式系统和服务的高可用性、可靠性和性能&#xff0c;通常采用实时可视化监控和分析&#xff0c;实现故障快速响应、资源优化和安全保障&#xff0c;从而提升用户满意度和运营效率。 在目前主流的解决方案中…

vue 获取当前页面路由

vue2 &#xff1a; import { getCurrentInstance } from ‘vue’; //获取当前页路由 data() { return { currentRouter: ‘’,//默认路由 } } const { proxy } getCurrentInstance(); this.currentRouter proxy.$router.currentRoute.meta.title vue3 &#xff1a; import …

智能语音电话机器人的优势有哪些?

现在每个企业的客服成本都是非常高的&#xff0c;但是工作效率还不高&#xff0c;有的还存在简单粗暴的情况&#xff0c;因此如果使用语音机器人的话&#xff0c;就将会发生重大的转变了&#xff0c;不仅会提高效率&#xff0c;还会降低很多的人力成本&#xff0c;&#xff0c;…

【浏览器】f12控制台,如何选中click、hover才出现的元素(断点调试)

使用断点调试 以切换语言的弹窗为例 当鼠标点击select框时才显现选项&#xff0c;没有办法直接选中元素进行样式的调试 1. 按f12打开控制台&#xff0c;点击sources&#xff0c;按 ctrlo 查找你要开发的文件 2. 给元素添加断点&#xff08;如果操作的时候没有停&#xff0c;就…

丰田的接单式生产、零库存、快速换模之间关系如何?

前面讲了&#xff0c;丰田采用接单式生产&#xff0c;这让它的库存一直保持在较低水平&#xff0c;但这一切是怎么实现的&#xff1f;接单式生产、零库存和快速换模之间又有怎样的关系&#xff1f;今天就来简单聊下。 接单式生产 这可谓是丰田典型的快速响应。当4S门店销售人员…

[openSSL]TLS 1.3握手分析

文章目录 前言一、ECDHE密钥交换二、TLS单向身份认证三、TLS双向身份认证 前言 关于TLS握手网上资料很多&#xff0c;但是有一些写的很不清楚&#xff0c;导致学习时对概念和流程出现混淆&#xff0c;以下是我觉得写得比较清晰和准确的供学习参考。 浅析 TLS&#xff08;ECDHE…