C++的特殊类设计 饥饿汉模式

目录

特殊类设计

设计一个不能被拷贝的类

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

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

设计一个不能继承的类

设计模式

单例模式

饿汉模式

饥汉模式


特殊类设计

设计一个不能被拷贝的类

C++98的设计方式:将该类的拷贝构造和赋值运算符重载函数均只声明不定义,并将它们的访问权限设置为私有

class CopyBan
{// ...//设置为私有
private:CopyBan(const CopyBan&);CopyBan& operator=(const CopyBan&);//...
};
  • 只声明不定义:本就不会使用再定义没意义,且如果有定义的话虽然设置了private,但只是为了防外部人调用的,但类内部的其它成员还可以使用拷贝构造和赋值重载

template<class T>
class SmartPtr
{
public:// RAIISmartPtr(T* ptr):_ptr(ptr){}//...void Printf(){SmartPtr<int> s1(new int(2));SmartPtr s2(s1);}private://拷贝构造SmartPtr(const SmartPtr& s){cout << "SmartPtr(const SmartPtr& s)" << endl;}T* _ptr;
};
  • 设置为private: 只声明不设置为private,外部用户就可以在类外实现这两个函数的定义
class Example {
public:Example() {};//只声明不定义Example(const Example& e);//拷贝构造Example& operator=(const Example& e);//赋值重载
};// 在类外部定义 拷贝构造 和 赋值重载
Example::Example(const Example& e)
{cout << "Example(const Example& e)\n";
}Example& Example::operator=(const Example& e)
{cout << "Example& Example::operator=(const Example& e)\n";return *this;
}int main()
{	// 使用类外定义的 拷贝构造 和 赋值重载Example e1;Example e2(e1);e2 = e1;return 0;
}

C++11的设计方式:使用=delete的方法,在成员函数后加上=delete,那么编译器就不会生成该成员函数的定义(不需要再使用private限制了,但仍需声明)

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

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

设计方式:将构造函数设为私有,防止用户在类外调用构造函数从而在栈上生成对象,然后再定义一个public权限的静态成员函数,该函数用于在堆上创建该类的对象并返回该对象的指针

补充:还需要将拷贝构造和赋值重载也设置为只声明不定义 + 访问权限为private 或者 =delete,防止用户调用默认的拷贝构造在栈上生成该类的对象

class HeapOnly
{
public://静态成员函数:可以直接通过类名调用,而不需要类的对象实例static HeapOnly* CreatObj(){return new HeapOnly;//在堆上new一个HeapOnly类型的匿名对象,并返回该对象的指针   }HeapOnly(const HeapOnly& e)=delete;HeapOnly& operator=(const HeapOnly& e)=delete;
private:HeapOnly() {};//默认构造函数};int main()
{//HeapOnlye1;//错误,不可访问//HeapOnly* e2 = CreatObj();//错误,找不到该函数HeapOnly* e2 = HeapOnly::CreatObj();//HeapOnlye3(*e2);//尝试调用拷贝构造在栈上生成一个该类的对象return 0;
}
  • 还可以加上多参数模板,实现传递多个参数进行构造,当然构造函数也要提供合适的版本

class HeapOnly
{
public:template<class... Args>static HeapOnly* CreateObj(Args&&... args){return new HeapOnly(args...);}HeapOnly(const HeapOnly&)=delete;HeapOnly& operator=(const HeapOnly&)=delete;private://无参构造
HeapOnly()
{}//接收两个参数的构造函数
HeapOnly(int x, int y):_x(x),_y(y)
{}};int main()
{HeapOnly* ho3 = HeapOnly::CreateObj();HeapOnly* ho4 = HeapOnly::CreateObj(1,1);return 0;
}

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

设计方式:构造函数设为私有,设计一个合适的静态成员函数,拷贝构造不用=delete限制、赋值重载需要=delete限制

class StackOnly
{
public:template<class... Args>static StackOnly CreateObj(Args&&... args){return StackOnly(args...);//用于返回在栈上创建的一个匿名对象的静态成员函数,返回类型不是StackOnly*而是StackOnly }//只封住了赋值重载StackOnly& operator=(const StackOnly&) = delete;private://无参默认构造函数StackOnly() {cout << "StackOnly()" << endl;};StackOnly(int x,int y)//支持两个参数的默认构造函数:_x(x),_y(y){cout << "StackOnly(int x,int y)" << endl;};int _x;int _y;
};int main()
{StackOnly ho1 = StackOnly::CreateObj();StackOnly ho2 = StackOnly::CreateObj(1, 1);StackOnly* ho3 = new StackOnly(ho1);//没有=delete拷贝构造,就可以使用系统提供的默认拷贝构造//通过反汇编可以看到是先new在堆上分配了一个8字节大小的内存,然后将调用默认拷贝构造生成的匿名对象放入该内存中,最后返回该对象的地址给ho3return 0;
}
  • new + 拷贝构造也可以在堆上创建对象,所以我们可以直接重写一个new,并=delete该new
//重载一个类专属的operator new,此时再去new StackOnly就不会去调用全局的operator new
void* operator new(size_t n) = delete;

设计一个不能继承的类

C++98的设计方式:构造函数私有化,派生类中调不到基类的构造函数。则无法继承

class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};

C++11的设计方式:final关键字,final修饰一个类,表示该类不能被继承

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

设计模式

基本概念:设计模式是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结,使用设计模式的目的是为了代码的可重用性、让代码更容易被他人理解、保证代码可靠性,设计模式使得代码编写真正工程化

单例模式

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

饿汉模式

#include <iostream>
#include <vector>
using namespace std;namespace hunger 
{//饿汉:执行main之前就创建出一个对象class Singleton{public:static Singleton* GetInstance(){return &_sint;//返回静态成员对象的地址}void Print(){cout << _x << _y << endl;for (auto& e : _vstr){cout << e << " ";}cout << endl;}//修改数据void AddStr(const string& s){_vstr.push_back(s);}//将拷贝构造和赋值重载禁掉,防止用户*指针然后调用拷贝构造新建对象Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private://构造函数:数据被放入数组中存放Singleton(int x = 0, int y = 0, const vector<string>& vstr = { "yyyyy","xxxx" }):_x(x),_y(y),_vstr(vstr){}// 想让一些数据,当前程序只有一份,可以把这些数据放到一个类里,然后再把这个类设计成单例,这样数据就只有一份了int _x;int _y;vector<string> _vstr;//类的静态成员对象,属于该类实例化出的所有对象,存在于静态区,在类中声明,使用时受类域限制(加类名)static Singleton _sint;};Singleton Singleton::_sint(1, 1, { "陕西","四川" });
}int main()
{hunger::Singleton::GetInstance()->Print();hunger::Singleton::GetInstance()->AddStr("甘肃");hunger::Singleton::GetInstance()->Print();hunger::Singleton::GetInstance()->AddStr("甘肃");hunger::Singleton::GetInstance()->Print();return 0;
}

缺点1:影响程序启动速度,若单例对象数据过多,构造静态成员对象的成本变高,导致迟迟进不了main函数(长时间不登录微信,拉取消息时很慢,可以通过多线程解决,比如用于拉取群聊消息的单例是一个线程,用于拉去单个用户消息的单例是一个线程,那么拉取群聊消息的单例的初始化速度缓慢不会影响拉取单个用户消息的单例的初始化速度)

缺点2:多个单例类有初始化启动依赖关系,饿汉无法控制(A和B两个单例,若要求A先初始化,B再初始化,饿汉无法保证)

缺点3:无法处理异常,在饿汉模式中,如果单例对象在实例化时抛出异常,整个类加载过程都会失败

饥汉模式

#include <iostream>
#include <vector>
using namespace std;namespace lazy
{class Singleton{public:static Singleton* GetInstance(){// 第一次调用时,创建单例对象,第二次时_psint就不为空,进入该函数也只是返回_psint//存在线程安全问题,需要加锁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;for (auto& e : _vstr){cout << e << " ";}cout << endl;}void AddStr(const string& s){_vstr.push_back(s);}Singleton(Singleton const&) = delete;Singleton& operator=(Singleton const&) = delete;private:Singleton(int x = 0, int y = 0, const vector<string>& vstr = { "yyyyy","xxxx" }):_x(x), _y(y), _vstr(vstr){}~Singleton(){// 把数据写到文件cout << "~Singleton()" << endl;}int _x;int _y;vector<string> _vstr;static Singleton* _psint;// 内部类,用于防止用户忘记显示调用DelInstance释放对象//实例化一个静态内部类成员对象(全局生命周期),当程序结束时就会调用GC类对象的析构进而调用DelInstanceclass GC{public:~GC(){Singleton::DelInstance();}};static GC gc;//不实例化GC类对象,该类没用不会调用该类的析构函数};// 两个静态成员对象在类外的定义Singleton* Singleton::_psint = nullptr;Singleton::GC Singleton::gc;//什么都不做
}int main()
{lazy::Singleton::GetInstance()->Print();lazy::Singleton::GetInstance()->AddStr("甘肃");lazy::Singleton::GetInstance()->Print();lazy::Singleton::GetInstance()->AddStr("甘肃");lazy::Singleton::GetInstance()->Print();//lazy::Singleton::DelInstance();//显示调用DelInstance可以释放,不显示也可以(注释和非注释两次运行试一试即可)return 0;
}

补充:也可以选择不用上述的内部类和指针的情况(需要注意显示调用和释放),而是在GetInstance中定义一个局部的静态成员对象,该成员会在第一次调用GetInstance函数时构造初始化一次且仅有一次(局部静态成员对象只能被初始化一次),但只有在C++11及之后才能使用

static Singleton* GetInstance()
{// 局部的静态对象,第一次调用函数时构造初始化// C++11及之后这样写才可以// C++11之前无法保证这里的构造初始化是线程安全static Singleton _sinst;return &_sinst;
}

C/C++ 中 static 的用法全局变量与局部变量 | 菜鸟教程 (runoob.com) 

~over~

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

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

相关文章

一小时搞定Git(含盖IDEA使用)

文章目录 1. git基本概念1.1版本控制1.1.1 版本控制软件 2. 命令的使用2.1 Linux命令2.2 git基础指令2.2.1 设置用户2.2.2 初始化本地仓库2.2.3 查看本地仓库状态2.2.4 添加暂存区域2.2.5 提交本地库2.2.6 切换版本 2.3 分支操作2.3.1 分支基本操作2.3.2 合并操作2.3.4 分支开发…

基于STM32的智能家居安防系统

目录 引言环境准备智能家居安防系统基础代码实现&#xff1a;实现智能家居安防系统 4.1 数据采集模块4.2 数据处理与分析4.3 控制系统实现4.4 用户界面与数据可视化应用场景&#xff1a;智能家居安防管理与优化问题解决方案与优化收尾与总结 1. 引言 智能家居安防系统通过使…

195.回溯算法:分割回文串(力扣)

代码解决 class Solution { public:vector<string> res; // 当前路径&#xff0c;用于存储一个可能的回文分割结果vector<vector<string>> result; // 存储所有可能的回文分割结果// 判断子串 s[left:right] 是否是回文bool isPalindrome(const string& …

Linux应用系统快速部署:docker快速部署linux应用程序

目录 一、背景 &#xff08;一&#xff09;引入docker的起因 &#xff08;二&#xff09;docker介绍 &#xff08;三&#xff09;Docker部署的优势 1、轻量级和可移植性 2、快速部署和扩展 3、一致性 4、版本控制 5、安全性 6、资源隔离 7、简化团队协作 8、多容器…

VMware虚拟机三种网络模式设置 - Bridged(桥接模式)

一、前言 由于linux目前很热门&#xff0c;越来越多的人在学习linux&#xff0c;但是买一台服务放家里来学习&#xff0c;实在是很浪费。那么如何解决这个问题&#xff1f;虚拟机软件是很好的选择&#xff0c;常用的虚拟机软件有vmware workstations和virtual box等。 在使用虚…

基于imx6ull开发板 移植opencv4.7.0

一、概述 本章节是针对opencv-4.7.0移植到Linux系统&#xff0c;运行在正点原子-I.MX6U ALPHA开发板 上&#xff0c;详细的移植流程如下。 二、环境要求 2.1 硬件环境 正点原子-I.MX6U ALPHA开发板虚拟机&#xff1a;VMware 2.2 软件环境 Ubuntu系统要求&#xff1a;20.0…

DIVE INTO DEEP LEARNING 50-55

文章目录 50. semantic segmentation50.1 Basic concepts50.2 Major application 51. Transposed convolution51.1 Basic concepts51.2 Major role51.3 Implementation steps and application areas51.4 Transposed convolution51.5 Transposed convolution is a type of convo…

谁说串口通信波特率越高越好?

在电子世界里&#xff0c;串口通信就像是电子设备之间的“悄悄话”&#xff0c;它们通过串行数据传输来交换信息。但你知道吗&#xff1f;串口通信的波特率并不是越高越好&#xff0c;这事儿得好好聊聊。 1.什么是串口通信&#xff1f; 串口通信&#xff0c;就像它的名字一样&a…

深度学习11-13

1.神经元的个数对结果的影响&#xff1a; &#xff08;http://cs.stanford.edu/people/karpathy/convnetjs/demo/classify2d.html&#xff09; &#xff08;1&#xff09;神经元3个的时候 &#xff08;2&#xff09;神经元是10个的时候 神经元个数越多&#xff0c;可能会产生…

计算机组成原理 —— 存储系统(DRAM和SRAM,ROM)

计算机组成原理 —— 存储系统&#xff08;DRAM和SRAM&#xff09; DRAM和SRAMDRAM的刷新DRAM地址复用ROM&#xff08;Read-Only Memory&#xff08;只读存储器&#xff09;&#xff09; 我们今天来看DRAM和SRAM&#xff1a; DRAM和SRAM DRAM&#xff08;动态随机存取存储器&…

展示3D模型的网站哪个好?

如果仅仅是模型展示&#xff0c;目前国内外值得推荐的无非就是那么几个&#xff0c;它们各自有不同的特点和优势&#xff1a; 1、Sketchfab&#xff1a;Sketchfab是一个知名的3D模型展示平台&#xff0c;提供了海量的模型资源和出色的3D展示效果。用户无需安装任何插件即可在线…

Spring Cloud - nacos +ubuntu环境搭建

1、安装ubuntu虚拟环境 VMware虚拟机安装Ubuntu与配置Ubuntu&#xff08;超详细教程&#xff09; 2、docker环境安装 1、apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common 2、curl -fsSL https://mirrors.ustc.edu.cn/docke…

Maven的依赖传递、依赖管理、依赖作用域

在Maven项目中通常会引入大量依赖&#xff0c;但依赖管理不当&#xff0c;会造成版本混乱冲突或者目标包臃肿。因此&#xff0c;我们以SpringBoot为例&#xff0c;从三方面探索依赖的使用规则。 1、 依赖传递 依赖是会传递的&#xff0c;依赖的依赖也会连带引入。例如在项目中…

自动驾驶仿真测试用例表格示例 ACC ELK FCW

自动驾驶仿真测试用例表格示例 测试用例概览 本测试用例表格涵盖了自动驾驶系统中多个关键功能和场景的测试&#xff0c;旨在确保系统在不同条件下的表现和稳定性。 用例编号测试项目测试描述预期结果实际结果通过/失败TC-001ACC功能测试在高速公路上启用ACC&#xff0c;测试车…

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测

SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测 目录 SCI一区级 | Matlab实现BO-Transformer-LSTM多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.【SCI一区级】Matlab实现BO-Transformer-LSTM多变量时间序列预测&#xff0c;贝叶斯…

力扣SQL50 超过5名学生的课

Problem: 596. 超过5名学生的课 Code select class from courses group by class having count(distinct student) > 5;

高通安卓12-固件升级

下载步骤 第一步 格式化 「下载一次即可&#xff1b;能开机能下载的板子 忽略这一步&#xff0c;直接执行第二步即可」 QFIL工具配置为UFS类型&#xff0c;勾选Provision&#xff0c;如下图&#xff1a; Programmer选择prog_firehose_ddr.elf&#xff0c;Provision Xml选择prov…

【STM32-新建工程-CubeMX】

STM32-新建工程-CubeMX ■ CubeMX 生产工程 ■ CubeMX 生产工程

QT事件处理系统之五:自定义事件的发送案例 sendEvent和postEvent接口

1、案例 双击窗口,会发送 自定义事件,然后在事件过滤中心进行拦截处理自定义事件。 2、核心代码 /*解释:双击窗口时,将产生双击事件,然后该事件被包裹成一个对象,随后将会被发往event事件中心,然后进行事件的处理(Widget对象);因为m_lineEdit开启了事件过滤机制,所…

Linux - 利用/proc/sys/vm/drop_caches实现手工清理系统缓存

文章目录 现象buff/cache 的作用和含义分析 buff/cache 占用大量内存的原因是否需要清理缓存及其方法 命令清理缓存方法1. sync 命令2. echo 3>/proc/sys/vm/drop_caches 命令 注意事项小结 现象 使用free 命令&#xff0c;看到 buff/cache 占用很多 。 free 命令用于显示系…