目录
一、c语言中的类型转换
1、隐式类型转化:
2、强制类型转化:
3、缺点
二、c++新的类型转换
1、内置类型转为自定义类型
3、自定义类型转换为内置类型
三、C++的规范的强制类型转换
1、C++新增四种规范的类型转换的原因
2、static_cast
3、reinterpret_cast
4、const_cast
5、dynamic_cast
6、警惕强制转化
结束语
前言
本篇文章来介绍C++11基于C语言对于类型转换变化的介绍,介绍类型转换的新增内容,内容干货满满,看这一篇包学会
一、c语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式强制类型转换。
1、隐式类型转化:
编译器在编译阶段自动进行,能转就转,不能转就编译失败。
通常发生在整形之间,整形和浮点数之间。bool和整形之间, bool和指针之间(利用指针是否为空指针做判断时存在隐式转换),如下图举例
其他场景介绍:
下图比较的时候end会隐式类型转换成size_t,再比较
2、强制类型转化:
一般用于指针转换,需要用户自己处理,显示的转换类型如下图(存在截断风险)所示
特别注意:只有类型之间有一定关联的时候才会发生类型转换,毫不相干的两个类型不能发生转换
如下图所示,无法将一个指针转换为double类型变量:
3、缺点
转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换
二、c++新的类型转换
c++是面向对象的语言,c++语言带来了自定义类型的对象,为类型的家族注入新鲜新鲜血液的同时,也带来了内置类型与自定义类型之间互相转换的问题。
1、内置类型转为自定义类型
定义类的时增添对应参数的构造,直接调用构造对象,内置类型作为传参构造为对应的自定义类型的对象。
2、自定义类型转换为自定义类型
对于这种转换,我们也是只需要定义类的时增添对应参数的构造就可以实现对应的类型转化(调用参数与被转换类型匹配的构造函数)。
联系到STL库中,某一个容器可以使用{ }进行多个元素初始化的原理,就实现了自定义类型及内置类型向自定义类型的一个转换,{ }中的多个内置类型,先转换为多个容器中的单位元素类型(内置类型转自定义类型对象);所有转换过来的的元素构造为initializer_list对象,最终利用initializer_list转换为对应的容器类型对象(构造函数支持自定义转自定义类型对象)。具体的原理实现大家可以参考博客《C++11实用方法介绍(一)》中的讲解,更深层次的理解。
特别注意:
在继承与多态当中,基类对象可以赋值给基类变量,好像是两个自定义类型之间的转换,但这不是类型转化,这是切片操作,这万万不可混为一谈!!!
3、自定义类型转换为内置类型
这种情况看起来很奇怪,内置类型可以转换为自定义类型是因为有对应的构造函数支持,而内置类型都是写好的,我们无法为其增添支持操作的构造函数,拿又该怎么办呢?
本质要重载一个operator类型 隐式类型转换 如:下面的A
由于隐式转换(C语言的沉重历史包袱)的存在,迫于无奈只能特殊处理,operator +类型,不需要有返回值
三、C++的规范的强制类型转换
1、C++新增四种规范的类型转换的原因
C风格的转换格式很简单,但是有不少缺点:
1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失
2. 显式类型转换将所有情况混合在一起,代码不够清晰
因此C++提出了自己的类型转化风格,注意因为C++要兼容C语言,所以C++中还可以使用C语言的转化风格。
即非必须实用C++11规范化类型转换(保证以前的代码仍然可以用),但最好是规范!!!(很多大型公司强制要求,要有好的代码编写习惯)
2、static_cast<T>
用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可用static_cast,但它不能用于两个不相关的类型进行转换.
等同于以前的隐式类型转换
下图为使用举例(double->int)
3、reinterpret_cast<T>
通常为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种不同的类型
等同于以前的强制类型转换(有一方为指针转换)
下图为使用举例(int->int*)
4、const_cast<T>
最常用的用途就是删除变量的const属性,方便赋值
Q:这也是强制类型转换,但是为什么要把去掉const属性单独拿出来做一个类型转换操作符?
(1)原来去除const类型的方式
我们预估a1的值已经被改变为3,可是结果表示并没有更改,结果与预想并不对应。难道真的是我们的a1数值没有改变吗?让我们来看一下监视窗口:
我们发现此时a1的数值确实被改为了3,但为什么仍然直接打印a1时会不对。这个时候我们就要补充一些知识:编译器看到const类型的变量,会将变量扔到寄存器(增加访问效率),我们这里更改其数值,更改的是它在内存中存储的数值,寄存器中的没有改动,输出时输出的是寄存器中没有改动过的变量。故而这里出现错误。
去掉const属性是有一些内存可见优化的的风险,通过在定义const变量前添加volatile修饰符,表明此数据不存入寄存器来解决。
2、使用关键字规范化去除
这里就是专门提醒,去掉const属性是有一些内存可见优化的的风险,要注意是否加了volatile,这也回答了上面提出的问题
5、dynamic_cast<T>
用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
我们给定一个基类,一个子类,以及参数为基类指针的函数(举例):
由于函数参数为基类的指针,它既可以指向基类对象,也可以指向子类对象
(1)、pa指向子类对象,转回子类,是安全的,正常转换
(2)、pa指向父类对象(基类可能没有子类新加的成员),转回子类,是不安全的,存在越界的风险问题,转换失败
利用dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
6、警惕强制转化
强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,程序员应该仔细考虑是否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用域,以减少发生错误的机会。强烈建议:避免使用强制类型转换!!!!
结束语
本篇文章的内容就到此结束了,对于c++11的类型转化的介绍也来到尾声,希望大家能有所收获,能够应用自如,如果有什么内容不明白的,大家可以在评论去向我提问,我会一一回答,当然有什么错误或者有什么不足的地方,希望大家可以包容并指出。希望大家可以持续关注之后内容,最后向每一位读者送上真诚的小花。