C++显式转换(static_cast/dynamic_cast/const_cast/reinterpret_cast)
1、static_cast
任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast。
当需要把一个较大的算数类型复制给较小的类型时,static_cast非常有用。此时,强制类型转换告诉读者和编译器,我们知道并且不在乎潜在的精度损失。
执行了强制类型转换之后,警告信息就关闭了。
int i = 1;
int j = 4;
double slop = static_cast<double>(j) / i;
void *ptr = &d;
double *dp = static_cast<double*>(ptr);
2、const_cast
const_cast只能改变运算对象的底层const。
const char *pc = nullptr;
char *p = const_cast<char*>(pc); // 正确,当时通过p写值是未定义的行为
对于将常量对象转换为非常量对象的行为,我们一般称其为“去掉const性质”。一旦去掉了某个对象的const性质,编译器就不再阻止对该对象进行写操作了。
如果对象本身不是常量,使用强制类型转换获得写权限是合法的行为。
如果对象本身是常量,使用const_cast类型转换后写操作是未定义的行为。
只有const_cast能改变表达式的常量属性,使用其他形式的命名强制类型转换改变表达式额常量属性都将引发编译器错误。同样也不能使用const_cast改变表达式的类型。
const char *cp = nullptr;
char *q = static_cast<char*>(cp); // 错误,只有const_cast能改变表达式的常量属性
static_cast<string>(cp); // 正确,字符串转换成string类型
const_cast<string>(cp); // 错误,const_cast只能改变表达式的常量属性
3、reinterpret_cast
reinterpret_cast通常为运算对象的位模式提供较低层次上的重新解释。reinterpret_cast可以用来在任意类型间进行转换,转换后其正确性由程序员保证。
reinterpret_cast运算符是用来处理无关类型之间的转换;它会产生一个新的值,这个值会有与表达式完全相同的比特位。
int *ip;
char *ptr = reinterpret_cast<char*>(ip); // 正确
然而,ptr指向的实际为int类型数据,将ptr当成char类型指针使用可能在运行时发生错误。
4、dynamic_cast
dynamic_cast运算符,用于将基类的指针或者引用安全地转换成派生类的指针或引用。
dynamic_cast运算符的使用形式有如下几种:
dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)
其中,type必须是一个类类型,并且通常情况下该类型应该含有虚函数。
- 在第一种形式中,e必须是一个有效的指针;
- 第第二种形式中,e必须是一个左值;
- 在第三种形式中,e不能是左值。
在上面所有的形式中,e的类型必须符合以下三个条件中的任意一个:
- e的类型是目标type的公有派生类;
- e的类型是目标type的公有基类;
- e的类型是目标type的类型;
如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0;如果转换目标是引用类型并且失败了,则dynamci_cast运算符抛出一个bad_cast异常。
4.1、指针类型的dynamic_cast
class Base {
public:
virtual int GetValue();
private:
int value;
};
class Derived : public Base {
public:
virtual int GetValue();
private:
int valueDerived;
};
Base *bp;
Derived *dp;
void func()
{
if (Derived *dp = dynamic_cast<Derived*>(bp)) {
// 使用dp指向的派生类对象
} else {
// 使用bp指向的基类对象
}
}
提示:可以对一个空指针执行dynamic_cast,结果是所需类型的空指针。
4.2、引用类型的dynamic_cast
引用类型的dynamic_cast与指针类型的dynamic_cast在表示错误发生的方式上略有不同。
void func(const Base &b)
{
try {
const Derived &d = dynamic_cast<const Derived*>(b);
// 使用d引用的派生类对象
} catch {
// 处理类型转换失败的情况
}
}