前言
在c语言中,通过下面的代码进行一次类型转换:
int a = (int)10.0;
这种转换通常称为强转,强转存在几个明显的缺点:
- 强转形式上不易被发现,c语言中有很多类型和括号的组合,几乎随处可见,编码人员一眼扫过通常不易察觉强转。
- 强转可能是不安全的,比如下面的代码中,将父类指针转为子类,从内存模型角度上来说,子类内存比父类多出一块,多出的部分结果是不可预知的。
#include <iostream>
class base{
public:
int a = 10;
};
class derive:public base{
public:
int b = 20;
};
int main(){
base* p = new base();
derive* s = (derive*)p;
std::cout << s->b << std::endl;
}
运行上面的代码,打印的b的值为0,与默认值不同,这通常是我们不希望看到的。为了解决强转的问题,c++引入了四种类型转换,下面我们来介绍这四种转换。
static_cast
理论上来说,任何具有明确定义的类型转换,只要不包含底层const,都可以使用static_cast,比如下面的例子:
int c;
double d = static_cast<double>(c);
static_cast也可以用于父子间的类型转换,但static_cast不提供类型检查,因此当用于具有继承关系的转换时,结果与强转相似。
base* p = new base;
derive* s = static_cast<derive*>(p);
std::cout << s->b << std::endl;
运行结果如下:
dynamic_cast
dynamic_cast用于处理具有继承关系的类的转换,传入的类必须是具有虚函数的类,否则编译时会报错。
base* e = new base;
derive* f = dynamic_cast<derive*>(e);
std::cout << f->b << std::endl;
编译结果如下:
dynamic_cast转换时提供运行时类型检查,转换失败会返回void*指针,相较于static_cast,对具有虚函数的转换,dynamic_cast更安全,建议这种转换均使用dynamic_cast进行转换。
const_cast
const_cast用于改变变量的const属性,需要注意的是,const_cast传入的参数必须是指针或者引用,示例代码如下:
int main(){
const int* g = new int(10);
int* h = const_cast<int*>(g);
*h = 20;
std::cout << *h << std::endl;
delete h;
}
可以看到*h被改变了:
const_cast不仅用于将const转换为非const,同样可以将非const转换为const:
int main(){
int* i = new int(10);
const int* j = const_cast<int*>(i);
*j = 20;
delete j;
}
可以看到运行时报错,说明j被赋予了const属性。
reinterpret_cast
reinterpret_cast是c++里面的强制转换,可以用于任意转换,但不论在任何情况下,尽量不要使用reinterpret_cast,可能带来不可预料的后果。