当前位置: 首页 > news >正文

C++ | 深入理解C++中的特殊类设计和单例模式(懒汉模式、饿汉模式)

目录

特殊类设计和单例模式

1、不可拷贝类

2、只能在堆上创建对象的类

3、只能在栈上创建对象的类

4、不可继承的类

5、单例模式(懒汉模式、饿汉模式)


特殊类设计和单例模式

在C++编程中,类的设计往往需要满足特定的需求和约束。特殊类设计模式提供了一种方法来实现这些需求,确保类的使用既安全又高效。本文将探讨几种常见的特殊类设计方式,包括不可拷贝类、只能在堆上创建对象的类、只能在栈上创建对象的类、不可继承的类以及单例模式。

1、不可拷贝类

在某些情况下,我们可能希望一个类的对象不能被拷贝。这可以通过以下两种方式实现:

C++98方式

在C++98中,我们可以通过只声明拷贝构造函数和赋值运算符,并将它们设置为私有成员来实现。这样,即使外部代码尝试拷贝对象,编译器也会因为访问权限问题而报错。

// 不可拷贝类
// 将拷贝构造和赋值运算符重载delete即可
class uncopy
{
private:int _a;uncopy(const uncopy& uc);uncopy& operator=(const uncopy& uc);
public:uncopy(int a = 0):_a(a){}};

C++11方式

C++11引入了delete关键字,可以直接在类声明中删除默认的拷贝构造函数和赋值运算符,使得编译器在尝试使用这些函数时直接报错。

// 不可拷贝类
// 将拷贝构造和赋值运算符重载delete即可
class uncopy
{
private:int _a;
public:uncopy(int a = 0):_a(a){}uncopy(const uncopy& uc) = delete;uncopy& operator=(const uncopy& uc) = delete;};
2、只能在堆上创建对象的类

有时,我们希望类的实例只能在堆上创建,这可以通过以下步骤实现:

  1. 将构造函数声明为私有
  2. 提供一个公共的静态成员函数,用于在堆上分配和初始化对象。

或者:

  1. 将析构函数声明为私有
  2. 提供公共的静态成员函数,用来调用析构函数销毁对象
// 只能在堆上创建对象的类
// 隐藏构造函数 开放静态获取接口 将拷贝构造函数delete
class Heap_only1
{
private:int _a;Heap_only1(int a = 0):_a(a){}Heap_only1(const Heap_only1& ho) = delete;
public:static Heap_only1* create_obj(int a){return new Heap_only1(a);}
};// 利用局部对象自动调用析构函数 隐藏析构函数 开放销毁接口 将拷贝构造函数delete
class Heap_only2
{
private:int _a;Heap_only2(const Heap_only2& ho) = delete;~Heap_only2(){}
public:Heap_only2(int a = 0):_a(a){}static bool delete_Heap_only(Heap_only2* p){if (p){delete p;p = nullptr;return true;}return false;}
};

3、只能在栈上创建对象的类

与只能在堆上创建对象的类相反,有时我们希望类的实例只能在栈上创建。这可以通过禁用operator newoperator delete来实现。

// 只能在栈上创建对象的类
// 将operator new和operator delete封住 提供传值返回接口获取栈上对象
// 但是 由于传值返回保留了拷贝构造函数 所以static拷贝构造无法完全封死
class stack_only
{
private:int _a;void* operator new(size_t size) = delete;void operator delete(void* p) = delete;stack_only(){}
public:static stack_only create_stack_only(){return stack_only();}
};

4、不可继承的类

在某些情况下,我们可能希望阻止其他类继承特定的类。这可以通过以下两种方式实现:

C++98方式

在C++98中,我们可以通过将构造函数声明为私有来实现,这样派生类就无法访问基类的构造函数。

class NonInherit {
private:NonInherit() {}
};

C++11方式

C++11引入了final关键字,可以直接在类声明中使用final来阻止继承。

class NonInherit final {// ...
};

5、单例模式(懒汉模式、饿汉模式)

单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。单例模式有两种实现方式:饿汉模式和懒汉模式。

饿汉模式

饿汉模式在程序启动时就创建实例,简单但可能导致启动延迟。

//单例模式
//饿汉模式
#include<iostream>
using namespace std;
class once1
{
private:once1(){}static once1* a;once1(const once1&) = delete;once1& operator=(const once1&) = delete;public:static once1* getObj(){return a;}
};
once1* once1::a = new once1;int main()
{once1* p1 = once1::getObj();cout << p1 << endl;return 0;
}

懒汉模式

懒汉模式在第一次使用时才创建实例,启动无负载。

[Warning] 以下为不考虑线程安全的版本

//懒汉模式
class once2
{
private:static once2* ret;once2(){}once2(const once2&) = delete;once2& operator=(const once2&) = delete;
public:static once2* getObj(){if (ret == nullptr){ret = new once2;}return ret;}
};
once2* once2::ret = nullptr;int main()
{once2* p2 = once2::getObj();cout << p2 << endl;return 0;
}

如果要求在程序退出时销毁单例对象,可以在once类中定义内部类,在内部类的析构函数中完成资源释放,程序结束时自动调用内部类的析构函数。

以懒汉模式为例:

//懒汉模式
class once2
{
private:static once2* ret;once2(){}once2(const once2&) = delete;once2& operator=(const once2&) = delete;class del{public:~del(){once2::delObj();}};static del D;
public:static once2* getObj(){if (ret == nullptr){ret = new once2;}return ret;}static void delObj(){if (ret){delete ret;ret = nullptr;cout << "delete[]" << endl;}}
};
once2* once2::ret = nullptr;
once2::del once2::D;int main()
{//once1* p1 = once1::getObj();//cout << p1 << endl;once2* p2 = once2::getObj();cout << p2 << endl;return 0;
}

相关文章:

C++ | 深入理解C++中的特殊类设计和单例模式(懒汉模式、饿汉模式)

目录 特殊类设计和单例模式 1、不可拷贝类 2、只能在堆上创建对象的类 3、只能在栈上创建对象的类 4、不可继承的类 5、单例模式(懒汉模式、饿汉模式) 特殊类设计和单例模式 在C编程中&#xff0c;类的设计往往需要满足特定的需求和约束。特殊类设计模式提供了一种方法来…...

Java设计模式之中介者模式

Java设计模式之中介者模式 在软件开发中&#xff0c;设计模式是解决常见问题的最佳实践。通过运用设计模式&#xff0c;我们可以提高代码的可维护性、可扩展性以及可读性。今天&#xff0c;我们将探讨一种非常重要的行为型设计模式——中介者模式&#xff08;Mediator Pattern…...

实现父组件调用子组件方法时报错:[Vue warn]: Invalid vnode type when creating vnode: null.

使用uniapp实现父组件调用子组件方法时报错&#xff1a;[Vue warn]: Invalid vnode type when creating vnode: null. 实现代码如下&#xff1a; 子组件&#xff1a; <template><view><view class"toolsHeader"><view class"toolsTitl…...

Java面试八股之什么是消息队列

什么是消息队列 消息队列&#xff08;Message Queue&#xff09;是一种应用程序间通信&#xff08;IPC&#xff09;的形式&#xff0c;它允许进程将消息发送到另一个消息队列&#xff0c;接收端则可以在任何时刻从队列中取出这些消息进行处理。消息队列提供了一种异步处理、解…...

【kubernetes】k8s配置资源管理

一、ConfigMap资源配置 ConfigMap保存的是不需要加密配置的信息 ConfigMap 功能在 Kubernetes1.2 版本中引入&#xff0c;许多应用程序会从配置文件、命令行参数或环境变量中读取配置信息。ConfigMap API 给我们提供了向容器中注入配置信息的机制&#xff0c;ConfigMap 可以被…...

高分六号卫星助力农业监测_卫星介绍_论文分享_数据获取

卫星遥感已经成为农业发展的重要支持工具。《“数据要素X”三年行动计划(2024-2026年)》指出,在现代农业交通运输、应急管理等领域鼓励探索利用遥感数据。为什么高分六号会经常应用于农业检测呢&#xff1f;本文将介绍高分六号卫星的农业检测特性、在农业应用中的优势、具体农业…...

【Linux网络】TCP协议

欢迎来到 破晓的历程的 博客 ⛺️不负时光&#xff0c;不负己✈️ 文章目录 引言1、TCP协议的特点2、确认应答机制3、超时重传机制4、TCP报头结构5、三次握手建立连接6、四次挥手断开连接总结 引言 TCP协议是传输层中非常重要的协议。本篇博客我们将从TCP头部信息、TCP状态转…...

Linux 基本指令讲解 上

linux 基本指令 clear 清屏 Alt Enter 全屏/退出全屏 pwd 显示当前用户所处路径 cd 改变目录 cd /root/mikecd … 返回上级目录cd - 返回最近所处的路径cd ~ 直接返回当前用户自己的家目 roor 中&#xff1a;/root普通用户中&#xff1a;/home/mike mkdir 创建一个文件夹(d) …...

深入了解指针(6)

文章目录 1.函数指针数组2.转移表3.回调函数 1.函数指针数组 存放函数指针的数组 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> int add(int x, int y) {return x y; } int sub(int x, int y) {return x - y; }int main() {int (*p1)(int x, int y) add;int (…...

【Linux系列】known_hosts详解

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

MySQL4 多表查询 内连接

内连接 多表查询内连接 多表查询 数据准备 CREATE DATABASE db4; USE db4; -- 创建部门表 create table if not exists dept(deptno varchar(20) primary key , -- 部门号name varchar(20) -- 部门名字 );-- 创建员工表 create table if not exists emp(eid varchar(20) pr…...

力扣45:跳跃游戏2题解

题目链接&#xff1a; https://leetcode.cn/problems/jump-game-ii/description/?envTypestudy-plan-v2&envIdtop-100-liked 参考的代码随想录里面的题解&#xff1a; 题目 难度 中等&#xff0c;标的是中等难度&#xff0c;而且我之前做过这道题&#xff0c;但是我没写…...

产品经理-产品被同行抄袭如何处理(32)

在面试当中,如果被问到,产品被同行抄袭如何处理 竞争分析、战略决策。 1&#xff09;对行业相关事件的关注度&#xff1a;如之前对腾讯抄袭事件的讨论&#xff0c;如果能结合“被抄袭”后的失败案例&#xff08;例如联众&#xff09;和反抄袭的成功案例&#xff08;例如豆瓣&am…...

LDR6020在Type-C手机同时充电与USB2.0数据传输方案

随着科技的飞速发展&#xff0c;Type-C接口已成为智能手机等移动设备的主流充电和数据传输接口。为了满足用户对于高效充电与稳定数据传输的双重需求&#xff0c;乐得瑞科技推出的LDR6020芯片凭借其卓越的性能和丰富的功能&#xff0c;为Type-C手机提供了同时充电与USB2.0数据传…...

Python学习笔记(七)

""" 演示数据容器字典的定义 """# # 定义字典{key:value,key2:value2} 注意key不能是字典&#xff0c;value可以任意 # my_dict1 {"王力鸿": 99, "周杰轮": 88, "林俊节": 77}# #定义空字典 # my_dict2 {} # my…...

mysql中log

目录 MySQL 日志系统概述 日志类型 日志的作用和重要性 Mermaid图示 1. Undo Log 和 Redo Log 的协同工作图 2. Redo Log 确保持久性的流程图 Undo Log&#xff08;回滚日志&#xff09; 事务的原子性&#xff08;Atomicity&#xff09;保障 事务回滚机制 MVCC&#…...

iOS Object-C 创建类别(Category) 与使用

有时候使用系统给出类或者第三方的类,但是呢它们自带的属性和方法又太少,不够我们的业务使用,这时候就需要给“系统的类或者第三方类”创建一个类别(Category),把自己的想添加的属性和方法写进来. Category模式用于向已经存在的类添加方法从而达到扩展已有类的目的 一:创建Ca…...

Rocky系统部署k8s1.28.2单节点集群(Containerd)+Kuboard

目录 Kubernetes介绍 Kubernetes具备的功能 Kubernetes集群角色 Master管理节点组件 Node工作节点组件 非必须的集群插件 Kubernetes集群类型 Kubernetes集群规划 集群前期环境准备 开启Bridge网桥过滤 关闭SWAP交换分区 安装Containerd软件包 K8s集群部署方式 集…...

Springboot整合Flowable入门-学习笔记

目录 1、定义流程&#xff08;画图&#xff09; 2、Springboot部署流程 3、Springboot删除所有流程 4、Springboot根据 流程部署ID 查询 流程定义ID 5、Springboot启动(发起)流程 6、Springboot查询任务 6.1全部任务 6.2我的任务&#xff08;代办任务&#xff09; 7、…...

C语言常见的题目

1、 从源码到可执行文件会经历怎样的过程&#xff1f; 预编译&#xff1a;去掉空格、注释&#xff0c;处理预定义的指令&#xff0c;生成处理后的源代码文件。 编译&#xff1a;翻译成汇编代码&#xff0c;生成汇编文件。 汇编&#xff1a;翻译成机器码&#xff0c;生成一个或…...

OpenLayers 可视化之热力图

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 热力图&#xff08;Heatmap&#xff09;又叫热点图&#xff0c;是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

如何在网页里填写 PDF 表格?

有时候&#xff0c;你可能希望用户能在你的网站上填写 PDF 表单。然而&#xff0c;这件事并不简单&#xff0c;因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件&#xff0c;但原生并不支持编辑或填写它们。更糟的是&#xff0c;如果你想收集表单数据&#xff…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

08. C#入门系列【类的基本概念】:开启编程世界的奇妙冒险

C#入门系列【类的基本概念】&#xff1a;开启编程世界的奇妙冒险 嘿&#xff0c;各位编程小白探险家&#xff01;欢迎来到 C# 的奇幻大陆&#xff01;今天咱们要深入探索这片大陆上至关重要的 “建筑”—— 类&#xff01;别害怕&#xff0c;跟着我&#xff0c;保准让你轻松搞…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》

近日&#xff0c;嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》&#xff0c;海云安高敏捷信创白盒&#xff08;SCAP&#xff09;成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天&#xff0c;网络安全已成为企业生存与发展的核心基石&#xff0c;为了解…...

rm视觉学习1-自瞄部分

首先先感谢中南大学的开源&#xff0c;提供了很全面的思路&#xff0c;减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接&#xff1a;https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架&#xff1a; 代码框架结构&#xff1a;readme有…...