C++类型转换

   在C++中,某些类型之间有关联,如果两种类型有关联,那么当程序需要其中一种运算对象的时候,可以用另外一种关联类型的对象或值替代。换句话说,如果两种类型可以相互转换,那么它们就是关联的。
   自动执行,无需程序员介入,有时甚至不需要了解的转换称为隐式转换,比如整型和浮点数相加,如果返回值是整型,则会自动把浮点数转换成整型数。

何时发生隐式类型转换:
在大多数表达式中,比int类型小的整型首先提升为较大的整型数。
在条件中,非布尔值转换成布尔类型。
初始化过程中,初始值转换成变量的类型。
在赋值语句中,右侧运算对象转换成左侧对象的类型。
如果算术类型或关系运算的运算对象有多种类型,需要转成同一种类型。
函数调用也会发生类型转换。

1.算术转换

   算术转换的含义是把一种算术类型转换成另一种算术类型,运算符的运算对象将转换成最宽的类型。

整型提升
整型提升负责把小整数转换成较大的整数类型。对于bool、char、singed char、unsigned char、short和unsigned short等类型来说,只要它们所有的可能值都在int里,它们就会提升成int类型;否则,提升成unsigned int类型。
   较大的char类型(wchar_t、char16_t、char32_t)提升成int、unsigned int、long、unsigned long、long long 、unsigned long long 中最小的一种类型,前提是转换后的类型要能容纳原类型所有可能的值。

无符号类型的运算对象
   如果某个运算符的对象类型不一致,这些运算对象将转成同一种类型。但是如果某个运算对象的类型是无符号,那么转换的结果就要依赖于机器中各个整数类型的相对大小了。
   首先执行整体提升。如果结果的类型匹配,无需进一步的转换。如果提升后的两个运算对象的类型要么都是无符号的,要么都是有符号的,则小类型的运算对象转成较大的类型。
   如果一个运算对象是无符号的类型,另外一个运算对象是带符号的类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转成无符号的。比如,两个类型分别是unsigned int和int,则int类型的运算对象转成unsigned int。
   剩下一种情况是带符号类型大于无符号类型,此时转换的结果依赖机器。如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转成带符号类型。如果不能,那么带符号的运算对象转成无符号类型。例如,两个运算对象是long和unsigned int,如果long和int的大小相同,则long类型的运算对象转成unsigned int类型;如果long类型占用的空间比int多,则unsigned int转换成 long类型。

2.其他隐式转换

   数组转成指针:在大多数用到数组的表达式中,数组自动转换成指向数组首元素的指针。当数组被用作decltype关键字的参数,或者作为取地址符&、sizeof以及typeid等运算对象时,上述转换不会发生。如果用一个引用来初始化数组,上述转换也不会发生。
   指针的转换:C++还规定了几种其他的指针转换方式,包括常量整数值0或者字面值nullptr能转换成任意类型的指针类型;指向任意非常量的指针能转换成void * ;指向任意对象的指针能转换成void *。
   布尔类型转换:如果指针或算术类型的值为0,转换的结果是false;否则是true。
   转换成常量:允许将指向非常量类型的指针或引用转成指向相应的常量类型的指针或引用。相反的转换则不存在,因为它试图删掉底层const。

int i;
const int &j = i;  //非常量转换成const int的引用
const int *p =&i;  //非常量的地址转成cosnt的地址
int &r = j, *q = p; //错误,不允许const转成非常量

3.显示转换

命名的强制转换
   一个命名的强制转换具有如下形式:
   cats-name(expression);
   其中type是转换的目标类型,expression是要转换的值。如果type是引用,则结果是左值。cast-name是static-cast、dynamic_cast、const_cast、reinterpret-cast中的一种。

static-cast
   任何具有明确定义的类型转换,只要不包括底层const,都可以使用static-cast。
   当需要把一个较大的算术类型赋值给较小的类型时,static-cast非常有用。此时强制类型转换告诉编译器:我们知道并且不在乎潜在的精度损失。一般来说,如果编译器发现一个较大的算术类型试图赋值给较小的类型,就会给出警告信息;但是当我们执行了显示的转类转换后,警告信息就会被关闭。
   static-cast对于编译器无法自动执行的类型转换也非常有用。例如,我们可以使用static-cast找回存在于void*指针中的值:

double d = 3.14;
void *p = &d;   //正确,任何非常量对象的地址都能存入void*
double *dp = static_caset<double *>(p);  //正确,将void*转回初始的指针类型	

const_cast
   const_cast只能改变运算对象的底层const

const char *pc;
char *p = const_cast<char *>(p); //正确,但还是通过p写值是未定义的行为

   对于将常量对象转成非常量对象,我们称为“去掉const性质”。一旦我们去掉某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的。然而如果对象是一个常量,再使用const_cast执行写操作就会产生未定义的后果:

 const char *cp;
 char *q = static_cast<char *>(cp); // 错误,static_cast不能转换掉const性质
 static_cast<string>(cp);  //正确,字符串字面值可以转成string类型
 const_cast<string>(cp);   //错误,const_cast只能改变常量属性

reinterpret_cast
   reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释:

int *ip;
char *pc = reinterpret_cast<char *>(p);

   我们必须牢记pc所指的真实对象是一个int而非字符,如果把pc当成普通字符指针使用就可能在运行时发生错误。例如下面的初始化可能导致异常行为:

string str(pc);

避免强制类型转换
   强制类型转换干扰了正常的类型检查,因此我们强烈建议避免使用强制类型转换。这个建议对reinterpret_cast尤其适用,因为此类类型转换总是充满了风险。就算实在无法避免,也应该尽量限制类型转换值的作用域,记录对相关类型的所有假定,这样可以减少错误发生的机会。

旧式的强制类型转换
   在早期版本的C++中,显示地进行强制转换包含两种形式:
   type(expr); //函数形式的强制类型转换
   (type) expr; //C语言风格的强制类型转换
   与命名的强制类型转换相比,旧式的强制类型转换从表现形式上来说不那么清晰明了,容易被看漏,所以一旦转换过程出问题,追踪起来也困难。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值