4.11 类型转换


在C++语言中,某些类型之间有关联。如果两种类型有关联,那么当程序需要其中一种类型的运算对象的时候,可以使用另一种关联类型的对象或值来代替。换句话说,如果两种类型可以相互转换,那么他们就是关联的。

举个例子:

int ival = 3.14+3;//结果是6

加法的两个运算对象的类型不一致:3.14是double,3是int。C++语言不会直接把两个不同类型的值进行相加,而是先根据类型转换规则设法将两个对象的类型统一后,再求值。上述的类型转换是自动进行的,不需要程序员的介入,因此这被称作隐式转换

算术类型之间的隐式转换被设计得尽可能避免损失精度。很多时候,如果表达式当中既有整数类型又有浮点数类型的运算对象,整型会转换成浮点型。在上面的例子中,3换成3.0,然后执行浮点数加法,所得的结果是浮点数类型的,但由于初始化过程的对象的类型无法进行改变,所以最后又把结果转换为int传给ival。

总结一小下,何时发生隐式类型转换:

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

算术转换

算术转换的含义是把一种算术运算类型转换成另一种算术类型。算术转换定义了一套类型转换的层次,其中运算符的运算对象将转换成最宽的类型。例如,刚刚的int和double,double所占的位数是8字节,int占的是4字节,所以转换为double类型。

整型提升

整型提升负责把小整数类型转化为较大的整数类型,对于bool、char、signed char、unsigned char 、short 、unsigned short等类型来说,只要他们所有可能的值都能存在int内部,它们就都会提升到int类型;否则提升到unsigned int类型。

较大的char类型(wchar_r 、char16_t 、char32_t)都会提升到int 、unsigned int 、long 、unsigned long 、long long、unsigned long long当中可以满足的较小的一种类型。

无符号类型运算对象

首先如果是运算符号两边的类型不一致,这些运算对象将转换成同一种类型。但是如果某个运算对象的类型是无符号类型,那么转换的结果就要依赖于机器中各个整数类型的相对大小了。

和往常一样,先进行整型提升。如果类型匹配,无需要进行下一步的转换,如果两个运算对象要么是带符号的和不带符号的,则小类型转换为大类型。

如果一个运算对象是无符号类型、另外-一个运算对象是带符号类型,而且其中的无符号类型不小于带符号类型,那么带符号的运算对象转换成无符号的。例如,假设两个类型分别是unsigned int和int, 则int类型的运算对象转换成unsigned int类型。需要注意的是,如果int型的值恰好为负值,其结果将以2.1.2节(第32页)介绍的方法转换,并带来该节描述的所有副作用。

剩下的一一种情况是带符号类型大于无符号类型,此时转换的结果依赖于机器。如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型。如果不能,那么带符号类型的运算对象转换成无符号类型。例如,如果两个运算对象的类型分别是long和unsigned int,并且int和long的大小相同,则long类型的运算对象转换成unsigned int 类型;如果long类型占用的空间比int 更多,则unsigned int类型的运算对象转换成long类型。

PS:所以对于这么复杂的类型转换,个人建议是在使用的时候就要想好他生成的是什么类型。

理解算术转换

这里举一些例子,给大家理解理解:

3.14L +‘a’//1
double + int //2
double + float//3
int = double//4
bool = double//5
char + float//6
short + char//7
char + long//8
int +unsigned long//9
unsigned short + int//10
unsigned int +int//11

  1. 'a’提升为int类型,然后该int类型转换为long double类型再进行相加。(提升和转换不是一种东西,提升是电脑默认进行的处理,转化是程序分析两个数据的类型差异给出的处理)。
  2. int类型转化为double类型,再进行相加。
  3. float类型转换为double类型,再进行相加。
  4. double转换为int类型,然后进行赋值。
  5. 当且仅当double为0,bool才为false,否则为true。
  6. char提升到int,然后int转换为float,再进行相加。
  7. short和char都提升为int,再进行相加。
  8. char提升到int,再转换为long。
  9. int转换为unsigned long再进行相加。
  10. 根据二者所占的空间大小进行提升。
  11. 根据二至所占的空间大小进行转换。

其他隐式类型转换

除了算术转换之外还有几种隐式类型转换,介绍如下:

数组转化成指针

int ia[10];
int *p=ia;//ia转换为指向数组首元素的指针

值得注意的是:

当数组被当作decltype关键字的参数,或者作为取地址符&sizeof以及typeid等运算符的运算对象的时候,上述的转换不会发生,或者是用一个引用来初始化数组上述的转换也不会发生。即int (&p)[10]=arr的时候,arr并不是指针,代表的是一个数组。

转换为布尔类型

存在一种从算术类型或指针类型向布尔类型自动转换的机制。如果指针或者算术值为0,转换结果为flase,否则为true。

转换成常量

允许将指向非常量类型的指针转换成指向相应的常量类型的指针,对于引用也是这样子。

例子:

int i;
const int& j = i;//正确,将非常量表达式转化为常量表达式。
const int* p = &i;//正确,将非常量表达式转化为常量表达式。
int& r = j ,*q = p;//错误,不允许将常量表达式转化为非常量表达式。或者这么理解,他试图删除底层const。

类类型定义的转换

这边举个例子,用处其实很少。

string s;
while(cin>>s)//实际上就是把cin输入的string类型值转换为布尔值。

显式转换

有时候我们希望显式的将对象强制转换为另外一种类型。例如,如果想在下面的代码中执行浮点数除法:

int i,j;
double slope = i / j;

就需要使用某种方法将i和j转化为double类型,这种方式叫做强制类型转换。

PS:虽然有时候不得不使用强制类型转换,但这种做法其实是十分危险的。

命名的强制类型转换

一个命名的强制类型转换具有如下的格式:

cast-name<type>(expression);

其中type是转换的目标类型,而expression是要转换的值。如果type是引用类型,则结果就是左值。cast-name是static_cast 、dynamic_cast 、const_cast 、reinterpret_cast当中的一种。

dynamic_cast

对于这个,我们将在之后进行更多的详细介绍,现在先不表,只需要知道其支持运行时的类型识别。主要用于虚函数当中。

static_cast

任何具有明确定义的类型转换,且不涉及到==底层const(指针指向的对象是不是常量)==的时候,都可以使用static_cast。例如:刚刚的除法:

double slope =static_cast<double> (i) / j;

这就是将int的i转化为double类型的C++模式。

基本等效于隐式转换的一种类型转换符号,可以使用于需要明确隐式转换的地方。

const_cast

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

const char *p;//底层const,形容的是指针指向的值不变。
char *p = const_char<char>(pc);

对于将常量对象转换为非常量对象的行为,我们把这个叫做"去掉const性质"。一旦我们去掉了某个对象的const的性质,编译器就不再阻止我们对该对象进行写操作。

const常用于函数重载的上下文当中,到时候也会进行详细介绍。

reinterpret_cast

reinterpret_cast通常作为运算对象的位模式提供较低层次上的重新解释,其实实际上也就是不管能不能进行,不管进行完出的是什么错误,就直接进行的一个操作。建议是不要使用,它实际上就是我们以前使用的强转。

旧式的强制类型转换

在早期的C++版本,显式的进行强制类型转换包含两种形式:

type(expr);
(type)expr;

根据所涉及的领域不同,旧式的强制类型转换分别具有const_cast 、static_cast 、reinterpret_cast相似的行为。当我们在某处执行旧式的强制类型转换的时候,如果换成const_cast和static_cast也合法,其行为与对应的命名转换一致。如果替换后不合法,则旧式的强制类型转换执行与reinterpret_cast有类似的功能。

这里的建议是尽量转换习惯,改成新标准下的转换。
常用的就是static_cast和const_cast。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值