类型转换

类型转换

如果两种类型可以相互转换,那么它们就是关联的。

隐式类型转换

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

算术转换

算术转换的含义是把一种算术类型转换成另外一种算术类型。

整型提升

整型提升是把小整数类型转换成较大的整数类型。

  • 对于 bool、char、signed 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 intint,则 int 类型的运算对象转换成 unsigned int
  • 带符号类型大于无符号类型,此时转换的结果依赖于机器:如果无符号类型的所有值都能存在该带符号类型中,则无符号类型的运算对象转换成带符号类型;如果不能,那么带符号类型的运算对象转换成无符号类型。例如:如果两个运算对象的类型分别是 longunsigned int,并且 intlong 的大小相同,则 long 类型转换成 unsigned int;如果long 类型占用的空间比 int更大, 则 unsigned int 类型转换成 long 类型。
boo flag;   
char cval;
short sval;
unsigned short usval;
int ival;
unsigned int uival;
long lval;
unsigned long ulval;
float fval;
double dval;

3.1415: + 'a';    //'a'被提升为int,然后该int再转换成long double
dval + ival;      //ival转换成double
dval + fval;     //fval转换成double
flag = dval;     //dval是0,则flag是false,否则flag是true
cval + fval;    //cval提升为int,然后该int被提升为float
sval + cval;    //savl、cval都被提升为int
cval + lval;    //cval 转换成long
ival + ulval;   //ival转换成unsigned long
usval + ival;   //根据unsigned short和int所占空间大小进行提升
uival + lval;   //根据unsigned int和long所占空间大小进行转换

其他隐式类型转换

数组转换成指针:在大多数用到数组的表达式中,数组会自动转换成指向数组首元素的指针。
指针的转换:

  • 常量整数值0或者字面值 nullptr 能够转换成任意的指针类型。
  • 指向任意非常量的指针都能转换成 void*
  • 指向任意对象的指针都能转换成 const void *

转换成布尔类型:存在一种从算术类型或指针类型自动向布尔类型自动转换的机制。如果指针或算术类型的值为0,转换的结果是 false,否则转换结果是 true
转换成常量:允许将指向非常量类型的类型转换成指向相应的常量类型的指针,对于引用也是这样。也就是说,如果T是一种类型,我们就能将指向T的指针或引用转换成指向 const T 的指针或引用。

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

类类型定义的转换:类类型能定义由编译器自动执行的转换,不过编译器每次只能执行一种类类型的转换。
例如:

  • 使用标准库 string 类型的地方使用C风格字符串。
  • while(cin>>s)while把条件部分 cin 转换成布尔值。

显示转换

虽然有时候不得不使用强制类型转换,但这种方法本质上是十分危险的。

命名的强制类型转换

命名的强制类型转换形式为:

cast_name<type> (expression);

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

static_cast

任何具有明确定义的类型转换,只要不包含底层 const,都可以使用 static_cast
例如:

double slope = static_cast<double>(j) / i;      //浮点数除法 

当需要把一个较大的算术类型转换成较小的类型,static_cast 非常有用,此时强制类型转换会提醒编译器忽略潜在的精度损失,否则编译器会报警告信息。

const_cast

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

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

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

reinterpret_cast

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

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

使用 reinterpret_cast 是十分危险的,在这里必须始终牢记, pc 所指向的真实对象是 int 而不是 char,如果把 pc 当成普通的字符指针使用就可能发生运行时错误,例如:

string str(pc);

reinterpret_cast 本质上依赖于机器,向安全的使用 reinterpret_cast 必须对涉及的类型和编译器实现转换的过程十分了解。

旧式的强制类型转换

早期版本的C++中,显示的强制类型转换有两种形式:

type (expr);    //函数形式的强制类型转换
(type) expr;    //C语言风格的强制类型转换
原文地址:https://www.cnblogs.com/xiaojianliu/p/12498325.html