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

【C++入门到精通】特殊类的设计 |只能在堆 ( 栈 ) 上创建对象的类 |禁止拷贝和继承的类 [ C++入门 ]

在这里插入图片描述

阅读导航

  • 引言
  • 一、特殊类 --- 不能被拷贝的类
    • 1. C++98方式:
    • 2. C++11方式:
  • 二、特殊类 --- 只能在堆上创建对象的类
  • 三、特殊类 --- 只能在栈上创建对象的类
  • 四、特殊类 --- 不能被继承的类
    • 1. C++98方式
    • 2. C++11方法
  • 总结
  • 温馨提示

引言

在面向对象编程中,特殊类是指具有不同于常规类的特殊属性或限制的类。这些类可以通过各种方式达到特定的目标和需求,例如只能在堆 ( 栈 ) 上创建对象的类、禁止拷贝和继承等。

本文将会讨论四种常见的特殊类:不能被拷贝的类、只能在堆上创建对象的类、只能在栈上创建对象的类以及不能被继承的类。我们将介绍它们的实现方法和应用场景,并提供相应的代码示例以帮助读者更好地理解这些特殊类的概念和用法。

一、特殊类 — 不能被拷贝的类

当一个类的拷贝是不允许的,可以采取以下两种方式来实现:

1. C++98方式:

在C++98中,可以通过将拷贝构造函数和赋值运算符重载声明为私有,并且不实现它们来禁止拷贝。这样做的原因是私有访问权限限制了类外部的代码无法访问这两个函数的实现

class CopyBan {
private:CopyBan(const CopyBan&); // 声明拷贝构造函数为私有CopyBan& operator=(const CopyBan&); // 声明赋值运算符重载为私有
public:// 其他公共成员函数和数据成员
};

这种方式通过将拷贝构造函数和赋值运算符重载放在私有区域,从而阻止了类的外部对象调用这两个函数,实现了禁止拷贝的目的。

2. C++11方式:

在C++11中,可以使用delete关键字来删除拷贝构造函数和赋值运算符重载。通过在函数声明后加上= delete,可以明确告诉编译器要删除此函数,防止类外部的代码调用它

class CopyBan {
public:CopyBan(const CopyBan&) = delete; // 删除拷贝构造函数CopyBan& operator=(const CopyBan&) = delete; // 删除赋值运算符重载// 其他公共成员函数和数据成员
};

这种方式更加简洁明了,直观地表达了禁止拷贝的意图。使用= delete语法可以方便地阻止拷贝构造函数和赋值运算符重载的调用。

无论是C++98还是C++11,这两种方式都能有效地禁止类的拷贝,增强代码的稳定性和安全性。选择哪种方式取决于你使用的C++版本和个人偏好。

二、特殊类 — 只能在堆上创建对象的类

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

class HeapOnly {
private:HeapOnly() {} // 私有的默认构造函数,防止在栈上创建对象~HeapOnly() {} // 私有的析构函数,防止在栈上销毁对象public:static HeapOnly* createInstance() {return new HeapOnly();}void destroyInstance() {delete this;}
};

这个类中,私有的默认构造函数和析构函数阻止了在栈上创建和销毁对象。而通过静态的createInstance()函数,可以在堆上创建该类的对象,并返回指向该对象的指针。然后,我们可以使用对象的destroyInstance()函数在适当的时候手动删除对象,从而释放内存

以下是示例代码的使用方式:

int main() {HeapOnly* obj = HeapOnly::createInstance();// 使用对象obj->destroyInstance();return 0;
}

🚨🚨注意:在这种设计中,由于析构函数是私有的,不能直接使用delete操作符来销毁对象。只能通过调用对象的destroyInstance()函数来手动删除对象

三、特殊类 — 只能在栈上创建对象的类

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

class StackOnly {
public:static StackOnly createInstance() {return StackOnly{};}private:StackOnly() = default; // 私有的默认构造函数,防止在堆上创建对象~StackOnly() = default; // 默认析构函数
};

这个类中,私有的构造函数阻止了在堆上创建对象。而通过公有的静态createInstance()函数,可以在栈上创建该类的对象,并返回该对象的副本由于没有指针和动态内存分配,对象的生命周期由对象所在的作用域控制,当对象离开作用域时,会自动调用析构函数销毁对象

以下是示例代码的使用方式:

int main() {StackOnly obj = StackOnly::createInstance();// 使用对象return 0;
}

这样设计的类限制了对象只能在栈上创建,可以避免使用者误用动态内存分配,从而提高了代码的健壮性。但请注意,在这种设计中,对象的拷贝构造函数、赋值运算符重载函数需要适当处理,以确保对象的正确复制行为。

四、特殊类 — 不能被继承的类

1. C++98方式

// C++98中构造函数私有化,派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
};

🚨🚨注意:在C++98中,虽然可以将构造函数私有化以阻止派生类调用基类的构造函数,但这并不能完全阻止继承。派生类仍然可以继承基类的成员函数和非私有成员变量

2. C++11方法

要设计一个不能被继承的类,可以使用C++中的关键字final来实现:

class NonInheritable final {// 类的定义
};

通过在类的声明中添加final关键字,可以阻止其他类继承该类。这样设计的类将是最终类,不能被其他类所继承。

以下是示例代码的使用方式:

class Derived : public NonInheritable { // 编译错误,无法继承NonInheritable类};int main() {NonInheritable obj; // 创建NonInheritable类的对象// 使用对象return 0;
}

这样设计的类不能被继承,可以确保类的封装性和稳定性,防止其他类对其进行修改或破坏。这在某些情况下非常有用,特别是当你希望限制类的继承性时。

总结

这些特殊类在面向对象编程中有着重要的作用,并且通过选择合适的类设计模式,我们可以更好地满足需求和解决问题。

在下一篇文章中,我们将深入研究单例模式。单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供了全局访问点。当我们需要确保只有一个对象来协调系统操作或管理共享资源时,单例模式非常有用。通过深入学习单例模式,我们将能够更好地理解其原理和使用方法,以及如何在实际开发中应用它。单例模式是一种非常有用的设计模式,掌握它将有助于我们编写可靠、高效的代码。让我们一起探索单例模式的精髓吧!敬请期待下一篇文章的发布!

温馨提示

感谢您对博主文章的关注与支持!另外,我计划在未来的更新中持续探讨与本文相关的内容,会为您带来更多关于C++以及编程技术问题的深入解析、应用案例和趣味玩法等。请继续关注博主的更新,不要错过任何精彩内容!

再次感谢您的支持和关注。期待与您建立更紧密的互动,共同探索C++、算法和编程的奥秘。祝您生活愉快,排便顺畅!

相关文章:

  • Ubuntu环境vscode配置Log4cplus库
  • vue3常用代码
  • thinphp 调用 \think\Log::write 写入回调日志信息
  • 手机操作系统Android
  • [UI5 常用控件] 02.Title,Link,Label
  • 《WebKit技术内幕》学习之十五(2):Web前端的未来
  • 重学java 11 封装
  • Spring Security 存储密码之 JDBC
  • 【C++】类和对象(中篇)(全网最细!!!)
  • 【C++11并发】mutex 笔记
  • 华为三层交换机之基本操作
  • leetcode88合并两个有序数组
  • python爬虫框架Scrapy
  • 案例分享 | 助力数字化转型:嘉为科技项目管理平台上线
  • CEF框架中的一些宏定义(二):CEF_CURRENTLY_ON
  • Django 博客开发教程 8 - 博客文章详情页
  • EOS是什么
  • JavaScript标准库系列——Math对象和Date对象(二)
  • JSONP原理
  • k8s如何管理Pod
  • Python进阶细节
  • tensorflow学习笔记3——MNIST应用篇
  • 编写高质量JavaScript代码之并发
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 离散点最小(凸)包围边界查找
  • 面试遇到的一些题
  • 七牛云 DV OV EV SSL 证书上线,限时折扣低至 6.75 折!
  • 七牛云假注销小指南
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 算法-图和图算法
  • 移动端 h5开发相关内容总结(三)
  • Oracle Portal 11g Diagnostics using Remote Diagnostic Agent (RDA) [ID 1059805.
  • ​Base64转换成图片,android studio build乱码,找不到okio.ByteString接腾讯人脸识别
  • (31)对象的克隆
  • (C)一些题4
  • (C++20) consteval立即函数
  • (Python第六天)文件处理
  • (笔试题)合法字符串
  • (附源码)计算机毕业设计SSM教师教学质量评价系统
  • (论文阅读11/100)Fast R-CNN
  • (原創) 未来三学期想要修的课 (日記)
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • ***php进行支付宝开发中return_url和notify_url的区别分析
  • .net 设置默认首页
  • .net 重复调用webservice_Java RMI 远程调用详解,优劣势说明
  • .Net8 Blazor 尝鲜
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • .Net接口调试与案例
  • // an array of int
  • @ResponseBody
  • @四年级家长,这条香港优才计划+华侨生联考捷径,一定要看!
  • [20190401]关于semtimedop函数调用.txt
  • [BZOJ4566][HAOI2016]找相同字符(SAM)
  • [CISCN2021 Quals]upload(PNG-IDAT块嵌入马)
  • [gdc19]《战神4》中的全局光照技术