类型转换——C++

news/2024/5/22 10:52:10/文章来源:https://blog.csdn.net/Ll_R_lL/article/details/130140172

1. C语言中的类型转换

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

  1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  2. 显式类型转化:需要用户自己处理

在C语言中:
整型之间的转换:大转小——截断;小转大——提升
整型与浮点之间的转换:补位
意义相近的类型:例如浮点和整型,因为它们互相之间都是用来表示数据的大小

 

void Test1()

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

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

 

//在pos位置插入一个字符
void Insert(size_t pos, char ch)
{size_t end = size - 1;while (end >= pos){_str[end + 1] = -str[end];--end;}
}

问题:调用的时候
Insert(2,‘a’);//没问题
Insert(0,‘a’);//会死循环
隐式类型转换在操作符的两边也会发生:while (end >= pos)
将-1就会提升为无符号位的整型最大值,访问数据就会发生越界

 

 

2. 为什么C++需要四种类型转换

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

  1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
  2. 显式类型转换将所有情况混合在一起,代码不够清晰
    因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格

 
 

3. C++强制类型转换

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

  1. 兼容C语言的隐式类型转换和强制类型转换
  2. 虽然兼容c但是最好不用,使用C++的强制类型转换更加规范
  3. static_cast(影视类型转换)、reinterpret_cast、const_cast(强制类型转换)

 
 

3.1 static_cast

用于意义相近的类型
static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用
static_cast,但它不能用于两个不相关的类型进行转换

int main()
{
double d = 12.34;
int a = static_cast<int>(d);
cout<<a<<endl;
return 0;
}

在这里插入图片描述

注意写法与括号。
不是意义相近类型是无法使用此方法的

 

3.2 reinterpret_cast

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

int main()
{int* p = &a;//int address = static_cast<int>(p);int adress = reinterpret_cast<int>(p);return 0;
}
甚至可以支持一些比较bug的转换:
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.3 const_cast

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

int main()
{const int a = 2;int* p = const_cast< int*>(&a);//a的地址给了p*p = 3;cout << a << endl;//2cout << *p << endl;//3
}

使用调试的方法:
添加断点
Ctrl+f10 开始调试
打开监视窗口,输入你想观察的变量名称
按f10,程序就会依次往下执行

监视窗口中是3和3,但打印出来就是2和3
在这里插入图片描述

原因:编译器对const类型有优化,因为它理论上认为const类型不会被修改。const类型不会在内存中取,会被加载到寄存器中
每个不同的编译器,优化方法可能会不一样

 

有方法可以解决吗?
关键字 volatile
在这里插入图片描述

 
 

3.4 dynamic_cast

C++独有的

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

注意:

  1. dynamic_cast只能用于父类含有虚函数的类
  2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0

类型转换无论是否规范都会产生临时变量
临时变量具有常性——要用const

int main()
{int i = 0;double d = i;const double& rd1 = i;const double& rd2 = static_cast<double>(i);return 0;
}

 

注意:父类对象无论如何都不允许转成子类对象的。
指针,引用都允许转换

class A
{
public:virtual void f(){}
public:int _a = 0;
};class B : public A
{
public:int _b = 1;
};// A*指针pa有可能指向父类,有可能指向子类
void fun(A* pa)
{// 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址// 如果pa是指向父类,那么不能转换,转换表达式返回nullptrB* pb = dynamic_cast<B*>(pa); // 安全的//B* pb = (B*)pa;             // 不安全,都是转换成功无法识别,会产生越界的风险if (pb){cout << "转换成功" << endl;pb->_a++;pb->_b++;cout << pb->_a << ":" << pb->_b << endl;}else{cout << "转换失败" << endl;pa->_a++;cout << pa->_a << endl;}
}int main()
{A aa;// 父类对象无论如何都是不允许转换成子类对象的/*B bb = dynamic_cast<B>(aa);B bb = (B)aa;*/B bb;fun(&aa);fun(&bb);//fun(nullptr);return 0;
}

在这里插入图片描述

 

延伸问题:

class A1
{
public:virtual void f(){}
public:int _a1 = 0;
};class A2
{
public:virtual void f(){}
public:int _a2 = 0;
};class B : public A1, public A2
{
public:int _b = 1;
};int main()
{B bb;A1* ptr1 = &bb;A2* ptr2 = &bb;cout << ptr1 << endl;cout << ptr2 << endl << endl;B* pb1 = (B*)ptr1;B* pb2 = (B*)ptr2;cout << pb1 << endl;cout << pb2 << endl << endl;B* pb3 = dynamic_cast<B*>(ptr1);B* pb4 = dynamic_cast<B*>(ptr2);cout << pb3 << endl;cout << pb4 << endl << endl;return 0;
}

切片会偏移,所以ptr1和ptr2的地址不一样
在这里插入图片描述

 
但是强制类型转换之后指针会偏移回去
在这里插入图片描述

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

 

4. RTTI(了解)

RAII 资源获取就是初始化
RTTI:Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTTI:

  1. typeid运算符——获取对象类型字符串
  2. dynamic_cast运算符——父类的指针指向父类对象还是子类对象
  3. decltype——推导一个对象类型,这个类型可以用来定义另一个对象

 
 

5. 常见面试题

  1. C++中的4中类型转化分别是:
  2. 说说4中类型转化的应用场景。

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

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

相关文章

linux工具gcc/g++/gdb/git的使用

目录 gcc/g 基本概念 指令集 函数库 &#xff08;重要&#xff09; gdb使用 基本概念 指令集 项目自动化构建工具make/makefile 进度条小程序 ​编辑 git三板斧 创建仓库 git add git commit git push git status git log gcc/g 基本概念 gcc/g称为编译器…

[ 应急响应基础篇 ] evtx提取安全日志 事件查看器提取安全日志

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

Java阶段一Day22

Java阶段一Day22 文章目录Java阶段一Day22线程安全synchronized教师总结新单词多线程多线程并发安全问题概念例synchronized关键字同步方法同步块在静态方法上使用synchronized互斥锁总结重点:多线程并发安全问题聊天室(续)实现服务端发送消息给客户端服务端转发消息给所有客户…

Android FrameWork 知识点与面试题整合~

1.如何对 Android 应用进行性能分析 android 性能主要之响应速度 和UI刷新速度。 首先从函数的耗时来说&#xff0c;有一个工具TraceView 这是androidsdk自带的工作&#xff0c;用于测量函数耗时的。 UI布局的分析&#xff0c;可以有2块&#xff0c;一块就是Hierarchy Viewe…

SpringBoot集成Mybatis-Plus实现多租户动态数据源

1. 概述 最近接手一个多租户系统&#xff0c;多租户主要的就是租户之间的数据是相互隔离的&#xff0c;每个租户拥有自己独立的数据&#xff0c;相互之间不干扰。目前实现多租户主要有三种方案&#xff1a; 独立数据库 每个租户拥有自己单独的数据库&#xff0c;从物理上隔离了…

手写一个IO泄露监测框架

作者&#xff1a;长安皈故里 大家好&#xff0c;最近由于项目原因&#xff0c;对IO资源泄漏的监测进行了一番调研深入了解&#xff0c;发现IO泄漏监测框架实现成本比较低&#xff0c;效果很显著&#xff1b;同时由于IO监测涉及到反射&#xff0c;还了解到了通过一种巧妙的方式实…

通达信欧奈尔RPS指标公式详解

RPS相对强度指标&#xff0c;是国内的投资者根据威廉欧奈尔所著书籍《笑傲股市》中的RS评级改进的。 根据书中介绍&#xff1a; RS评级衡量了某一给定股票在过去52周内相对股市中其他股票的表现。市场上每一只股票都被指定了1~99范围内的某一数值&#xff0c;99代表相对强度最高…

YOLOV7运行步骤(推理、训练全过程)

下载源代码&#xff1a;点击下载 执行以下命令安装requirements.txt中的相关依赖 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple官网下载权重yolov7.pt&#xff08;测试使用&#xff09;、yolov7-tiny.pt&#xff08;训练使用&#xff0c;这里…

10 JS01——初识JS

目标&#xff1a; 1、初识JavaScript 2、JavaScript注释 3、JavaScript输入输出语句 一、初识JavaScript 1、JavaScript是什么 JavaScript是世界上最流行的语言之一&#xff0c;是一种运行在客户端的脚本语言(Script是脚本的意思) 脚本语言:不需要编译&#xff0c;运行过程…

Vue2-黑马(九)

0目录&#xff1a; &#xff08;1&#xff09;router-动态菜单 &#xff08;2&#xff09;vuex-入门 &#xff08;3&#xff09;vuex-mapState &#xff08;1&#xff09;router-动态菜单 我们点击按钮跳转到主页面&#xff0c;主页在制作动态菜单&#xff0c;路由的跳转方…

keil代码格式化快捷方法

美化当前文件&#xff1a;-n !E --styleansi -p -s4 -S -f -xW -w -xw 美化整个工程文件&#xff1a;-n "$E*.c" "$E*.h" --styleansi -p -s4 -S -f -xW -w -xw -R 当前时间&#xff1a;!E~E^E 添加文件注释&#xff1a;!E 函数功能注释&#xff1a;!E ~…

快排(动图详细版,快速理解)

注&#xff1a;本文主要介绍六大排序中的快排 文章目录前言一、三大法则1.1 Hoare法1.2 挖坑法1.3 双指针法&#xff08;更加便捷&#xff09;1.4 三种方法时间复杂度计算二、快排栈问题优化方式2.1 三数取中2.2 小区间优化三、非递归快排前言 快速排序是Hoare于1962年提出的一…

Linux高并发服务器(webserver)

一.有限状态机 它的转移函数表示系统从一个状态转移到另一个状态的条件 二.EPOLL 在内核中创建一个数据&#xff0c;这个数据有两个比较重要的数据&#xff0c;一个是需要检测的文件描述符的信息&#xff08;红黑树&#xff09;&#xff0c;一个双向链表&#xff0c;存放检测到…

利用多专家模型解决长尾识别任务

来源&#xff1a;投稿 作者&#xff1a;TransforMe 编辑&#xff1a;学姐 贡献 提出了RoutIng Diverse Experts&#xff08;RIDE&#xff09;&#xff0c;不仅可以减少所有类别的variance&#xff0c;并且还可以减少尾部类的bias。同时提升了头部和尾部的性能。 思路 目前存…

easyrecovery2023电脑文件数据恢复软件功能介绍

EasyRecovery功能全面&#xff0c;即便是没有经验的小白用户也可以很快上手&#xff0c;让你足不出户即可搞定常见的数据丢失问题。 在使用和操作存储设备期间&#xff0c;数据丢失问题在所难免。比如&#xff0c;误删除某个文件、不小心将有数据的分区格式化、误清空了有重要…

2023“认证杯”数学中国数学建模赛题浅析

2023年认证杯”数学中国数学建模如期开赛&#xff0c;本次比赛与妈杯&#xff0c;泰迪杯时间有点冲突。因此&#xff0c;个人精力有限&#xff0c;有些不可避免地错误欢迎大家指出。为了大家更方便的选题&#xff0c;我将为大家对四道题目进行简要的解析&#xff0c;以方便大家…

【vue3】04-vue基础语法补充及阶段案例

文章目录vue基础语法补充vue的computedvue的watch侦听书籍购物车案例vue基础语法补充 vue的computed computed&#xff1a;用于声明要在组件实例上暴露的计算属性。&#xff08;官方文档描述&#xff09; 我们已经知道&#xff0c;在模板中可以直接通过插值语法显示一些data中…

智能网卡相关知识(smart nic 、DPU)

网卡作为穿行在网络与计算之间的桥梁&#xff0c;是可以解决计算瓶颈的关键硬件。 随着CPU 密度和数据中心网络带宽的进一步提升&#xff0c;用户对预期性能的需求&#xff0c;系统运行平稳性都会有更高的要求。云厂商一方面面临巨大的成本压力&#xff0c;另一方面面临巨大的…

新一代异步IO框架 io_uring | 得物技术

1.Linux IO 模型分类 相比于kernel bypass 模式需要结合具体的硬件支撑来讲&#xff0c;native IO是日常工作中接触到比较多的一种&#xff0c;其中同步IO在较长一段时间内被广泛使用&#xff0c;通常我们接触到的IO操作主要分为网络IO和存储IO。在大流量高并发的今天&#xff…

光伏电池片技术N型迭代,机器视觉检测赋能完成产量“弯道超车”

电池片是光伏发电的核心部件&#xff0c;其技术路线和工艺水平直接影响光伏组件的发电效率和使用寿命。随着硅料、硅片技术逐渐接近其升级迭代空间的瓶颈&#xff0c;电池片环节正处于技术变革期&#xff0c;是光伏产业链中迭代最快的部分。P型中PERC电池片是现阶段市场的主流产…