ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] ## C++中的类型强制转换 《Effective C++》中将c语言强制类型转换称为**旧式转型**,c++强制类型转换称为**新式转型**。 * dynamic_cast:   通常在基类和派生类之间转换时使用,run-time   cast * const_cast:   主要针对const和volatile的转换.  * static_cast:   一般的转换,no   run-time   check.通常,如果你不知道该用哪个,就用这个。    * reinterpret_cast:   用于进行没有任何关联之间的转换,比如一个字符指针转换为一个整形数。 ## static_cast<T*> a static_cast相当于传统的**C语言里的强制转换**,该运算符把expression转换为new_type类型,用来强迫隐式转换,例如non-const对象转为const对象,编译时检查,用于非多态的转换,可以转换指针及其他,但*没有运行时类型检查来保证转换的安全性*。它主要有如下几种用法: ①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。 * 进行上行转换(把派生类的指针或引用转换成基类表示)是**安全**的;* * 进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是**不安全**的。* ②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。 ③把空指针转换成目标类型的空指针。 ④把任何类型的表达式转换成void类型。 >注意:static_cast不能转换掉expression的const、volatile、或者__unaligned属性。 ## dynamic_cast<T*> a ``` dynamic_cast<type*>(e) //type必须是一个有效的指针 dynamic_cast<type&>(e) // type必须是一个左值 dynamic_cast<type&&>(e) // type必须是一个右值 ``` * e的类型必须符合以下三个条件中的任何一个: * e的类型是是目标类型type的公有派生类 * e的类型是目标type的共有基类 * e的类型就是目标type的的类型。 >如果一条dynamic_cast语句的转换目标是指针类型并且失败了,则结果为0。如果转换目标是引用类型并且失败了,则dynamic_cast运算符将抛出一个std::bad_cast异常(该异常定义在typeinfo标准库头文件中)。e也可以是一个空指针,结果是所需类型的空指针。 ### dynamic_cast的应用 dynamic_cast主要用于**类层次间**的上行转换和下行转换,还可以用于**类之间**的交叉转换(cross cast)。 * 在类层次间进行上行转换时 :dynamic_cast和static_cast的效果是一样的; * 在进行下行转换时: dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作 1. 指针类型 举例,Base为包含至少一个虚函数的基类,Derived是Base的共有派生类,如果有一个指向Base的指针bp,我们可以在运行时将它转换成指向Derived的指针,代码如下: ``` if(Derived *dp = dynamic_cast<Derived *>(bp)){ //使用dp指向的Derived对象 } else{ //使用bp指向的Base对象 } ``` >值得注意的是,在上述代码中,if语句中定义了dp,这样做的好处是可以在一个操作中同时完成类型转换和条件检查两项任务。 2. 引用类型 因为不存在所谓空引用,所以引用类型的dynamic\_cast转换与指针类型不同,在引用转换失败时,会抛出std::bad\_cast异常,该异常定义在头文件typeinfo中。 ``` void f(const Base &b){ try{ const Derived &d = dynamic_cast<const Base &>(b); //使用b引用的Derived对象 } catch(std::bad_cast){ //处理类型转换失败的情况 } } ``` ## const_cast const_cast,用于修改类型的const或volatile属性。  该运算符用来修改类型的const(唯一有此能力的C++-style转型操作符)或volatile属性。除了const 或volatile修饰之外, new\_type和expression的类型是一样的。 ①常量指针被转化成非常量的指针,并且仍然指向原来的对象; ②常量引用被转换成非常量的引用,并且仍然指向原来的对象; ③const_cast一般用于修改底指针。如const char \*p形式。 举例转换如下: ``` const int g = 20; int *h = const_cast<int*>(&g);//去掉const常量const属性 const int g = 20; int &h = const_cast<int &>(g);//去掉const引用const属性 const char *g = "hello"; char *h = const_cast<char *>(g);//去掉const指针const属性 ``` ## reinterpret_cast new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。 >reinterpret_cast意图执行低级转型,实际动作(及结果)可能取决于编辑器,这也就表示它**不可移植** 举一个错误使用reintepret\_cast例子,将整数类型转换成函数指针后,vc++在执行过程中会报"...中的 0xxxxxxxxx 处有未经处理的异常: 0xC0000005: Access violation"错误: ``` #include <iostream> using namespace std; int output(int p){ cout << p <<endl;  return 0; } typedef int (*test_func)(int );//定义函数指针test_func int main(){ int p = 10; test_func fun1 = output; fun1(p);//正确 test_func fun2 = reinterpret_cast<test_func>(&p); fun2(p);//...处有未经处理的异常: 0xC0000005: Access violation return 0; } ```