【C++】—— 特殊类设计

news2024/11/27 4:35:37

目录

序言

(一)设计一个不能被拷贝的类

(二)设计一个只能在堆上创建对象的类

(三)设计一个只能在栈上创建对象的类

(四)设计一个不能被继承的类

总结


序言

特殊类设计是指在面向对象编程中,根据特定需求或情况,创建具备特殊功能或属性的类。特殊类设计旨在解决特定问题或满足特殊需求,使代码更加灵活和可扩展。


(一)设计一个不能被拷贝的类

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

接下来,我们分别从C++98和C++11的两种场景去看二者是如何实现:

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

  •  代码如下:
class CopyBan
{
private:
	CopyBan(const CopyBan&); // 声明拷贝构造函数为私有
	CopyBan& operator=(const CopyBan&); // 声明拷贝赋值运算符为私有

public:
	CopyBan() {} // 默认构造函数
};

【解释说明】

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

使用该类时,只需简单地继承它即可:

class MyClass : public CopyBan{
    // 类的定义
};

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

  • 代码如下:
class CopyBan
{
	//.....

	CopyBan(const CopyBan&) = delete;			// 删除拷贝构造函数
	CopyBan& operator=(const CopyBan&) = delete; // 删除拷贝赋值运算符

	//.....
};

【解释说明】

  1. 在上面的示例中,我们定义了一个名为 CopyBan 的类。通过将拷贝构造函数和拷贝赋值运算符声明为 delete ,我们禁用了对象的拷贝功能;
  2. 这样一来,任何试图拷贝 CopyBan 类型对象的操作都会在编译时引发错误。

 

同样的使用该类时,只需简单地继承它即可:

class MyClass : public CopyBan{
    // 类的定义
};
  • 在这个示例中,MyClass  继承了CopyBan 类。但是,由于基类CopyBan 禁用了拷贝构造函数和赋值运算符函数,所以无法对 MyClass  进行拷贝操作。

【小结】

  • 使用这种设计,你可以确保该类的实例不会被拷贝,从而避免不必要的对象复制和可能引发的错误。


(二)设计一个只能在堆上创建对象的类

实现方式:

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

【C++98】 :

  • 代码如下:
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly();
	}
private:
	HeapOnly() {}		// 私有化默认构造函数
	// C++98
	// 1.只声明,不实现。因为实现可能会很麻烦,而你本身不需要
	// 2.声明成私有
	HeapOnly(const HeapOnly&);
};

【C++11】:

  • 代码如下:
class HeapOnly
{
public:
	static HeapOnly* CreateObject()
	{
		return new HeapOnly();
	}
private:
	HeapOnly() {}		// 私有化默认构造函数

	// C++11
	HeapOnly(const HeapOnly&) = delete;
};

 【解释说明】

  1. 在 C++11 标准之后,可以使用 = delete 来删除复制构造函数,而不仅仅是将其声明为私有;
  2. 这种方式更加清晰明了,使得代码更具可读性和表达性。因此,推荐使用 C++11 及以上版本的标准来实现这样的需求。

这样,你就可以使用下面的代码在堆上创建 HeapOnly 类对象: 

HeapOnly* obj = HeapOnly::CreateObject();

请确保在使用完对象后手动调用 delete 来释放内存:

delete obj;

 

【小结】

  • 这样设计的类将只能在堆上创建对象,并且无法通过拷贝或赋值的方式创建新对象,从而确保了对象的唯一性和创建方式的约束。

(三)设计一个只能在栈上创建对象的类

实现方法:

  • 要设计一个只能在栈上创建对象的类,可以使用私有的析构函数和公有的静态成员函数来实现。

【C++98】 :

  • 代码如下:
class StackOnly 
{
public:
    static StackOnly CreateObj() {
        return StackOnly();
    }

private:
    StackOnly() {} // 私有化默认构造函数
    ~StackOnly() {} // 私有化析构函数
};

【解释说明】

  1. 在上面的示例中,我们将默认构造函数和析构函数私有化。这意味着外部无法直接实例化或销毁 StackOnly 类的对象。
  2. 为了能够创建对象,我们提供了一个名为 CreateObj 的公有静态成员函数。该函数返回一个 StackOnly 类型的对象。

使用代码示例:

StackOnly obj = StackOnly::CreateObj();
  •  这样就确保了 StackOnly 类的对象只能在栈上创建,因为无法直接访问私有的默认构造函数;
  • 对象的析构由编译器自动处理(不需要手动调用delete释放内存),当对象超出作用域时会自动调用析构函数进行资源的释放。

【C++11】:可以使用删除特殊成员函数以及阻止使用new和delete操作符的方式来实现只能在栈上创建对象的类。

  • 代码如下:
class StackOnly
{
public:
    StackOnly() = default; // 允许默认构造函数

    // 删除拷贝构造函数和赋值运算符函数
    StackOnly(const StackOnly&) = delete;
    StackOnly& operator=(const StackOnly&) = delete;

    // 禁止使用new和delete操作符
    void* operator new(size_t) = delete;
    void operator delete(void*) = delete;
};

使用代码示例:

StackOnly obj1; // 在栈上创建对象

// 下面的代码将导致编译错误,因为拷贝构造函数被删除
// StackOnly obj2 = obj1;

// 下面的代码将导致编译错误,因为赋值运算符函数被删除
// StackOnly obj3;
// obj3 = obj1;

// 下面的代码将导致编译错误,因为使用了删除的new运算符
// StackOnly* ptr = new StackOnly;

// 下面的代码将导致编译错误,因为使用了删除的delete运算符
// delete ptr;

【解释说明】

  • 这样设计的类将只能在栈上创建对象,并且无法通过拷贝或赋值的方式创建新对象,同时禁止使用newdelete来分配和释放对象的内存,从而确保了对象的唯一性和创建方式的限制。

除了上述方法之外,还有一种比较奇特的方式,可以用于实现只能在栈上创建对象的类。这种方式是通过定义一个私有化的 operator newoperator delete 函数来实现无需删除构造函数和析构函数

  • 代码如下:
class StackOnly 
{
public:
    // 在 public 区域声明 operator new 和 operator delete 函数
    static void* operator new(size_t size) = delete; // 删除 operator new 函数
    static void operator delete(void* ptr) noexcept = delete; // 删除 operator delete 函数

private:
    // 私有化所有构造、析构函数,包括默认构造函数
    StackOnly() {}
    StackOnly(const StackOnly&) {}
    ~StackOnly() {}
};

【解释说明】

  1. 在上面的示例中,将构造函数和析构函数都设为了私有的,防止对象在堆上创建或销毁。同时,我们在公有区域声明了一个删除的 operator new 和 operator delete 函数,这些函数用于在堆上分配内存和释放内存。
  2. 由于默认情况下类的 operator new 和 operator delete 函数都是 public 的,因此我们要重新定义它们。而将其声明为 delete,则完全禁止直接在堆上分配和释放内存,从而避免对象在堆上创建。

 使用该类时,只能通过栈上的对象进行操作:

StackOnly obj;

【注意】

  • 确保了 StackOnly 类的对象只能在栈上创建。但是这种方法需要注意的是,在某些情况下,可能会因为需要使用 operator new 和 operator delete 函数而无法编译通过,因此使用时需要慎重考虑。


(四)设计一个不能被继承的类

实现方法:

  • 在使用 C++98 标准时,可以通过将构造函数和析构函数设为私有,并且不提供公共的静态工厂方法来实现一个不能被继承的类。

【C++98】 :

  • 代码如下:
class NonInherit
{
private:
    NonInherit() {}
    ~NonInherit() {}

public:
    // 禁止通过静态工厂方法创建对象
    static NonInherit* GetInstance() {
        return NULL;
    }
};

实现方法:

  • 在C++11以及后续的标准中,你可以在类声明的末尾添加关键字final,来显式地指示该类是不可被继承的。

【C++11】:

  • 代码如下:
class A final
{
    // ....
};

【解释说明】

  1. 在上述示例中,我们在类的定义前使用了 final关键字,将 A声明为最终类。这意味着其他类无法从A继承。
  2. 如果其他类尝试继承 A,编译器将会报错。

 例如:

class A final 
{
	//...
};

class B : public A { // 编译错误
	// 类定义
};

报错如下: 


总结

这些特殊类的设计目的是根据特定的需求和编程场景来确定的;

它们有助于代码的组织、可维护性、可扩展性和重用性。通过合理地设计和使用这些特殊类,可以提高代码的质量、可读性和可靠性。

到此,关于本期特殊类设计便讲解结束了。感谢大家的观看和支持!!!

 

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

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

相关文章

AR产业变革中的“关键先生”和“关键力量”

今年6月的WWDC大会上,苹果发布了头显产品Vision Pro,苹果CEO库克形容它: 开启了空间计算时代。 AR产业曾红极一时,但因为一些技术硬伤又减弱了声量,整个产业在起伏中前行。必须承认,这次苹果发布Vision P…

百度文心一言可以接入微信小程序啦!

文心一言(英文名:ERNIE Bot)是百度全新一代知识增强大语言模型,文心大模型家族的新成员,能够与人对话互动,回答问题,协助创作,高效便捷地帮助人们获取信息、知识和灵感 …

python学习之【深拷贝】

#我的编程语言学习笔记# 前言 上一篇文章python学习之【浅拷贝】 学习了python中的浅拷贝相关内容,这篇文章接着学习深拷贝。 简单回顾 浅拷贝只拷贝浅层元素,深层元素的内存地址不改变 ;当对拷贝产生的新的对象的浅层元素进行更改时&…

擎创技术流 | 深入浅出运维可观测工具(三):eBPF如何兼容多架构模式性能管理

嗨~又见面了大家! 之前给大家分享过2篇eBPF技术干货,后台收到的反馈还挺好的,以至于总有朋友过来催更这一系列,这不第3篇在大家的千呼万唤下终于出来了。 新来的朋友点这里,键回看eBPF精彩技术贴,别忘了随…

Vue2安装vuex和vue-router报错处理

Vue2安装vuex和vue-router报错处理 Vue2.6安装VuexVue2.6安装vue-router Vue2.6安装Vuex 报错信息 处理方法 #查看vuex版本 npm view vuex versions --json #安装合适版本 npm install vuex3.6.2 --saveVue2.6安装vue-router 报错信息 处理方法 #查看vue-router版本 npm…

2009-2022年商业银行竞争度数据(勒纳指数)(含原始数据和计算代码 dofile+结果)

2009-2022年商业银行竞争度数据(勒纳指数)(含原始数据和计算代码 dofile结果) 1、时间:2009-2022年 2、来源:整理自wind 3、指标:证券代码、证券简称、上市日期、年份、资产总计、利息支出、…

C语言系统化精讲(一):C 语言开发环境搭建

文章目录 一、Windows 开发环境搭建1.1 安装 mingw 编译器1.2 下载并安装 CLion1.3 启动 CLion 二、Linux 开发环境搭建(建议使用)2.1 VMware Workstation Pro软件简介及安装2.2 安装 Ubuntu 系统2.2.1 Ubuntu 下载2.2.2 安装 Ubuntu2.2.3 安装共享文件夹…

汽车3D HMI图形引擎选择

2002年,电影《少数派报告》让观众深入了解未来。 除了情节的核心道德困境之外,大多数人都对它的技术着迷。 我们看到了自动驾驶汽车、个性化广告和用户可以无缝交互的 3D 计算机界面。 令人惊讶的是,虽然故事发生在 2054 年,但许多科幻想象的作品已经成为现实。 对于汽车和…

【C++】STL-常用算法-常用遍历算法

0.前言 1.for_each #include <iostream> using namespace std;// 常用遍历算法 for_each #include<vector> #include<algorithm>//普通函数 void print01(int val) {cout << val << " "; }//仿函数 class Print02 { public:void oper…

Playwright for Python:断言

一、支持的断言 Playwright支持以下几种断言&#xff1a; 断言描述expect(locator).to_be_checked()复选框被选中expect(locator).to_be_disabled()元素是禁用状态expect(locator).to_be_editable()元素是可编辑状态expect(locator).to_be_empty()容器是空的expect(locator).…

重复的DNA序列(力扣)JAVA

DNA序列 由一系列核苷酸组成&#xff0c;缩写为 ‘A’, ‘C’, ‘G’ 和 ‘T’.。 例如&#xff0c;“ACGAATTCCG” 是一个 DNA序列 。 在研究 DNA 时&#xff0c;识别 DNA 中的重复序列非常有用。 给定一个表示 DNA序列 的字符串 s &#xff0c;返回所有在 DNA 分子中出现不止…

异常-java

目录 一、异常的概念和体系结构 1.1 异常的概念 1.2 异常的体系结构 1.3 异常的分类 二、异常的处理 2.1 防御式编程 2.2 异常抛出 2.3 异常捕获 2.4 异常处理流程 三、自定义异常类 一、异常的概念和体系结构 1.1 异常的概念 程序员在开发过程中&#xff0c;想要将代码写得…

【已解决】使用xshell来ssh到vmware的虚拟机,请求超时的问题

我的情况&#xff1a; 1.本地ping虚拟机请求超时&#xff0c;但是虚拟机ping本地成功 2.本地和虚拟机的防火墙都关了&#xff0c;ssh服务也开了 3.端口也是正确的 百思不得其解&#xff0c;不知道为什么就是连接不上 当出现这种情况的时候&#xff0c;可以考虑一下vmware的…

数学建模--Subplot绘图的Python实现

目录 1.Subplot函数简介 2.Subplot绘图范例1:绘制规则子图 3.Subplot绘图范例2:绘制不规则子图 4.Subplot绘图范例3:gridspec辅助实战1 5.Subplot绘图范例4:gridspec辅助实战2 1.Subplot函数简介 """ 最近在数学建模种需要绘制多张子图,发现对于subplot函…

win11安装jdk

Windows11JDK20安装及环境变量配置 - 简书 Java学习--Win11配置环境变量-腾讯云开发者社区-腾讯云 电脑上安装多个JDK版本时如何自由切换_安装多版本jdk_有青枫林的博客-CSDN博客 Windows同时安装两个版本JDK&#xff0c;并实现动态切换JAVA8或者JAVA11 【无标题】windows1…

教你轻松制作个性化的电子婚礼请柬

在一个婚礼的筹备过程中&#xff0c;制作一份独特而个性化的请柬是非常重要的。传统的纸质请柬已经逐渐被现代的电子请柬所取代&#xff0c;而用H5制作个性化的电子请柬正是目前越来越受欢迎的选择。让我们一起来看看如何通过乔拓云网的后台来定制属于你的梦幻婚礼电子请柬吧&a…

Leetcode.1123 最深叶节点的最近公共祖先

题目链接 Leetcode.1123 最深叶节点的最近公共祖先 rating : 1607 题目描述 给你一个有根节点 root 的二叉树&#xff0c;返回它 最深的叶节点的最近公共祖先 。 回想一下&#xff1a; 叶节点 是二叉树中没有子节点的节点&#xff1b;树的根节点的 深度 为 0 0 0&#xff0…

2023年09月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年09月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

【数据分享】2006-2021年我国省份级别的供水相关指标(20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国省份级别的市政设施水平相关指标、2006-2021年我国省份级别的各类建设用地面积数…