C++中的类型转化

news2024/11/27 12:49:31

目录

1.C语言中的类型转化

2.C++强制类型转换

2.1、static_cast

2.2、reinterpret_cast

2.3、const_cast

2.4、dynamic_cast


 

1.C语言中的类型转化

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理

看下面这段代码来理解:

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

int和double意义比较接近,所以可以隐式类型转化,将int升为double类型

而address时整型,p是指针,再隐式类型转化会出错,所以此时必须显式强制转化.

 

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

下面这种场景也是让人非常难受的.

void insert(size_t pos, char ch)
{
    size_t _size = 5;
    int end = _size - 1;
    while (end >= pos)
    {
        --end;
    }
}

当pos=0时,end会--直到0,最后一次进去end会变成-1,然后再次与pos进行比较,此时-1< 0不符合条件应该跳出,然而这里却发生了一个隐式类型转化,将end从int(有符号)提升为size_t(无符号),这样-1就成了2^32-1,便造成了死循环.

所以C++为了解决这些问题,便提出了这四种强制类型转换.

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

    int* p = &a;
    //不支持不相关类型转化
    int address = static_cast<int>(p);
}

只要记住,static_cast多用于隐式类型转化.

2.2、reinterpret_cast

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

可以理解为可强转为不相关的类型.

比如刚才上面的例子,static_cast不支持不相关类型转化,即不能将指针p转为int整型.我们改用reinterpret_cast即可.

    int* p = &a;
    //支持不相近类型转化
    int address = reinterpret_cast<int>(p);

这样我们看到static_cast就知道这是相近类型转化. reinterpret_cast就知道是不相近类型转化.

2.3、const_cast

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

int main()
{
    const int a = 2;
    //错误的,由于a具有常性
    //int* p = reinterpret_cast<int*>(&a);
    int* p = const_cast<int*>(&a);
    *p = 3;
}

利用const_cast,此时便成功把常量a的地址给了p,然后并且可以修改了.

但有一个奇怪的现象:

我们输出下a和*p的值,由于p的地址是也是a,对p修改也会影响a。

所以我们预期的结果应该都是3.我们输出一下:

    cout << a << endl;
    cout << *p << endl;

答案是2和3.为什么a没有被修改呢?我们调试观察一下:

 

 奇怪的现象又出现了,内存中显示a也已经被修改为3了,怎么输出出来还是2呢

这源于编译器的优化,编译器认为a是const已经不能被改了,那么我每次从内存中取多慢,编译器便直接把a加载到寄存器里面去,每次访问直接从寄存器读,效率便会提高。因为是const所以不会写,这才敢放到寄存器.所以每次读取的都是一开始的2.

至于监视窗口,也是另外一个单独的进程,没有优化,而是实时检测的,它这个时候便去内存中取,显示的便是3了.

那么我们如果不想让编译器优化,每次就要从内存中取,这时就要在前面加上volatile关键字.

此时便得到了正确的结果.

下面一种转化是C++独有的一种转化.

2.4、dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用 -> 父类指针/引用(不需要转换,赋值兼容规则)

向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意: 1. dynamic_cast只能用于含有虚函数的类 2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回nullptr。

看这段代码:

class A
{
public:
    int _a = 0;
};
class B : public A
{
public:
    int _b = 1;
};
int main()
{
    B bb;
    //子类->父类
    A aa1 = bb;
    A& ra1 = bb;
}

以上是可以正常转化的,子类转成父类,会有切片操作,这我们可以理解的.

但是向下转型,父类转化成子类时,可以正常转吗?

首先要知道的是,父类对象是无论如何都不可以转化成子类对象的.

但是利用dynamic_cast可以把父类对象的指针或引用转化成子类的指针或引用.

class A
{
public:
    virtual void f() {}
};
class B : public A
{};
//A*指针有可能指向父类,有可能指向子类
void fun(A* pa)
{
    // dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
    //如果pa是指向子类,那么可以转化,转化表达式返回正确的地址
    //如果pa是指向父类,那么不可以转化,转化表达式返回nullptr
    B* pb = dynamic_cast<B*>(pa);//安全的
    //B* pb = (B*)pa;//不安全的,都会转化成功
    if (pb)
    {
        cout << "转化成功" << endl;
    }
    else
    {
        cout << "转化失败" << endl;
    }
}
int main()
{
    A a;
    B b;
    fun(&a);
    fun(&b);
    return 0;
}

总的来说:dynamic_cast真正的功能是区分指针是指向父类还是子类.

如果"父类"指针是父类指针,dynamic_cast转化成子类会出现错误.

如果"父类"指针是子类指针,dynamic_cast转化成子类会成功.

所以说dynamic_cast向下转型是安全的.

这样c++的四种类型转化也就全部讲完了.

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

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

相关文章

华为ERP思考:国产自研迈出第一步

华为的进入会刺激用友、金蝶、浪潮等国产厂商加快技术革新&#xff0c;以及伴随着华为自身技术自研全栈的布局和不断测试&#xff0c;国产ERP的兼容性和标准性都将上一个新的台阶。 作者|斗斗 编辑|皮爷 出品|产业家 15小时完成全球88家子公司Meta ERP系统的切换&#x…

c++游戏小技巧6:rand()+随机迷宫(3写法:BFS,DFS,并查集)

目录 1.前言 2.前文(rand,随机数引入) 1.rand() 2.srand&#xff0c;随机数种子 3.用法&#xff1a; 1. 生成0~RAND_MAX里面的数 2.生成大于RAND_MAX的数 3.生成负数 3.正文(确信) 1.bfs写法&#xff1a; 1.让迷宫全是墙确定起点 2.初始化 3.循环操作&#xff1a; 4.总…

路径规划算法:基于天鹰优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于天鹰优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于天鹰优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法天鹰…

漏洞复现 || TerraMaster TOS exportUser.php 远程命令执行

阅读须知 技术文章仅供参考,此文所提供的信息只为网络安全人员对自己所负责的网站、服务器等(包括但不限于)进行检测或维护参考,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使用者本人负责。…

既有颜值又能打,达尔优实用之外的设计进化

对于时下不少二次元或游戏玩家来说,外设产品不再只是实用就够了,设计、风格也很重要,可盐可甜,有帅的也要有萌的,主打一个个性十足又非常实用。在这样的趋势下,达尔优的A系列,一改以往“硬朗”的设计风格,加入更多更贴合年轻人审美取向的主题配色。除此,新推出的针对女性市场的…

为什么Qt没有像其他框架一样广泛流行起来?

Qt 是一种功能强大且广泛应用的跨平台开发框架&#xff0c;具有许多优点。然而&#xff0c;以下是一些可能解释为什么 Qt 没有像其他框架那样广泛流行起来的原因&#xff1a; 我这里刚好有嵌入式、单片机、plc的资料需要可以私我或在评论区扣个6 知名度和推广力度&#xff1a…

GPT模型应用丨遥感云大数据在灾害、水体与湿地领域典型案例实践

​ ​ ​ ​ 第一部分 基础实践 一 平台及基础开发平台 GEE平台及典型应用案例介绍&#xff1b; GEE开发环境及常用数据资源介绍&#xff1b; ChatGPT、文心一言等GPT模型介绍 JavaScript基础简介&#xff1b; GEE遥感云重要概念与典型数据分析流程&#xff1b; …

技术导向下的业务测试何去何从?

前两天我发了篇鼓励测试人员学编程&#xff08;思维&#xff09;的文章《做测试到底要不要学编程&#xff1f;》&#xff0c;有不少同学在后台问我&#xff0c;自己底子差&#xff0c;实在跟不上怎么办&#xff1f; 看起来&#xff0c;应该是我没说清楚&#xff0c;导致大家有…

SOCVPOCV、global/local variation

Global/local variation global variation 用PVT 跟 RC-corner 来模拟&#xff1b;local variation 用 OCV/ AOCV/ SOCV 来模拟。在40nm 之前OCV 被广泛采用&#xff0c;但是OCV 对同一条path 上的所有cell 都设同一个derate 值&#xff0c;如果设的太严则过于悲观&#xff0c;…

自定义设置echarts label里的颜色

自定义echarts label里的颜色 option {xAxis: {type: category,data: [Mon, Tue, Wed, Thu, Fri, Sat, Sun]},yAxis: {type: value},series: [{data: [120, 200, 150, 80, 70, 110, 130],type: bar,label:{show: true,formatter: function (params){console.log(params)if (pa…

Three.js加载外部glb,fbx,gltf,obj 模型文件

vue3使用Three.js加载外部模型文件 1.安装Three.js yarn add three npm install three2.新建一个renderModel.js 用于处理Three.js相关逻辑 import * as THREE from three //导入整个 three.js核心库 import { GLTFLoader } from three/examples/jsm/loaders/GLTFLoader im…

FENDI CLUB啤酒,浅谈精酿分类

啤酒被爱酒人士戏称为是世界是最复杂的快乐酒精饮料。据不完全统计&#xff0c;啤酒的分类不少于120种。如果要详细分类的话&#xff0c;需要很大的篇幅。FENDI CLUB啤酒给大家一个简单的区分类别方法。 一般谈到精酿啤酒说的就是各式各样的艾尔&#xff0c;英文是Ale&#xff…

c++中的时间处理(2)time.h库及几个time相关的函数

关于time.h&#xff0c;有人总结了这么3句话&#xff1a; &#xff08;1&#xff09;time_t&#xff1a;表示距离 UTC 时间 1970-01-01 00:00:00 的秒数。也叫做日历时&#xff0c;类型是 long &#xff08;2&#xff09;clock_t: 只用于程序计时&#xff0c;貌似其他的没它什…

【SAP UI5 控件学习】DAY03 Input组Part III

1. Input 控件 1.1 最简单的Input控件 在UI5框架中&#xff0c;最简单的Input控件也提供了输入提示功能。当用户输入内容的时候&#xff0c;会自动匹配Input控件中所绑定的JSON模型中是数据。 Input的默认匹配规则是匹配从头匹配每一个单词 前端代码如下&#xff1a; <mv…

Django新手必看:如何创建应用和定义数据表。看完这一篇就够了

1. Django创建应用 Django 项目就是基于 Django 框架开发的 Web 应用&#xff0c;它包含了一组配置和多个应用&#xff0c;我们把应用称之为App&#xff0c;在前文中对它也做了相应的介绍&#xff0c;比如 auth、admin&#xff0c;它们都属于 APP。一个 App 就是一个 Python 包…

这7个AI软件让设计效率飞起,快来收藏

伴随着AI技术的发展&#xff0c;设计师使用AI工具来提高工作效率已成为一种趋势&#xff0c;越来越多的AI工具也出现在市场上。本文收集了市场上7个好用的AI工具推荐给大家&#xff0c;一起来看看吧&#xff01; 1、即时 AI 即时 AI是一款依赖AI技术&#xff0c;实现网页设计…

梯度(第四节)

目录 一.总结 二.l的方向余弦 三.方向导数 四.方向导数和方向余弦的联系 五.梯度 1.定义 2.性质 3.运算公式 4.例题 六.最快下降法 一.总结 上一节我们研究了数量场和矢量场的宏观特征&#xff0c;但宏观特征&#xff0c;在细节上往往无法展现事物的真正全 貌&…

Instruct2Act:使用大型语言模型将多模态指令映射到机器人动作

Instruct2Act&#xff1a;使用大型语言模型将多模态指令映射到机器人动作 基础模型在多种应用中取得了重大进步&#xff0c;包括文本到图像的生成、全景分割和自然语言处理。本文提出了一个名为Instruct2Act的框架&#xff0c;该框架利用大型语言模型将多模态指令映射为机器人…

代码随想录算法学习心得 42 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II...

一、买卖股票的最佳时机 链接&#xff1a;力扣 描述&#xff1a;给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算…

iOS添加测试设备报错ineligible for 14 days

2023年7月8日申请苹果个人开发账号审核通过。 2023年7月10日在苹果开发平台分别创建Certificates、Identifiers、Devices添加一台测试设备、Profiles&#xff0c;将已经准备好的项目打包上传&#xff0c;使用testflight测试app&#xff0c;使用测试设备一切顺利。 2023年7月1…