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.rhkb.cn/news/97192.html

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

相关文章

OSPF在广播类型的网络拓扑中DR和BDR的选举

指定路由器(DR): 一个网段上的其他路由器都和指定路由器(DR)构成邻接关系,而不是它们互相之间构成邻接关系。 备份指定路由器(BDR): 当DR出现问题,由BDR接…

prompt-engineering-note(面向开发者的ChatGPT提问工程学习笔记)

介绍: ChatGPT Prompt Engineering Learning Notesfor Developers (面向开发者的ChatGPT提问工程学习笔记) 课程简单介绍了语言模型的工作原理,提供了最佳的提示工程实践,并展示了如何将语言模型 API 应用于各种任务的应用程序中。 此外&am…

WebRTC | SDP详解

目录 一、SDP标准规范 1. SDP结构 2. SDP内容及type类型 二、WebRTC中的SDP结构 1. 媒体信息描述 (1)SDP中媒体信息格式 i. “artpmap”属性 ii. “afmtp”属性 (2)SSRC与CNAME (3)举个例子 &…

回归预测 | MATLAB实现BES-SVM秃鹰搜索优化算法优化支持向量机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现BES-SVM秃鹰搜索优化算法优化支持向量机多输入单输出回归预测(多指标,多图) 目录 回归预测 | MATLAB实现BES-SVM秃鹰搜索优化算法优化支持向量机多输入单输出回归预测(多指标,多图)效…

vue-element-admin新增view后点击侧边栏加载慢问题

按照官网文档新增view 新增之后点击显示一直在加载中 解决方案:删除script中这段代码

C++之std::unordered_map<int, int, string>应用实例(一百八十)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 人生格言: 人生…

C# 读取pcd、ply点云文件数据

最近研究了下用pcl读取点云数据,又做了个C#的dll,方便读取,同样这个dll基于pcl 最新版本1.13.1版本开发。 上次做的需要先得到点云长度,再获取数据。这次这个定义了一个PointCloudXYZ类来存数据。将下面的dll拷贝到可执行目录下&a…

输入输出+暴力模拟入门:魔法之树、染色の树、矩阵、字母加密、玫瑰鸭

秋招实习刷题网站推荐&#xff1a;codefun2000.com&#xff0c;还有题解博客&#xff1a;blog.codefun2000.com/。以下内容都是来自塔子哥的~ 输入输出 2023.04.15-春招-第三题-魔法之树 //#include<bits/stdc.h> #include<vector> #include<iostream>usin…

如何创建和查看软链接和硬链接?这二者的区别是什么?

索引节点&#xff08;inode&#xff09;硬链接创建硬链接查看硬链接 软链接创建软链接查看软链接 inode编号妙用总结软链接和硬链接的区别感谢 &#x1f496; hello大家好&#x1f60a; 在linux中&#xff0c;文件链接可以使多个文件名引用同一个文件。有两种方式可以创建指向同…

基于traccar快捷搭建gps轨迹应用

0. 环境 - win10 虚拟机ubuntu18 - i5 ubuntu22笔记本 - USB-GPS模块一台&#xff0c;比如华大北斗TAU1312-232板 - 双笔记本组网设备&#xff1a;路由器&#xff0c;使得win10笔记本ip&#xff1a;192.168.123.x&#xff0c;而i5笔记本IP是192.168.123.215。 - 安卓 手机 1.…

JAVA基础知识(五)——面向对象(中)

面向对象&#xff08;中&#xff09; 一、面向对象特征之一&#xff1a;封装与隐藏1.1 简介1.2 封装性的体现1.3 四种访问权限修饰符 二、类的成员之三&#xff1a;构造器2.1 构造器的特征2.2 构造器的作用2.3 语法格式2.4 构造器分类2.5 构造器重载2.6 属性赋值过程 三、扩展知…

Scratch 游戏 之 随机大地图生成教程

在很多生存 / 沙盒类游戏中&#xff0c;地图往往是随机生成的&#xff0c;例如&#xff1a;饥荒、我的世界等。那我们该如何在scratch中实现这一点呢&#xff1f; 在scratch中有两种办法可以实现——画笔和克隆体。我们这次先聊克隆体。 我们可以先将克隆体设置为方形的&#x…

什么是单例模式

什么是单例模式 文章目录 什么是单例模式1. 单例(单个的实例)2. 单例模式应用实例3. 饿汉式 VS 懒汉式 1. 单例(单个的实例) 所谓类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一…

CF 1354 C1 C2 Polygon Embedding(求奇偶正多边形的外接最小正方形的边长)

CF 1354 C1 / C2 Polygon Embedding(求奇偶正多边形的外接最小正方形的边长) Problem - C1 - Codeforces Problem - C2 - Codeforces EASY &#xff1a; 大意&#xff1a;给出一个偶数 n &#xff0c; 求 正 (2 * n) 边形的最小外接正方形的边长。 可以想出两种最直观的情况…

如何构造不包含字母和数字的webshell

目录 利用不含字母与数字进行绕过 1.异或进行绕过 2.取反进行绕过 3.利用php语法绕过 利用不含字母与数字进行绕过 基本代码运行思路理解 <?php echo "A"^""; ?> 运行结果为! 我们可以看到&#xff0c;输出的结果是字符"!"。之所…

【论文解读】Hybrid-SORT: Weak Cues Matter for Online Multi-Object Tracking

因为Hybrid-SORT的baseline是基于OCSORT进行改进的&#xff0c;在这之前建议先了解byteTrack和【】的相关知识 1.介绍 1.1 基本框架 多目标跟踪(MOT)将问题分为两个子任务。第一个任务是检测每个帧中的对象。第二个任务是将它们在不同的框架中联系起来。关联任务主要通过显式…

Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)

文章目录 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三)前情提要客户端部分 Unity进阶–通过PhotonServer实现联网登录注册功能(客户端)–PhotonServer(三) 前情提要 单例泛型类 using System.Collections; using System.Collections.Generic; …

sql:知识点记录一

1.Mysql逻辑架构&#xff1a;连接层、服务层、引擎层、存储层 2.show engines&#xff1a;查看存储引擎 3.Mysql两种存储引擎的区别&#xff1a; 建立索引&#xff1a;比如说用户很喜欢用name去查询表&#xff0c;就可以给数据库的name字段建立索引&#xff0c;提高查询效率&a…

【潮州饶平】联想 IBM x3850 x6 io主板故障 服务器维修

哈喽 最近比较忙也好久没有更新服务器维修案例了&#xff0c;这次分享一例潮州市饶平县某企业工厂一台IBM System x3850 x6服务器亮黄灯告警且无法正常开机的服务器故障问题。潮州饶平ibm服务器维修IO主板故障问题 故障如下图所示&#xff1a; 故障服务器型号&#xff1a;IBM 或…