C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast)

  C++ 引入了四种功能不同的强制类型转换运算符以进行强制类型转换:static_cast、reinterpret_cast、const_cast和dynamic_cast,当然C++为保持与C的兼容,也保留了C语法中强制类型转换运算符的写法。

  C++引入新的强制类型转换机制,主要为是为克服C语言强制类型转换的三个主要的切点:

  1、没有从形式上体现转换功能和风险的不同

    例如,将 int 强制转换成 double 是没有风险的,而将常量指针转换成非常量指针,将基类指针转换成派生类指针都是高风险的,而且后两者带来的风险不同(即可能引发不同种类的错误),C语言的强制类型转换形式对这些不同并不加以区分。

  2、将多态基类指针转换成派生类指针时不检查安全性,即无法判断转换后的指针是否确实指向一个派生类对象

  3、难以在程序中寻找到底什么地方进行了强制类型转换

  而用 C++ 的方式,则只需要查找_cast字符串就可以了。甚至可以根据错误的类型,有针对性地专门查找某一种强制类型转换。例如,怀疑一个错误可能是由于使用了 reinterpret_cast 导致的,就可以只查找reinterpret_cast字符串。

  C++强制类型转换运算符的用法如下:

强制类型转换运算符 <要转换到的类型> (待转换的表达式)

  例如:

double d = static_cast <double> (3*5);  //将 3*5 的值转换成实数

  现在来说下这四种强制类型转换运算符

  1、static_cast

  作用:static_cast用于比较“自然”和低风险的转换,比如整型和浮点型、字符型之间的转换。另外,如果对象所属的类重载了强制类型运算符T(如T是int、int*或其他类型名),则static_cast也能用来进行对象到T类型的转换。(但不能用于不同类型指针、整型与指针等这些高风险的转换中)

  2、reinterpret_cast

  作用:reinterpret_cast用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型的转换(高风险的转换)。转换时,执行的是逐个比特复制的操作。

  这种转换提供了很强的灵活性,但转换的安全性只能由程序员的细心来保证了。例如,程序员执意要把一个 int* 指针、函数指针或其他类型的指针转换成 string* 类型的指针也是可以的,至于以后用转换后的指针调用 string 类的成员函数引发错误,程序员也只能自行承担查找错误的烦琐工作:(C++ 标准不允许将函数指针转换成对象指针,但有些编译器,如 Visual Studio 2010,则支持这种转换)。

  reinterpret_cast体现了 C++ 语言的设计思想:用户可以做任何操作,但要为自己的行为负责。

  3、const_cast

   作用:const_cast仅用于进行去除const属性的转换,它也是四个强制类型转换运算符中唯一一个能够去除const属性的运算符

const string s = "Inception";
string& p = const_cast <string&> (s);
string* ps = const_cast <string*> (&s);  // &s 的类型是 const string*

  4、dynamic_cast

  用reinterpret_cast可以将多态基类(包括虚函数的基类)的指针强制转换成派生类的指针,但这种转换不检查安全性,即不检查转换后的指针是否确实指向一个派生类对象。dynamic_cast专门用于将多态基类的指针或引用强制转换为派生类的指针或引用,而且能够检查转换的安全性。对于不安全的指针转换,转换结果范围NULL指针。

  dynamic_cast 是通过“运行时类型检查”来保证安全性的。dynamic_cast 不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,只好用 reinterpret_cast 来完成。

#include <iostream>
#include <string>
using namespace std;
class Base
{  //有虚函数,因此是多态基类
public:
    virtual ~Base() {}
};
class Derived : public Base { };
int main()
{
    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;  //不会执行
    return 0;
}

输出结果:

unsafe dynamic_cast1

第 20 行,通过判断 pd 的值是否为 NULL,就能知道第 19 行进行的转换是否是安全的。第 23 行同理。

如果上面的程序中出现了下面的语句:

Derived & r = dynamic_cast <Derived &> (b);

那该如何判断该转换是否安全呢?不存在空引用,因此不能通过返回值来判断转换是否安全。C++ 的解决办法是:dynamic_cast 在进行引用的强制转换时,如果发现转换不安全,就会拋出一个异常,通过处理异常,就能发现不安全的转换。

参考:http://c.biancheng.net/view/410.html

posted @ 2020-03-29 22:37  牛犁heart  阅读(423)  评论(0编辑  收藏  举报