C++ 常见特殊类的设计

 一、设计一个不能被拷贝的类

1.1 为什么需要一些不能被拷贝的类呢?

很多情况下如果允许进行拷贝逻辑是说不通的,比如IO流有缓冲区如何进行拷贝,又比如说对于线程这个类,线程对象已经运行了如何进行拷贝?

想要让某个类不能被拷贝直接将拷贝构造函数和operator=封死就可以解决了。

1.2 策略

C++98中的做法是:

将构造函数私有化并只声明不定义

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

这种私有化+只声明不定义的策略是因为:

现来说一下私有化,私有化防止进行该类实例化出来的对象执行拷贝和复制重载;只声明不定义是因为该函数不可能被调用,将这两个函数进行定义也没有任何意义,如果不声明的话会自动在publish中生成默认构造函数就会允许拷贝构造和赋值重载了。

C++11中的做法是:

通过在函数后面加上 delete关键字(准确的说是加上 = delete)

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

通过使用 = delete 让编译器进行删除该类的构造函数。

二、设计一个类只能在堆上进行创建对象

2.1 策略

构造函数私有化

要想让一个类只能在堆上进行创建空间,也就是说需要将传统的通过构造函数进行在栈上进行创建对象的这种方式进行封锁,然后进行提供提供一个静态的公共函数接口,专门用来提供在对上进行创建对象的这种需求。

class HeapOnly { public: static HeapOnly* CreateObject() { return new HeapOnly; } private: HeapOnly() { } HeapOnly(const HeapOnly& ho) = delete; HeapOnly& operator=(const HeapOnly& ho) = delete; };
这里说明一下为什么也要将拷贝构造和赋值重载进行封死?



如果要不封死,虽然不能通过构造函数进行在栈上进行创建对象,但是可以先通过在堆上进行创建对象再通过拷贝构造或者赋值重载在栈上进行创建。

还有一种非常特别的思路

将析构函数进行私有化

class HeapOnly { public: HeapOnly() { } void DeleteObject() { delete this; } private: HeapOnly(const HeapOnly& ho) = delete; HeapOnly& operator=(const HeapOnly& ho) = delete; ~HeapOnly() { } };

将析构函数进行私有化这种策略是利用了编译器的性质,当编译器识别到在栈上进行创建对象时,会考虑到该对象的作用域,超过作用域会将该对象进行销毁并进行资源释放,当将析构函数进行私有化时,此时编译器在进行识别到在栈上进行创建对象时,发现析构函数定义在了private中意味着不能进行在类外调用,此时就会报错,不允许在堆上进行创建对象。

三、设计一个类只能在栈上进行创建对象

3.1 策略

先说一种错误的策略:

构造函数私有化


想要将一个设计成只能在栈上进行创建对象,首先肯定要禁止 new 进行创建对象,new 关键字进行创建对象本质上又在类外调用了构造函数,所以将类的构造函数进行私有化即可屏蔽在类外进行通过new进行创建对象,但是还要在栈上能创建对象,所以还需要在类中的public中进行定义一个创建对象的静态成员函数。

这样进行实验是确实可以通过编译的,但是这样进行构建的对象是死的,无法将 CreateObject 函数进行创建出来的对象进行赋值给外面进行接收的对象,这些都是在c++17之前;但是c++17之后是允许通过编译的,之所以能够通过编译是因为这个return StackOnly()这行代码在c++17之前是先进行创建临时对象将临时对象拷贝或者移动到外面接收的变量中,但是c++17之后直接将拿着这个对象中的成员一个一个赋值给外面对象的成员,既然没有临时对象也就不在涉及拷贝构造。

这里能编译通过也是很坑的,举个例子:
 

vector容器中存储的元素是在堆上,当通过vec对象进行调用push_back想要将s对象进行存储到容器中时,此时会报错,因为:push_back并不会直接收纳s本身,是在栈上容器存储的是在堆上,真正的逻辑是:

在堆上找到一个空位

然后调用s的拷贝构造函数将s中的数据进行拷贝到堆上

正确的方式

将 new 和 delete 系类的函数禁用

class StackOnly { public: StackOnly() { } ~StackOnly() { } static void* operator new(size_t sz) = delete; static void operator delete(void* memy) = delete; static void* operator new[](size_t sz) = delete; static void operator delete[](void* memy) = delete; };

四、设计一个类不能被继承

4.1 策略

c++98 做法:将构造函数私有化

将基类的构造函数私有化,当子类进行继承基类时并且进行定义对象时,此时该对象会进行调用基类和子类的构造函数进行初始化,但是基类中构造函数私有了,调不到从而做到基类无法被继承。

class NonInherit { public: static NonInherit GetInstance() { return NonInherit(); } private: NonInherit() {} };

c++11 做法:利用 final 关键字进行修饰

class NonInherit final { // .... };

Read more

从代码混乱到井然有序:飞算JavaAI的智能治理之道

从代码混乱到井然有序:飞算JavaAI的智能治理之道

文章目录 * 一、前言 * 二、飞算JavaAI平台 * 三、飞算JavaAI安装流程 * 3.1 Idea安装配置 * 3.2 官网注册登入 * 四、飞算JavaAI独特魅力:合并项目场景 * 4.1 ERP老项目精准翻新:保留核心逻辑的智能改造方案 * 4.2 智能合并:重构ERP系统的代码迷宫 * 4.3 ERP接口智能导航:模块化精准治理每一处数据流 * 4.4 其他功能 * 五、工程代码快速构建 * 六、飞算 JavaAI 与其他 AI 编程工具对比 * 七、总结与分析 飞算JavaAI彻底颠覆了传统AI代码生成的不可靠印象,以精准的需求理解和高质量的代码输出重新定义了智能编程体验。不同于那些需要反复调试的"半成品代码",它能直接生成符合企业级规范的Java代码,从Entity到Controller一气呵成,让开发者真正感受到&

By Ne0inhk
如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题

如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题

如何排查并解决项目启动时报错Error encountered while processing: java.io.IOException: closed 的问题 摘要 本文针对Java项目启动时出现的java.io.IOException: closed错误,提供系统性解决方案。该异常通常由流资源异常关闭或损坏引发,常见于Maven依赖损坏(mvn dependency:purge-local-repository)、Wrapper脚本缺失(mvn wrapper:wrapper)、IDE缓存异常(Invalidate Caches)或Spring Boot插件配置不当(显式指定spring-boot-maven-plugin版本)等情况。通过分步操作(清理本地仓库、重装Wrapper、清理IDE缓存、检查pom配置)并结合日志调试(-X参数),可快速定位问题根源。最后提出预防建议:CI/CD定期清理依赖、版本化Wrapper文件、固定插件版本,有效提升项目启动稳定性与团队协作一致性。 关键词: Java IOException, Maven依赖修复, Spring

By Ne0inhk
华为OD机试双机位C卷-FLASH坏块监测系统(Py/Java/C/C++/Js/Go)

华为OD机试双机位C卷-FLASH坏块监测系统(Py/Java/C/C++/Js/Go)

FLASH坏块监测系统 华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 100分题型 华为OD机试双机位C卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解 题目描述 开发一个 FLASH 坏块监测系统,能够监测 FLASH 中坏块的数量。FLASH 介质以一个大小为 m×n的二维二进制矩阵表示,其中:0 表示正常,1 表示异常。最初,FLASH 介质中的所有单元格都是正常(即,所有单元格都是 0)。 系统运行过程中,FLASH 坏块不断产生:随着系统持续运行,某一个时刻 i,FLASH 介质中的某个单元格 (ri,ci)由正常变为异常。返回一个整数数组 result,其中 result[i] 是 FLASH 介质中第

By Ne0inhk