类型转换可以让我们将一种类型的变量当做另外一种类型来使用,常见的类型转换方式包括
C风格的类型转换
转换格式为:(类型)变量
int a = 10; double b = a; float c = b;
Base* base = (Base*)new Derived();
C++自带的类型转换
- static_cast
- dynamic_cast
- const_cast
- reinterpret_cast
为什么有了C风格的类型转换方式后C++还添加这四种类型转换方式呢?
因为C风格的类型转换可以在任意类型之间转换,比如你可以把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的c语言风格的类型转换没有区分这些。还有一个缺点就是,c风格的转换不容易查找,他由一个括号加上一个标识符组成,而这样的东西在c++程序里一大堆。
static_cast
类似与C风格的无条件静态类型转换
1、基类和子类之间的转换,其中:子类->基类是安全的,但是基类->子类是不安全的,建议使用dynamic_cast进行运行时判断进行基类转子类。
2、基本数据类型之间的转换,int, char, float,注意不可以进行无关类型指针的转换。
3、转换空指针为任何类型的空指针
Base* base1 = static_cast<Base*>(new Derived()); Derived* base2 = static_cast<Derived*>(new Base()); //基类->子类,有风险,不推荐使用 double num = static_cast<double>('a'); //char->double // double* ptr = static_cast<double*>(new int(10)); 错误,无关类型的指针转换,转换无效 double* ptr = static_cast<double*>(nullptr); //空指针->任意类型的空指针
dynamic_cast
动态转换主要是用于类的层次间、基类子类间转换,具有检验功能,在无法进行转换时返回nullptr。如果转换的是引用,失败时会抛出std::base_cast异常。可以通过返回值进行判断是否成功转换。
Base* base = dynamic_cast<Base*>(new Derived()); //成功 if (base == nullptr) { std::cout << "derived -> base 失败" << std::endl; } Derived* derived = dynamic_cast<Derived*>(new Base()); //失败 if (derived == nullptr) { std::cout << "base -> derived 失败" << std::endl; }
返回失败
const_cast
用于移除、添加变量的const属性,注意C++中其他的三类转换都没有移除const属性的能力,对于const_cast主要用来对顶层、底层的const进行转换。为什么不可以对变量的const进行修改呢?因为没有意义。
int i = 10; const int* p = &i; const int* ci = const_cast<const int*>(p); //*ci = 20; 提示错误,表达式必须是可修改的左值 int* c = const_cast<int*>(p); *c = 20;
reinterpret_cast
re重新的意思,interpret解读、翻译的意思,顾名思义将数据重新按照另外一种类型进行解读,一般很少用到,不清楚自己在操作什么数据时,请谨慎使用。比如将四个字符当做当做一个浮点数进行处理。
char ch[4] = { 'a', 'b', 'c', 'd' }; float* f = reinterpret_cast<float*>(ch); //四个字符共四个字节正好当做一个浮点数来处理(不严谨,具体根据各个平台浮点数字节大小可能不一样) std::cout << *f << std::endl;
输出
本质上C++中的四种类型转换都是语法糖,所有能做的C风格转换也可以做到。但是使用C++中的类型转换,可以让我们更好的追踪到我们的项目里面的哪里有用到类型转换,这是C风格转换所不具有的优势的。
更多参考: