【C++】特殊类实现——设计一个类、不能被拷贝、只能在堆上创建对象、只能在栈上创建对象、不能被继承、单例模式、饿汉模式、懒汉模式

文章目录

  • C++
  • 特殊类实现
    • 1.设计一个类、不能被拷贝
    • 2.设计一个类、只能在堆上创建对象
    • 3.设计一个类、只能在栈上创建对象
    • 4.设计一个类、不能被继承
    • 5.设计一个类,只能创建一个对象(单例模式)
    • 5.1饿汉模式
    • 5.2懒汉模式

C++

在这里插入图片描述

特殊类实现

1.设计一个类、不能被拷贝

  在C++中,拷贝构造函数和拷贝赋值运算符是两种可以用于创建新对象或为现有对象赋值的方法。

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

  以下是一个示例,展示如何创建一个不能被拷贝的类:

  C++98做法:

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

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

  原因:

  (1)只声明不定义:因为没有定义,所以该函数根本不会进行任何操作,定义了其实也没有什么意义,不写反而还简单,而且如果定义了就不会防止成员函数内部拷贝了。

  (2)同时设置成私有:这样可以防止直接使用它们, 如果只声明没有设置成private,用户自己如果在类外定义了,就可以不能禁止拷贝了。

  

  C++11做法:

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

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

            

2.设计一个类、只能在堆上创建对象

  实现方式:

  1.将类的析构函数私有;或者将类的构造函数私有,拷贝构造声明成私有。

  2.提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建(单例模式)。

  

  1.1析构函数私有化:

//析构函数私有化,因为堆要手动释放对象
class HeapOnly
{
public:void Destroy(){delete this;}private:~HeapOnly(){//...}
};int main()
{//HeapOnly hp1;//static HeapOnly hp2;HeapOnly* hp3 = new HeapOnly;hp3->Destroy();return 0;
}

  原因:

  我们可以将析构函数私有化,因为在栈上和静态区的对象需要自动调用析构函数,而析构函数无法显示调用了,就会导致我们无法在栈上和静态区创建对象。

  因为堆上的对象是需要我们手动的创建和删除的,所以在堆上创建对象只先调用构造函数; 如果我们需要对堆上创建的对象进行销毁,我们可以提供一个公有函数接口,用这个函数接口调用私有函数。

在这里插入图片描述

  

  1.12构造函数私有化:

//2、设计一个类只能在堆上创建对象
//构造函数私有化
class HeapOnly
{
public:static HeapOnly* CreateObj(){return new HeapOnly;}private:HeapOnly(){//...}//防止拷贝构造HeapOnly(const HeapOnly& hp) = delete;HeapOnly& operator=(const HeapOnly& hp) = delete;
};int main()
{//HeapOnly hp1;//static HeapOnly hp2;//HeapOnly* hp3 = new HeapOnly;HeapOnly* hp3 = HeapOnly::CreateObj();//HeapOnly copy(*hp3);//拷贝构造在栈上return 0;
}

  原因:

  我们将构造函数私有,禁止任何方式创建示例。但是提供一个可以在堆上创建对象的公有函数,这样我们就可以通过公有函数来调用私有的构造函数。

  注意:这里的要创建对象的公有函数应该是static修饰的,因为如果要调用公有函数,需要有一个对象示例,而我们要用公有函数创建一个示例,而我们现在没有对象示例,需要调用公有函数(类似鸡生蛋,蛋生鸡)…如果函数在静态区,就可以直接调用了。

  同时,为了防止我们创建的对象示例被拷贝构造或者赋值,所以我们还需要将拷贝构造函数和赋值运算符重载函数封死。

在这里插入图片描述

            

3.设计一个类、只能在栈上创建对象

  实现方法:

  将构造函数私有化,然后设计静态方法创建对象返回即可。

//3、设计一个只能在栈上的类
//构造函数私有
class StackOnly
{
public:static StackOnly CreateObj(){StackOnly st;return st;}private:StackOnly(){//...}//对一个类实现专属的operator newvoid* operator new(size_t size) = delete;
};int main()
{//StackOnly hp1;//static StackOnly hp2;//StackOnly* hp3 = new StackOnly;StackOnly hp3 = StackOnly::CreateObj();StackOnly copy(hp3);//new  operator new  +  构造//StackOnly* hp4 = new StackOnly(hp3);return 0;
}

  原因:

  和上面的实现一样,我们将构造函数私有化,提供一个只能在栈上创建对象的公有函数,static修饰。但是如果我们封死拷贝构造,CreateObj返回的临时对象就无法拷贝给我们的hp3,为了解决我们可以提供一个移动构造

  但是事实上也无法很有效的防止静态区创建对象,所以对于只在栈上创建对象的实现,这样就可以了。

在这里插入图片描述
            

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

  C++98方法:

  我们将构造函数私有化,派生类中调不到基类的构造函数,则无法继承。

//C++98  私有构造函数
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){//...}
}

  

  C++11方法:

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

//C++11  final
class A final
{//...
};

            

5.设计一个类,只能创建一个对象(单例模式)

  单例模式:

  一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。比如在某个服务器程序中,该服器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。
  

5.1饿汉模式

  饿汉模式:

  就是说不管你将来用不用,程序启动时(main函数之前创建)就创建一个唯一的实例对象;

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

  优点:简单;

  缺点:可能会导致进程启动慢,且如果有多个单例类对象实例启动顺序不确定。

// 饿汉模式:一开始(main函数之前)就创建单例对象
// 1、如果单例对象初始化内容很多,影响启动速度
// 2、如果两个单例类,互相有依赖关系。 
// 假设有A B两个单例类,要求A先创建,B再创建,B的初始化创建依赖A
namespace hungry
{class Singleton{public:// 2、提供获取单例对象的接口函数static Singleton& GetInstance(){return _sinst;}void func();void Add(const pair<string, string>& kv){_dict[kv.first] = kv.second;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}cout << endl;}private:// 1、构造函数私有Singleton(){// ...}// 3、防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;map<string, string> _dict;// ...static Singleton _sinst;};Singleton Singleton::_sinst;void Singleton::func(){// _dict["xxx"] = "1111";}
}

  

5.2懒汉模式

  懒汉模式:

  如果单例对象构造十分耗时或者占用很多资源,比如加载插件, 初始化网络连接,读取文件等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。 所以这种情况使用懒汉模式(延迟加载,在main函数之后创建)更好。

  优点:第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制;

  缺点:复杂。

namespace lazy
{class Singleton{public:// 2、提供获取单例对象的接口函数static Singleton& GetInstance(){if (_psinst == nullptr){// 第一次调用GetInstance的时候创建单例对象_psinst = new Singleton;}return *_psinst;}// 一般单例不用释放。// 特殊场景:1、中途需要显示释放  2、程序结束时,需要做一些特殊动作(如持久化)static void DelInstance(){if (_psinst){delete _psinst;_psinst = nullptr;}}void Add(const pair<string, string>& kv){_dict[kv.first] = kv.second;}void Print(){for (auto& e : _dict){cout << e.first << ":" << e.second << endl;}cout << endl;}class GC{public:~GC(){lazy::Singleton::DelInstance();}};private:// 1、构造函数私有Singleton(){// ...}~Singleton(){cout << "~Singleton()" << endl;// map数据写到文件中FILE* fin = fopen("map.txt", "w");for (auto& e : _dict){fputs(e.first.c_str(), fin);fputs(":", fin);fputs(e.second.c_str(), fin);fputs("\n", fin);}}// 3、防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;map<string, string> _dict;// ...static Singleton* _psinst;static GC _gc;};Singleton* Singleton::_psinst = nullptr;Singleton::GC Singleton::_gc;
}

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

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

相关文章

【微软技术栈】C#.NET 中使用依赖注入

本文内容 先决条件创建新的控制台应用程序添加接口添加默认实现添加需要 DI 的服务为 DI 注册服务结束语 本文介绍如何在 .NET 中使用依赖注入 (DI)。 借助 Microsoft 扩展&#xff0c;可通过添加服务并在 IServiceCollection 中配置这些服务来管理 DI。 IHost 接口会公开 IS…

模拟法——张三的零花钱(C#)

题目&#xff1a;张三的零花钱 不知道你有没有零花钱&#xff1f;你是如何管理⾃⼰的零花钱的&#xff1f;张三总爱乱花钱。每个⽉的⽉初妈妈给张三300元钱 &#xff0c;张三会预算这个⽉的花销&#xff0c;并且能做到实际的花销和预算相同。为了让张三学会对⾦钱的管理&#x…

node插件MongoDB(四)—— 库mongoose 操作文档使用(新增、删除、更新、查看文档)(二)

文章目录 前言&#xff08;1&#xff09;问题&#xff1a;安装的mongoose 库版本不应该过高导致的问题&#xff08;2&#xff09;重新安装低版本 一、插入文档1. 代码2. node终端效果3. 使用mongo.exe查询数据库的内容 二、删除文档1. 删除一条2. 批量删除3. 代码 三、修改文档…

pyTorch Hub 系列#4:PGAN — GAN 模型

一、主题描述 2014 年生成对抗网络的诞生及其对任意数据分布进行有效建模的能力席卷了计算机视觉界。两人范例的简单性和推理时令人惊讶的快速样本生成是使 GAN 成为现实世界中实际应用的理想选择的两个主要因素。 然而&#xff0c;在它们出现后的很长一段时间内&#xff0c;GA…

案例续集留言板

前端没有保存数据的功能,后端把数据保存下来(内存,数据库等等......) 前端代码如下 : <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…

ChatGPT 4 分析天猫双十一历年成交额趋势情况

收集历年的双十一成交额数据如下: 年份成交额:亿元20090.520109.362011

Linux——vim简介、配置方案(附带超美观的配置方案)、常用模式的基本操作

vim简介、配置方案、常用模式的基本操作 本章思维导图&#xff1a; 注&#xff1a;本章思维导图对应的xmind和.png文件都已同步导入至资源 1. vim简介 vim是Linux常用的文本编辑器&#xff0c;每个Linux账户都独有一个vim编辑器 本篇我们介绍vim最常用的三种模式&#xff1a;…

LeetCode 189.轮转数组(三种方法解决)

文章目录 题目暴力求解空间换时间三段逆置总结 题目 LeetCode 189.轮转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 输入: nums [1,2,3,4,5,6,7], k 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5…

代码随想录算法训练营第四十九天丨 动态规划part12

309.最佳买卖股票时机含冷冻期 思路 相对于动态规划&#xff1a;122.买卖股票的最佳时机II (opens new window)&#xff0c;本题加上了一个冷冻期 在动态规划&#xff1a;122.买卖股票的最佳时机II (opens new window)中有两个状态&#xff0c;持有股票后的最多现金&#xf…

【学习笔记】Understanding LSTM Networks

Understanding LSTM Networks 前言Recurrent Neural NetworksThe Problem of Long-Term DependenciesLSTM Networks The Core Idea Behind LSTMsStep-by-Step LSTM Walk ThroughForget Gate LayerInput Gate LayerOutput Gate Layer Variants on Long Short Term MemoryConclus…

Rd-03D串口协议

帧头部帧内数据帧尾部AA FF 03 00目标 1 信息 目标 2 信息 目标 3 信息55 CC 其中单个目标具体包含的信息: 目标 x 坐标目标 y 坐标目标速度像素距离值signed int16 类型&#xff1b;最高位 1 对应正坐标&#xff0c;0 对应负坐标&#xff1b;其余 15 位代表 x 坐标绝对值&am…

Dart笔记:build_runner-用于 Dart 代码生成和模块化编译的构建系统

Dart笔记 build_runner 用于 Dart 代码生成和模块化编译的构建系统 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263/artic…

npm 换源

你可以通过以下命令来将 npm 的源切换到阿里源&#xff1a; bashnpm config set registry https://registry.npm.taobao.org 这个命令会将 npm 的源设置为阿里的镜像源&#xff0c;这样你在安装 npm 包时&#xff0c;就会从阿里的镜像源下载&#xff0c;速度会更快。 如果你…

海康Visionmaster-Qt+VS 二次开发环境如何配置?

1 新建 Qt 工程&#xff0c;添加 Qt 模块 Core、GUI、Active Qt 和 Container Widgets 2 拷贝 DLL:VM\VisionMaster4.0.0\Development\V4.0.0\ComControl\bin\x64 下的所有拷贝到项目工程输出目录下&#xff0c;如下图所示&#xff0c;项目的输出路径是 Dll 文件夹。 3 第一…

JavaWeb Day10 案例 准备工作

目录 一、需求说明 二、环境搭建 &#xff08;一&#xff09;数据库 &#xff08;二&#xff09;后端 ①controller层 1.DeptController.java 2.EmpController.java ②mapper层 1.DeptMapper.java 2.EmpMapper.java ③pojo层 1.Dept.java 2.Emp.java 3.Result.ja…

STM32一

0.前言 在B站经常看见有人用stm32做出了有趣的电子小玩艺儿&#xff0c;感到很羡慕&#xff0c;于是想了解一下。 1.什么是stm32 STM32 是一系列由STMicroelectronics&#xff08;意法半导体&#xff09;公司设计和制造的32位ARM Cortex-M微控制器。这一系列的微控制器广泛用…

GetSimple CMS忘记密码

GetSimple CMS是一个超简单的 CMS&#xff0c;适合建立个人网站等只需要极少数页面的网站。在站上百科上&#xff0c;是这么说的&#xff1a; GetSimple是一款基于XML存储数据的开源内容管理系统&#xff0c;且易于安装和定制&#xff0c;无需MySQL支持。提供撤销保护和备份功能…

skynet学习笔记03— 服务

01、API newservice(name, ...)&#xff1a; 阻塞的形势启动一个名为 name 的新服务&#xff0c;待start函数执行完后会返回这个服务的地址。uniqueservice(name, ...)&#xff1a;针对于当前节点&#xff0c;启动一个唯一服务&#xff08;相当于单例&#xff09;&#xff0c;…

stm32 - Cortex

stm32 - Cortex 概念Cortex-M4 的工作模式和工作状态寄存器 概念 Cortex-M4 的工作模式和工作状态 处理模式 当处理器发生了异常或者中断&#xff0c;则进入处理模式进行处理&#xff0c;处理完成后返回到线程模式 权限大&#xff0c;访问处理器中所有的资源 线程模式 芯片复…

深度解剖Linux权限的概念

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;牢记Linux权限的概念。 > 毒鸡汤&#xff1a;你…