?C++不会直接将两个不同类型的值相加,而是先根据类型转换规则设法将运算对象的类型统一后再求值。
隐式转换:
1、大多数表达式中,比int类型小的整型值首先提升为较大的整数类型。 2、在条件中,非布尔值转换成布尔类型。 2、初始化过程中,初始值转换成变量的类型。 3、在赋值语句中,右侧运算对象转换成左侧运算对象的类型。 4、如果算术运算或关系运算的运算对象有多种类型,需要转换成同一种类型。 5、函数调用时也会发生类型转换。
算术转换:
算术转换就是把一种算术类型转换成另一种算术类型。 1、运算符的运算对象将转换成最宽的类型。 ? 例如:一个运算对象的类型是long double,那么无论另一个运算对象的类型是什么都会转换成long double;当表达式中既有浮点类型又有整数类型时,整个数值将转换成相应的浮点类型。 2、整型提升:把小整数类型转换成较大的整数类型。 ? 对于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 logn、unsigned long long中能够容纳原类型所有可能的值的最小的类型。 3、无符号类型与有符号类型 ? 一个运算对象是无符号类型,另一个运算对象是有符号类型:如果无符号类型不小于有符号类型(比较的是类型的大小,而不是具体值的大小),那么有符号类型转换成那个无符号类型的(注意符号位);如果无符号类型小于有符号类型,则转换结果依赖于机器,若是无符号类型的所有可能的值能够存在有符号类型中,则将无符号类型转换成有符号类型,否则有符号类型转换成无符号类型。 例: unsigned int和int,无符号类型不小于有符号类型,将int转换成unsigned int; unsigned int和long,无符号类型小于有符号类型,如果ing和long的大小相同,则long转换成unsigned int,如果long类型占用空间比int多,则unsigned int转换成long。
其他隐式类型转换:
1、数组名转换成指针:大多数用到数组名的表达式中,数组名自动转换成指向数组首元素的指针。 当数组名被用作decltype关键字的参数,或者作为取址符&、sizeof、typeid等运算符的运算对象时,或者用一个引用来初始化数组,上述转换不会发生。 2、指针的转换:常量整数值0和字面值nullptr能转换成任意指针类型;指向任意非常量的指针能转换成void *;指向任意对象的指针能转换成const void *。 3、算数类型或指针类型转换成布尔型:值为0转换为false,否则都转换成true。 4、指向非常量类型的指针能转换成指向相应常量类型的指针。(引用亦是如此) 5、类类型定义的转换:类类型定义由编译器自动执行转换,但一次只能执行一种类类型的转换。
显式转换 - 强制类型转换:
注:强制类型转换干扰了正常的类型检查,应避免使用 命名的强制类型转换的形式: cast-name<type>(expression); cast-name是static_cast、dynamic_cast、const_cast、reinterpret_cast中的一种、type是转换的目标类型,expression是要转换的值。 static_cast:任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。 例:
//进行强制转换一边执行浮点数除法
double slope = static_cast<double>(j) / i;
//找回存在于void *指针里的值
void *p = &slope;?? ?//任何非常量对象的地址都能存入void *类型指针
double *dp = static_cast<double*>(p);?? ?//将void *转换回初始的指针类型
dynamic_cast:支持运行时类型识别,用于将基类的指针或引用安全地转换成派生类的指针或引用。 const_cast:只能改变运算对象的底层const,且只有const_cast能改变常量属性,其他形式的强制转换都会引发编译器错误。 例:
const char *p;
char *p = const_cast<char*>(pc);//正确,但是通过p写值时未定义的行为
reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释。
reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释。(没懂) 例:
int *ip;
char *cp = reinterpret_cast<char*>(ip);?? ?//须牢记cp所指的真实对象是一个int而非字符,如果把cp当成普通的字符指针使用就可能在运行时发生错误。
string str(cp);?? ?//可能导致异常的运行时行为。
使用reinterpret_cast是非常危险的,如上例,关键是类型改变了但编译器没有给出任何警告或者错误的提示信息。reinterpret_cast本质上依赖于机器。想要安全使用必须对涉及的类型转换的过程都非常了解。
旧式的强制类型转换: type (expr);?? ?//函数形式 (type) expr;?? ?//C语言风格 旧时的强制类型转换与命名的强制类型转换cast-name的static_cast、const_cast、reinterpret_cast有着相似的行为,但与其相比,表现形式不够清晰,易被看漏,出错追踪起来也更困难
|