【C++】特殊类设计及单例模式

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

实现方式:

  1. 将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
  2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。代码示例如下:
class HeapOnly
{
public:static HeapOnly* CreateObject(){	return new HeapOnly;}
private:HeapOnly(){}//c++98写法//1.只声明,不实现。实现可能会很麻烦,而本身不需要//2.声明成私有HeapOnly(const HeapOnly&);//or C++11写法HeapOnly(const HeapOnly&)=delete;
};

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

  1. 同上将构造函数私有化,然后设计静态方法创建对象返回。
  2. 屏蔽new。因为new在底层调用void* operator new(size_t size)函数,只需将该函数屏蔽掉即可。
    注意:也要防止定位new
class StackOnly
{
public:static StackOnly CreateObj(){return StackOnly();}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;
private:StackOnly():_a(0){}
private:int _a;
};

3.请设计一个类,不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

3.1C++98方式

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

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

解释:

  1. 设置成私有:如果只声明没有设置为private,用户自己如果在类外定义了,就可以不能禁止拷贝了。
  2. 只声明不定义:不定义是因为该函数根本不会调用,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

3.2 C++11方式

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

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

4.请设计一个类,不能被继承

4.1 C++98方式

C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承。如下代码所示:

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

4.2 C++11方式

final关键字,final修饰类,表示该类不能被继承。

class A final
{//....//此时该类不可被继承
};

5.单例模式:只能创建一个对象的类

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。 单例模式有两种实现模式:饿汉模式和懒汉模式

5.1饿汉模式

优点: 简单,提前准备好。在mian函数之前就创建好了单例对象,程序随时可以访问这个单例对象。
缺点

  1. 无法控制单例创建初始化顺序。假设两个单例类A和B,要求A单例先创建,B单例后创建,B的创建依赖A。就会存在局限性。
  2. 如果单例对象初始化很费时间,会导致程序启动慢,就像卡死一样。

代码示例:
C++98写法

class Singleton
{
public:static Singleton* GetInstance(){return &m_instance;}
private://构造函数私有Singleton(){};//私有化,防拷贝Singleton(Singleton const&);Singleton& operator=(Singleton const&);static Singleton m_instance;
};
//在程序入口之前就完成单例对象的初始化
Singleton Singleton::m_instance;

C++11写法

class Singleton
{
public:static Singleton* GetInstance(){return &m_instance;}
private://构造函数私有Singleton(){};//使用delete防拷贝Singleton(Singleton const&)=delete;Singleton& operator=(Singleton const&)=delete;static Singleton m_instance;
};

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。

5.2 懒汉模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件啊, 初始化网络连接啊,读取文件啊等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载)更好。
优点: 事先没有准备,第一次访问时,才创建单例对象。对应解决饿汉的两个缺点。
缺点: 设计相对负责,还要控制线程安全问题。
代码实例:

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
class Singleton
{
public:static Singleton* GetInstance() {// 注意这里一定要使用Double-Check的方式加锁,才能保证效率和线程安全if (nullptr == m_pInstance) {m_mtx.lock();if (nullptr == m_pInstance) {m_pInstance = new Singleton();}m_mtx.unlock();}return m_pInstance;}// 实现一个内嵌垃圾回收类 class CGarbo {public:~CGarbo() {if (Singleton::m_pInstance)delete Singleton::m_pInstance;}};// 定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象static CGarbo Garbo;
private:// 构造函数私有Singleton() {};// 防拷贝Singleton(Singleton const&);Singleton& operator=(Singleton const&);static Singleton* m_pInstance; // 单例对象指针static mutex m_mtx; //互斥锁
};
Singleton* Singleton::m_pInstance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::m_mtx;
void func(int n)
{cout << Singleton::GetInstance() << endl;
}
// 多线程环境下演示上面GetInstance()加锁和不加锁的区别。
int main()
{thread t1(func, 10);thread t2(func, 10);t1.join();t2.join();cout << Singleton::GetInstance() << endl;cout << Singleton::GetInstance() << endl;
}

6.深入理解懒汉模式和饿汉模式

其实就是看定义的事静态成员对象变量还是静态成员对象指针变量,因为如果定义了静态成员对象变量,程序在运行之初已经分配了空间,就要调用构造函数了,而你在调用getinstance的时候,不会再调用构造函数了,因为之前已经调用过了,你就是用的现成的,就是所谓的饿汉模式,上来先把吃的准备好了,因为饿怕了,怕后期准备会挨饿。

而定义了静态成员对象指针变量,程序运行之初也会分配空间,但是那个是指针的空间,而不是对象的空间,所以不会调用对象的构造函数,而只有调用getinstance进行new操作的时候,才会对其调用构造函数,就是现上轿现扎耳朵眼,比较懒惰,所以叫懒汉模式。

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

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

相关文章

CSS新手入门笔记整理:CSS常用属性表

字体样式 属性 属性值 说明 font-family 微软雅黑/苹方 字体类型 font-size 数值 字体大小 font-weight 数值/关键字 字体粗细&#xff08;字重&#xff09; font-style normal&#xff08;正常(默认值)&#xff09;italic&#xff08;斜体&#xff09;oblique&am…

Graylog解决超出ES搜索最大窗口限制问题

今天在查询日志的时候graylog报了一个错&#xff1a; While retrieving data for this widget, the following error(s) occurred: Unable to perform search query: Elasticsearch exception [typeillegal_argument_exception, reasonResult window is too large, from size …

云原生向量计算引擎 PieCloudVector:为大模型提供独特记忆

拓数派大模型数据计算系统&#xff08;PieDataComputingSystem&#xff0c;缩写&#xff1a;πDataCS&#xff09;在10月24日程序员节「大模型数据计算系统」2023拓数派年度技术论坛正式发布。πDataCS 以云原生技术重构数据存储和计算&#xff0c;「一份存储&#xff0c;多引擎…

我的NPI项目之Android 安全系列 -- 先认识一下ST33Jxxx

目前接触过的高通平台都没有集成单独的SE&#xff0c;安全运行环境都是高通自家的TEE&#xff0c;又言Trustzone。高通Keystore功能也是依赖TEE来实现的。那么&#xff0c;如果另外集成SE&#xff0c;那么高通的Keystore如何集成&#xff1f;TEE部分要如何配置&#xff1f; 最近…

Ubuntu Shutdown while other user logged on

1. sudo vim /etc/systemd/logind.conf 修改代码KillUserProcessesyes 2. sudo touch /etc/polkit-1/localauthority/50-local.d/multi-user-inhibit-shutdown-restart.pkla 3. 打开修改配置文件 sudo vim /etc/polkit-1/localauthority/50-local.d/multi-user-inhibit-shut…

TrustZone之总线请求

接下来&#xff0c;我们将查看系统中的总线请求者&#xff0c;如下图所示&#xff1a; 系统中的A型处理器具有TrustZone感知&#xff0c;并在每个总线访问中发送正确的安全状态。然而&#xff0c;大多数现代SoC还包含非处理器总线请求者&#xff0c;例如GPU和DMA控制器。 与完成…

MC-30A (32.768 kHz用于汽车应用的晶体单元)

MC-30A 32.768 kHz用于汽车应用的晶体&#xff0c;车规晶振中的热销型号之一。该款石英晶体谐振器&#xff0c;可以在-40 to 85 C的温度内稳定工作&#xff0c;能满足起动振动的要求。同时满足AEC-Q200无源元件质量标准认证&#xff0c;满足汽车仪表系统的所有要求。 频率范围…

蓝桥杯专题-真题版含答案-【基因牛的繁殖】【黄金分割数】【振兴中华】【圆周率与级数】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

特斯拉第二代机器人:市场期待与看解

随着特斯拉在人工智能领域的不断突破&#xff0c;其研发的第二代机器人即将面世。这款机器人集结了特斯拉在机器人技术、人工智能和自动驾驶等方面的最新成果&#xff0c;引发了市场和业界的广泛关注。本文将探讨市场对特斯拉第二代机器人的期待与看法。 一、期待&#xff1a;…

Apache Flume(4):日志文件监控

1 案例说明 企业中应用程序部署后会将日志写入到文件中&#xff0c;可以使用Flume从各个日志文件将日志收集到日志中心以便于查找和分析。 2 使用Exec Soucre Exec Source Exec Source通过指定命令监控文件的变化&#xff0c;加粗属性为必须设置的。 属性名默认值说明chan…

ida脚本环境开发配置idapythonidacpp三端环境(win,mac,linux)

ida脚本也有一段时间了,一直有个痛点是找不到比较好的方法热重载脚本来实时改动生效,导致开发效率老慢了。固总结下比较友好的环境搭配 使用ida热加载插件让你开发脚本更高效 github地址: GitHub - 0xeb/ida-qscripts: An IDA plugin to increase productivity when developi…

什么是PHP中的命名空间冲突?

在PHP中&#xff0c;命名空间冲突指的是在程序中存在两个或多个命名空间&#xff08;namespace&#xff09;下的类、函数、常量等标识符具有相同的名称&#xff0c;从而导致命名空间冲突的情况。这可能会引发以下问题&#xff1a; 类名、函数名或常量名的冲突&#xff1a; 如果…

【Python】json.dumps()函数详解和示例

json.dumps() 是 Python 中 json 模块的一个函数&#xff0c;用于将 Python 对象编码为 JSON 格式的字符串。这个函数非常有用&#xff0c;当你需要将 Python 对象保存为 JSON 文件&#xff0c;或者通过网络传输到另一个系统时&#xff0c;它可以很方便地将 Python 数据结构转换…

Error: Required request body is missing:……

错误的原因&#xff1a;后端的一个get请求在参数前加了Requestbody注解导致的。 可能很多小伙伴在编写后端脚本后都会用postman去测试接口的正确性。但是上述的问题在postman中根本测试不出来&#xff0c;因为postman工具支持上述的操作。 所以还是建议大家多多在浏览器中进行…

来聊聊CAS

什么是CAS CAS全称Compare-And-Swap&#xff0c;是一种无锁编程算法&#xff0c;即比较当前的值与旧值是否相等若相等则进行修改操作(乐观锁机制)&#xff0c;该类常用于多线程共享变量的修改操作。而其底层实现也是基于硬件平台的汇编指令&#xff0c;JVM只是封装其调用仅此而…

探秘npm:解锁前端生态的魔法工具

在当今的软件开发世界中&#xff0c;前端技术以其快速发展和不断创新的特点吸引了无数开发者的关注。然而&#xff0c;随着前端项目越来越庞大和复杂&#xff0c;如何高效地管理和共享代码成为了一个紧迫的问题。在这个领域中&#xff0c;npm&#xff08;Node Package Manager&…

【Spark精讲】Spark与MapReduce对比

目录 对比总结 MapReduce流程 ​编辑 MapTask流程 ReduceTask流程 MapReduce原理 阶段划分 Map shuffle Partition Collector Sort Spill Merge Reduce shuffle Copy Merge Sort 对比总结 Map端读取文件&#xff1a;都是需要通过split概念来进行逻辑切片&…

【嵌入式面试】嵌入式经典面试题汇总(C语言)

一、预处理器 1、用预处理指令#define 声明一个常数&#xff0c;用以表明1年中有多少秒&#xff08;忽略闰年问题&#xff09; #define SECONDS_PER_YEAR (365*24*60*60)UL在这个例子中&#xff0c;SECONDS_PER_YEAR是一个宏常量&#xff0c;它的值被计算为365乘以24乘以60乘以…

CVE-2023-50164 Apache Struts2漏洞复现

CVE-2023-50164 简介&#xff1a; 从本质上讲&#xff0c;该漏洞允许攻击者利用 Apache Struts 文件上传系统中的缺陷。它允许他们操纵文件上传参数并执行路径遍历。这种利用可能会导致在服务器上执行任意代码&#xff0c;从而导致各种后果&#xff0c;例如未经授权的数据访问…

DS冲刺整理做题定理(四)查找与排序

最后一期更新&#xff0c;考试之前应该不会再出该专题了&#xff0c;之后有时间会出一些有关链表的代码题&#xff0c;其他章节只挑选重点的总结~ 一.查找 1.顺序查找 又被称为线性查找&#xff0c;对顺序表和链表都使用~基本思想是从某一端开始&#xff0c;逐个检查关键字是否…