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

C++特殊类设计(不能被拷贝的类、只能在堆上创建对象的类、不能被继承的类、单例模式)

C++特殊类设计

在实际应用中,可能需要设计一些特殊的类对象,如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类(单例模式)

1. 不能被拷贝的类

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

1.1 c++98做法

c++98通过将拷贝构造函数和赋值运算符重载只声明不定义,并将其访问权限设置为私有实现禁止被拷贝。

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

1.2 现代做法

使用c++11提供的delete关键字“删除”拷贝构造函数和赋值运算符重载。

class CopyBan
{
private:CopyBan(const CopyBan& cb) = delete;CopyBan& operator=(const CopyBan& cb) = delete;
};

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

2.1 直接法

要使一个类只能在堆上创建对象,思路是:

  1. 将类的构造函数和拷贝构造函数私有,防止别人调用拷贝在栈上生成对象。
  2. 再提供一个静态成员函数,在该静态成员函数内部完成堆对象的创建。
class HeapOnly
{static HeapOnly* Create()//静态解决“先有函数还是现有对象问题”{return new HeapOnly;}
private:HeapOnly(){}
};

但此不能完全封死在栈上创建对象,如果通过 Create()函数先创建一个堆上的对象,再使用默认拷贝构造拷贝堆上的对象,就能够实现在栈上创建对象。

HeapOnly* ho1 = HeapOnly::Create();
HeapOnly* ho2(ho1);

所以最后还需要封死通过拷贝构造创建栈上对象:

c++98:private:HeapOnly& HeapOnly(const HeapOnly& ho){}

c++11:HeapOnly& HeapOnly(const HeapOnly& ho)=delete;

2.2 私有析构函数法

设计不能被拷贝的类还有一种方法,通过私有化析构函数,让栈上对象无法在离开作用域时自动调用析构函数,因此在栈上的创建对象的代码都不能被编译通过。再设计一个 release()函数手动释放堆上的对象

class HeapOnly
{
public:static HeapOnly* Create(){return new HeapOnly;}void relase(){delete this;}
private:~HeapOnly(){}
};

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

要使一个类只能在栈上创建对象,思路是:

  1. 私有化构造函数
  2. 设计静态函数返回对象
class StackOnly
{
public:static StackOnly Create(){return StackOnly();}void* operator new(size_t size) = delete;void operator delete(void* p) = delete;private:StackOnly():_a(0){}int _a;
};

设计只能在栈上创建对象的类还要注意将new和delete删除,避免使用new通过拷贝构造创建堆上对象。且由于 Create()函数被设计成传值返回,不能直接通过删除拷贝构造实现(因为临时对象)。

删除new和delete的原理是,编译器默认生成一个new和一个delete,现将重载new和delete在类中重载,那么类对象会调用重载的new和重载的delete(重载后不再默认生成),但由于重载的new和重载的delete被删除,类对象在创建时便无法使用。

StackOnly so1 = StackOnly::Create();
StackOnly* so2 = new StackOnly(so1);

4. 不能被继承的类

要使一个类不能被继承,方法是:

  1. c++98:基类析构函数私有,派生类不能调用基类的构造函数,无法编译通过
  2. c++11:使用final关键字标记基类,表示该类不能被继承

5. 单例模式

单例模式要求一个类只能创建一个对象,该模式可以抱枕系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

单例模式有两种实现模式:

  1. 饿汉模式

  2. 懒汉模式

5.1 饿汉模式

饿汉形容程序对对象的需要比较紧迫,不管将来用不用,在程序启动时就马上先创建一个唯一的实例对象(一般在main函数之前创建)。

#include<iostream>
using namespace std;class ehan
{
public:static ehan* GetInstance(){return &_e;}int SetInfo(int info){_info = info;return _info;}ehan(const ehan& e) = delete;ehan& operator=(const ehan& e) = delete;
private:ehan(){}int _info;static ehan _e;//声明
};ehan ehan::_e;//定义
int main()
{cout<<ehan::GetInstance()->SetInfo(1);return 0;
}

优先:简单

缺点:可能会导致进程启动慢,且如果有多个单例类使用饿汉模式,它们的对象实例启动顺序不确定

5.2 懒汉模式

懒汉模式可以完美解决饿汉模式的缺点,懒汉模式一般在第一次调用 GetInstance() 的时候创建单例对象。

#include<iostream>
using namespace std;class lanhan
{
public:static lanhan* GetInstance(){static lanhan _lh;return &_lh;}int SetInfo(int info){_info = info;return _info;}lanhan(const lanhan& e) = delete;lanhan& operator=(const lanhan& e) = delete;
private:lanhan(){}int _info;
};int main()
{cout<<lanhan::GetInstance()->SetInfo(1);return 0;
}

这里在 GetInstance()里 定义了一个局部静态对象 static lanhan _lh; ,即使调用多次 GetInstance(),这个创建对象的代码也只会执行一次,但这种使用方法是c++11之后支持,且有线程安全风险

传统且线程安全方法:

#include<iostream>
#include<mutex>
using namespace std;class lanhan
{
public:static lanhan* GetInstance(){if (_lh == nullptr)//双重检查保证线程安全{unique_lock<mutex> lock(_mtx);if (_lh == nullptr){_lh = new lanhan;}}return _lh;}int SetInfo(int info){_info = info;return _info;}lanhan(const lanhan& e) = delete;lanhan& operator=(const lanhan& e) = delete;
private:lanhan(){}int _info;static mutex _mtx;static lanhan* _lh;};
lanhan* lanhan::_lh = nullptr;
mutex lanhan::_mtx;int main()
{cout<<lanhan::GetInstance()->SetInfo(1);return 0;
}

相关文章:

C++特殊类设计(不能被拷贝的类、只能在堆上创建对象的类、不能被继承的类、单例模式)

C特殊类设计 在实际应用中&#xff0c;可能需要设计一些特殊的类对象&#xff0c;如不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类、不能被继承的类、只能创建一个对象的类&#xff08;单例模式&#xff09;。 1. 不能被拷贝的类 拷贝只会发生在两个场景…...

【小白学机器学习34】用python进行基础的数据统计 mean,var,std,median,mode ,四分位数等

目录 1 用 numpy 快速求数组的各种统计量&#xff1a;mean, var, std 1.1 数据准备 1.2 直接用np的公式求解 1.3 注意问题 1.4 用print() 输出内容&#xff0c;显示效果 2 为了验证公式的后背&#xff0c;下面是详细的展开公式的求法 2.1 均值mean的详细 2.2 方差var的…...

安装 Docker(使用国内源)

一、安装Docker-ce 1、下载阿里云的repo源 [rootlocalhost ~]# yum install yum-utils -y && yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo && yum makecache # 尝试列出 docker-ce 的版本 [rootlocalh…...

Ajax学习笔记,第一节:语法基础

Ajax学习笔记&#xff0c;第一节&#xff1a;语法基础 一、概念 1、什么是Ajax 使用浏览器的 XMLHttpRequest 对象 与服务器通信2、什么是axios Axios是一个基于Promise的JavaScript库&#xff0c;支持在浏览器和Node.js环境中使用。相较于Ajax&#xff0c;Axios提供了更多…...

《用Python画蔡徐坤:艺术与编程的结合》

简介 大家好&#xff01;今天带来一篇有趣的Python编程项目&#xff0c;用代码画出知名偶像蔡徐坤的形象。这个项目使用了Python的turtle库&#xff0c;通过简单的几何图形和精心设计的代码来展示艺术与编程的结合。 以下是完整的代码和效果介绍&#xff0c;快来试试看吧&…...

Unity中动态生成贴图并保存成png图片实现

实现原理&#xff1a; 要生成长x宽y的贴图&#xff0c;就是生成x*y个像素填充到贴图中&#xff0c;如下图&#xff1a; 如果要改变局部颜色&#xff0c;就是从x1到x2(x1<x2),y1到y2(y1<y2)这个范围做处理&#xff0c; 或者要想做圆形就是计算距某个点&#xff08;x1,y1&…...

Mac配置maven环境及在IDEA中配置Maven

Mac配置maven环境及在IDEA中配置Maven 1. 介绍 Maven是一款广泛用于Java等JVM语言项目的工具&#xff0c;它以项目对象模型&#xff08;POM&#xff09;为基础进行项目管理&#xff0c;通过POM文件来定义项目信息和依赖关系。同时&#xff0c;它也是构建自动化工具&#xff0…...

Reactor 模式的理论与实践

1. 引言 1.1 什么是 Reactor 模式&#xff1f; Reactor 模式是一种用于处理高性能 I/O 的设计模式&#xff0c;专注于通过非阻塞 I/O 和事件驱动机制实现高并发性能。它的核心思想是将 I/O 操作的事件分离出来&#xff0c;通过事件分发器&#xff08;Reactor&#xff09;将事…...

vim 一次注释多行 的几种方法

在 Vim 中一次注释多行是一个常见操作。可以使用以下方法根据你的具体需求选择合适的方式&#xff1a; 方法 1&#xff1a;手动插入注释符 进入正常模式&#xff1a; 按 Esc 确保进入正常模式。 选择需要注释的多行&#xff1a; 移动到第一行&#xff0c;按下 Ctrlv 进入可视块…...

问题记录-Java后端

问题记录 目录 问题记录1.多数据源使用事务注意事项&#xff1f;2.mybatis执行MySQL的存储过程&#xff1f;3.springBoot加载不到nacos配置中心的配置问题4.服务器产生大量close_wait情况 1.多数据源使用事务注意事项&#xff1f; 问题&#xff1a;在springBoot项目中多表处理数…...

李春葆《数据结构》-课后习题代码题

一&#xff1a;假设不带权有向图采用邻接矩阵 g 存储&#xff0c;设计实现以下功能的算法&#xff1a; &#xff08;1&#xff09;求出图中每个顶点的入度。 代码&#xff1a; void indegree(MatGraph g){int i,j,n;printf("各个顶点的入度&#xff1a;\n");for(i…...

51c~C语言~合集2

我自己的原文哦~ https://blog.51cto.com/whaosoft/12652943 一、嵌入式开发中的C语言编译器 如果你和一个优秀的程序员共事&#xff0c;你会发现他对他使用的工具非常熟悉&#xff0c;就像一个画家了解他的画具一样。----比尔.盖茨1 不能简单的认为是个工具 嵌入式程序开发…...

【Python】构建事件驱动架构:用Python实现实时应用的高效系统

解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界 事件驱动架构(Event-Driven Architecture,EDA)是一种基于事件流动进行系统设计的模式,广泛应用于游戏开发、实时监控和分布式系统中。它通过解耦事件的生产者和消费者,提升系统的可扩展性和灵活性。本文章从…...

Git(一)基本使用

目录 一、使用git -v 查看安装git版本 二、使用mkdir 创建一个文件&#xff0c;并使用 git init 在该目录下创建一个本地仓库&#xff0c; 三、通过git clone命令接入线上仓库 四、使用git status查看仓库状态信息 五、利用echo写入一个文件 并使用cat进行查看 【Linux】e…...

HarmonyOS应用开发者基础认证,Next版本发布后最新题库(10月8日更新题库未收录)

笔者会尽量找到答案的出处&#xff0c;力求答案准确无误。有些题目答案可能有错&#xff0c;也有一些笔者实在找不到出处&#xff0c;也不知道答案的&#xff0c;如果读者发现错误或有补充建议&#xff0c;欢迎评论或私信笔者。您的每一条反馈都是宝贵的&#xff0c;能够帮助笔…...

【PGCCC】Postgresql BRIN 索引原理

前言 postgresql 提供了块级索引&#xff08;简称 BRIN&#xff09;&#xff0c;主要适用于类似时序数据之类的&#xff0c;有着天然的顺序&#xff0c;而且都是添加写的场景。相比于 btree 索引&#xff0c;它的体积小得多&#xff0c;非常适用于大数据量的场景。 原理 pos…...

腾讯云 AI 代码助手:产品研发过程的思考和方法论

一、文章摘要 本文将详细阐述 腾讯云 AI 代码助手的历史发展形态与产品整体架构&#xff0c;并从技术、研发方法论的角度分别阐述了产品的研发过程。 全文阅读约 5&#xff5e;8 分钟。 二、产品布局 AI 代码助手产品经历了三个时代的发展 第一代诸如 Eclipse、Jetbrains、V…...

Matlab 深度学习 PINN测试与学习

PINN 与传统神经网络的区别 与传统神经网络的不同之处在于&#xff0c;PINN 能够以微分方程形式纳入有关问题的先验专业知识。这些附加信息使 PINN 能够在给定的测量数据之外作出更准确的预测。此外&#xff0c;额外的物理知识还能在存在含噪测量数据的情况下对预测解进行正则…...

【Angular】async详解

在 Angular 中&#xff0c;async 关键字用于定义异步函数&#xff0c;通常与 await 一起使用来处理 Promise。这使得异步代码看起来更像同步代码&#xff0c;从而更容易理解和维护。 基本用法 定义异步函数&#xff1a;使用 async 关键字。等待 Promise 解析&#xff1a;使用…...

抖音SEO矩阵系统:开发技术分享

市场环境剖析 短视频SEO矩阵系统是一种策略&#xff0c;旨在通过不同平台上的多个账号建立联系&#xff0c;整合同一品牌下的各平台粉丝流量。该系统通过遵循每个平台的规则和内容要求&#xff0c;输出企业和品牌形象&#xff0c;以矩阵形式增强粉丝基础并提升商业价值。抖音作…...

线程与协程

1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指&#xff1a;像函数调用/返回一样轻量地完成任务切换。 举例说明&#xff1a; 当你在程序中写一个函数调用&#xff1a; funcA() 然后 funcA 执行完后返回&…...

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

快刀集(1): 一刀斩断视频片头广告

一刀流&#xff1a;用一个简单脚本&#xff0c;秒杀视频片头广告&#xff0c;还你清爽观影体验。 1. 引子 作为一个爱生活、爱学习、爱收藏高清资源的老码农&#xff0c;平时写代码之余看看电影、补补片&#xff0c;是再正常不过的事。 电影嘛&#xff0c;要沉浸&#xff0c;…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

es6+和css3新增的特性有哪些

一&#xff1a;ECMAScript 新特性&#xff08;ES6&#xff09; ES6 (2015) - 革命性更新 1&#xff0c;记住的方法&#xff0c;从一个方法里面用到了哪些技术 1&#xff0c;let /const块级作用域声明2&#xff0c;**默认参数**&#xff1a;函数参数可以设置默认值。3&#x…...

恶补电源:1.电桥

一、元器件的选择 搜索并选择电桥&#xff0c;再multisim中选择FWB&#xff0c;就有各种型号的电桥: 电桥是用来干嘛的呢&#xff1f; 它是一个由四个二极管搭成的“桥梁”形状的电路&#xff0c;用来把交流电&#xff08;AC&#xff09;变成直流电&#xff08;DC&#xff09;。…...

node.js的初步学习

那什么是node.js呢&#xff1f; 和JavaScript又是什么关系呢&#xff1f; node.js 提供了 JavaScript的运行环境。当JavaScript作为后端开发语言来说&#xff0c; 需要在node.js的环境上进行当JavaScript作为前端开发语言来说&#xff0c;需要在浏览器的环境上进行 Node.js 可…...