《C++ primer》英文第五版阅读笔记(二十)——类型转换

Type Conversions——类型转换


1.C++里面有许多相互关联的类型。当在两个类型之间有类型转换时,它们就是相互关联的。
2.通常C++会自动地进行隐式转换,而不需要让编程者知道。
3.在算术类型之间的隐式转换通常都会保护精度,以免丢失精度。例如:一个整型和一个浮点型相加,整型会转换为浮点类型——double,相加的结果也是double类型。
4.发生隐式转换的几种情形:
(1)在大多数的表达式里面,比int类型小的类型的值会被提升为适当的更大的整型类型。
(2)在条件判断时,非布尔表达式会被转换为布尔表达式。
(3)在进行初始化时,初始化器会被转换为变量的类型;在赋值时,右操作数会转换为左操作数的类型。
(4)在算术表达式和关系表达式中如果操作数是混合类型的,那么所有的类型都会被转换为相同的类型。
(5)类型转换常发生在函数调用的时候。


算术类型转换

通常满足转换到“更大”范围类型的规则。


整型提升
1.整型提升会将小整型转换为更大的整型。bool、char、signed char、unsigned char、short和unsigned short类型会被提升为int类型如果这些类型的值都能在int表示的值的范围内的话。否则,这些类型会被提升为unsigned int类型。就像我们通常看到的那样,bool类型的true被提升为1,false被提升为0。
2.更大的字符类型(wchar_t,char16_t,char32_t)会被转换为更小的int,unsigned int,long,unsigned long,long long,或者unsigned long long类型如果所有的值都能够适合字符类型的话。


Unsigned类型的操作数
1.通常参与计算的操作数的如果类型不同时,则会转换成相同的类型。如果其中任意一个操作数是unsigned类型,那个这个操作数将要转换到的类型取决于机器上的整型大小。
2.整型提升通常是最先发生的。如果得到的类型都匹配,那么就不需要再进行类型转换了。如果操作数有相同的符号,那么小类型的操作数会被转换为更大的类型。

3.当操作数的符号不相同时:

(1)无符号的操作数类型大于或等于有符号的操作数类型,那么有符号的操作数会被转换为无符号的unsigned int类型。

例如:如果有unsigned int和int类型,则int类型被转换为unsigned int类型。注意:如果此时int是负数,转换后的结果为用“给定的这个负数”除以“目标类型能表示的值的个数”的余数。
(2)有符号操作数比无符号操作的类型更大时,结果是机器独立的。如果有符号数的类型表示范围比无符号数的表示范围大,那个无符号数会转换为有符号数的类型。否则,有符号数会转换为无符号数。

其它的隐式转换
除了算术类型转换,还有许多其它的隐式转换:

1.数组到指针的转换

在大多数的表达式里,当我们使用数组时,数组会自动地转换为指向那个数组第一个元素的指针。

但是当数组和decltype一起使用或者作为取地址符&、sizeof运算符、typeid运算符的操作数时这种转换就不会发生了。

当我们初始化一个数组引用时这种转换也不会发生。(数组引用:int n3[3] = {2, 4, 6};int (&rn3)[3] = n3;,引用数组:int &array[]; )

当在一个表达式里使用一个函数类型时也会发生类似的指针转换。


指针之间的转换

一个不变的整数0和literal中的nullptr能够被转换为任意的指针类型。指向非const类型的指针能够被转换为void*类型,指向任意类型的指针能够被转换为const void*。

有一种附加的指针类型转换,它们应用在通过继承相关联的类型中。


转换为布尔类型

从算术类型或指针类型到布尔类型有一种自动地类型转换。如果指针或算术的值是0,转换的结果是false,其它情况结果都为true。



转换为const类型

我们能把一个指向非const类型的指针转换为一个指向相关的const类型的指针,引用与其类似。也就是说,如果T是一个类型,我们能将指向T的指针或引用分别转换为指向const T的指针或引用。但是反过来的转换是不存在的。



由类类型定义的转换

类类型能够定义编译器自动使用的转换。编译器一次只能应用一种类类型的转换。

例如:从C语言中的string到库里面的string的转换。当在条件中读入输入流时。

IO库定义了从输入流到布尔类型的转换。布尔类型的结果取决于流的状态,如果最后读取成功,则返回true;否则,返回false。


显示转换
有时我们需要显示地强制一个对象转换为一个不同的类型。例如在下面的代码里,我们会需要一个浮点类型:
int i,j; double slope = i/j;
此时,我们需要一种方式显示地将i和j转换为double类型,我们可以使用cast去进行这次显示地转换。注意:尽管有时会有这种显示转换的需要,但是cast是一种内在的危险结构


Named Casts——命名转换
形式如下: cast-name<type> (expression)
type:是转换的目标类型。如果type是引用,那么结果是左值。
expression:是要被转换的值。
cast-name可以是下面中的一个:static_cast,dynamic_cast,const_cast,和reinterpret_cast。
cast-name决定了将要进行那种转换。


static_cast:任何明确定义的转换,而不是那些包含低级const的转换,可以请求使用static_cast。
例如:我们可以通过将表达式中的一个操作数转换为double类型来进行强制使用浮点类型。
    double slope = static_cast<double>(j)/i;
(1)当大的算术类型赋值给小的算术类型时常使用static_cast。这种转换通知了读程序的人和编译器我们并不关心精度的丢失。当大类型转换为小类型时编译器通常会生成一个警告,但是当进行显示转换时,是不显示警告信息的。
(2)static_cast转换也可以实现编译器不能自动生成的转换。例如:我们可以使用static_cast去恢复存储在void*指针里面的指针的值。当把指针存储在void*里面,然后使用static_cast将指针转换为原来的类型时,我们必须保证这个指针的值是被保存下来的。也就是说,转换的结果会和原来的地址值相同。因此,我们必须确定指针转换的类型确实是那个指针的类型,如果类型不匹配,结果将是undefined未知的。



const_cast:const_cast只改变它的操作数中的低级const。
(1)通常将一个const对象转换为非const类型会把const去掉。一旦我们将const去掉,编译器不会再阻止我们改变那个对象的值。如果那个对象原来不是一个const,转换后进行“写”操作是合法的。但是如果那个对象原来是const的,想要通过const_cast去对那个对象进行“写”操作的话,这种操作是未知的。
(2)只有const_cast能够改变一个表达式的const属性。如果想要通过使用其他形式的cast_name去改变一个表达式的const会产生编译错误。相似地,我们不能使用const_cast去改变一个表达式的类型。例:const char *p;
char *q = static_cast<char*> (cp);//出错
const_cast<string> (cp);//出错。
(3)const_cast在函数重载时会很有用。



reinterpret_cast(重新解释)
reinterpret_cast通常会对它的操作数的位形式执行一个低级的重新解释。
例如:int *ip;
char *pc = reinterpret_cast<char*>(ip);
我们必须要记住的是pc地址下的对象是int类型,不是字符类型。任何把pc当成字符类型指针的操作可能都会在运行时出错。例如:string str(pc);可能会导致奇怪的运行行为。
用pc来初始化str的例子说明了reinterpret_cast是危险的。原因是类型变化了,但是编译器没有给出任何警告或错误的提示。
当我们用ip去初始化pc时编译器没有警告或错误提示是因为我们显示地说明了这个转换是可以的。任何对pc的使用都会认为它是一个字符类型的指针,而编译器无法知道它实际上是一个整型指针,因此用pc去初始化str是完全正确的,虽然在这里是有错误的!查找到这种类型的错误是很困难的,尤其是当ip转换为pc发生的位置和用pc初始化str的位置相差的很远时。
注意:reinterpret_cast是机器独立的。安全地使用reinterpret_cast需要对类型有着完全的理解,并且知道编译器实现这种转换的细节。



Old-Style Casts
在早期的C++里面,显示的转换使用下面的两种形式:
type (expr);//函数转换法
(type) expr;//C语言风格转换法
根据类型的不同,早期的转换形式和const_cast,static_cast或者reinterpret_cast有着相同的结果。当我们在使用const_cast或static_cast合法的地方使用早期的转换形式,早期的转换形式会和它们有着相同的转换结果。如果哪种转换都不合法,那么早期的转换会执行reinterpret_cast。例如:char *pc = (char*)ip;//ip是指向int的指针
这种写法和使用reinterpret_cast有着同样的效果。
注意:早期的转换形式比用名字转换的方式可见度更低。因为它们是容易忽略的,并且查找到不好的转换位置是很难的。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值