【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);//errordouble* p2 = reinterpret_cast<double*>(i);//double* p3 = static_cast<double*>(p);//errordouble* 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 进行不相近类型的转换。

真诚点赞,手有余香

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

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

相关文章

配置Redis时yml的格式导致报错

报错如下 java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98) at org.springframework.test.context.su…

Unity 优化合集

1️⃣ 贴图优化 1. Read/Write Enable 这个属性勾选后允许你在运行时读取和写入纹理数据&#xff0c;这对于需要实时生成内容或者需要动态修改纹理的场合非常有用但在大部分情况下这是不必要的。如果打开这个属性&#xff0c;会使运行时贴图大小翻倍&#xff0c;内存中会额外…

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

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

香橙派AIpro部署YOLOv5:探索强悍开发板的高效目标检测能力

香橙派AIpro部署YOLOv5&#xff1a;探索强悍开发板的高效目标检测能力 一、香橙派AIpro开箱使用体验 1.1香橙派AIpro开箱 拿到板子后第一件事情就是开箱&#xff1a; 开箱后可以看见一个橘子的标识&#xff0c;也就是香橙派了&#xff0c;并且还有四个大字&#xff1a;为AI…

RABBITMQ的本地测试证书生成脚本

由于小程序要求必须访问wss的接口&#xff0c;因此需要将测试环境也切换到https&#xff0c;看了下官方的文档 RabbitMQ Web STOMP Plugin | RabbitMQ里面有这个信息 然后敲打GPT一阵子&#xff0c;把要求输入几个来回&#xff0c;得到这样一个脚本&#xff1a; generate_cer…

双向带头循环链表

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

R语言实战——栅格聚合方法(超方便)

今天给大家分享一个栅格聚合方法&#xff0c;使用R语言实现&#xff01; 1 为什么要做栅格聚合 栅格数据是我们地理学使用最广泛的数据类型之一。所谓栅格聚合其实就是根据栅格数据进行一系列运算得到一个我们想要的数据。 我个人认为&#xff0c;应用最广泛的&#xff0c;可…

notepad++中文出现异体汉字,怎么改正

notepad显示异体字&#xff0c;如何恢复&#xff1f; 比如 “门” 和 “直接” 的"直"字&#xff0c;显示成了 方法 修改字体&#xff0c; 菜单栏选择 Settings(设置&#xff09;&#xff0c;Style Configurator…&#xff08;语言格式设置…&#xff09;&#xf…

SSM城镇居民社区再生资源回收系统-计算机毕业设计源码04175

摘 要 本论文介绍了一个基于SSM&#xff08;Spring Spring MVC MyBatis&#xff09;技术的城镇居民社区再生资源回收系统的设计与实现。随着社会对环境保护意识的不断提高&#xff0c;再生资源回收成为了一种重要的环保行动。然而&#xff0c;传统的再生资源回收方式存在着信…

[数仓]十二、离线数仓(Atlas元数据管理)

第1章 Atlas入门 1.1 Atlas概述 Apache Atlas为组织提供开放式元数据管理和治理功能,用以构建其数据资产目录,对这些资产进行分类和管理,并为数据分析师和数据治理团队,提供围绕这些数据资产的协作功能。 Atlas的具体功能如下: 元数据分类 支持对元数据进行分类管理,例…

springboot3——项目部署

springboot的项目开发完了&#xff0c;怎么样把他放到服务器上或者生产环境上让他运行起来跑起来。就要牵扯到项目部署&#xff0c;打包的方式了。 springboot支持jar和war: 打jar包&#xff1a;默认方式&#xff0c;项目开发完打个jar包&#xff0c;通过命令把jar包起起来就…

刚刚,Claude国内可直连!

刚刚&#xff0c;Claude国内可直连&#xff01; 大家好&#xff01;我是科技博主Maynor。今天我们要分享一个激动人心的消息&#xff1a;知名AI助手Claude现在可以在国内直接访问了&#xff01; 这对于科技爱好者、学生、研究人员和各行各业的专业人士来说都是一个重大利好。…

大模型时代的小红书+马蜂窝:华人团队开发 的AI旅行app

简介 一周前&#xff0c;由红杉投资的硅谷初创公司UTA AI推出了其核心产品Wanderboat AI&#xff0c;这是一个基于GPT-4技术的智能旅行规划工具。 该平台允许用户通过对话交互来明确旅行的偏好和需求&#xff0c;并提供包括目的地、活动和实用建议在内的定制化旅行建议。 Wa…

算法题-字符串

1.C字符串 c提供了一下两种类型的字符串表示形式&#xff1a; c风格字符串c引入的string类类型 1.1C风格字符串 C 风格的字符串起源于 C 语言&#xff0c;并在 C 中继续得到支持。字符串实际上是使用 null 字符 \0 终止的一维字符数组。因此&#xff0c;一个以 null 结尾的…

前端项目本地的node_modules直接上传到服务器上无法直接使用(node-sasa模块报错)

跑 jekins任务的服务器不能连接外网下载依赖包&#xff0c;就将本地下载的 node_modules直接上传到服务器上&#xff0c;但是运行时node-sass模块报错了ERROR in Missing binding /root/component/node_modules/node-sass/vendor/linux-x64-48/binding.node >> 报错信息类…

MySQl高级篇-事务、锁机制、MVCC

存储引擎的选择 在选择存储引擎时&#xff0c;应该根据应用系统的特点选择合适的存储引擎。对于复杂的应用系统&#xff0c;还可以根据实际情况选择多种存储引擎进行组合。 InnoDB&#xff1a;是Mysql的默认存储引擎&#xff0c;支持事务、外键。如果应用对事务的完整性有比较…

多媒体软件开发选择Animate软件还是Unity3D软件?

以下内容可能有一些片面&#xff0c;因为多媒体软件开发平台有很多&#xff0c;因为接触Animate和Unity3D比较多&#xff0c;所以这里仅对这两款进行分析&#xff01; Animate软件与Unity3D软件都是经常在多媒体展馆中用来制作互动展示内容的&#xff0c;对于这两种开发平台&a…

【可视化大屏系列】Echarts之饼图绘制

本文为个人近期学习总结,若有错误之处,欢迎指出! Echarts之饼图绘制 前言1.需求2.实现效果3.大概思路4.代码实现子组件写法父组件写法5.附加(1)圆环饼图的绘制(2)南丁格尔玫瑰饼图A.半径展示数据的大小B.面积展示数据的大小前言 在前文页面布局、DataV 的使用、Echarts…

【数据结构】--- 堆的应用

​ 个人主页&#xff1a;星纭-CSDN博客 系列文章专栏 :数据结构 踏上取经路&#xff0c;比抵达灵山更重要&#xff01;一起努力一起进步&#xff01; 一.堆排序 在前一个文章的学习中&#xff0c;我们使用数组的物理结构构造出了逻辑结构上的堆。那么堆到底有什么用呢&…

GO channel 学习

引言 单纯地将函数并发执行是没有意义的。函数与函数间需要交换数据才能体现并发执行函数的意义。 虽然可以使用共享内存进行数据交换&#xff0c;但是共享内存在不同的goroutine中容易发生竞态问题。为了保证数据交换的正确性&#xff0c;必须使用互斥量对内存进行加锁&#…