C++ 类型转换
1. static_cast
用于进行比较“自然”和低风险的转换,如整型和浮点型、字符型之间的互相转换。另外,如果对象所属的类重载了强制类型转换运算符 T(如 T 是 int、int* 或其他类型名),则 static_cast 也能用来进行对象到 T 类型的转换。
static_cast 不能用于整型和指针之间的互相转换,当然也不能用于不同类型的引用之间的转换。因为这些属于风险比较高的转换。
A a; int n; char* p = "New Dragon Inn"; n = static_cast<int>(3.14); // n 的值变为 3 n = static_cast<int>(a); //调用 a.operator int,n 的值变为 1 p = static_cast<char*>(a); //调用 a.operator char*,p 的值变为 NULL n = static_cast<int>(p); //编译错误,static_cast不能将指针转换成整型 p = static_cast<char*>(n); //编译错误,static_cast 不能将整型转换成指针2. dynamic_cast
进行类层次间的下行转换时更加安全
dynamic_cast 运算符可以在执行期决定真正的类型。如果下行转换是安全的(也就是说,如果基类指针或者引用确实指向一个派生类对象),这个运算符会传回转型过的指针。如果下行转换不安全,这个运算符会传回空指针(也就是说,基类指针或者引用没有指向一个派生类对象)。
说了这么多是什么意思呢?总结可以是两句话:
(1) 在类层次间进行上行转换时,dynamic_cast 和 static_cast 的效果是一样的。
(2) 在类层次间进行下行转换时,dynamic_cast 具有类型检查的功能,比 static_cast 更安全。
Base b; Derived d; Derived* pd; pd = reinterpret_cast <Derived*> (&b); if (pd == NULL) //此处pd不会为 NULL。reinterpret_cast不检查安全性,总是进行转换 cout << "unsafe reinterpret_cast" << endl; //不会执行 pd = dynamic_cast <Derived*> (&b); if (pd == NULL) //结果会是NULL,因为 &b 不指向派生类对象,此转换不安全 cout << "unsafe dynamic_cast1" << endl; //会执行 pd = dynamic_cast <Derived*> (&d); //安全的转换 if (pd == NULL) //此处 pd 不会为 NULL cout << "unsafe dynamic_cast2" << endl; //不会执行3. reinterpret_cast
用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作。
这种转换提供了很强的灵活性,但转换的安全性只能由程序员的细心来保证了。例如,程序员执意要把一个 int* 指针、函数指针或其他类型的指针转换成 string* 类型的指针也是可以的,至于以后用转换后的指针调用 string 类的成员函数引发错误,程序员也只能自行承担查找错误的烦琐工作。
A a(100); int &r = reinterpret_cast<int&>(a); //强行让 r 引用 a r = 200; //把 a.i 变成了 200 cout << a.i << "," << a.j << endl; // 输出 200,100 int n = 300; A *pa = reinterpret_cast<A*> ( & n); //强行让 pa 指向 n pa->i = 400; // n 变成 400 pa->j = 500; //此条语句不安全,很可能导致程序崩溃 cout << n << endl; // 输出 400 long long la = 0x12345678abcdLL; pa = reinterpret_cast<A*>(la); //la太长,只取低32位0x5678abcd拷贝给pa unsigned int u = reinterpret_cast<unsigned int>(pa);//pa逐个比特拷贝到u cout << hex << u << endl; //输出 5678abcd typedef void (* PF1) (int); typedef int (* PF2) (int,char *); PF1 pf1; PF2 pf2; pf2 = reinterpret_cast<PF2>(pf1); //两个不同类型的函数指针之间可以互相转换4. const_cast
用于进行去除 const 属性的转换
const string s = "Inception"; string& p = const_cast <string&> (s); string* ps = const_cast <string*> (&s); // &s 的类型是 const string*5. bad_cast
由于强制转换为引用类型失败,dynamic_cast 运算符引发 bad_cast 异常。
try { Circle& ref_circle = dynamic_cast<Circle&>(ref_shape); } catch (bad_cast b) { cout << "Caught: " << b.what(); }6. 智能指针转换
使用std::dynamic_pointer_cast和std::static_pointer_cast
#include <iostream> #include <memory> class base { public: // 一定要定义这个虚析构函数,否则基类无法转换为派生类 virtual ~base() = default; }; class derived : public base { }; int main(void) { // 定义两个不同的派生类对象 std::shared_ptr<derived> derived_obj = std::make_shared<derived>(); // 隐式转换 derived->base std::shared_ptr<base> pointer1 = derived_obj; // static_pointer_cast derived->base std::shared_ptr<base> pointer2 = std::static_pointer_cast<base>(derived_obj); // dynamic_pointer_cast base->derived std::shared_ptr<derived> pointer3 = std::dynamic_pointer_cast<derived>(pointer1); std::cout << (pointer3.get() == nullptr) << std::endl; // dynamic_pointer_cast base->derived auto pointer4 = std::dynamic_pointer_cast<test>(pointer1); std::cout << (pointer4.get() == nullptr) << std::endl; return 0; }参考文献
c++ dynamic_cast 和 static_cast 的区别-CSDN博客
https://zhuanlan.zhihu.com/p/35153051
https://stackoverflow.com/questions/16374671/cannot-dynamic-cast-when-using-dynamic-pointer-cast
C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast) - C语言中文网