当运算符的操作数具有不同的数据类型时, C++会自动将它们按照一定的规则转换为相同的数据类型. 理解这些规则将有助于程序员防止一些细微的错误蔓延到自己的程序中.
基本数据类型隐式转换
简言之, 基本数据类型的隐式转换遵循的规则是基本数据类型的等级.
从高到低的基本数据类型的等级排序如下:
基本数据类型 |
---|
long double |
double |
float |
unsigned long long int |
long long int |
unsigned long int |
long int |
unsigned int |
int |
从上表可以看出, 数据类型越宽等级越高. 所以上述等级排序存在一个例外: 当 int 和 long int 的大小相同时, 在这种情况下, unsigned int 将超越 long int, 因为它可以保存更高的值.
具体规则:
- char, short 和 unsigned short 值自动升级为 int 值. 即无论何时在数学表达式中使用这些数据类型的值, 它们都将自动升级为 int 类型. 这也是为什么这几个类型不在上述等级排序中.
- 当运算符使用不同数据类型的两个值时, 较低排名的值将被升级为较高排名值的类型.
- 当表达式的最终值分配给变量时, 它将被转换为该变量的数据类型.
需要注意的是, 隐式转换不仅有升级(一种数据类型被转换为更髙的数据类型), 也有降级(一种数据类型被转换为更低的数据类型). 比如:
double y = 3.14;
// x被赋值为3,y仍然保留3.14
int x = y;
强制类型转换
数据类型的转换应该是尽量被避免的. 但如果避无可避, 应该使用显示类型转换, 也就是强制类型转换.
强制类型转换有 C 风格和 C++ 风格.
C 风格强制类型转换形如:
(type)expression
C 风格强制类型转换存在下面两个两个方面的不足, 是不推荐的使用的.
- 可以在任意类型之间转换, 但不区分转换类型之间的差异. 比如将指向 const 对象的指针转换成指向非 const 对象的指针, 或者将指向基类对象的指针转换成指向派生类对象的指针.
- 不易查找. 比如在存量代码中改变转换的类型, 无法快速找出已存在的类型转换.
而 C++ 风格的强制类型转换可以弥补 C 风格的不足.
C++ 提供了下面四种类型转换.
类型 | 作用 |
---|---|
static_cast | 转换数据类型, 类的上下行转换 |
const_cast | 去除指针或引用的const属性 |
dynamic_cast | 子类和父类之间的多态类型转换 |
reinterpreter_cast | 重新解释类型转换 |
static_cast
- 转换数据类型, 由于没有运行时类型检查来保证转换的安全性, 不安全
- 类的上下行转换, 由于没有运行时类型检查, 下行转换不安全
- static_cast不能转换掉原有类型的const, volatile, 或者 __unaligned 属性
const_cast
- 转化常量指针为非常量的指针, 并且仍然指向原来的对象
- 转化常量引用为非常量的引用, 并且仍然指向原来的对象
- const_cast 一般用于修改指针, 如 const int *ptr 形式
dynamic_cast
安全的上行转换(子类到基类的转换)和下行转换(基类到子类的转换).
dynami_cast 在程序运行时对类型转换的”运行期类型信息”(Runtime type information, RTTI)进行了检查,是使用安全的: 转换成功则返回的是指向类的指针或引用,转换失败则返回NULL.
reinterpreter_cast
行无关类型的转换. 用在任意的指针间的转换, 任意引用间的转换, 指针和足够大的整型之间的转换, 整型到指针的转换.