C++:类型转换

目录

一、C语言中的类型转换

二、为什么C++要新的转换格式

三、 C++强制类型转换

1.static_cast

2.reinterpret_cast 

3.const_cast

4.dynamic_cast 


一、C语言中的类型转换

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

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

注意:一般关联性强,表示的意义相近的变量可以隐式转换,如int转换成double;一般关联性不强的一些内置类型可以显示转换,比如(void*)int转换成void*;没有关联性的几乎不能转换。

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

二、为什么C++要新的转换格式

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

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

我们举个例子。

void insert(size_t pos, char ch)
{int end = 10;while (end >= pos){cout << end << endl;--end;}
}int main()
{insert(5, 'x');return 0;
}

这段代码正常插入没有问题,但当pos是0时,就会陷入“死循环”。

因为size_t是无符号整形,--变成-1,其实是size_t表示的最大无符号整数。

针对这些问题,C++提出了自己的类型转化风格,因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。

三、 C++强制类型转换

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

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.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;
}

3.const_cast

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

const_cast转换中有一个细节需要注意, 请看下面代码,

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

执行,

我们发现a的地址和p的值一样,也就是p指向的空间就是a的值,可为什么p指向空间的值是3,a的值还是2呢,我们修改了*p,a的值也应该被修改了呀,a为什么没有变?

因为const修饰的变量,编译器会进行优化。正常const修饰的变量不会被修改,不会被修改就不用经常去内存中取,所以编译器会把const修饰的值拷贝到寄存器,甚至用常量去替代,所以我们正常修改const_cast强制类型转换“去const属性的指针”,不会修改到内存中的const变量。

要想禁止编译器对const变量的优化,可以在const前加一个关键字——volatile。

cv (const and volatile) type qualifiers - cppreference.com

 这样我们运行,就可以修改到内存中a的值了,那么为什么a的地址是1呢?这是流插入(<<)的bug。

注意:流插入<<是指将程序中的数据插入到流中,输出到屏幕或文件中或者其他流中;流提取>>是从流中提取数据到程序中。

我们可以用printf打印看一下,

printf打印就没有问题,难道是类型识别错误,我们打印一下&a的类型。

 发现&a的类型是int const valatile*,

ostream::operator<< - C++ Reference (cplusplus.com)

可能编译器类型匹配错了,应该要匹配成指针类型的模板参数。我们强制转换成指针类型看一下,

int* 和void*都可以,看来就是模板匹配错误。

 其实流插入还有一个缺点,就是当我们想打印字符的地址时,operator会匹配到字符类型的参数,从而打印的是字符而不是字符地址。

所以这里也必须强转一下, 以上三种转换都是C++对C语言转换的规范。

4.dynamic_cast 

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

  • 向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
class A
{
public:virtual void f() {}int _a = 0;
};
class B : public A
{
public:int _b = 1;
};
int main()
{B objb;A obja = objb;A& ra = objb;//直接将objb继承的部分切割给ra,中间没有类型转换double d = 1.1;const int& i = d;//隐式类型转换,中间产生临时变量,要const修饰return 0;
}
  • 向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)

父类的指针或引用,转换成子类的指针和引用,如果再用子类指针或引用访问子类独有的成员变量,就会造成越界访问,如下:

class A
{
public:virtual void f() {}int _a = 0;
};
class B : public A
{
public:int _b = 1;
};
void fun(A* pa)
{//  向下转换:直接转换是不安全的// 如果pa是指向父类A对象,存在越界问题B* ptr = (B*)pa;ptr->_a++;ptr->_b++;//越界访问
}int main()
{// 向下转换规则:父类对象不能转换成子类对象,但是父类指针和引用可以转换子类指针和引用A a;B b;fun(&a);fun(&b);return 0;
}

为了防止这类越界,C++推出了dynamic_cast用于将一个父类指针或引用转换。

dynamic_cast conversion - cppreference.com

class A
{
public:virtual void f() {}int _a = 0;
};class B : public A
{public:int _b = 1;
};void fun(A* pa)
{//  向下转换:直接转换是不安全的// 如果pa是指向父类A对象,存在越界问题B* ptr = dynamic_cast<B*>(pa);if (ptr){ptr->_a++;ptr->_b++;}else{cout << "转换失败" << endl;}
}int main()
{// 向下转换规则:父类对象不能转换成子类对象,但是父类指针和引用可以转换子类指针和引用A a;B b;fun(&a);fun(&b);return 0;
}

调试一下可以看到,向上转换时,程序输出,

对于指针类型向上转换会返回空指针,对于引用类型向上转换dynamic_cast会抛异常std::bad_cast 。

当然,这有一个前提,“表达式是对多态类型 Base 的指针或引用,并且 target-type 是对 Derived 类型的指针或引用,则执行运行时检查”。

四、RTTI

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

五、参考

ttps://blog.csdn.net/hp_cpp/article/details/104095700

RTTI、虚函数和虚基类的实现方式、开销分析及使用指导 (baiy.cn)

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

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

相关文章

Land survey boundary report (template)

Land survey boundary report (template) 土地勘测定界报告&#xff08;模板&#xff09;.doc

可视化学习之pytorch可视化工具visdom

文章摘自详解PyTorch可视化工具visdom&#xff08;一&#xff09;-CSDN博客 模型训练过程中需要实时监听并可视化一些数据&#xff0c;如损失值loss&#xff0c;正确率acc等。在tensorflow中&#xff0c;使用的工具为tensorboard&#xff1b; 安装一下试试 1.安装 pip inst…

Android的课程学习助手APP-计算机毕业设计源码19307

基于Android的课程学习助手APP 摘 要 在数字化、信息化的时代背景下&#xff0c;移动学习已成为现代教育发展的重要趋势。为了满足广大学生对高效、便捷学习方式的迫切需求&#xff0c;一款基于Android平台的课程学习助手APP应运而生。这款APP巧妙地将先进的信息技术与学习体验…

通过一个单相逆变器仿真深度学习PR控制器

目录 前言 ​编辑 PR控制器的理论 PR控制器不同表达式及其建模 PR控制器连续积分组合及模型 PR控制器连续传递函数及模型 PR控制器离散积分及模型 PR控制器离散传递函数及模型 PR控制器差分方程及模型 系统仿真效果 总结 前言 在项目开发中常用PI控制器&#xff0c;这次在…

解读 Amazon Q | 用 AI 聊天机器人连接你与未来的无限可能

在美国当地时间11月28日&#xff0c;亚马逊云科技在拉斯维加斯举办了 re:Invent 大会&#xff0c;大会介绍了许多今年来新增的核心产品与功能&#xff0c;着重讲解了生成式 AI 引领人工智能未来的前进方向&#xff0c;亚马逊作为云计算领域的龙头&#xff0c;相信会继续给我们的…

基于路径长度的样条插补算法(自动驾驶和路径跟踪控制适用)

以前在做车辆跟踪控制的时候发现在针对有多个X和多个Y对应的路径插补时候&#xff0c;总是报错&#xff0c;因为MATLAB里面的interp1插补函数它要求x要唯一对应一个y&#xff0c;当路径以单独的x或者y来求插补时候的时候就报错。由于在使用Matlab的interp1函数进行插值时&#…

重生之算法刷题之路之链表初探(三)

算法刷题之路之链表初探&#xff08;三&#xff09; 今天来学习的算法题是leecode2链表相加&#xff0c;是一道简单的入门题&#xff0c;但是原子在做的时候其实是有些抓耳挠腮&#xff0c;看了官解之后才恍然大悟&#xff01; 条件 项目解释 有题目可以知道&#xff0c;我们需…

C#Modbus专题

1&#xff0c;辅助工具。 1&#xff0c;虚拟串口工具&#xff08;vspd.exe&#xff09; 2&#xff0c;Modubus模拟主站(Modbus Poll) 3&#xff0c;Modbus模拟从站(Modbus Slave) 4&#xff0c;OPC服务软件(KEPServerEx V4.0)。 下载链接&#xff1a;https://download.csdn.n…

Redisson框架

1. Redisson锁与Redis订阅与发布模式的联系&#xff1a; Redisson锁中&#xff0c;使用订阅发布模式去通知等待锁的客户端&#xff1a;锁已经释放&#xff0c;可以进行抢锁。 publish channel_name message&#xff1a;将消息发送到指定频道 解锁时&#xff0c;在Lua解锁脚本…

算法思想总结:优先级队列

一、最后一块石头的重量 . - 力扣&#xff08;LeetCode&#xff09; 我们每次都要快速找到前两个最大的石头进行抵消&#xff0c;这个时候用优先级队列&#xff08;建大堆&#xff09;,不断取堆顶元素是最好的&#xff01;每次删除堆顶元素后&#xff0c;可以自动调整&#xf…

[C++][CMake][CMake基础]详细讲解

目录 1.CMake简介2.大小写&#xff1f;3.注释1.注释行2.注释块 4.日志 1.CMake简介 CMake是一个项目构建工具&#xff0c;并且是跨平台的 问题 – 解决 如果自己动手写Makefile&#xff0c;会发现&#xff0c;Makefile通常依赖于当前的编译平台&#xff0c;而且编写Makefile的…

【动态规划】动态规划一

动态规划一 1.第 N 个泰波那契数2.面试题 08.01. 三步问题3.使用最小花费爬楼梯4.解码方法 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#xff0c;我们一起努力吧!&#x1f603;&#x1f603; 1.…

分布式限流:Spring Cloud Gateway 限流

分布式限流&#xff1a;Spring Cloud Gateway 限流 在现代微服务架构中&#xff0c;流量控制是一个至关重要的部分。分布式限流作为一种有效的流量控制手段&#xff0c;能够帮助我们保护系统不被突发的流量冲垮。Spring Cloud Gateway支持多种限流方式。 什么是分布式限流 分…

模拟5亿年自然进化史,全新蛋白质大模型ESM3诞生!前Meta老将力作LeCun转赞

模拟5亿年自然进化史&#xff0c;全新蛋白质大模型ESM3诞生&#xff01;前Meta老将力作LeCun转赞。 能抗衡AlphaFold 3的生命科学大模型终于出现了。初创公司Evolutionary Scale AI发布了他们最新的98B参数蛋白质语言模型ESM3。不仅支持序列、结构、功能的all-to-all推理&#…

Unreal Engine@Jetson Orin Nano尚不支持

Unreal EngineJetson Orin Nano尚不支持 1. 源由2. Unreal Engine介绍3. 问题4. 编译方法5. 补充6. 其他 1. 源由 最近在看SC-Explorer方面的内容&#xff0c;在模拟方面采用了Unreal Engine。 本打算跑下模拟&#xff0c;因此打算在JetsonOrin的板子上试试看。 2. Unreal En…

opencv实现目标检测功能----20240704

早在 2017 年 8 月,OpenCV 3.3 正式发布,带来了高度改进的“深度神经网络”(dnn)模块。 该模块支持多种深度学习框架,包括 Caffe、TensorFlow 和 Torch/PyTorch。这次我们使用Opencv深度学习的功能实现目标检测的功能,模型选用MobileNetSSD_deploy.caffemodel。 模型加载…

mac视频压缩简单办法,mac如何把视频压缩到指定大小内存

在数字时代&#xff0c;视频已成为我们日常生活和工作的重要交流工具。然而&#xff0c;视频文件体积庞大&#xff0c;给存储和分享带来了不少困扰。本文将为你揭秘视频压缩的秘密&#xff0c;让你轻松减小视频文件体积&#xff0c;提升分享效率&#xff01; 方法一下载文件压缩…

Python爬虫教程第0篇-写在前面

为什么写这个系列 最近开发了个Python爬虫的脚本&#xff0c;去抢一个名额&#xff0c;结果是程序失败了&#xff0c;中间有各种原因&#xff0c;终究还是准备不足的问题。我想失败的经验或许也可贵&#xff0c;便总结一下当初从0开始学Python&#xff0c;一步步去写Python脚本…

【SpringCloud】Ribbon源码解析

ribbon是一个负载均衡组件&#xff0c;它可以将请求分散到多个服务提供者实例中&#xff0c;提高系统的性能和可用性。本章分析ribbon是如何实现负载均衡的 1、LoadBalanced 消费者在引入ribbon组件后&#xff0c;给http客户端添加LoadBalanced注解就可以启用负载均衡功能。Lo…

Github 2024-07-01开源项目月报 Top15

根据Github Trendings的统计,本月(2024-07-01统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6JavaScript项目3C++项目2PHP项目1Blade项目1非开发语言项目1C#项目1Lua项目1Go项目1MDX项目1Jupyter Notebook项目1从零开始构建你喜…