C++显式类型转换
(注:本文例程改编自《C++ Primer》)
关于类型转换,C++保留了C语言中的类型转换方式,并提供了4中新的类型转换方式。《Effective C++》鼓励我们使用新的转换方式:
第一,它们很容易在代码中被识别出来(不论是人工辨识或使用工具如grep),因而得以简化“找出类型系统在哪个地点被破坏”的过程。第二,各转型动作的目标愈窄化,编译器愈可能诊断出错误的运用。举个例子,如果你打算将常量性去掉,除非使用新式转型中的const_cast否则无法通过编译。
四类显式类型转换
static_cast
static_cast
用于对对象进行强制的类型转换,但要求对象不是底层上的常量(指针常量为顶层常量,指针指向内容为常量即底层常量)。
int i = 2, j = 1;
double dval = static_cast<double>(j) / i;
另外static_cast
还可以用于对编译器无法自动执行的类型转换,如:
double dval;
void *p = &dval;
double *dp = static_cast<double*>(p);
const_cast
const_cast
用于移除const对象的常量性质,并且C++中只有const_cast
这一类型转换方式可以做到这一点。移除对象的常量性是合法的,但是移除后对常量对象进行写操作会产生未定义后果。
示例:
const char *cp;
char *q = static_cast<char*>(cp); // 错误:static_cast不能移除常量性
static_cast<string>(cp); // 正确
const_cast<string>(cp); // 错误:const_cast只能用于移除常量性,不能进行强制类型转换
reinterpret_cast
reinterpret_cast
会执行位数据上的底层类型转换操作,顾名思义是一种“重新解释”。
示例:
int *ip;
char *pc = reinterpret_cast<char*>(ip);
然而需要注意的是,reinterpret_cast
的实际动作与编译器具体实现密切相关,可能会产生无法意料的错误,并且降低程序的可移植性,本文的参考书目不建议过多使用。
dynamic_cast
dynamic_cast
运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用,是实现RTTI(运行时类型识别)的两个运算符之一。
使用形式如下:
// type必须是一个类类型
dynamic_cast<type*>(e) // e必须是一个有效的指针
dynamic_cast<type&>(e) // e必须是一个左值
dynamic_cast<type**>(e) // e不能是左值
注意:
- 一般来说,只要有可能我们应该尽量使用虚函数。当操作被定义成虚函数时,编译器将根据对象的动态类型自动地选择正确的函数版本。
- 然而并非任何时候都能定义一个虚函数。假设我们无法使用虚函数,则可以使用一个RTTI运算符。
- 另一方面,与虚成员函数相比,使用RTTI运算符蕴含更多潜在风险:程序员必须清除地知道转换的目标类型并且必须检查类型转换是否被成功执行。
- 转换失败会的后果:
- 如果转换目标是指针类型并且失败了,则结果为0.
- 如果转换目标是引用类型并且失败了,则运算符将抛出一个
bad_cast
异常。
参考书目
- 《C++ Primer》中文第五版
- 《Effective C++》中文第三版