【C++】特殊类设计

article/2025/6/8 15:36:30

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

C++98中:

将拷贝构造函数和赋值运算符重载只声明不定义,将访问权限设置私有
在这里插入图片描述

原因:

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

C++11中:

扩展了delete的用法,delete除了释放new申请的资源外,如果在默认成员函数后跟上=delete,表示让编译器删除掉该默认成员函数。
在这里插入图片描述

复习内存分配

栈:

用途
1.存储局部变量(包括函数参数局部变量)。
2.存储函数调用的上下文信息(如返回地址、寄存器保存值等)。
特点
1.生命周期由作用域决定。当函数调用结束时,局部变量的内存自动释放。
2.内存分配和释放速度快,因为栈的操作是连续的。
3.栈的大小通常有限制(例如,Windows默认栈大小为1MB)。
4.存在栈溢出(Stack Overflow):如果栈空间不足,可能会导致程序崩溃。

堆:

用途
1.存储动态分配的对象
2.适合存储生命周期较长或大小不确定的对象
特点
1.内存分配和释放由程序员手动管理(C++中使用new和delete,C中使用malloc和free)。
2.堆的大小通常由系统可用内存决定,理论上可以分配较大的内存块。
3.内存分配和释放速度相对较慢,因为需要查找可用内存块并进行管理。
4.如果忘记释放内存,会导致内存泄漏(Memory Leak)。

静态区(数据段):

用途
1.存储全局变量静态变量
2.存储静态分配的对象
特点
1.生命周期贯穿整个程序的运行时间。
2.内存分配在程序启动时完成,释放时在程序结束时完成。(注意:main函数是程序的入口点。程序的生命周期由操作系统管理,常量区的内容初始化和释放也是由操作系统管理的)
3.静态变量的值在函数调用之间保持不变。

常量区(代码段):

用途
1.存储常量数据
2.包括字符串常量数字常量等。
特点
1.内存中的值不能被修改(只读)。
2.常量区的内容在程序启动时初始化,程序结束时释放。
3.常量区的内容通常存储在只读内存中,以防止意外修改。

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

实现方式:
将类的构造函数私有,拷贝构造声明成私有。防止别人调用拷贝在栈上生成对象。
提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建

有两种思路来实现

  • 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.在栈上创建的对象会在函数作用域结束后自动调用析构函数来释放资源
2.在静态区上创建的对象会在程序结束时自动调用析构函数
由于在编译阶段检查析构函数私有化它们无法调用,出现报错程序无法运行起来,所以无法创建它们。
3.私有域只对类外面的对象起限制作用,可以定义一个成员函数来调用析构,这样在堆上创建的变量就能够正常释放

注意:

  1. 程序运行起来,才会执行相关的代码,涉及到变量的创建等
    2.析构被禁用,虽然说不影响构造,但无法析构,导致程序报错,是无法编译通过 也就是无法访问析构程序无法运行,所以没法创建在栈上和静态区上的变量
    3.如果显示写析构函数,C++运行环境会依赖,若默认就是公有的
  • 2.构造函数私有化
class HeapOnly
{
public:static HeapOnly* creatobj(){return new HeapOnly;}private:HeapOnly(){//...}HeapOnly(const HeapOnly& hp) = delete;HeapOnly& operator=(const HeapOnly& hp) = delete;
};//测试
int main()
{//HeapOnly hp1;不允许,给禁止了//Heaponly* hp3 = new HeapOnly;//HeapOnly copy(hp3);HeapOnly* hp3 = HeapOnly::creatobj();delete hp3;return 0;
}

将构造函数设为私有,利用C++11中delete关键字来禁止拷贝构造和赋值重载的生成,使得无法在类外面直接创建或通过拷贝创建对象,也就是无法在栈上或静态区上创建对象
1.定义一个成员函数使得能new一个在堆上创建的对象,加上static修饰,可以使该函数属于类,它的调用不在依赖于实例化的对象,而是直接通过类名+访问限定符就可以直接访问。避免了创建对象需要对象来调用构造函数的先有鸡还是先有蛋的问题

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

class StackOnly
{
public:static StackOnly creatobj(){return StackOnly();/*StackOnly st;return st;*/}
private:StackOnly(){//...禁用}//~StackOnly() = delete;void* operator new(size_t size) = delete;
};int main()
{//StackOnly st1;//static StackOnly st2;静态区,禁用//StackOnly st3 = new StackOnly;堆,禁用StackOnly st1 = StackOnly::creatobj();//StackOnly* hp4 = new StackOnly(hp3); new+构造return 0;
}

1.与2.相同禁用构造,使之无法调用在静态区创建对象
2.通过定义一个静态方法可以不依赖对象的实例直接构造对象返回
3.禁用operator new,禁止在堆上创建对象:
new是一个运算符,用于动态分配内存并调用构造函数来初始化对象。operator new是一个全局函数,负责实际的内存分配。new 关键字在内部调用 operator new 来获取内存。operator new 可以被重载,所以要禁用operator new而不是new

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

1.C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
2.C++11可以使用final关键字,final修饰类,表示该类不能被继承,在类名后面修饰

5.单例模式

定义:一个类中只能创建一个对象

设计模式:

是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的
总结。通俗来讲就是套路
目的:为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化;设计模式是软件工程的基石脉络,如同大厦的结构一样。

单例模式:

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

单例模式的两种实现模式:
1.饿汉模式

一开始(main函数之前)就创建单例对象
优点:
简单,不需要手动管理,交给程序来管理其生命周期
缺点:
1.如果单例对象初始化内容很多,影响启动速度
2.如果两个单例类,互相有依赖关系。不好控制先后创建的关系

使用场景:

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

namespace hungry
{class Singleton{public://提供获取单例对象接口的函数static Singleton& GetInstance(){return _sinst;}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:Singleton(){//...}//防拷贝Singleton(const Singleton& s) = delete;Singleton& operator=(const Singleton& s) = delete;map<string, string> _dict;static Singleton _sinst;};// 在程序入口之前就完成单例对象的初始化Singleton Singleton::_sinst;
}

2.懒汉模式

优点:
第一次使用实例对象时,创建对象。进程启动无负载。多个单例实例启动顺序自由控制。
缺点:
相比饿汉模式相对复杂

使用场景:

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

namespace lazy
{class Singleton{public://提供获取单例对象的接口函数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://构造私有化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);}}//防拷贝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;
}//测试模式
int main()
{cout << &lazy::Singleton::GetInstance() << endl;cout << &hungry::Singleton::GetInstance() << endl;lazy::Singleton::GetInstance().Add({ "mint","薄荷" });lazy::Singleton::GetInstance().Add({ "1024","34" });lazy::Singleton::GetInstance().Print();return 0;
}

http://www.hkcw.cn/article/YMnwqXiSZx.shtml

相关文章

Oracle 用户/权限/角色管理

1. 用户 1.1. 用户的创建和删除 1.1.1. 创建用户 create user user identified {by password | externally} [ default tablespace tablespace ] [ temporary tablespace tablespace ] [ quota {integer [k | m ] | unlimited } on tablespace [ quota {integer [k | m ] | …

机器人现可完全破解验证码:未来安全技术何去何从?

引言 随着计算机视觉技术的飞速发展&#xff0c;机器学习模型现已能够100%可靠地解决Google的视觉reCAPTCHAv2验证码。这标志着一个时代的结束——自2000年代初以来&#xff0c;CAPTCHA&#xff08;"全自动区分计算机与人类的图灵测试"的缩写&#xff09;一直是区分…

AI赋能SEO关键词革新

内容概要 随着人工智能技术与搜索引擎优化的深度融合&#xff0c;传统关键词策略正经历系统性变革。基于智能语义分析与深度学习算法&#xff0c;AI能够实时解析海量搜索数据&#xff0c;构建动态更新的关键词库&#xff0c;突破人工筛选的局限性。通过自然语言处理技术&#…

深入解析Java11核心新特性

文章目录 前言一、标准化HTTP Client&#xff1a;告别HttpURLConnection1.1 HttpURLConnection 的痛点1.2 标准化 HTTP Client 的解决方案1.3 实战应用指南1.4 总结 二、局部变量类型推断增强&#xff1a;Lambda中的var2.1 解决的问题&#xff1a;类型声明的一致性困境2.2 实现…

香橙派3B学习笔记6:基本的Bash脚本学习_UTF-8格式问题

今日学习基本的linux 的一些 bash 脚本 ssh &#xff1a; orangepi本地ip 密码 &#xff1a; orangepi 操作系统发行版&#xff1a; 基于 Ubuntu 20.04.6 LTS&#xff08;Focal Fossa&#xff09;的定制版本&#xff0c;专门为 Orange Pi 设备优化。PRETTY_NAME"Orange P…

腾讯下乡了。。。

大家好&#xff0c;我是苍何。 这两天在网上出现很多腾讯元宝在乡下的横幅&#xff0c;着实把我吓了一大跳。 甚至养猪问题也可以直接问元宝&#x1f436; 前两天&#xff0c;刚好回乡下给我儿子过 2 岁生日&#xff0c;家里大婶的弟弟就是专业的养猪大户&#xff0c;在吃饭的…

如何在PowerBI中使用Analyze in Excel

如何在PowerBI中使用Analyze in Excel 之前分享过如何使用DAXStudio将PowerBI与Excel连接 &#xff0c;今天介绍另外一个工具&#xff0c;也可以实现同样的功能&#xff0c;Analyze in Excel。 使用Analyze in Excel 第一步&#xff1a; 首先准备好一个PBIX文件&#xff0c…

接口测试的用例设计

1.简介 在这篇文章里&#xff0c;我们来学习一下接口测试用例设计&#xff0c;主要是来学习一些用例设计要点。其实说白了&#xff0c;接口用例设计和功能用例设计差不多&#xff0c;照猫画虎即可。不要把它想象的多么高大上&#xff0c;多么的难&#xff0c;其实一样&#xff…

AI“实体化”革命:具身智能如何重构体育、工业与未来生活

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术的飞速发展正在重塑各行各业&#xff0c;而具身智能&#xff08;Embodied AI&#xff09;作为AI领域的重要分支&#xff0c;正逐渐从实验室走向现实应用。具身智能的核心在于让AI系统具备物理实体&#xff0c;能够与环…

车规级BMS芯片国产化!精准电量监测延长电池寿命

通品替代芯片充电管理类应用值得一看&#xff1a;华芯邦以创新技术领航国产化新赛道。 在消费电子、新能源汽车、工业设备等领域&#xff0c;电源管理芯片如同设备的“心脏”&#xff0c;直接决定了产品的续航能力、安全性和用户体验。然而&#xff0c;长期以来&#xff0c;这…

【摘录】LCD/LED/OLED/Micro LED

端午节焦点访谈播出了&#xff1a;成都辰显光电有限公司总经理黄秀颀博士作为科技领军人才代表出镜&#xff0c;分享了其带领团队推进Micro-LED技术创新与产业化。作为显示行业的一份子很惭愧&#xff0c;对这些技术还是一片空白&#xff0c;补补知识吧。 1、LCD&#xff08;液…

C++和C#界面开发方式的全面对比

文章目录 C界面开发方式1. **MFC&#xff08;Microsoft Foundation Classes&#xff09;**2. **Qt**3. **WTL&#xff08;Windows Template Library&#xff09;**4. **wxWidgets**5. **DirectUI** C#界面开发方式1. **WPF&#xff08;Windows Presentation Foundation&#xf…

【氮化镓】钝化层对p-GaN HEMT阈值电压的影响

2021年5月13日,中国台湾阳明交通大学的Shun-Wei Tang等人在《Microelectronics Reliability》期刊发表了题为《Investigation of the passivation-induced VTH shift in p-GaN HEMTs with Au-free gate-first process》的文章。该研究基于二次离子质谱(SIMS)、光致发光(PL)…

Juce实现Table自定义

Juce实现Table自定义 一.总体展示概及概述 在项目中Juce中TableList往往无法满足用户需求&#xff0c;头部和背景及背景颜色设置以及在Cell中添加自定义按钮&#xff0c;所以需要自己实现自定义TabelList&#xff0c;该示例是展示实现自定义TableList&#xff0c;实现自定义标…

VBA 64位API声明语句第010讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

【鸿蒙】HarmonyOS NEXT之如何正常加载地图组件

1、不支持模拟器&#xff0c;需要真机&#xff01; 2、Map地图需要在AGC上申请权限&#xff0c;需要在AGC上创建对应的项目 地址&#xff1a; AppGallery Connect 2.1 AGC中项目创建 2.1.1 添加项目 2.1.2 起个名字 2.1.3 添加应用&#xff1a; 2.1.4 选择HarmonyOS APP&…

精美的软件下载页面HTML源码:现代UI与动画效果的完美结合

精美的软件下载页面HTML源码&#xff1a;现代UI与动画效果的完美结合 在数字化产品推广中&#xff0c;一个设计精良的下载页面不仅能提升品牌专业度&#xff0c;还能显著提高用户转化率。本文介绍的精美软件下载页面HTML源码&#xff0c;通过现代化UI设计与丰富的动画效果&…

3. 简述node.js特性与底层原理

&#x1f63a;&#x1f63a;&#x1f63a; 一、Node.js 底层原理&#xff08;简化版&#xff09; Node.js 是一个 基于 Chrome V8 引擎构建的 JavaScript 运行时&#xff0c;底层核心由几部分组成&#xff1a; 组成部分简要说明 1.V8 引擎 将 JS 编译成机器码执行&#xff0…

【后端高阶面经:架构篇】51、搜索引擎架构与排序算法:面试关键知识点全解析

一、搜索引擎核心基石&#xff1a;倒排索引技术深度解析 &#xff08;一&#xff09;倒排索引的本质与构建流程 倒排索引&#xff08;Inverted Index&#xff09;是搜索引擎实现快速检索的核心数据结构&#xff0c;与传统数据库的正向索引&#xff08;文档→关键词&#xff0…

LayoutLM 模型文章总结

模型处理的文本图片样例&#xff1a; LayoutLM&#xff0c;一种简单而有效的文本和布局预训练方法&#xff0c;用于文档图像理解任务。BERT模型中输入的文本信息主要通过文本嵌入和位置嵌入来表示&#xff0c;LayoutLM 增加了两种输入嵌入&#xff1a; (1) 二维位置嵌入&…