『C++』C++的类型转换

news2024/12/1 0:49:40

「前言」文章是关于C++特殊类型转换

「归属专栏」C嘎嘎

「笔者」枫叶先生(fy)

「座右铭」前行路上修真我

「枫叶先生有点文青病」

「每篇一句」

有些事不是看到了希望才去坚持,
而是因为坚持才会看到希望。
——《十宗罪》

 

目录

一、C语言中的类型转换

二、为什么C++需要四种类型转换

三、C++强制类型转换

3.1 static_cast

3.2 reinterpret_cast

3.3 const_cast

3.4 dynamic_cast

四、RTTI


一、C语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换

  • 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  • 显式类型转化:需要用户自己处理
void Test()
{
	int i = 1;
	// 隐式类型转换
	double d = i;
	printf("%d, %.2f\n", i, d);

	int* p = &i;
	// 显示的强制类型转换
	int address = (int)p;
	printf("%x, %d\n", p, address);
}

缺陷:转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换

二、为什么C++需要四种类型转换

C语言风格的转换格式很简单,但是有不少缺点的:

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。

三、C++强制类型转换

标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast

3.1 static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;

	int* p = &a;
	// static_cast不能用于两个不相关类型之间转换
	//int address = static_cast<int>(p); //error
	return 0;
}

3.2 reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型

int main()
{
	int a = 10;
	int* p = &a;
	int address = reinterpret_cast<int>(p);
	cout << address << endl;
	return 0;
}

3.3 const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

int main()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 3;
	cout << a << endl;  
	cout << *p << endl; 
	return 0;
}

运行结果

 

调试查看

解释:

  • 由于编译器认为const修饰的变量是不会被修改的,因此会将const修饰的变量存放到寄存器当中,当需要读取const变量时就会直接从寄存器中进行读取,而我们修改的实际上是内存中的a的值,因此最终打印出a的值是未修改之前的值。
  • 如果不想让编译器将const变量优化到寄存器当中,可以用volatile关键字对const变量进行修饰,这时当要读取这个const变量时编译器就会从内存中进行读取,即保持了该变量在内存中的可见性

添加关键字volatile

 

3.4 dynamic_cast

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

  • 向上转型:子类对象指针/引用 -> 父类指针/引用(不需要转换,赋值兼容规则)
  • 向下转型:父类对象指针/引用 -> 子类指针/引用(用dynamic_cast转型是安全的)

向上转型就是所说的切割/切片,是语法天然支持的,不需要进行转换,而向下转型是语法不支持的,需要进行强制类型转换

注意:

  • dynamic_cast只能用于父类含有虚函数的类
  • dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

如果父类的指针(或引用)指向的是一个父类对象,那么将其转换为子类的指针(或引用)是不安全的,因为转换后可能会访问到子类的资源,而这个资源是父类对象所没有的

class A
{
public:
	virtual void f() {}
};
class B : public A
{};
void fun(A* pa)
{
	// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
	B* pb1 = (B*)pa;               //不安全
	B* pb2 = dynamic_cast<B*>(pa); //安全
	cout << "pb1:" << pb1 << endl;
	cout << "pb2:" << pb2 << endl;
}
int main()
{
	A a;
	B b;
	fun(&a);
	fun(&b);
	return 0;
}

编译运行

dynamic_cast,它会先进行类型检查,如果能够安全地将pa转换为B类型的指针pb2,则进行转换,否则返回一个空指针。这种方式比较安全,可以避免程序崩溃或者出现未定义的行为。

注意

  • 强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。

强烈建议:避免使用强制类型转换 

四、RTTI

RTTI:Run-time Type identification的简称,即:运行时类型识别

C++通过以下方式来支持RTTI:

  1. typeid运算符
  2. dynamic_cast运算符
  3. decltype

常见面试题

C++中的4中类型转化分别是:

  •  static_cast、reinterpret_cast、const_cast和dynamic_cast

4中类型转化的应用场景 

  1. static_cast用于相近类型的类型之间的转换,编译器隐式执行的任何类型转换都可用static_cast。
  2. reinterpret_cast用于两个不相关类型之间的转换。
  3. const_cast用于删除变量的const属性,方便赋值。
  4. dynamic_cast用于安全的将父类的指针(或引用)转换成子类的指针(或引用)

--------------------- END ----------------------

「 作者 」 枫叶先生
「 更新 」 2023.5.15
「 声明 」 余之才疏学浅,故所撰文疏漏难免,
          或有谬误或不准确之处,敬请读者批评指正。

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

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

相关文章

tinyWebServer 学习笔记——三、定时器处理非活跃链接

文章目录 一、基础知识1. 概念2. API3. 信号处理机制 二、代码解析1. 信号处理函数2. 信号通知逻辑3. 定时器4. 定时器容器5. 定时任务处理函数6. 使用定时器 参考文献 一、基础知识 1. 概念 非活跃&#xff1a;指客户端与服务器建立连接后&#xff0c;长时间不交换数据&…

第二章 数据的表示和运算

1.进位计数制 其他进制转十进制 二进制<——> 八进制&#xff0c;十六进制 (注意&#xff1a;小数部分也是从右往左算十进制——>任意进制&#xff08;整数部分&#xff09; 十进制——>任意进制&#xff08;小数部分&#xff09; 十进制转二进制&#xff08;拼凑…

【gitee流水线实现自动化部署】

首先进入自己的gitee仓库 创建流水线 配置基本信息 名称标识 事件监听 -----触发条件 主要是任务排编内 vue前端则选择node构建 这些就是字面意思 若无特殊需求 按照默认的即可 构建完之后添加新任务 主机部署 选择部署 主机部署 添加主机组 新建主机组 自主导入 之后配…

配置Git

1.安装Git git官网 2.配置Git 在点击桌面上的Git Bash快捷图标中输入&#xff1a; 配置用户名&#xff1a; git config --global user.name "username" //&#xff08; "username"是自己的账户名&#xff0c;&#xff09; 配置邮箱&#xff1a; git…

Mac终端主题配置

如果你不想安装item2这类第三方终端&#xff0c;可以试试我下面的步骤&#xff0c;先上效果图&#xff0c;如果感觉还符合你的胃口&#xff0c;可以继续读下去啦!!! 1.下载item2的主题安装包 https://github.com/mbadolato/iTerm2-Color-Schemes 2.解压缩&#xff0c;打开…

电脑断电文件丢失如何找回?给你支几招!

电脑断电文件丢失如何找回&#xff1f;我好不容易熬夜加班做的活动方案&#xff0c;正当将U盘文件转移到笔记本电脑的时候&#xff0c;没有注意笔记本的电量&#xff0c;在转移数据的过程中突然断电了。我的电脑一下子就“熄”了&#xff0c;方案都没来得及保存。这真是一个悲剧…

06. git关联远程仓库

大家好&#xff0c;前面几节&#xff0c;我们用很长的篇幅介绍了git本地使用过程中的一些基本命令&#xff0c;本节开始&#xff0c;我们介绍通过远程仓库多人协作的时候&#xff0c;基本操作以及遇见的问题。 本节内容预告&#xff1a; 1、github 与gitlab简介 2、git本地连接…

【软考高项】项目范围管理中的需求跟踪矩阵说明

文章目录 需求跟踪矩阵的创建角色步骤 需求跟踪矩阵变更角色步骤 需求跟踪矩阵是把产品需求从其来源连接到能满足需求的可交付成果的一种表格。使用需求跟踪矩阵&#xff0c;把每个需求与业务目标或项目目标联系起来&#xff0c;有助于确保每个需求都具有业务价值。 需求跟踪矩…

从零开始Vue3+Element Plus的后台管理系统(三)——按需自动引入组件和unplugin-vue-components

按需导入Element Plus遇到页面卡顿问题 本项目使用Element Plus的方式是按需自动导入 首先安装unplugin-vue-components 和 unplugin-auto-import这两款插件 npm install -D unplugin-vue-components unplugin-auto-import然后把下列代码插入到你的 Vite 配置文件中 Vite# …

Salesforce Experience Cloud_体验云顾问认证考试-备考攻略 (内含模拟练习题)

Salesforce Experience Cloud顾问认证专为具有Experiences应用程序实施和咨询经验的顾问设计的&#xff0c;适用于使用Experience平台的声明性自定义功能展示其在设计、配置、构建和实施Salesforce Experience应用程序方面的技能和知识的备考者。 备考者需要有6个月的Experien…

周赛345(模拟、分类讨论、DFS求完全联通分量)

文章目录 周赛345[2682. 找出转圈游戏输家](https://leetcode.cn/problems/find-the-losers-of-the-circular-game/)模拟 [2683. 相邻值的按位异或](https://leetcode.cn/problems/neighboring-bitwise-xor/)方法一&#xff1a;分类讨论&#xff08;反向思考&#xff09;方法二…

Android 调用TTS语音引擎过程及问题记录

Android 调用TTS引擎过程及问题记录 前言 背景是需要在华为平板上部署一个能够进行相关中文语音提示的APP&#xff0c;华为系统为鸿蒙3.0&#xff0c;对应Android API 12. Android 调用TTS引擎 调用TTS引擎之前&#xff0c;首先要确认自己的设备中是否安装了相关的文本转语音…

从《水浒传》看项目管理

水浒传和项目管理&#xff0c;这两个看似毫不相关的话题&#xff0c;其实有着惊人的相似之处。你没听错&#xff0c;就是水浒传&#xff01;这个充满了江湖义气和刀光剑影的故事&#xff0c;竟然能给我们现代人提供一些关于项目管理的启示。别怀疑&#xff0c;跟我一起来看看吧…

nginx liunx最新版本安装flask部署

一、nginx安装 1.进入Nginx官网的资源下载页&#xff1a;http://nginx.org/en/download.html 2.下载nginx-1.22.1.tar.gz&#xff0c; 3解压&#xff1a; tar -zxvf nginx-1.22.1.tar.gz解压完成后会在当前目录下得到一个新的nginx文件夹 4.终端进入nginx文件夹目录&#x…

C++ -- AVL树插入实现和测试

文章目录 1. AVL树概念2. AVL树满足性质3. AVL节点结构4. 插入操作5. 检测6. 完整代码 1. AVL树概念 AVL树就是自平衡二叉查找树&#xff0c;为了解决二叉树退化为单链表&#xff0c;使得增删查改时间度为O(N)&#xff0c;这里采用控制平衡策略达到效率是O(logN)。 2. AVL树满足…

Golang结构体入门

目录 结构体基础 结构体示例 为结构体定义方法 组合结构体 嵌套结构体 指针结构体 匿名字段 面向对象 封装 继承 多态 结构体基础 1.结构体是值类型&#xff1a;在Go语言中&#xff0c;结构体是一种值类型&#xff0c;与数组和基本数据类型一样。当结构体被赋值给一…

【MySQL】MySQL批量插入测试数据的几种方式

文章目录 前言一、表二、使用函数生成设置允许创建函数产生随机字符串产生随机数字 三、创建存储过程插入角色表插入用户表 四、执行存储过程小结五、使用 Navicat自带的数据生成 前言 在开发过程中我们不管是用来测试性能还是在生产环境中页面展示好看一点, 又或者学习验证某…

企业为什么要数字化转型?

数字化转型是使用数字技术从根本上改变企业运营方式并为客户创造价值的过程。企业进行数字化转型&#xff0c;常见因素包括&#xff1a; 提高效率&#xff1a;数字化转型可以简化流程并自动执行重复性任务&#xff0c;从而减少执行这些任务所需的时间和精力。可以节省成本并提高…

网页三剑客之 Javascript

JavaScript (简称 JS) 是世界上最流行的编程语言之一是一个脚本语言, 通过解释器运行主要在客户端(浏览器)上运行, 现在也可以基于 node.js 在服务器端运行 其实&#xff0c;语言都是触类旁通的&#xff0c;我们学过了C语言和JavaSE&#xff0c;那么学起其他任何语言都不难&a…

CSS 中的常用属性(图文详解版)

CSS 中的常用属性 &#x1f50e;引入方式&#x1f50e;CSS 选择器&#x1f50e;字体&#x1f50e;文本&#x1f50e;背景&#x1f50e;圆角矩形&#x1f50e;元素的显示模式&#x1f50e;CSS 盒模型&#x1f50e;弹性布局&#x1f50e;结尾 CSS 中的属性有很多 本文列举了一些较…