C++中特殊类的设计与单例模式的简易实现

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

对于这种特殊类的设计我们一般都是优先考虑私有构造函数。然后对于一些特殊要求就直接通过静态成员函数的实现来完成。

class A//构造函数私有(也可以析构函数私有)
{
public:static A* creat(){return new A;}
private:A(){}A(const A&) = delete;A operator=(const A&) = delete;int _a;
};

 这里选择禁掉拷贝构造函数和拷贝函数是为了防止将已创建的对象去拷贝构造新的对象。

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

class B
{
public:static B creat(){B tmp;return tmp;}//直接禁掉new和delete//全局也有,类中也有,会优先调用类中的operator new(类中专属的)void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:B(){}int _b;
};

 这里如果没有禁掉operator new和operator delete的话就会导致以下情况是在栈上创建对象

B* pb = new B(B::creat());//会调用拷贝构造

对于这种new一个对象的情况下是会调用拷贝构造函数的 ,而且我们是不能直接禁掉拷贝构造函数的,因为我们创建的对象必须通过调用拷贝构造函数来接受,所以就有了禁掉operator new和operator delete的方式。

对于在类中禁掉这两个函数,我们需要了解:当我们类中实现了operator new和operator delete这两个函数的话,在我们new该类对象或delete该类对象的话就会调用该类的operator new和operator delete函数,而不会选择调用全局的operator new和operator delete函数。

设计一个不能被继承的类

class D final
{D()//私有构造也可以{}
};

这里需要认识一个关键词final,该关键词修饰得类会不允许被继承。 

而且还有一点,我们知道继承一个类之后,子类创建对象会调用父类的构造函数,如果父类没有默认的构造函数的话,子类必须要显示的调用父类的构造函数。

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

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

饿汉模式

饿汉模式就是不管你用不用该实例,系统在启动程序时就会直接创建一个唯一的实例。

class A
{A(const A& tmp) = delete;//禁掉拷贝构造,防止再次创建对象A& operator=(const A& tmp) = delete;public:static A& getinstance()//通过成员函数得到该对象{return sigle;}void Add(string s1, string s2){_dict[s1] = s2;}void Print(){for (auto tmp : _dict){cout << tmp.first << ":" << tmp.second << endl;}}private:A()//只能创建一个对象,构造私有{cout << "构造完成" << endl;}map<string, string> _dict;static A sigle;//声明 类里面静态成员可以直接调用私有函数
};
A A::sigle;//定义(此时已经调用好了构造函数)

对于单例模式一般就是在类中提前声明好该静态对象 所以在定义自定义类型的的时候就会直接调用构造函数。而这sigle对象就是我们所创建的唯一实例。 

懒汉模式

懒汉模式就是在你开始调用的时候才会创建对象。

class B
{B(const B& tmp) = delete;//禁掉拷贝构造,防止再次创建对象B& operator=(const B& tmp) = delete;
public:static B* getinstance(){if (sigle == nullptr)//只有为空才创建sigle = new B;//一般不需要释放,进程结束的时候会释放return sigle;}static void del(){delete sigle;//为空就不会再调用析构函数sigle = nullptr;}void Add(string s1, string s2){_dict[s1] = s2;}void Print(){for (auto tmp : _dict){cout << tmp.first << ":" << tmp.second << endl;}}
private:B()//只能创建一个对象,构造私有{cout << "构造完成" << endl;}~B(){//持久化:要求数据写到文件中cout << "数据录入文件中 并析构" << endl;}map<string, string> _dict;static B* sigle;//内部类是外部类的友元class gc//类似智能指针,程序结束前调用析构{public:gc(){cout << "gc()" << endl;}~gc(){del();}};static gc _gc;//声明  创建静态成员,属于一个类,不会创建多份//程序结束前就会自动调用gc析构函数};
B* B::sigle = nullptr;//初始化为空
B::gc B::_gc;//定义  main结束会调用构造

对于懒汉模式和饿汉模式本质区别就是对象和指针的转变,饿汉模式的唯一实例是一个静态的类指针,但是该指针的释放就会有点困难,需要我们手动去delete,其实进程结束也是会释放内存的,但是对于一些需要持久化的将数据写到文件的情况时就会采用内部类gc来解决(内部类是外部类的友元,可以访问外部类的所有成员)而同样在外部类中创建静态成员,类外进行定义(调用构造),所以当main函数结束前,对于自定义的该成员就会自动调用析构函数,此时就可以进行持久化处理。

对于以上代码如果_gc不设为外部类的静态成员而是一般成员的话,就会陷入循环析构,因为对于外部类来说_gc属于类的自定义成员,所以当调用外部类的析构时就会先调用自生的析构函数再调用自定义成员_gc的析构函数,此时就会造成循环析构的情况。

int main()
{B::getinstance()->Add("sort", "排序");B::getinstance()->Add("left", "左边");B::getinstance()->Print();//B::del();return 0;
}

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

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

相关文章

docker容器下php框架laravel的使用问题与解决方案

DB_CONNECTIONmysqlDB_HOSTlocalhost DB_CONNECTIONmysqlDB_HOSTdocker33-mysql-1 容器中只有数据库结构 进入MySQL容器内&#xff0c;创建表结构&#xff0c;添加数据 代码层面需要转换成数组 $query->get([*])->toArray(); 分页数据框架会返回带有data的数据&#xf…

计算机网络-AAA原理概述

对于任何网络&#xff0c;用户管理都是最基本的安全管理要求之一&#xff0c;在华为设备管理中通过AAA框架进行认证、授权、计费实现安全验证。 一、AAA概述 AAA&#xff08;Authentication(认证), Authorization(授权), and Accounting(计费)&#xff09;是一种管理框架&#…

大模型微调实战笔记

大模型三要素 1.算法&#xff1a;模型结构&#xff0c;训练方法 2.数据&#xff1a;数据和模型效果之间的关系&#xff0c;token分词方法 3.算力&#xff1a;英伟达GPU&#xff0c;模型量化 基于大模型对话的系统架构 基于Lora的模型训练最好用&#xff0c;成本低好上手 提…

CentOS 7安装全解析:适合初学者的指导

目录 前言 一.centos安装 1.下载镜像文件 2.安装 二.远程连接&#xff0c;换源 1.下载并且使用MobaXtermMobaXterm free Xserver and tabbed SSH client for Windows (mobatek.net)https://mobaxterm.mobatek.net/ 远程连接 2.换源 前言 在当今的信息化时代&#xff0c…

【Leetcode 965.】判断单值二叉树

单值二叉树&#xff1a; 示例一&#xff1a; 示例二&#xff1a; 代码&#xff1a; bool isUnivalTree(struct TreeNode* root) {if(rootNULL)return true;if(root->left&&root->left->val!root->val)return false;if(root->right&&root-&…

【LeetCode-135】分发糖果(贪心)

LeetCode135.分发糖果 题目描述 老师想给孩子们分发糖果&#xff0c;有 N 个孩子站成了一条直线&#xff0c;老师会根据每个孩子的表现&#xff0c;预先给他们评分。 你需要按照以下要求&#xff0c;帮助老师给这些孩子分发糖果&#xff1a; 每个孩子至少分配到 1 个糖果。…

Neos的渗透测试靶机练习——DarkHole-2

DarkHole-2 一、实验环境二、开始渗透1. 搜集信息2. git文件泄露3. SQL注入4. 提权 三、总结 一、实验环境 虚拟机软件&#xff1a;VirtualBox 攻击机&#xff1a;kali linux&#xff08;网卡初始为仅主机模式&#xff0c;要有安全意识&#xff09; 靶机&#xff1a;DarkHole-…

vue3+Element plus实现登录功能

一、想要实现的效果 二、搭建登录静态 1、实现左边背景和右边登录栏的总体布局布局&#xff1a; <el-row class"content"><!--el-col 列&#xff1a; --><el-col :span"16" :xs"0" class"content-left"></el-c…

仓储管理系统——软件工程报告(可行性研究报告及分析)①

可行性研究报告及分析 一、问题定义 1.1项目背景 随着社会的发展以及企业规模的扩大和业务的复杂化&#xff0c;仓库管理变得愈发重要。传统的手工管理方式已经导致了一系列问题&#xff0c;包括库存准确性低、订单处理效率慢等。为了提高仓库运作效率、降低成本并优化库存管…

unity 单例模式(实例详解)

文章目录 在Unity中&#xff0c;单例模式是一种常用的编程设计模式&#xff0c;用于确保在整个应用程序生命周期中&#xff0c;只有一个类的实例存在。这样可以保证数据的全局唯一性和共享性&#xff0c;例如游戏场景中的资源管理器、游戏控制器、事件管理器等。 以下是一个简单…

如何用 500 行 SQL 实现 GPT2学习

目录 理论背景实现过程GenerationTokenizerEmbeddingsAttention为什么我们需要有因果掩码&#xff1f;为什么矩阵是 Q&#xff0c;K 和 V&#xff1f; BlocksTokens为什么要使用 softmax 转换概率&#xff1f;Inference 俄罗斯有个大佬每年都会用 SQL 来实现一个挑战庆祝新年&a…

Android:JNI实战,理论详解、Java与Jni数据调用

一.概述 上一篇博文讲解了如何搭建一个可以加载和链接第三方库、编译C/C文件的Jni Demo App。 这篇博文在这个Jni Demo App的基础上&#xff0c;从实战出发详细讲解 Jni 开发语法。 接下来&#xff0c;先用一小节将Jni开发比较重要的理论知识点过一下&#xff0c;然后进行代…

matlab appdesigner系列-常用17-编辑字段(数值、文本)

编辑字段&#xff08;数值、文本&#xff09;可直接键入数值、文本&#xff0c;其他组件直接调用其值。也可以利用把其他组件回调的值&#xff0c;返回到编辑字段&#xff08;数值、文本&#xff09;进行显示。 示例&#xff1a;利用按钮组件改变编辑字段&#xff08;数值&…

详解APQC流程分级分类框架PCF13个高阶分类和5级业务流程

一&#xff1a;什么是APQC 美国生产力与质量中心(American Productivity and Quality Center&#xff0c;简称为APQC)&#xff0c;创立于1977年是一个会员制的非营利机构&#xff0c;使命是“发现有效的改进方法&#xff0c;广泛地传播其发现成果&#xff0c;实现个人之间及其…

etcd基本介绍

etcd基本介绍 ETCD是SoreOs公司发布的一个分布式的、高可用的、key-value存储的数据库。基于Go语言实现&#xff0c;k8s中也使用了ETCD作为数据库。主要用于共享配置和服务发现。相对于zookeeper采用的Paxos&#xff0c;ETCD采用的是Raft算法&#xff0c;该算法具备的性能更佳…

Centos7 安装redis 详细步骤访问不了github和windows系统下载

windows系统下载 https://hellowindows.cn/ VMware虚拟机安装Windows Server 2016 VL https://blog.csdn.net/qq_37545849/article/details/134828341 VMware全屏时不显示上方命令栏的边缘 此时如果要返回&#xff0c;可以把鼠标移动至屏幕上方边缘短暂停留以呼出命令栏。或使…

第二篇【传奇开心果短博文系列】Python的OpenCV库技术点案例示例:图像处理

传奇开心果短博文系列 系列短博文目录Python的OpenCV库技术点案例示例短博文系列 博文目录一、项目目标二、第一个示例代码三、第二个示例代码四、第三个示例代码五、第四个示例代码六、第五个示例代码七、知识点归纳总结 系列短博文目录 Python的OpenCV库技术点案例示例短博文…

OPENGL光线追踪

纪念一下运行出了光线追踪代码,用了glfw和glad。 光线的数学表达式 一条光线实际上只是一个起点和一个传播方向&#xff0c;因此光线表达式为&#xff1a; p(t) e t (s-e) 光线与球相交 已知球体的隐式方程为&#xff1a; 把光线 p(t) e t d 代入上述方程&#xff0c;得…

基于SpringBoot Vue医院门诊管理系统

大家好✌&#xff01;我是Dwzun。很高兴你能来阅读我&#xff0c;我会陆续更新Java后端、前端、数据库、项目案例等相关知识点总结&#xff0c;还为大家分享优质的实战项目&#xff0c;本人在Java项目开发领域有多年的经验&#xff0c;陆续会更新更多优质的Java实战项目&#x…

RPC和HTTP,它们之间到底啥关系

既然有 HTTP 请求&#xff0c;为什么还要用 RPC 调用&#xff1f; gPRC 为什么使用 HTTP/2 Spring Cloud 默认是微服务通过Restful API来进行互相调用各自微服务的方法&#xff0c;同时也支持集成第三方RPC框架&#xff08;这里的说的RPC是特指在一个应用中调用另一个应用的接…