【C++练级之路】【Lv.26】类型转换



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 一、C风格类型转换
    • 1.1 隐式类型转换
    • 1.2 显式类型转换
  • 二、C++风格类型转换
    • 2.1 static_cast
    • 2.2 dynamic_cast
    • 2.3 const_cast
    • 2.4 reinterpret_cast
  • 三、RTTI
    • 3.1 typeid
    • 3.2 dynamic_cast
    • 3.3 decltype
  • 总结

一、C风格类型转换

1.1 隐式类型转换

隐式类型转换(Implicit Type Conversion),又称自动类型转换,由编译器在编译阶段自动进行,能转就转,不能转就编译失败。

常见的隐式类型转换包括:

  • 赋值运算符中的类型转换:例如从 int 赋值转换为 double
  • 算术运算符中的类型转换: 例如 intlong 进行运算,会被提升为 long 。同时,超出类型的表示范围,会进行符号扩展或截断。
  • 函数调用中的类型转换:实参与形参类型不匹配,会尝试转换为与形参匹配的类型。
  • 布尔值中的类型转换:对于数值类型,非零值转换为 true ,零值转换为 false ;对于指针类型,非空指针转换为 true ,空指针转换为 false
  • 指针中的类型转换:指针可以隐式转换为 void* 类型。数组名会被转换为指向数组第一个元素的指针,函数名会被转换为指向该函数的指针。
void func(double d){}

void test()
{
	int i = 1;
	double d = i;//赋值运算符
	double ret = i + d;//算术运算符
	func(i);//函数调用
	void* p = &i;//指针
}

1.2 显式类型转换

显式类型转换(Explicit Type Conversion),又称为强制类型转换,需要程序员显式地指定转换方式。

格式:(type)expression

void test()
{
	int i = 1;
	double d = (double)i;
}

二、C++风格类型转换

2.1 static_cast

格式:static_cast<new_type>(expression)

用于非多态类型的转换(静态转换),并且只适用相近类型之间的转换,对应C的隐式类型转换,例如基本数据类型之间的转换。

void test()
{
	int i = 1;
	double d = static_cast<double>(i);//静态转换,相近类型
	int* pi = &i;
	void* p = static_cast<void*>(pi);
}

2.2 dynamic_cast

格式:dynamic_cast<new_type>(expression)

用于多态类型的转换(动态转换),并且用于向下转型:将一个父类对象的指针/引用转换为子类对象的指针或引用。

ps:向上转型,没有类型转换,属于赋值兼容规则。

class A
{
public:
	virtual void f(){}

	int _a = 1;
};

class B :public A
{
public:
	virtual void f(){}

	int _b = 2;
};

void test()
{
	B b;
	A a = b;
	A& ra = b;//此处没有隐式类型转换

	double d = 3.14;
	const int& ri = d;//此处有隐式类型转换
}

由于类型转换后的临时对象具有常性,所以要用常引用。而向上转型(切片)不用常引用,所以没有发生类型转换。


dynamic_cast 在运行时检查转换是否有效。如果转换无效,则指针类型返回空指针 nullptr,引用类型抛出异常 std::bad_cast

void func(A* pa)
{
	//B* p = (B*)pa;//直接向下转换,如果指向父类,则存在越界风险
	B* p = dynamic_cast<B*>(pa);
	if (p)
	{
		p->_a++;
		p->_b++;
	}
	else
	{
		cout << "转换失败" << endl;
	}
}

void test()
{
	B b;
	A a = b;
	func(&a);
	func(&b);
}

直接向下转换,如果指向父类,则存在越界风险。运用 dynamic_cast 则可安全地进行向下转型。

2.3 const_cast

格式:const_cast<new_type>(expression)

用于修改对象的常量属性,可添加或移除变量的 constvolatile 属性。

void test()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 3;
	
	cout << a << endl;
	cout << *p << endl;

	cout << &a << endl;
	cout << p << endl;
}

通过打印可以发现,a的值依旧为2,而*p的值为3,并且它们的地址相同。这是为什么呢?其实,编译器在这里做了优化,常变量a会被放进寄存器或者直接替换

这时我们可以加上 volatile 关键字,其作用是阻止编译器对标记的变量进行某些优化。

void test()
{
	volatile const int a = 2;
	int* p = const_cast<int*>(&a);
	*p = 3;
	
	cout << a << endl;
	cout << *p << endl;

	//cout << &a << endl;
	printf("%p\n", &a);
	cout << p << endl;
}

此时还有一个问题,那就是用 volatile 修饰的变量类型无法和参数为 void*operator<< 函数匹配,从而会匹配到不合适的重载函数,输出错误的地址值。所以,此处我们用 printf 进行打印即可。

2.4 reinterpret_cast

格式:reinterpret_cast<new_type>(expression)

为操作数的位模式提供较低层次的重新解释。用于不相近类型之间的转换,对应C的显式类型转换。

void test()
{
	int i = 1;
	int* p = &i;
	//double* p1 = static_cast<double*>(i);//error
	double* p2 = reinterpret_cast<double*>(i);
	//double* p3 = static_cast<double*>(p);//error
	double* p4 = reinterpret_cast<double*>(p);
}

三、RTTI

RTTI(Run-Time Type Identification)是C++语言中的一个特性,它允许程序在运行时确定对象的实际类型

3.1 typeid

用于打印变量的类型。

void test()
{
	auto f = [](int x, int y){return x + y;};
	cout << typeid(f).name() << endl;
}

3.2 dynamic_cast

class Base
{};
class Derive :public Base
{};

void func(Base* pb)
{
	Derive* pd = dynamic_cast<Derive*>(pb);
}

3.3 decltype

可将变量的类型提取,作为参数传递。

void test()
{
	int x = 1;
	double y = 2.0;

	auto ret = x * y;
	vector<decltype(ret)> v;
}

总结

C风格的类型转换,将不同类型的转换混在一起,不够清晰,可视性差,难以跟踪错误的转换。所以我们推荐使用C++的类型转换,加强类型转换的可视性,提高代码的可读性与可维护性。


一般来说:

  • 使用 static_cast 进行相近类型的转换。
  • 使用 dynamic_cast 在运行时进行多态类型检查。
  • 使用 const_cast 移除或添加常量性。
  • 使用 reinterpret_cast 进行不相近类型的转换。

真诚点赞,手有余香

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

【eNSP模拟实验】单臂路由实现VLAN间通信

实验需求 如下图所示&#xff0c;辅导员办公室需要访问处在不同vlan的学生管理服务器的文件&#xff0c;那么如何实现两台终端相互通信呢&#xff1f;我们可以使用单臂路由的方式来实现。 单臂路由&#xff08;router-on-a-stick&#xff09;是指在路由器的一个接口上通过配置…

小型医疗门诊挂号收费后台系统源码 医院管理系统后台thinkphp内核源码(带微信登录)

源码简介&#xff1a; 好用的小型医疗门诊后台管理系统的源码&#xff0c;就是那种医院管理用的&#xff0c;核心是用thinkphp做的。这个系统源码啊&#xff0c;功能多&#xff0c;用起来也方便。它还支持第三方配置和微信登录。 这玩意儿是基于ThinkPHP搞出来的医疗门诊系统…

AJAX知识点(详解)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

Flowable-流程图标与流程演示

BPMN 2.0是业务流程建模符号2.0的缩写。它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识&#xff0c;BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范&#xff0c;它能增进业务建模时的沟通效率。目前BPMN2.0是最新的…

持续集成01--Git版本管理及基础应用实践

前言 本系列文章旨在深入探讨持续集成/持续部署&#xff08;Continuous Integration/Continuous Deployment, CI/CD&#xff09;流程中的各个环节&#xff0c;而本篇将聚焦于Git版本管理及其基本应用。通过本文&#xff0c;读者将了解到Git的基本原理、安装配置、基本命令以及如…

高校动作捕捉与数字人开发实训室方案:助推高校开设虚拟数字人微专业

目前一些学校除了传统的实训室建设之外&#xff0c;部分院校会建设一些“微专业”&#xff0c;专业方向与AIGC以及虚拟数字人有关&#xff0c;通过引进一些虚拟数字人以及全身动作捕捉设备相关的产品和系统工具&#xff0c;进行设计课程方案&#xff0c;比如虚拟人直播&#xf…

Vue3学习体验(一)

搭建工程 使用vue-cli脚手架创建vue3工程 vue create vue3-app-vue-cliVue-cli官网&#xff1a;https://cli.vuejs.org/zh/guide/installation.html 使用vite搭建vue3工程 npm init表示临时的下载vite应用来创建vue3工程&#xff0c;工程名称为vue3-app-vite npm init vit…

银河麒麟高级服务器操作系统V10加固操作指南

1:检查系统openssh安全配置: 2:检查是否设置口令过期前警告天数: 3:检查账户认证失败次数限制: 修改/etc/pam.d/system-auth文件中deny的参数即可 4:检查是否配置SSH方式账户认证失败次数限制:

SAP DR创建借项凭证简介

DR创建借项凭证简介 创建借项凭证请求的详细步骤1. 进入创建销售订单的界面2. 选择销售凭证类型3. 输入销售组织数据4. 输入客户和参考数据5. 添加项目明细6. 检查和保存创建实际的借项凭证借项凭证后台配置定义凭证类型定义项目类别定义销售开票类型借项凭证请求的业务意义跟踪…

@RequestBody注解的使用及源码解析

前言 RequestBody 注解是我们进行JavaEE开发&#xff0c;最常见的几个注解之一&#xff0c;这篇博文我们以案例和源码相结合&#xff0c;帮助大家更好的了解 RequestBody 注解 使用案例 1.自定义实体类 Data NoArgsConstructor AllArgsConstructor public class User {priv…

非对称加解密和签名

非对称加解密特点 一对密钥&#xff0c;公钥和私钥。私钥自己持有&#xff0c;公钥公开给通信的对方。 如果公钥用作加密&#xff0c;那么私钥用作解密。 如果私钥用做加密&#xff0c;那么公钥用作解密。 如果数据量少可用非对称加密算法直接加密。 如果数据量大&#xff0c;…

【双色转模拟调光磁吸灯应用方案】调光线性度好 调光频率1K以上都兼容 LED护眼教室黑板灯降压恒流驱动IC芯片FP7195

文章目录 前言 一、行业要求和痛点 1、设计空间小&#xff0c;双路调光调色不容易排布 2、磁场对调光的影响 二、FP7195如何解决这些要求和痛点 1、FP7195实际应用双色温调光电路框架 2、FP7195的转模拟调光技术 总结 前言 磁吸灯作为一种时尚、实用的家居装饰灯具&#xff0c;…

javaweb学习

javaweb就是实现浏览器和服务器之间的交互 1、服务器配置 Run->Edit Configurations&#xff0c;点击右上角的号&#xff0c;选择Tomcat Server的local&#xff1a; 选择server下的Configure...&#xff0c;在弹出的界面里点击有上角的号&#xff0c;选择自己解压的合适的t…

220V降压5ⅤIC-AH8652

220V降压至5V的IC - AH8652 在电子设计中&#xff0c;电压转换是一个常见的需求&#xff0c;尤其是在需要将高电压转换为低电压以供电给微电子设备时。AH8652是一款专为降压转换设计的集成电路&#xff0c;它能够将220V的交流输入电压转换为稳定的5V直流输出&#xff0c;非常适…

java基础之变量,类型的转换,跟着哔站尚硅谷自学笔记。

变量 变量的介绍以及使用 1.变量的数据类型&#xff1a;基本数据类型&#xff1a;4类8种整数&#xff1a;byte short int long 浮点数&#xff1a;float double字符型&#xff1a;char布尔型&#xff1a;boolean引用数据类型&#xff1a;类 数组 接口 枚举 注解2.概述&#xf…

gptpdf:使用大模型(如 GPT-4o)将 PDF 解析为 markdown。

今天给大家分享一个开源的项目&#xff0c; 使用视觉大语言模型&#xff08;如 GPT-4o&#xff09;将 PDF 解析为 markdown。 方法非常简单(只有293行代码)&#xff0c;但几乎可以完美地解析排版、数学公式、表格、图片、图表等。 使用 GeneralAgent lib 与 OpenAI API 交互。…

C++笔试强训4

文章目录 一、选择题1-5题6-10题 二、编程题题目一题目二 一、选择题 1-5题 %o就是输出八进制的无符号数&#xff0c;0123&#xff0c;&#xff0c;以0开头&#xff0c;本来就是八进制&#xff0c;所以输出为123&#xff0c;123是十进制&#xff0c;转化为八进制就是173. 故选…

双向带头循环链表

一、概念 何为双向&#xff1a;此链表每一个节点的指针域由两部分组成&#xff0c;一个指针指向下一个节点&#xff0c;另一个指针指向上一个节点&#xff0c;并且两头的节点也是如此&#xff0c;头节点的下一个节点是尾节点&#xff0c;尾节点的上一个节点是头节点&#xff1b…

C++ — 引用浅谈

引言 在C的语法规则中&#xff0c;定义了一种新的方法&#xff0c;叫做引用。在学习的初期&#xff0c;引用的作用很类似于指针&#xff08;但需要注意引用不等于指针&#xff09;&#xff0c;引⽤不是新定义⼀个变量&#xff0c;⽽是给已存在变量取了⼀个别名。 在上边…