类型转换(C++)

一、C语言中的类型转换

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

1.1、 隐式类型转化

隐式类型转换,也称自动类型转换,是指不需要用户干预,编译器默认进行的类型转换行为,使得两个变量的数据类型一致,才能进行相关的计算。它通常发生在赋值转换和运算转换两种情况。
  • 赋值转换:将一种类型的数据赋值给另外一种类型的变量时,发生隐式类型转换。例如:
int x = 1.23; // 1.23是double类型,先隐式转换为int
  • 运算转换:C语言中不同类型的数据需要转换成同一类型,才可以进行计算。字符型、整型、浮点型之间的变量通过隐式类型转换,可以进行混合运算(不是所有数据类型之间都可以隐式转换)。

总的来说,C语言的隐式类型转换发生在意义相近的类型之间,例如整型和浮点型家族,它们都是表示数字的规模。将一个数字转化为一个对象这样的操作,显然不是编译器应该自动做的。

1.2、显式类型转化

显式类型转换则是我们人为地进行数据类型的转换,这里可以理解为是一种强制的类型的转换。这种转换将不再遵守上面的转换规则,而是按照我们人为地标明的类型进行转换。就是在我们需要指定类型的变量前加上数据类型,并用圆括号包裹。例如:(int)a(float)b(long)c等。

总的来说,显式类型转换有各自的意义,例如整型转换成指针类型。

1.3、特点

  • 优点:在于它能够帮助我们解决一些特殊情况下的问题。例如,当我们需要将一个浮点数赋值给一个整型变量时,隐式类型转换会自动将浮点数转换为整型,使得程序能够正常运行。显式类型转换也可以用来解决一些特殊情况下的问题。

  • 缺点:隐式类型转换可能会导致数据失真(精度降低),因此不一定是安全的。显式类型转换也可能会导致数据失真或其他问题。因此,在使用类型转换时应谨慎。

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++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符: static_cast、
reinterpret_cast、const_cast、dynamic_cast

2.1、static_cast

static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用
static_cast,但它不能用于两个不相关的类型进行转换
int main()
{double d = 12.34;int a = static_cast<int>(d);cout<<a<<endl;return 0;
}

2.2、reinterpret_cast

reinterpret_cast操作符通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换
为另一种不同的类型
int main()
{double d = 12.34;int a = static_cast<int>(d);cout << a << endl;// 这里使用static_cast会报错,应该使用reinterpret_cast//int *p = static_cast<int*>(a);int *p = reinterpret_cast<int*>(a);return 0;
}

2.3、const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值
int main()
{const int a = 2;//a = 3;int* p = const_cast<int*>(&a); // &a的类型:const int**p = 3;cout << a << endl; // 输出 2cout << *p << endl; // 输出 3return 0;
}

经过调试会发现a对应空间里的值其实已经通过const_cast去const属性后用p指针改为了3只是编译器优化认为a是const属性里面的值不会变,所以cout读取的是开始保存在寄存器里的备份2并非a对应空间里面目前存放的真值3;

添加voliate关键字解决:

int main()
{volatile const int a = 2;//voliate--隐含易变的意思,表明每次读取a的值需要从其空间取出,不用之前寄存器放的备份,保证读取正确的值;//a = 3;int* p = const_cast<int*>(&a); // &a的类型:const int**p = 3;cout << a << endl; // 输出 2cout << *p << endl; // 输出 3return 0;
}

volatile 关键字告诉编译器 变量a 是随时可能发生变化的,每次使用它的时候必须从内存中取出a的值,因而编译器生成的汇编代码会重新从 a 的地址处读取数据。这样看来,如果 a 是一个寄存器变量或者表示一个端口数据或者是多个线程的共享数据,就容易出错,所以说volatile 可以保证对特殊地址的稳定访问。

2.4、dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public :
virtual void f(){}
};
class B : public A
{};
void fun (A* pa)
{
// dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
B* pb1 = static_cast<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防止崩溃
void fun(A* pa)
{B* ptr = dynamic_cast<B*>(pa);//使用dynamic_cast动态转换可以在下面的if中将规避掉不安全的内存访问情况;if (ptr){ptr->_b = 10;cout << ptr << endl;}else{cout << "转换失败" << endl;}
}int main()
{A a;B b;fun(&a);//不安全 fun中的A*是基类 a 对象传入,那么这个A* pa指针就没有权限访问派生类的_b成员(压根没有),dynamic_cast检测到直接返回nullptr了,通过后续if逻辑规避了报错;fun(&b);//安全 fun中的A*指针是派生类 b 对象传过去的,进行切片了但是下文数据还在,A* pa可以访问_b成员,dynamic_cast允许其进行转换;return 0;
}

注意

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

总结,即:

1、pa如果是指向父类对象(指针\引用),严格来说是不能转的,因为存在风险,访问时存在越界风险;
2、pa如果是指向子类对象(指针\引用),可以转换,是安全的(切片技术);
3、如果使用c的强制类型转换,那么这里是不安全的,无法识别上面的两种情况; (1是越界风险,2是安全的)
4、建议使用dynamic_cast,则他是安全的。如果是第2种情况可以转换成功,就算是第1种非法情况会认定转换失败,返回nullptr给指针,后面程序会if判断出来,不会崩溃;

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

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

相关文章

Linux-用户和权限(黑马学习笔记)

认识root用户 root用户&#xff08;超级管理员&#xff09; 无论是Windows、MacOS、Linux均采用多用户的管理模式进行权限管理。 ● 在Linux系统中&#xff0c;拥有最大权限的账户名为&#xff1a;root&#xff08;超级管理员&#xff09; ● 而在前期&#xff0c;我们一直…

YApi-pro docker安装在centos7上

之前安装失败了&#xff0c;只好在docker中装了。 准备环境 1.docker安装 centos7 docker 安装-CSDN博客 2.mongodb数据库docker安装 创建mongo容器目录 mkdir /data/mongo -p docker pull mongo:4.2.21 创建一个yapi网络插件 docker network create yapi …

FFmpeg解析之avformat_find_stream_info函数

avformat_find_stream_info 的主要作用就是&#xff1a;解析媒体文件并获取相关的流信息 整体的逻辑如下图所示&#xff1a; /*** Read packets of a media file to get stream information. This* is useful for file formats with no headers such as MPEG. This* function…

关于Kinect 互动沙盘 深度图 Shader Graph 分层

把Kinect的深度图穿给Shader Graph using com.rfilkov.kinect; using UnityEngine; using UnityEngine.UI; public class GetDepthTex : MonoBehaviour { public Material Mat_SandTable; void Update() { Mat_SandTable.SetTexture("_MainTex"…

MongoDB实战 – 用Python访问MongoDB数据库

MongoDB实战 – 用Python访问MongoDB数据库 MongoDB in Action – Access MongoDB Databases with Python By JacksonML Python语言功能强大众所周知&#xff0c;在数据库管理领域也无所不能。MongoDB是文档数据库&#xff0c;属于NoSQL数据库的一种&#xff0c;在业界也非常…

javaEE图书馆自习室订座系统信用springmvc+springboot+mybatis

研究的内容是设计和实现图书馆自习室系统&#xff0c;便捷广大师生对自习室的使用&#xff0c;协助图书馆自习室管理。在设计过程中&#xff0c;系统的用户角色和权限分配如下&#xff1a; &#xff08;1&#xff09;馆长 用户管理&#xff1a;拥有自习室管理员、普通用户的所有…

LiveQing视频点播流媒体RTMP推流服务功能-支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务

LiveQing视频点播流媒体RTMP推流服务功能支持配置开启 HTTPS 服务什么时候需要开启HTTPS服务 1、配置开启HTTPS1.1、准备https证书1.1.1、选择Nginx类型证书下载 1.2、配置 开启 HTTPS1.2.1 web页面配置1.2.2 配置文件配置 2、验证HTTPS服务3、为什么要开启HTTPS3.1、安全性要求…

访问raw.githubusercontent.com失败问题的处理

1 问题 GitHub上的项目的有些资源是放在raw.githubusercontent.com上的&#xff0c;通常我们在安装某些软件的时候会从该地址下载资源&#xff0c;直接访问的话经常容易失败。 # 安装operator kubectl apply -f https://raw.githubusercontent.com/oceanbase/ob-operator/2.1…

Element Plus 的下拉选择器el-option的字体全部蓝色,全部是选中状态

问题 原因 参考官方&#xff1a; Select 选择器 | Element Plus 解决方案1&#xff1a; 给外层el-select增加一个value-key指定值: value-key"ID" <el-select value-key"ID"ref"productName"v-model"selectedProduct.GOODS_DESC"…

uni-app 经验分享,从入门到离职(五)——由浅入深 uni-app 数据缓存

文章目录 &#x1f4cb;前言⏬关于专栏 &#x1f3af;什么是数据存储&#x1f9e9;数据存储——存储&#x1f4cc; uni.setStorage(OBJECT)&#x1f4cc; uni.setStorageSync(KEY,DATA) &#x1f9e9;数据存储——获取&#x1f4cc; uni.getStorage(OBJECT)&#x1f4cc; uni.g…

​​​​​​​Sora:OpenAI的革命性AI视频模型与其对未来影像创作的影响

随着深度学习技术和计算能力的进步&#xff0c;人工智能不仅在图像识别、自然语言处理等领域取得了卓越成就&#xff0c;同时也在不断突破视频处理和生成的边界。在这一背景下&#xff0c;OpenAI推出了Sora——一种新型的AI视频模型&#xff0c;标志着AI在视频内容创作领域的又…

Web 前端 UI 框架Bootstrap简介与基本使用

Bootstrap 是一个流行的前端 UI 框架&#xff0c;用于快速开发响应式和移动设备优先的网页。它由 Twitter 的设计师和工程师开发&#xff0c;现在由一群志愿者维护。Bootstrap 提供了一套丰富的 HTML、CSS 和 JavaScript 组件&#xff0c;可以帮助开发者轻松地构建和定制网页和…