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

【C++】特殊类的设计与类型转换

文章目录

  • 1. 特殊类的设计
    • 1.1 不能被拷贝的类
    • 1.2 只能在堆上创建对象的类
    • 1.3 只能在栈上创建对象的类
    • 1.4 不能被继承的类
    • 1.5 只能创建一个对象的类(单列模式)
  • 2. 类型转换
    • 2.1 C/C++的类型转换
    • 2.2 C++规定的四种类型转换
      • 2.2.1 static_cast
      • 2.2.2 reinterpret_cast
      • 2.2.3 const_cast
      • 2.2.4 dynamic_cast

在这里插入图片描述

1. 特殊类的设计

1.1 不能被拷贝的类

请设计一个类,不能被拷贝

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

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

在这里插入图片描述
原因:

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

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

此时只要调用到这两个函数就会报错。
在这里插入图片描述

1.2 只能在堆上创建对象的类

实现方式:

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

在这里插入图片描述

class A
{
public://设置为静态可直接使用类名访问,无需对象调用static A* Create(int a){return new A(a);}private:A(int a = 0):_a(a){}A(const A& a):_a(a._a){}int _a;
};int main()
{//不能在栈上创建对象//A aa1;//A aa2(10);A* aa3 = A::Create(20);//调用规定函数在堆上创建对象//A aa4(*aa3);//若不禁掉拷贝构造,仍可在栈上创建对象return 0;

1.3 只能在栈上创建对象的类

设计一个类,不得使用new创建对象

方法一:将构造函数私有化,然后设计静态方法创建对象返回,同时将拷贝构造禁掉,使其使用移动构造。

在这里插入图片描述

很明显,方法一并不能封的很死。

方法二:将构造函数私有化,然后设计静态方法创建对象返回,同时将operator new 与operator delete 禁掉,使其无法使用new;并且将拷贝构造禁掉,创建对象时使用移动构造

在这里插入图片描述
这种方法也不能完全封死,依旧有隐患。
所以只要把拷贝构造或者移动构造暴露,就会有隐患,使用时按需选择。

1.4 不能被继承的类

C++98中构造函数私有化,派生类中调不到基类的构造函数,则无法继承。

在这里插入图片描述

C++11中,使用final关键字,final修饰类,表示该类不能被继承。

在这里插入图片描述

1.5 只能创建一个对象的类(单列模式)

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

单例模式有两种实现模式:

  • 饿汉模式:不管你将来用不用,程序启动时就创建一个唯一的实例对象。

在这里插入图片描述
注意:static类型的对象不在对象里面,在静态区,它仅受类域的限制,因此不会引发无穷递归

为了防止使用拷贝构造和赋值重载创建多个对象,所以也应该封一下。

在这里插入图片描述
到此就完整了

class InfoManager
{
public:static InfoManager& GetInstance(){return _instance; //每次返回的都是同一个}private:InfoManager()  //将构造函数私有{cout << "InfoManager()" << endl;}InfoManager(const InfoManager& p) = delete;InfoManager& operator=(const InfoManager& p) = delete;private:string _ip = "192.168.2.4";int _potr = 80;//...static InfoManager _instance; //声明一个在静态区的对象,该对象受类域的限制
};InfoManager InfoManager::_instance; //创建对象int main()
{InfoManager::GetInstance();//InfoManager copy(InfoManager::GetInstance());
}

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

  • 懒汉模式:第一次使用实例对象时,创建对象

对于该模式来说,它跟饿汉模式差不多,只不过它在第一次调用GetInstance时创建对象,所以我们可以将其设置为指针。
在这里插入图片描述

还有一种更简单的方式(C++11后推荐使用):

在这里插入图片描述

注意:成员函数也不在对象里面,在代码段

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

2. 类型转换

2.1 C/C++的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化。

C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换

  • 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败(整型之间、整型和浮点数之间都可以转换)
  • 显式类型转化:需要用户自己处理
  1. 内置类型之间可以转
void Test()
{int i = 10;// 隐式类型转换double d = i;printf("%d, %.1f\n", i, d);int* p = &i;// 显示的强制类型转换int address = (int)p;printf("%x, %d\n", p, address);
}
  1. 内置类型和自定义类型之间不可以直接转,但可以依靠构造函数、运算符重载转换

内置类型->自定义类型,依靠构造函数转换

class A
{
public:A(int a):_a(a),_b(a){}A(int a,int b):_a(a),_b(b){}
private:int _a;int _b;
};int main()
{A aa1 = 1;//调单参数的构造转换A aa2 = { 10,20 };//调多参数的构造转换
}

自定义类型->内置类型,使用 operator + 类型,没有返回值

在这里插入图片描述

  1. 自定义类型和自定义类型之间

依靠构造函数,实现自定义类型之间的转换

在这里插入图片描述

2.2 C++规定的四种类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符,目的就是规范转换,使转换更加清晰。

2.2.1 static_cast

static_cast对应的是隐式类型转换

在这里插入图片描述

2.2.2 reinterpret_cast

reinterpret_cast用于将一种类型转换为另一种不同的类型,对应强制类型转换

在这里插入图片描述

2.2.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值(对应强制类型转换中有风险的去掉const属性

但是下面的代码中我们发行并没有修改掉变量a,这是由于编译器的优化。

在这里插入图片描述
这里我们可以加上volatile关键字。

在这里插入图片描述

volatile作用:不让编译器优化,规规矩矩的执行,达到稳定访问内存的目的(volatile忽略编译器的优化,保持内存可见性)

2.2.4 dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(运行时转换)

  • 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,切片)
  • 向下转型:父类对象指针/引用->子类指针/引用(使用强制类型转换是不安全的,可能会越界访问;用dynamic_cast转换是安全的)

dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0。(如果父类指针或引用指向子类,此时转换为子类是安全的;如果父类指针或引用指向父类,此时转换为子类是不安全的,会越界)
在这里插入图片描述

dynamic_cast只能用于父类含有虚函数的类(因为其会在虚表中添加一些标识,以识别指向父类还是子类)

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 「栈」实现LIFO栈(先进后出栈|堆栈|stack)的功能 / 手撕数据结构(C++)
  • DALL-E 2:当AI遇上画笔,艺术界的“魔术师”横空出世!
  • 电脑屏幕录制工具分享5款,附上详细电脑录屏教程(2024全新)
  • 【Java】 深入了解 Java util 包中的 add() 方法
  • Elasticsearch 创建索引库指南
  • ERROR 1698 (28000): Access denied for user ‘root‘@‘localhost‘
  • vulhub,docker一直启动不起来?docker配置文件错误(/etc/docker/daemon.json )
  • 前端传递ids ,gorm 删除
  • IMU助力跑步参数评估
  • 漏洞复现-Apache Kafka Clients JNDI注入漏洞 (CVE-2023-25194)
  • springboot项目搭建集成 redis/跨域/远程请求
  • 在Ubuntu上有什么命令,或者是系统文件能告诉我链接nvme ssd的pcie槽位是不是支持热插拔功能?
  • 【Cpp筑基】三、对象和类
  • g++ 编译器参数作用
  • “5G+Windows”推动全场景数字化升级:美格智能5G智能模组SRM930成功运行Windows 11系统
  • angular学习第一篇-----环境搭建
  • C++入门教程(10):for 语句
  • co.js - 让异步代码同步化
  • Java 23种设计模式 之单例模式 7种实现方式
  • JavaScript对象详解
  • Java到底能干嘛?
  • jquery cookie
  • mysql常用命令汇总
  • PyCharm搭建GO开发环境(GO语言学习第1课)
  • Python socket服务器端、客户端传送信息
  • React-flux杂记
  • SegmentFault 2015 Top Rank
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 技术胖1-4季视频复习— (看视频笔记)
  • 扑朔迷离的属性和特性【彻底弄清】
  • 微信开放平台全网发布【失败】的几点排查方法
  • ​​​​​​​ubuntu16.04 fastreid训练过程
  • ​软考-高级-信息系统项目管理师教程 第四版【第23章-组织通用管理-思维导图】​
  • ​学习笔记——动态路由——IS-IS中间系统到中间系统(报文/TLV)​
  • #Linux(Source Insight安装及工程建立)
  • #我与Java虚拟机的故事#连载16:打开Java世界大门的钥匙
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (2)空速传感器
  • (20)docke容器
  • (2020)Java后端开发----(面试题和笔试题)
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (zz)子曾经曰过:先有司,赦小过,举贤才
  • (附源码)springboot学生选课系统 毕业设计 612555
  • (理论篇)httpmoudle和httphandler一览
  • (五) 一起学 Unix 环境高级编程 (APUE) 之 进程环境
  • (转)Unity3DUnity3D在android下调试
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .NET/C# 的字符串暂存池
  • /var/lib/dpkg/lock 锁定问题
  • [001-03-007].第07节:Redis中的管道
  • [04]Web前端进阶—JS伪数组
  • [1]从概念到实践:电商智能助手在AI Agent技术驱动下的落地实战案例深度剖析(AI Agent技术打造个性化、智能化的用户助手)