当前位置: 首页 > 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;生成一个或…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)

目录 1.TCP的连接管理机制&#xff08;1&#xff09;三次握手①握手过程②对握手过程的理解 &#xff08;2&#xff09;四次挥手&#xff08;3&#xff09;握手和挥手的触发&#xff08;4&#xff09;状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

动态 Web 开发技术入门篇

一、HTTP 协议核心 1.1 HTTP 基础 协议全称 &#xff1a;HyperText Transfer Protocol&#xff08;超文本传输协议&#xff09; 默认端口 &#xff1a;HTTP 使用 80 端口&#xff0c;HTTPS 使用 443 端口。 请求方法 &#xff1a; GET &#xff1a;用于获取资源&#xff0c;…...

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

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...