zoukankan      html  css  js  c++  java
  • C++语言基础(24)-四种类型转换运算符(static_cast、dynamic_cast、const_cast和reinterpret_cast)

    一.static_cast

    static_cast 只能用于良性转换,这样的转换风险较低,一般不会发生什么意外,如:

    #include <iostream>
    #include <cstdlib>
    using namespace std;
    
    class Complex{
    public:
        Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ }
    public:
        operator double() const { return m_real; }  //类型转换函数
    private:
        double m_real;
        double m_imag;
    };
    
    int main(){
        //下面是正确的用法
        int m = 100;
        Complex c(12.5, 23.8);
        long n = static_cast<long>(m);  //宽转换,没有信息丢失
        char ch = static_cast<char>(m);  //窄转换,可能会丢失信息
        int *p1 = static_cast<int*>( malloc(10 * sizeof(int)) );  //将void指针转换为具体类型指针
        void *p2 = static_cast<void*>(p1);  //将具体类型指针,转换为void指针
        double real= static_cast<double>(c);  //调用类型转换函数
       
        //下面的用法是错误的
        float *p3 = static_cast<float*>(p1);  //不能在两个具体类型的指针之间进行转换
        p3 = static_cast<float*>(0X2DF9);  //不能将整数转换为指针类型
    
        return 0;
    }

    二.const_cast

    const_cast用来去掉表达式的 const 修饰或 volatile 修饰。换句话说,const_cast 就是用来将 const/volatile 类型转换为非 const/volatile 类型。如:

    #include <iostream>
    using namespace std;
    
    int main(){
        const int n = 100;
        int *p = const_cast<int*>(&n);
        *p = 234;
        cout<<"n = "<<n<<endl;
        cout<<"*p = "<<*p<<endl;
    
        return 0;
    }

    运行结果:

    n = 100
    *p = 234

    &n用来获取 n 的地址,它的类型为const int *,必须使用 const_cast 转换为int *类型后才能赋值给 p。由于 p 指向了 n,并且 n 占用的是栈内存,有写入权限,所以可以通过 p 修改 n 的值。

    至于为什么通过 n 和 *p 输出的值不一样呢?这是因为 C++ 对常量的处理更像是编译时期的#define,是一个值替换的过程,代码中所有使用 n 的地方在编译期间就被替换成了 100。换句话说,第 8 行代码被修改成了下面的形式:

    cout<<"n = "<<100<<endl;

    这样以来,即使程序在运行期间修改 n 的值,也不会影响 cout 语句了。

    三.reinterpret_cast 

    reinterpret_cast 这种转换仅仅是对二进制位的重新解释,不会借助已有的转换规则对数据进行调整,非常简单粗暴,所以风险很高

    #include <iostream>
    using namespace std;
    
    class A{
    public:
        A(int a = 0, int b = 0): m_a(a), m_b(b){}
    private:
        int m_a;
        int m_b;
    };
    
    int main(){
        //将 char* 转换为 float*
        char str[]="http://c.biancheng.net";
        float *p1 = reinterpret_cast<float*>(str);
        cout<<*p1<<endl;
        //将 int 转换为 int*
        int *p = reinterpret_cast<int*>(100);
        //将 A* 转换为 int*
        p = reinterpret_cast<int*>(new A(25, 96));
        cout<<*p<<endl;
       
        return 0;
    }

    运行结果:

    3.0262e+29
    25

    个人感觉这个关键字很危险,所以不推荐使用.

    四.dynamic_cast

    dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。

    有以下两点需要注意:

    1).newType 和 expression 必须同时是指针类型或者引用类型。换句话说,dynamic_cast 只能转换指针类型和引用类型,其它类型(int、double、数组、类、结构体等)都不行。

    2).对于指针,如果转换失败将返回 NULL;对于引用,如果转换失败将抛出std::bad_cast异常。

    例:

    #include <iostream>
    using namespace std;
    
    class A{
    public:
        virtual void func() const { cout<<"Class A"<<endl; }
    private:
        int m_a;
    };
    
    class B: public A{
    public:
        virtual void func() const { cout<<"Class B"<<endl; }
    private:
        int m_b;
    };
    
    class C: public B{
    public:
        virtual void func() const { cout<<"Class C"<<endl; }
    private:
        int m_c;
    };
    
    class D: public C{
    public:
        virtual void func() const { cout<<"Class D"<<endl; }
    private:
        int m_d;
    };
    
    int main(){
        A *pa = new A();
        B *pb;
        C *pc;
       
        //情况①
        pb = dynamic_cast<B*>(pa);  //向下转型失败
        if(pb == NULL){
            cout<<"Downcasting failed: A* to B*"<<endl;
        }else{
            cout<<"Downcasting successfully: A* to B*"<<endl;
            pb -> func();
        }
        pc = dynamic_cast<C*>(pa);  //向下转型失败
        if(pc == NULL){
            cout<<"Downcasting failed: A* to C*"<<endl;
        }else{
            cout<<"Downcasting successfully: A* to C*"<<endl;
            pc -> func();
        }
       
        cout<<"-------------------------"<<endl;
       
        //情况②
        pa = new D();  //向上转型都是允许的
        pb = dynamic_cast<B*>(pa);  //向下转型成功
        if(pb == NULL){
            cout<<"Downcasting failed: A* to B*"<<endl;
        }else{
            cout<<"Downcasting successfully: A* to B*"<<endl;
            pb -> func();
        }
        pc = dynamic_cast<C*>(pa);  //向下转型成功
        if(pc == NULL){
            cout<<"Downcasting failed: A* to C*"<<endl;
        }else{
            cout<<"Downcasting successfully: A* to C*"<<endl;
            pc -> func();
        }
       
        return 0;
    }

    运行结果:

    Downcasting failed: A* to B*
    Downcasting failed: A* to C*
    -------------------------
    Downcasting successfully: A* to B*
    Class D
    Downcasting successfully: A* to C*
    Class D

  • 相关阅读:
    Java中hashCode() 和 equals()
    【转】Java操作Excel竟然这么简单!
    SpringMVC上
    网络基础知识(2)
    网络基础知识 (1)
    线程的安全
    多线程
    字符编码ANSI和ASCII区别、Unicode和UTF-8区别
    序列化对象
    IO流_File类
  • 原文地址:https://www.cnblogs.com/yongdaimi/p/7125086.html
Copyright © 2011-2022 走看看