C/C++中奇妙的类型转换

server/2024/9/23 7:36:21/

1.引言

大家在学习C语言的时候,有没有遇见过类似于下面这样的代码呢?

// 整形转bool
int count = 10;
while(count--)
{cout << count << endl;
}// 指针转bool
int* ptr = cur;
while(ptr)
{//……
}

众所周知,while循环的判断是bool类型的变量,那为什么整形变量和指针变量可以直接作为  while循环的判断条件呢?之所以可以这样直接利用整形变量和指针变量作为while循环的判断条件,是不是说明整形类型的变量和指针类型的变量可以转换成bool类型呢?没错,是的。

大家在学习编程的过程中肯定都有遇到过各种各样的 “神奇的” 类型转换,这些类型转换给我们编程带来了很大的方便,比如说 上面的整形直接转bool值判断、指针直接转bool值判断等等……下面我们就一起来学习一下C/C++中的那些神奇的类型转换。

提醒:所有的类型转换之间要有关联,没有关联的类型之间即使是强制类型转换,也是不能转换的。

2.C语言中的那些类型转换 

在C编写C/C++代码的时候,我们经常会遇到发生类型转换的场景,比如 赋值运算符的两个操作数不同实参和形参类型不同函数返回值类型和接收返回值的类型不同,都会发生类型转换;所以,在C语言中提供了两种类型转换 —— 隐式类型转换和显示类型转换

隐式类型转换

隐式类型转换是隐式的,是我们看不见的,比如下面这段代码:

double a = 1.0;
int b = a; // 发生隐式类型转换

隐式的类型转换有以下几种:

  • 1.整形和整形之间:不同的整形之间是可以发生隐式类型转换的,比如:char,short,int,long 、long long之间(char是属于整形家族的哦!)。
  • 2.整形和浮点型之间:整形和浮点型数据之间也具有一定的关联性,也是可以发生隐式类型转换的,比如:int 和 double,int 和 float 类型的数据……
  • 3.整形和bool之间:因为在编程中,我们习惯用0表示假,非0表示真,所以整形和bool型的数据是可以相互转换的。
  • 4.指针和bool之间:指针有可以分为空指针和非空指针,相当于0和非0,所以指针类型的数据也是可以和bool型之间的数据进行转换的。

显示类型转换

 显示类型转换式可以看见的,是用户显示使用的,比如下面这段代码:

int main(){int c = 0;char* pc = (char*)&c;return 0;
}

显示的类型转换有以下几种:

  • 整形和指针类型之间:这两者之间可以转换是因为指针是进程地址空间中字节的编号,和整形数据之间还是具有关联性的,所以可以互相转换。
  • 不同类型的指针变量之间:之所以可以互相转换,和上面一点是相同道理的;但是指针的类型决定了指针解引用之后,可以访问的内存地址字节数的大小(比如说,int*类型的指针解引用之后,可以访问四字节的内存空间,char*类型的指针解引用之后,只能访问1字节的内存空间;这是由指针所指向的数据的类型决定的)。有了这个点,其实所有类型的对象之间都能间接转换了,但是解引用之后所能访问的内存空间大小不一样

3.C++中的那些类型转换 

为什么C++还要改进类型转换呢?

我们都知道,C++是对C的改进和扩充,C++不仅仅改进了C语言中的错误处理机制,还改进了C语言中的类型转换。相信你可能有这样的疑问,C语言中的类型转换挺好用的,那为什么还要改进呢?看下面这段代码:

#include <iostream>
using namespace std; void func(size_t pos)
{int end = 10;while (end >= pos){cout << end << endl;--end;}
}int main()
{func(0);return 0;
}

大家可以猜一猜上面这段程序运行的结果是什么?结果如图:

  • 出乎意料吧,程序的结果是死循环;这是因为,end 和 pos是不同类型的数据,相互比较时会发生隐式的类型转换,范围小的会向范围大的数据类型转换,所以end会转换为无符号数,无符号数中没有负数,所以比较的时候,end总是大于pos,导致死循环。

从上面这个案例可以看出,C语言中的类型转化可视性比较差,可能存在难以预料的风险,所以C++的前辈们觉得有必要对类型转换升级升级了。

C++中的类型转换

C++语言中引入了面向对象的思想,提供了继承机制,所以多多少少都会涉及父类和子类之间的转换,这是C语言中的类型转换不能很好的解决的问题之一;再者,C语言中的类型转换可视性较差,所以C++中为了加强类型转换的可视性和可控性,提供了四种类型转换操作符,分别是 static_cast、reinterpret_cast、const_cast、dynamic_cast;

static_cast:static_cast 操作符对应C语言中的隐式类型转换,使用方式如一下代码,加强了隐式类型转换的可视性。

int main()
{double a = 3.14;int b = static_cast<int>(a);return 0;
} 

 reinterpret_cast:reinterpret_cast 操作符对应C语言中的强制类型转换,使用方式如下,以前使用强制类型转换的地方就可以这样使用了。

int main()
{int a = 0;int* p = reinterpret_cast<int*>(a);return 0;
} 

 const_cast:const_cast 操作符用于强制类型转换中,去掉const属性。去掉变量的const属性的这种强制类型转换存在一定的内存可视化风险,虽然强制类型转换也可以去掉const属性,但是可视性较差,不便于分析程序。

  • 分析上面的代码可以得出,a变量并没有被重新赋值,但是*p指向的空间被重新赋值了,但是*p指向的不就是变量a吗?为什么会出现这样的现象呢?这是因为,编译器认为a是const修饰的,是不会改变的变量,所以在寄存器上存放了一份a,这样一来,当需要使用a变量的时候,直接就可以去寄存器上面取,提高程序的运行效率,*p = 3;改变的是内存空间中a的值,打印的时候,a是在寄存器中取的值,*p是在内存空间中取的值,所以两个值不一样。

  • 分析上面代码可以看出给 const 修饰的变量添加volatile关键字,答应出的结果在意料之中,这是因为,volatile关键字表明,不把该 const 修饰的变量 a 放在寄存器中,所以不会出现上面那种情况。

 dynamic_cast:dynamic_cast操作符用于支持向下转换,也就是将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换);dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0;dynamic_cast只能用于父类含有虚函数的类,这是因为,dynamic_cast的实现和虚函数表有关,要想有虚函数表,类中得有虚函数。

  • 如上图左侧所示,如果父类的指针指向子类对象,该父类的指针是可以转化成子类的指针的,因为可以看到本来就属于它的空间
  • 如上图右侧所示,如果父类的指针指向父类对象,该父类的指针是不能转化为子类的指针的,因为会导致解引用之后,该指针的步长变大,访问本来就不属于它的空间。
  • 总结一下就是子类的指针or引用or对象,是可以直接转换成父类的指针or引用or对象(赋值兼容转换规则),但是父类的指针or引用需要通过dynamic_cast操作符类进行转换,如果能转换,则转换,反之,则返回0;


http://www.ppmy.cn/server/101376.html

相关文章

Redis相关介绍

Redis 是一个开源的高性能键值数据库&#xff0c;它不仅可以作为数据库使用&#xff0c;还可以作为缓存和消息中间件。Redis 支持多种数据结构&#xff0c;包括字符串、哈希、列表、集合、有序集合、位图、超日志和地理空间索引等。它因其高性能和丰富的数据结构支持在各种场景…

用Python实现9大回归算法详解——05. 梯度提升回归(Gradient Boosting Regression)

1. 梯度提升回归的基本概念 1.1 什么是梯度提升&#xff1f; 梯度提升是一种集成学习方法&#xff0c;通过组合多个弱学习器来构建一个强大的预测模型。在梯度提升框架中&#xff0c;每个弱学习器都试图修正前一个模型的错误。与简单的加法模型不同&#xff0c;梯度提升通过逐…

uview-plus多列模式与多列联动实践

项目场景&#xff1a;部门多级联动&#xff0c;实现效果&#xff1a; 选项数组的格式如下&#xff1a; party_info: [ [一级部门 1,一级部门 ,2,一级部门 3,一级部门 4], [二级部门 1,二级部门 ,2,二级部门 3], [三级部门 1,三级部门 ,2] …

实现一个自定义的Collector!

背景 当前有多个用户&#xff0c;产品提出一个需求&#xff0c;根据userStatus分组&#xff0c;然后将每个分组中的用户按照gender进行累加得到不同userStatus组下的gender总和 以map类型返回&#xff0c;而且要求使用stream.collect(Collector.groupingBy())方法一行写完&…

【数据结构与算法】图

图目录 一.图的原理二.图的表示1.邻接列表2.邻接矩阵 三.图的结构——邻接表四.邻接表的初始化五.邻接表的创建六.完整代码 一.图的原理 图在我们的日常生活中,可谓是应用广泛,最长见的就有地图. 图可以是双向的,也可以是单向的. 图是一种由节点和边组成的数据结构. 节点&…

android FD_SET_chk问题定位

android FD_SET_chk问题定位 一、FD报错二、问题定位2.1 APM定位2.2 adb定位2.3. 代码获取FD数 三、FD优化 一、FD报错 App在运行中记录报错如下&#xff0c;FD_SET&#xff0c;这个问题大概是文件描述符&#xff08;File Descriptor&#xff0c;简称FD&#xff09;超过了最大…

2024新型数字政府综合解决方案(三)

新型数字政府综合解决方案通过融合人工智能、大数据和云计算技术&#xff0c;建立了一个智能化、互联互通的政府服务平台&#xff0c;旨在提升政府服务效率与透明度。该方案通过全面数字化政务流程&#xff0c;实现数据的实时共享和自动化处理&#xff0c;使公众能够便捷地访问…

map/set和unordered_map/unordered_set的区别及使用情况

map/set和unordered_map/unordered_set的区别 容器底层数据结构是否有序实现版本复杂度迭代器map/set红黑树有序C98O(logN&#xff09;双向迭代器unordered_map/unordered_set哈希表/散列表无序C11O(1)单向迭代器 unordered_set无序的&#xff08;VS下&#xff09; void uno…