C++进阶 特殊类的设计

本篇博客介绍:介绍几种特殊的类

特殊类的设计

    • 设计一个类不能被拷贝
    • 设计一个类 只能在堆上创建对象
    • 设计一个类 只能在栈上创造对象
    • 设计一个类不能被继承
    • 单例模式
      • 饿汉模式
      • 懒汉模式
      • 单例模式对象的释放问题
    • 总结

设计一个类不能被拷贝

我们的拷贝只会发生在两个场景当中

  • 拷贝构造函数
  • 赋值运算符重载

所以说我们只需要让类失去 或者说不能使用这两个函数即可

这里有两个解决方案

在C++98中

我们将拷贝构造函数只声明不定义 并且将其访问权限设置为私有即可

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

原因如下

  • 我们设置为私有化之后 就能够禁止用户在外面调用 如果不设置私有 用户可以在外面定义并且调用
  • 因为我们不需要这个函数 所以定义没有意义 并且如果定义的话就可以在类内部调用从而以另一个函数完成拷贝

在C++11中

在C++11中 如果我们需要禁用一个函数直接使用delete关键字即可

代码标识如下

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

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

这个题目很有意思 让我们只能在堆上创建对象 也就是说我们不能在栈区还有静态区创建对象

再通俗一点说 我们不能创建局部变量和全局变量

用代码标识就是 下面的定义方式不允许

HeapOnly ho;
static HeapOnlu ho;

我们都知道 创建对象是需要构造函数的 所以说我们只需要将构造函数私有化之后 上面的创建方式就不允许了

但是实际上构造函数私有化之后我们也不能定义堆上的对象了

此时我们就需要创建一个新的函数 让这个函数帮助我们创建一个对象来

设计代码如下

  static HeapOnly* CreateObject() {   return new HeapOnly;  }

我们使用一个静态函数new出来一个新的对象 然后返回这个对象的指针 当然我们也只有这种方式可以获取新的对象 也就是说我们只能在堆上创建对象了

与此同时我们要禁用拷贝构造和赋值运算符重载

因为可能会有人写出这样子的代码导致我们的对象创建在栈上

HeapOnly* HO2 = HeapOnly(HO1);

禁用拷贝构造和赋值运算符重载的思路同第一

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

设计思路和只能在堆上创建对象类似 我们都是私有化构造函数之后暴露出一个静态函数来让外部调用

这个静态函数的唯一功能就是在栈上创建一个对象并且返回这个对象

class StackOnly
{
public:static StackOnly Createobj(){return StackOnly();}
private://将构造函数设置为私有StackOnly(){}
};

这里有一点需要特别注意 因为我们是在函数的内部创建了一个对象 所以说这个对象是一个局部变量 所以说我们必须要使用传值返回而不能使用传引用返回

而传值返回不可避免的一点就是 我们需要使用拷贝构造函数

但是呢 有了拷贝构造函数之后我们就没办法限制在堆和静态区创建对象了 因为用户可以通过拷贝构造的方式来实现这一点

所以说我们一定没办法禁止全局对象的创建 即在静态区中创建对象

但是我们还是有办法禁止对象在堆上创建

因为new和delete的底层使用的是operator new和operator delete所以说我们只需要在类中禁用这两个成员函数即可

void* operator new(size_t size) = delete;
void operator delete(void* p) = delete;

设计一个类不能被继承

在C++98中

在C++98中 因为子类必须要调用父类的构造函数 所以说我们只需要将父类的构造函数私有化

此时父类就成为了事实上不能被继承的类了 代码标识如下

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

在C++11中

在C++11中 提供了一个关键字给我们使用 final

  • final关键字 如果我们在一个类的后面加上final 那么该类就是最终类 不能被继承
class A final
{//...  
};

单例模式

设计模式概念:
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。为什么会产生设计模式这样的东西呢?就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期,七国之间经常打仗,就发现打仗也是有套路的,后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。

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

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

单例模式有两种实现方式 分别是 饿汉模式懒汉模式

饿汉模式

饿汉模式我们可以理解为这个人十分的饥饿 所以说食物必须要提前准备好

反应到代码中 就是这个单例要在main函数启动前就要准备好

设计思路如下

  • 我们让这个类中有一个静态的类对象 只声明不定义
  • 将构造函数私有化 私有化之后外部就不能通过构造函数来创建对象
  • 删除拷贝构造和赋值运算符重载函数
  • 在类外面定义这个静态对象
  • 暴露出一个静态函数 返回这个静态对象的指针

至此外面的饿汉模式就设计完毕了

//单例模式:全局只有唯一对象
//饿汉模式:一开始就创建对象(main函数之前)
class InfoSingleton
{
public:static InfoSingleton& GetInstance(){return _sins;}
private:InfoSingleton(){}InfoSingleton(InfoSingleton& info) = delete;InfoSingleton& operator=(const InfoSingleton& info) = delete;
private:static InfoSingleton _sins;//声明
};
InfoSingleton InfoSingleton::_sins;//定义,属于类域::,可以调用构造函数

饿汉模式的优缺点

优点:

  • 实现方式简单
  • 没有线程安全相关问题

缺点:

  • 因为在main函数之前就要定义 可能会导致启动慢
  • 无法控制单例初始化顺序

懒汉模式

懒汉模式我们可以理解为这个人十分的懒 所以说不到最后一刻要交任务的时候绝对不会做事的

反应到代码中 就是我们需要使用这个单例的时候这个单例才会创建 也就是说在main函数里面创建

设计思路如下

  • 我们让这个类中有一个静态的类对象 只声明不定义
  • 将构造函数私有化 私有化之后外部就不能通过构造函数来创建对象
  • 删除拷贝构造和赋值运算符重载函数
  • 在类外面定义这个静态对象指针设置为空
  • 暴露出一个静态函数 如果说指针为空则我们构造并返回一个新的对象

至此我们的懒汉模式就设计完毕了

//懒汉模式
class InfoSingleton
{
public:static InfoSingleton& GetInstance(){//第一次获取单例对象的时候创建对象if (_psins == nullptr){//第一次获取单例对象的时候创建对象_psins = new InfoSingleton;}return *_psins;}
private:InfoSingleton(){}InfoSingleton(const InfoSingleton& info) = delete;InfoSingleton& operator=(const InfoSingleton& info) = delete;private:static InfoSingleton* _psins;
};
InfoSingleton* InfoSingleton::_psins=nullptr;

懒汉模式的优缺点

优点:

  • 可以主动控制定义顺序
  • 在main函数后面启动 不影响启动时间

缺点:

  • 有很严重的线程安全问题

如果有两个线程同时进入了GetInstance()函数内部就有可能发生线程安全问题 而导致产生两个或多个对象出来

我们这里推荐一种双检查加锁模式

代码标识如下

static InfoSingleton& GetInstance(){//第一次获取单例对象的时候创建对象if (_psins == nullptr)//对象new出来以后,避免每次都加锁的检查,提高性能{_smtx.lock();if (_psins == nullptr)//保证线程安全的检查且只new一次{_psins = new InfoSingleton;}_smtx.unlock();}return *_psins;}

首先我们检查下 对象指针是否为空 如果为空我们加锁 (主要是为了避免无脑先加锁带来的效率损失)

其次我们加锁 并且再次检查对象指针是否为空 (主要是为了线程安全问题)

如果为空我们创建对象之后解锁 如果不为空我们直接解锁

单例模式对象的释放问题

我们的单例模式对象创建之后一般会运行到程序结束 所以说一般不存在释放问题

如果说就非要释放的话我们可以创造一个函数来释放我们的对象

static void DelInstance()
{_mtx.lock();if (_inst != nullptr){delete _inst;_inst = nullptr;}_mtx.unlock();
}

此外如果我们担心内存泄漏问题的话也可以使用智能指针来管理该对象

总结

在这里插入图片描述

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

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

相关文章

利用POM完成脚本分离实现企业级自动化(POM设计模式+页面的框架封装+测试报告截图)

利用POM完成脚本分离实现企业级自动化(POM设计模式页面的框架封装测试报告截图) 项目-测试-手工测试 项目-测试-手工测试 1.了解需求; 2.编写测试用例(开始)——功能测试组会去做的事情 3.执行测试用例——发送测试报…

Mac 开发 Tang Nano FPGA 指南(使用终端和使用 VS Code 和插件,适用所有 Gowin FPGA)

最近收到了一个 Tang nano 9K FPGA开发板,就想借此机会研究一下。 官方文档里介绍如果想使用高云的 FPGA,就需要使用 GOWIN IDE,但是需要申请 license 提交一堆资料,我是别人送的就不太方便让别人弄。加上 IDE 其实并不是很适合学…

C#语音播报问题之 无法嵌入互操作类型SpVoiceClass,请改用适用的窗口

C#语音播报问题之 无法嵌入互操作类型SpVoiceClass,请改用适用的窗口 解决办法如下: 只需要将引入的Interop.SpeechLib的属性嵌入互操作类型改为false 改为false 即可解决!

SpringCloud新人入门手册

一、SpringBoot流程图 二、创建一个单pom项目改为父子pom项目 0、检查idea是否在父模块pom中生成子模块 <modules><module>eureka</module></modules> 1、子模块pom.xml添加 <dependencies><dependency><groupId>org.springframew…

golang云原生项目之:etcd服务注册与发现

服务注册与发现&#xff1a;ETCD 1直接调包 kitex-contrib&#xff1a; 上面有实现的案例&#xff0c;直接cv。下面是具体的理解 2 相关概念 EtcdResolver: etcd resolver是一种DNS解析器&#xff0c;用于将域名转换为etcd集群中的具体地址&#xff0c;以便应用程序可以与et…

04_15页表缓存(TLB)和巨型页

前言 linux里面每个物理内存(RAM)页的一般大小都是4kb(32位就是4kb),为了使管理虚拟地址数变少 加快从虚拟地址到物理地址的映射 建议配值并使用HugePage巨型页特性 cpu和mmu和页表缓存(TLB)和cache和ram的关系 CPU看到的都是虚拟地址&#xff0c;需要经过MMU的转化&#xf…

ES的索引结构与算法解析

提到ES&#xff0c;大多数爱好者想到的都是搜索引擎&#xff0c;但是明确一点&#xff0c;ES不等同于搜索引擎。不管是谷歌、百度、必应、搜狗为代表的自然语言处理(NLP)、爬虫、网页处理、大数据处理的全文搜索引擎&#xff0c;还是有明确搜索目的的搜索行为&#xff0c;如各大…

使用Scikit-Learn实现多标签分类,助力机器学习

大家好&#xff0c;在机器学习任务中&#xff0c;分类是一种监督学习方法&#xff0c;用于根据输入数据预测标签。例如&#xff0c;我们想要根据历史特征预测某人是否对销售优惠感兴趣&#xff0c;通过使用可用的训练数据训练机器学习模型&#xff0c;可以对输入数据执行分类任…

基于VUE3+Layui从头搭建通用后台管理系统(前端篇)八:自定义组件封装上

一、本章内容 本章实现一些自定义组件的封装,包括数据字典组件的封装、下拉列表组件封装、复选框单选框组件封装、单选框组件封装、文件上传组件封装、级联选择组件封装、富文本组件封装等。 1. 详细课程地址: 待发布 2. 源码下载地址: 待发布 二、界面预览 ![在这里插入图…

Python应用工具-Jupyter Notebook

工具简介 Jupyter Notebook是 基于 网页的用于交互计算的 应用程序&#xff0c;以网页的形式打开&#xff0c;可以在网页页面中直接编写代码和运行代码&#xff0c;代码的运行结果也会直接在代码块下 显示&#xff0c;文档是保存为后缀名为 . ipynb 的 JSON 格式文件。 操作指令…

使用Spring Initializr方式构建Spring Boot项目

除了可以使用Maven方式构建Spring Boot项目外&#xff0c;还可以通过Spring Initializr方式快速构建Spring Boot项目。从本质上说&#xff0c;Spring lnitializr是一个Web应用&#xff0c;它提供了一个基本的项目结构&#xff0c;能够帮助我们快速构建一个基础的Spring Boot项目…

【图论】最短路的传送问题

一.分层图问题&#xff08;单源传送&#xff09; &#xff08;1&#xff09;题目 P4568 [JLOI2011] 飞行路线 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) &#xff08;2&#xff09;思路 可知背景就是求最短路问题&#xff0c;但难点是可以使一条路距离缩短至0&#xf…

系统报错mfc100u.dll丢失的解决方法(完美解决dll问题)

系统文件mfc100u.dll丢失和出错&#xff0c;极有可能是盗号木马、流氓软件等恶意程序所导致&#xff0c;其感染相关文件并加载起来&#xff0c;一旦杀毒软件删除被感染的文件&#xff0c;就会导致相关组件缺失&#xff0c;游戏等常用软件运行不起来&#xff0c;且提示“无法启动…

通过爬虫抓取上市企业利润表并在睿思BI中展示

睿思BI从v5.3开始支持网络爬虫&#xff0c;可以从指定URL抓取表格数据&#xff0c;本示例实现从网络上抓取上市企业招商银行的利润表数据&#xff0c;并在睿思BI中进行展现。 首先&#xff1a;从搜狐财经抓取招商银行利润表数据&#xff0c;操作过程如下&#xff1a; 1.在睿思…

迈向通用听觉人工智能!清华电子系、火山语音携手推出认知导向的听觉大语言模型SALMONN

日前&#xff0c;清华大学电子工程系与火山语音团队携手合作&#xff0c;推出认知导向的开源听觉大语言模型SALMONN (Speech Audio Language Music Open Neural Network)。 大语言模型 SALMONN LOGO 相较于仅仅支持语音输入或非语音音频输入的其他大模型&#xff0c;SALMONN对…

Spring学习笔记+SpringMvc+SpringBoot学习笔记

壹、核心概念&#xff1a; 1.1. IOC和DI IOC&#xff08;Inversion of Control&#xff09;控制反转&#xff1a;对象的创建控制权由程序转移到外部&#xff0c;这种思想称为控制反转。/使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程种对象…

【第三阶段】kotlin语言使用replace完成加解密操作

fun main() {val password"ASDAFWEFWVWGEGSDFWEFEWGFS"println("原始密码&#xff1a;$password")//加密操作,就是把字符替换成数字&#xff0c;打乱加密var newPsdpassword.replace(Regex("[ADWF]")){when(it.value){//it.value 这里的每一个字…

Vue实战

初始化项目 创建项目 指令&#xff1a; pnpm create vite 实例&#xff1a; C:\Users\Administrator\Desktop\Vue\Vue3_admin_template>pnpm create vite .../Local/pnpm/store/v3/tmp/dlx-6140 | 1 Packages are hard linked from the content-addressable store to…

aardio简单网站css或js下载练习

import win.ui; /*DSG{{*/ var winform win.form(text"下载网站css或js";right664;bottom290;maxfalse) winform.add( buttonClose{cls"button";text"退出";left348;top204;right498;bottom262;color14120960;fontLOGFONT(h-14);note" &qu…

期权就是股指期货吗,哪个好做一点?

近年来&#xff0c;场内ETF期权产品不断扩大&#xff0c;越来越多的投资者有投资期权的想法。当我们看到期权时&#xff0c;我们会不知不觉地想到期货&#xff0c;虽然期货与期权只有一个字的区别&#xff0c;但实际上有很大的不同&#xff0c;那么期权就是股指期货吗&#xff…