当前位置: 首页 > news >正文

秒懂C++之特殊类设计

fe594ea5bf754ddbb223a54d8fb1e7bc.gif

目录

 

设计一个类,不能被拷贝

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

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

设计一个类,无法被继承

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

饿汉模式

懒汉模式


设计一个类,不能被拷贝

这个很简单,利用C11新特性中的关键字delete给到拷贝构造与赋值重载即可~

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

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

既然是要在堆上创建对象,那么首先要做的就是确保该对象是new出来的而非是由构造函数生成的~

class HeapOnly
{
public://禁止赋值重载HeapOnly& operator=(const HeapOnly&) = delete;//禁止拷贝构造HeapOnly(const HeapOnly&) = delete;
private://构造私有化//无参HeapOnly(){}//有参HeapOnly(int x, int y):_x(x),_y(y){}int _x;int _y;
};int main()
{HeapOnly ho1;HeapOnly* ho2 = new HeapOnly;return 0;
}

不过这样new的时候也无法调用构造了,所以我们再包装一层~

不过还是遇到问题,OBJ是创建对象用的,但调用OBJ得是对象调用,那么我们就不要让它作为成员函数,而是超脱其作用域~

然后再把默认的拷贝函数与赋值重载禁掉,防止在栈上拷贝对象~

class HeapOnly
{
public:template<class... Args>static HeapOnly* CreateObject(Args&&... args){return new HeapOnly(args...);}/*static HeapOnly* CreateObject(){return new HeapOnly;}*///禁止赋值重载HeapOnly& operator=(const HeapOnly&) = delete;//禁止拷贝构造HeapOnly(const HeapOnly&) = delete;
private://构造私有化//无参HeapOnly(){}//有参HeapOnly(int x, int y):_x(x),_y(y){}int _x =1;int _y =2;
};int main()
{/*HeapOnly ho1;HeapOnly* ho2 = new HeapOnly;*/HeapOnly* ho2 = HeapOnly::CreateObject();HeapOnly* ho3 = HeapOnly::CreateObject(3,4);//禁止拷贝//HeapOnly copy(*ho2);return 0;
}

ps:可搭配上前面所学的可变参数模板使用~

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

只能在栈上的话思路和前面差不多,先把构造给私有化,由我们来控制在那开辟对象,再把new给禁止掉,防止在堆上开辟~

class StackOnly
{
public:template<class... Args>static StackOnly CreateObj(Args&&... args){return StackOnly(args...);}// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;int _b;
};int main()
{StackOnly so1 = StackOnly::CreateObj();StackOnly so2 = StackOnly::CreateObj(3,4);//无法使用StackOnly* ptr3 = new StackOnly(obj);return 0;
}

设计一个类,无法被继承

class A final
{//...
};

直接用C11新特性的关键字final即可~

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

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

饿汉模式

饿汉:一开始(main之前)就创建出对象。就是说不管你将来用不用,程序启动时就创建一个唯一的实例对象。

想让一些数据,当前程序只有一份,那就可以把这些数据放到这个类里面,再把这个类设计成单例,这个数据就只有一份了

namespace hunger
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){return &_sint;}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x,int y):_x(x), _y(y){}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制// 这才符合在main之前创建对象static Singleton _sint;};//静态成员声明:成员类型+成员所处內域Singleton Singleton::_sint(1, 1);
}
int main()
{//直接调静态函数拿到对象hunger::Singleton::GetInstance()->Print();
}

ps:之所以拿指针而非对象一个是安全问题,指针销毁方便~但我感觉无论用指针还是引用返回都差不多~

不过饿汉模式有两个问题存在:

  • 如果单例对象数据较多,构造初始化成本较高,那么会影响程序启动的速度。迟迟进不了main函数
  • 多个单例类有初始化启动依赖关系,饿汉无法控制。假设:A和B两个单例,假设要求A先初始化,B再初始化,饿汉无法保证

懒汉模式

懒汉优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控
制。
如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊,初始化网络连接啊,读取
文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,
就会导致程序启动时非常的缓慢。所以这种情况使用懒汉模式( 延迟加载 )更好。
//在饿汉模式基础上进行改造
namespace lazy
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){// 第一次调用时,创建单例对象// 线程安全问题,需要加锁if (_psint == nullptr){_psint = new Singleton;}return _psint;}static void DelInstance(){if (_psint){delete _psint;_psint = nullptr;}}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x =0,int y=0):_x(x), _y(y){}~Singleton(){cout << "~Singleton()" << endl;}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psint;// 内部类class GC{public:~GC(){Singleton::DelInstance();}};// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象static GC gc;};Singleton* Singleton::_psint = nullptr;Singleton::GC Singleton::gc;
}
int main()
{//直接调静态函数拿到对象lazy::Singleton::GetInstance()->Print();return 0;
}

在懒汉模式中我们最开始是构建出一个对象指针,只有在第一次被调用的时候才会创建对象,这样可以减少初始化时的开销~由于静态成员变量是指针,那就需要写对应的析构函数及时释放其资源,如果我们不想手动释放也可以学一下构建内部类的方式让其自动调用对指针的析构函数~

如果不想用GC内部类析构对象指针也可以这样写:

namespace lazy
{class Singleton{public://利用静态成员函数拿到静态成员static Singleton* GetInstance(){// 第一次调用时,创建单例对象// 线程安全问题,需要加锁//局部静态对象,在第一次调用该函数时才初始化static Singleton _sint;return &_sint;}static void DelInstance(){if (_psint){delete _psint;_psint = nullptr;}}void Print(){cout << _x << endl;cout << _y << endl;}//禁止拷贝构造与赋值重载,防止其他对象生成Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数私有防止构造其他对象Singleton(int x = 0, int y = 0):_x(x), _y(y){}~Singleton(){cout << "~Singleton()" << endl;}int _x;int _y;// 静态成员对象,不存在对象中,存在静态区,相当于全局的,定义在类中,受类域限制static Singleton* _psint;};Singleton* Singleton::_psint = nullptr;
}int main()
{//直接调静态函数拿到对象lazy::Singleton::GetInstance()->Print();return 0;
}

不用new而是直接创建对象~

总结:在main之前初始化就是饿汉,在main中第一次调用就是懒汉~

相关文章:

秒懂C++之特殊类设计

目录 设计一个类&#xff0c;不能被拷贝 设计一个类&#xff0c;只能在堆上创建对象 设计一个类&#xff0c;只能在栈上创建对象 设计一个类&#xff0c;无法被继承 设计一个类&#xff0c;只能创建一个对象(单例模式) 饿汉模式 懒汉模式 设计一个类&#xff0c;不能被拷…...

人工智能学习

&#x1f310;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 &#x1f449;【点击跳转到网站&#xff1a;人工智能教程】 什么是人工智能&#xff1f;通俗来讲&#xff0c;就是让机器能像人一样思考。这…...

WINDOWS AGENTARENA:EVALUATING MULTI-MODAL OS AGENTS AT SCALE论文学习

文章开头说现有的agent都是局限于特定领域&#xff08;什么网络问答啊&#xff0c;仅限文字啊&#xff0c;仅限于某一个app啊&#xff09;这样的&#xff0c;本文的工作主打一个贴近用户使用场景&#xff0c;用户用什么软件&#xff0c;看什么网页&#xff0c;本文的模型就用什…...

3步轻松定制报价方案,亿发商城报价神器你用过了吗?

如果您正寻求突破传统业务模式的束缚&#xff0c;希望拥抱数字化转型带来的无限可能&#xff0c;我们诚邀您体验亿发软件。亿发专业团队将为您提供个性化的咨询和定制服务&#xff0c;帮助您的企业快速适应市场变化&#xff0c;实现业务模式和商业模式的创新。...

CISP备考题库(五)

在当今这个飞速发展的数字化时代&#xff0c;信息安全已跃居至前所未有的战略地位&#xff0c;其重要性伴随着技术的日新月异而持续攀升&#xff0c;成为了一个不容小觑的关键领域。为了激发并引领广大青年才俊积极投身于网络安全专家的崇高事业&#xff0c;我们精心策划并编纂…...

【Kubernetes】常见面试题汇总(二十三)

目录 69.考虑一家拥有分布式系统的跨国公司&#xff0c;拥有大量数据中心&#xff0c;虚拟机和许多从事各种任务的员工。您认为这样公司如何以与 Kubernetes 一致的方式管理所有任务&#xff1f; 70.考虑一种情况&#xff0c;即公司希望通过维持最低成本来提高其效率和技术运营…...

linux-Shell 编程-Shell 脚本基础

Linux Shell 编程&#xff1a;Shell 脚本基础 在Linux系统中&#xff0c;Shell脚本是一种强大的自动化工具。通过编写Shell脚本&#xff0c;用户可以自动化重复性任务、系统管理操作和程序控制流程&#xff0c;极大提高工作效率。 1. 什么是Shell脚本&#xff1f; Shell脚本是…...

Linux运维篇-tigervnc工具的使用

目录 简介下载使用clientserver配置文件服务管理 设定密码&#xff08;先切换成对应的用户&#xff09;&#xff1a;配置多用户的VNC tigervnc连接排错一、vnc密码错误二、vncserver端口忘记了三、连接很卡&#xff0c;或者画面没有反应四、服务报错 简介 TigerVNC是VNC的一种…...

基于Spark的电影推荐系统设计与实现(论文+源码)_kaic

摘 要 在云计算、物联网等技术的带动下&#xff0c;我国已步入大数据时代。电影是人们日常生活中重要的一种娱乐方式&#xff0c;身处大数据时代&#xff0c;各种类型、题材的电影层出不穷&#xff0c;面对琳琅满目的影片&#xff0c;人们常感到眼花缭乱。因此&#xff0c;如…...

基于python+django+vue的医院预约挂号系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于协同过滤pythondjangovue…...

镀金引线---

一、沉金和镀金 沉金和镀金都是常见的PCB金手指处理方式&#xff0c;它们各有优劣势&#xff0c;选择哪种方式取决于具体的应用需求和预算。 沉金&#xff08;ENIG&#xff09;是一种常用的金手指处理方式&#xff0c;它通过在金手指表面沉积一层金层来提高接触性能和耐腐蚀性…...

『功能项目』窗口可拖拽脚本【59】

本章项目成果展示 我们打开上一篇58第三职业弓弩的平A的项目&#xff0c; 本章要做的事情是给坐骑界面挂载一个脚本让其显示出来的时候可以进行拖拽 创建脚本&#xff1a;DraggableWindow.cs using UnityEngine; using UnityEngine.EventSystems; public class DraggableWindo…...

Map--08--CurrentHashMap 与 Hashtable的异同?

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Map方法computeIfAbsent1.computeIfAbsent 方法的简介2.案例computeIfAbsent() Map方法computeIfAbsent computeIfAbsent方法是Java 8中引入的一种简化操作Map的方…...

Docker学习笔记(三)存储与卷

挂载机制介绍 我们都知道&#xff0c;默认下&#xff0c;Docker容器与宿主机是完全隔离的&#xff0c;这种特性使得我们创建与删除容器都变得更方便&#xff0c;不需要再去删除宿主机上容器遗留下来的痕迹。   但是&#xff0c;当我们使用数据库一类需要持久化数据、共享数据…...

硬件工程师笔试面试——滤波器

目录 12、滤波器 12.1 基础 滤波器原理图 滤波器实物图 12.1.1 概念 12.1.2 滤波器的分类 12.1.3 滤波器的工作原理 12.1.4 滤波器的应用 12.1.5 滤波器设计的关键参数 12.2 相关问题 12.2.1 不同类型的滤波器在实际应用中的具体作用是什么? 12.2.2 如何设计一个简…...

【SpringBoot3】面向切面 AspectJ AOP 使用详解

文章目录 一、AspectJ介绍二、简单使用步骤1、引入依赖2、定义一个Aspect3、开启AOP支持 三、AOP 核心概念四、切点&#xff08;Pointcut&#xff09;1. execution2. within3. this & target4. args & args5. within & target & annotation 五、通知&#xff0…...

wav怎么转mp3格式?给你推荐几种音频格式转换方法

wav怎么转mp3格式&#xff1f;将wav文件转换为MP3格式是一个常见的操作&#xff0c;尤其适用于需要节省存储空间或确保文件兼容性的场景。wav文件保存了音频的所有原始数据&#xff0c;这使得它们的文件体积往往非常庞大。相比之下&#xff0c;MP3格式通过有损压缩技术显著减小…...

Redis的AOF持久化、重写机制、RDB持久化、混合持久化

1、AOF持久化 1.1.AOF持久化大致过程 概括&#xff1a;命令追加&#xff08;append&#xff09;、文件写入、文件同步&#xff08;sync&#xff09; Redis 每执行一条写操作命令&#xff0c;就把该命令以追加的方式写入到一个文件里&#xff0c;然后重启 Redis 的时候&#…...

Dom4j使用xpath查询xml文

Dom4j使用xpath查询带有命名空间的xml文件 方式1 忽略命名空间 DocumentFactory factory DocumentFactory.getInstance(); SAXReader reader new SAXReader(factory); Document document reader.read(xmlFilePath); Element rootElement document.getRootElement(); Nod…...

国家专精特新小巨人企业指标解析与扶持领域

一、什么是国家专精特新小巨人 &#xff08;一&#xff09;概念与定义 专精特新“小巨人”企业是指那些在细分市场中具有专业化、精细化、特色化和新颖化特征的中小企业中的佼佼者。这些企业在创新能力强、市场占有率高、掌握关键核心技术以及质量效益方面表现突出&#xff0…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

ElasticSearch搜索引擎之倒排索引及其底层算法

文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

使用 SymPy 进行向量和矩阵的高级操作

在科学计算和工程领域&#xff0c;向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能&#xff0c;能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作&#xff0c;并通过具体…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...