【C++从0到王者】第四十一站:特殊类的设计

文章目录

  • 一、设计一个类,不能被拷贝
    • 1.C++98方法
    • 2.C++11方法
  • 二、设计一个类,只能在堆上创建对象
    • 1.析构函数私有化
    • 2.构造函数私有化
  • 三、请设计一个类,只能在栈上创建对象
  • 四、设计一个类不能被继承
    • 1.C++98方式
    • 2.C++11方式
  • 五、设计一个类,只能创建一个对象(单例模式)
    • 1.饿汉模式
    • 2.懒汉模式

一、设计一个类,不能被拷贝

这个我们前面已经说过了

有两种方法

1.C++98方法

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

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

原因:

  1. 设置成私有:如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了

  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

2.C++11方法

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

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

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

1.析构函数私有化

如下所示,由于在栈区和静态区的资源在生命周期结束的时候会调用析构函数。所以我们大可以直接将析构函数私有化。

这样一来,栈区和静态区的就无法创建对象了。而对于堆区的,由于他本身不会自动调用析构函数。我们需要手动去释放,但是由于我们现在的析构函数私有化了,所以我们可以通过一个接口去析构。如下代码所示:

class HeapOnly
{
public:void Destory(){delete this;}
private:~HeapOnly(){//...}
};
int main()
{HeapOnly hp1;static HeapOnly hp2;HeapOnly* hp3 = new HeapOnly;hp3->Destory();return 0;
}

我们可以明显的注意到,前两个是报错的

image-20240205013719829

2.构造函数私有化

这里需要注意的是,我们也要封住拷贝构造函数。因为可能会通过拷贝构造函数去创建栈区上的对象

class HeapOnly
{
public:static HeapOnly* CreatObj(){return new HeapOnly;}
private:HeapOnly(){//...}//C++11的方法,拷贝构造必须封HeapOnly(const HeapOnly& hp) = delete;//赋值运算符重载可封可不封HeapOnly& operator=(const HeapOnly& hp) = delete;
};
int main()
{HeapOnly hp1;static HeapOnly hp2;HeapOnly* hp3 = HeapOnly::CreatObj();//封住拷贝构造是为了防止下面的情形HeapOnly hp4(*hp3);return 0;
}

我们显然看到,我们这个只能在堆区创建了

image-20240205014636704

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

如下代码所示

为了让只在栈上创建对象,我们肯定不可以封住析构函数,因为栈区的一定会调用析构函数。

所以我们只能从构造函数下手,于是我们可以将构造函数私有化,然后提供一个接口去接收这个对象。

这里还需要注意的是,我们的new也可以是拷贝构造。但是我们是不可以封住拷贝构造的,因为我们返回一个对象的时候,需要调用拷贝构造。

我们注意到operator new是在全局中的一个函数重载,所以我们可以利用它会优先访问类域的特性,我们在类里面实现一个专属的operator new,然后我们就可以将这个函数给删掉。也就是无法使用new了。

最终我们就彻底屏蔽了堆区的创建。

但是这里我们其实还有一个静态区如果调用拷贝构造怎么办?这里如果还有屏蔽掉静态就比较麻烦了。虽然无法彻底解决问题,但是也已经可以了。

class StackOnly
{
public:static StackOnly CreatObj(){return StackOnly();}
private:StackOnly(){//...}//对一个类实现专属的operator newvoid* operator new(size_t size) = delete;
};int main()
{StackOnly st1;static StackOnly st2;StackOnly* st3 = new StackOnly;StackOnly st4 = StackOnly::CreatObj();StackOnly st5(st4);StackOnly* st6 = new StackOnly(st4);return 0;
}

我们可以注意到,确实只可以在栈上创建对象

image-20240205225248713

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

1.C++98方式

由于继承的派生类必须调用基类的构造函数。所以我们可以封住构造函数

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};

2.C++11方式

final关键字可以禁止某个虚函数无法被重写

final还可以修饰类,表示该类不能被继承。

class A  final
{// ....
};

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

1.饿汉模式

饿汉模式就是:一开始(main函数之前)就创建单例对象

问题:

  1. 如果单例对象很大或者初始化内容很多,影响启动速度
  2. 如果两个单例类,互相有依赖关系。要求A先创建,B再创建,B的初始化创建依赖A

饿汉模式的实现如下

要注意,为了防止拷贝构造或者赋值运算符重载去创建新的对象,要将他们给封住

class Singleyton
{
public:static Singleyton* GetInstance(){return &_sinst;}
private:Singleyton(){}//禁止拷贝Singleyton(const Singleyton& s) = delete;//禁止赋值Singleyton& operator=(const Singleyton& s) = delete;map<string, string> _dict;//可以放到静态区,注意这里只是声明static Singleyton _sinst;
};
//定义,这里的_sinst是在类里面声明的,所以可以调用类里面的构造函数
//就像一个函数在类里面声明,在外面定义是可以直接使用类里面的成员变量一样的
Singleyton Singleyton::_sinst;int main()
{Singleyton* s1 = Singleyton::GetInstance();Singleyton* s2 = Singleyton::GetInstance();Singleyton* s3 = Singleyton::GetInstance();Singleyton* s4 = Singleyton::GetInstance();cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;return 0;
}

image-20240205233101010

2.懒汉模式

我们先看下面的代码

懒汉模式其实就是一开始先不创建创建对象,而是在第一次去获取这个对象的时候去创建的。

对于单例模式它一般是不需要释放的。但是在一些特殊场景还是需要的。这时候我们需要显示释放,程序结束时,需要做一些持久化的动作(写到文件中去)

如下中,是写了一个Delnstance函数去释放这块资源的。

为了方便,我们可以专门去写一个类,定义一个全局对象去专门来释放它。

namespace lazy
{class Singleyton{public:static Singleyton* GetInstance(){//如果还没有创建,就创建一下这个对象if (_psinst == nullptr){_psinst = new Singleyton;}return _psinst;}//一般而言单例不用释放,//在一些特殊场景: 1. 需要显示释放, 2. 程序结束时,需要做一些特殊动作(如持久化)static void DelInstance(){if (_psinst){delete _psinst;_psinst = nullptr;}}~Singleyton() {cout << "~Singleyton()" << 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);}}void ADD(string s1, string s2){_dict[s1] = s2;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}}private:Singleyton(){}//禁止拷贝Singleyton(const Singleyton& s) = delete;//禁止赋值Singleyton& operator=(const Singleyton& s) = delete;map<string, string> _dict;//可以放到静态区,注意这里只是声明static Singleyton* _psinst;};Singleyton* Singleyton::_psinst = nullptr;
}
class GC
{
public:~GC(){lazy::Singleyton::DelInstance();}
};
GC g;
int main()
{lazy::Singleyton* s1 = lazy::Singleyton::GetInstance();s1->ADD("xxx", "111");s1->ADD("yyy", "222");s1->ADD("zzz", "333");s1->ADD("abc", "444");s1->Print();//s1->DelInstance();return 0;
}

运行结果为

image-20240205235753609

image-20240206000233100

不过我们也可以将这个类写到内部类里面,这样的话这个也是可以的

namespace lazy
{class Singleyton{public:class GC{public:~GC(){lazy::Singleyton::DelInstance();}};static Singleyton* GetInstance(){//如果还没有创建,就创建一下这个对象if (_psinst == nullptr){_psinst = new Singleyton;}return _psinst;}//一般而言单例不用释放,//在一些特殊场景: 1. 需要显示释放, 2. 程序结束时,需要做一些特殊动作(如持久化)static void DelInstance(){if (_psinst){delete _psinst;_psinst = nullptr;}}~Singleyton() {cout << "~Singleyton()" << 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);}}void ADD(string s1, string s2){_dict[s1] = s2;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}}private:Singleyton(){}//禁止拷贝Singleyton(const Singleyton& s) = delete;//禁止赋值Singleyton& operator=(const Singleyton& s) = delete;map<string, string> _dict;//可以放到静态区,注意这里只是声明static Singleyton* _psinst;static GC _gc;};Singleyton* Singleyton::_psinst = nullptr;Singleyton::GC Singleyton::_gc;
}int main()
{lazy::Singleyton* s1 = lazy::Singleyton::GetInstance();s1->ADD("xxx", "111");s1->ADD("yyy", "222");s1->ADD("zzz", "333");s1->ADD("abc", "444");s1->Print();//s1->DelInstance();return 0;
}

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

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

相关文章

【JavaScript 漫游】【013】Date 对象知识点摘录

文章简介 本文为【JavaScript 漫游】专栏的第 013 篇文章&#xff0c;记录了 JS 语言中 Date 对象的重要知识点。 普通函数的用法构造函数的用法日期的运算静态方法&#xff0c;包括&#xff1a;Date.now()、Date.parse() 和 Date.UTC()实例方法&#xff0c;包括&#xff1a;…

156基于Matlab的光纤陀螺随机噪声和信号

基于Matlab的光纤陀螺随机噪声和信号&#xff0c;利用固定步长和可调步长的LMS自适应滤波、最小二乘法、滑动均值三种方法进行降噪处理&#xff0c;最后用阿兰方差评价降噪效果。程序已调通&#xff0c;可直接运行。 156 信号处理 自适应滤波 降噪效果评估 (xiaohongshu.com)

[office] Excel自带的编辑函数求和方法 #其他#媒体

Excel自带的编辑函数求和方法 今天小编为大家分享Excel自带的编辑函数求和方法&#xff0c;方法很简单的&#xff0c;对于不是很熟悉excel表格的朋友可以参考一下&#xff0c;希望能对大家有所帮助 很多同学以及上班族需要大量使用Excel这款表格编辑器&#xff0c;当表格中有大…

论文笔记:相似感知的多模态假新闻检测

整理了RecSys2020 Progressive Layered Extraction : A Novel Multi-Task Learning Model for Personalized Recommendations&#xff09;论文的阅读笔记 背景模型实验 论文地址&#xff1a;SAFE 背景 在此之前&#xff0c;对利用新闻文章中文本信息和视觉信息之间的关系(相似…

CSP-202009-1-称检测点查询

CSP-202009-1-称检测点查询 解题思路 本题的时间复杂度貌似没有限制&#xff0c;直接暴力枚举就能知识盲点&#xff1a;sort()函数-升序排序 #include <algorithm>给名为dis&#xff0c;长度为n的数组排序sort(new_dis, new_dis n); #include <iostream> #inc…

labelimg 在pycharm下载使用

labelimg 使用数据标注工具 labelimg 制作数据集 在pycharm中搜索labelimg 选择版本安装 labelimg install 使用数据标注工具制作数据集 启动 带参数启动 1、cmd cd到指定目录 2、带参数启动标注工具 左侧可以选择切换为需要的数据格式 一些快捷键 和自动保存&#xff0c…

Stable Diffusion 模型下载:RealCartoon-Realistic - V13

文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十下载地址模型介绍 该检查点是 RealCartoon3D 检查点的一个分支。这个目标是在背景和人物中产生更“真实”的外观。我试图避免这个模型中更多的动漫、卡通和“完美”外观。这是一个肯

hexo 博客搭建以及踩雷总结

搭建时的坑 文章置顶 安装一下这个依赖 npm install hexo-generator-topindex --save然后再文章的上面设置 top: number&#xff0c;数字越大&#xff0c;权重越大&#xff0c;也就是越靠顶部 hexo 每次推送 nginx 都访问不到 宝塔自带的 nginx 的 config 里默认的角色是 …

easyx 随机火花生成器 视觉盛宴

作品介绍&#xff1a; 在数字化艺术的世界里&#xff0c;我们经常寻求模拟自然现象的方式&#xff0c;为观众带来沉浸式的体验。本作品“随机火花生成器”就是一个尝试&#xff0c;通过编程模拟了火花的随机生成和消散过程。 在这段代码中&#xff0c;我们使用了EasyX图形库&…

前端JavaScript篇之如何获得对象非原型链上的属性?

目录 如何获得对象非原型链上的属性&#xff1f; 如何获得对象非原型链上的属性&#xff1f; 要获取对象上非原型链上的属性&#xff0c;可以使用 hasOwnProperty() 方法。这个方法是 JavaScript 内置的对象方法&#xff0c;用于检查一个对象是否包含指定名称的属性&#xff0…

【论文阅读笔记】InstantID : Zero-shot Identity-Preserving Generation in Seconds

InstantID:秒级零样本身份保持生成 理解摘要Introduction贡献 Related WorkText-to-image Diffusion ModelsSubject-driven Image GenerationID Preserving Image Generation Method实验定性实验消融实验与先前方法的对比富有创意的更多任务新视角合成身份插值多身份区域控制合…

Linux操作系统基础(六):Linux常见命令(一)

文章目录 Linux常见命令 一、命令结构 二、ls命令 三、cd命令 四、mkdir命令 五、touch命令 六、rm命令 七、cp命令 八、mv命令 九、cat命令 十、more命令 Linux常见命令 一、命令结构 command [-options] [parameter]说明: command : 命令名, 相应功能的英文单词…

Dubbo源码一:【Dubbo与Spring整合】

正常在项目中&#xff0c;我们都是在Spring环境下使用Dubbo&#xff0c;所以我们这里就在Spring的环境下看看Dubbo是如何运作的 入口 在源码下载下来之后&#xff0c;有一个dubbo-demo目录&#xff0c;里面有一个基于spring注解的子目录dubbo-demo-annotation, 里面有一个生产…

【PyQt】10 QLineEdit

文章目录 前言一、回显模式&#xff08;EchoMode&#xff09;1.1 四种回显模式1.2 代码展示运行结果 二、校验器2.1 代码2.2 运行结果 三、通过掩码限制输入3.1 代码3.2 运行结果 总结 前言 1、QLineEdit 可以输入单行文字 2、回显模式 3、校验器 4、掩码输入 一、回显模式&am…

k8s-资源限制与监控 15

资源限制 上传实验所需镜像 Kubernetes采用request和limit两种限制类型来对资源进行分配。 request(资源需求)&#xff1a;即运行Pod的节点必须满足运行Pod的最基本需求才能 运行Pod。 limit(资源限额)&#xff1a;即运行Pod期间&#xff0c;可能内存使用量会增加&#xff0…

Jupyter Notebook如何在E盘打开

Jupyter Notebook如何在E盘打开 方法1&#xff1a;方法2&#xff1a; 首先打开Anaconda Powershell Prompt, 可以看到默认是C盘。 可以对应着自己的界面输入&#xff1a; 方法1&#xff1a; (base) PS C:\Users\bella> E: (base) PS E:\> jupyter notebook方法2&#x…

跳表详解和实现|深挖Redis底层数据结构

文章目录 跳表前言项目代码仓库认识跳表跳表的实现思路跳表性能分析对比平衡树&#xff08;avl和红黑树&#xff09;和哈希表使用手册成员变量成员函数构造析构迭代器sizeclearemptyoperatorfindinserterase 跳表细节实现节点定义跳表结构定义构造、析构、拷贝构造和赋值重载si…

人工智能算法:理解其工作原理及其在现实世界中的应用

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已逐渐成为我们生活中不可或缺的一部分。从智能语音助手到自动驾驶汽车&#xff0c;再到医疗诊断系统&#xff0c;人工智能算法正以前所未有的速度改变着我们的世界。本文将带您深入探讨人工智能算法的工作原…

【MySQL】数据库的基础——数据库的介绍、MySQL的介绍和架构、SQL分类、MySQL的基本使用、MySQL的存储引擎

文章目录 MySQL1. 数据库的介绍1.2 主流数据库 2. MySQL的介绍2.1 MySQL架构2.2 SQL分类2.3 MySQL的基本使用2.4 MySQL存储引擎 MySQL 1. 数据库的介绍 数据库&#xff08;Database&#xff0c;简称DB&#xff09;是按照数据结构来组织、存储和管理数据的仓库。它是长期存储在计…

uni-app x,一个纯原生的Android App开发工具

uni-app x&#xff0c;下一代uni-app&#xff0c;一个神奇的产品。 用vue语法、uni的组件、api&#xff0c;以及uts语言&#xff0c;编译出了kotlin的app。不再使用js引擎和webview。纯纯的kotlin原生app。 uni-app x&#xff0c;让“跨平台开发性能不如原生”的这条曾广为流…