• reinterpret


    原文地址https://www.cnblogs.com/xiangtingshen/p/11063805.html

    reinterpret意为“重新解释”

    reinterpret_cast是C++中与C风格类型转换最接近的类型转换运算符。它让程序员能够将一种对象类型转换为另一种,不管它们是否相关。

    reinterpret_cast用在任意指针(或引用)类型之间的转换以及指针与足够大的整数类型之间的转换;从整数类型(包括枚举类型)到指针类型,无视大小。

    (所谓"足够大的整数类型",取决于操作系统的参数,如果是32位的操作系统,就需要整形(int)以上的;如果是64位的操作系统,则至少需要长整形(long)。具体大小可以通过sizeof运算符来查看)。

    【注意】reinterpret_cast不能用于内置类型之间的转换,只能用于不同指针之间的转换。

    CBase* pBase = new CBase( ) ;  
    CDerived* pDerived = reinterpret_cast<CDerived*>(pBase) ;  

    这种类型转换实际上是强制编译器接受static_cast通常不允许的类型转换,它并没有改变指针值的二进制表示,只是改变了编译器对源对象的解释方式。

    【应尽量避免使用reinterpret_cast】

    reinterpret_cast  VS  static_cast

    static_cast主要管:有继承关系类的指针和内置数据类型的转换(和C的内置类型转换规则一致,可能改变底层的位,也可能不改变)。

    reinterpret_cast主要管:所有指针(引用)之间的转换

    在它们管理的交叉点处——有继承关系的指针的转换,处理方式有所不同。

    static_cast和reinterpret_cast的区别主要在于多重继承

    复制代码
    class A  
    {  
    public:  
        int m_a;  
    };  
    class B  
    {  
    public:  
        int m_b;  
    };  
    class C : public A, public B {};  
      
    C c;  
    printf("%p, %p, %p", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));  
    复制代码

    前两个的输出值是相同的,最后一个则会在原基础上偏移4个字节。

    这是因为static_cast计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处),而reinterpret_cast却不会做这一层转换。

    reinterpret_cast  VS  const_cast

    reinterpret_cast不能像const_cast那样去除const修饰符。

    复制代码
    int main()   
    {  
        typedef void (*FunctionPointer)(int);  
        int value = 21;  
        const int* pointer = &value;  
          
        int * pointer_r = reinterpret_cast<int*> (pointer); //编译报错  
          
        FunctionPointer funcP = reinterpret_cast<FunctionPointer> (pointer);  
    }  
    复制代码

    reinterpret_cast只能改变指针(或引用)的解释方式,不能把其上的const锁转换掉。

    const_cast

    const_cast让程序员能够关闭对象的访问修饰符const。

    在理想的情况下,程序员将经常在正确的地方使用关键字const。

    但是现实世界,经常可以看到该使用const的地方没有使用。

    这样,在外部函数中调用类中的这些成员函数,可能会报错。

    复制代码
    CSomeClass  
    {  
    public:  
        ….  
        void DisplayMember( ) ;  
    };  
    void DisplayAllData( const CSomeClass& mData )  
    {  
        mData.DisplayMembers ( ) ; //编译报错  
    }  
    复制代码

    为什么会编译报错?

    因为DisplayMembers为普通的成员函数,故DisplayMembers成员函数中隐藏的this指针,会被编译器设置为CSomeClass* this。而mData是被const修饰的,mData.DisplayMembers ( ) ;即是DisplayMembers ( &mData); 这样,实参和形参类型不一致,编译器会报错。

    如何修改这一问题?

    ①把函数列表上mData前的const去掉。

    这样,使代码的安全性降低,其后的代码可能会修改mData中的值。

    ②在成员函数DisplayMembers前添上const。

    这样固然最好,但是如果CSomeClass是第三方的类,我们没有其源代码,那怎么办?

    ③使用const_cast把mData上的const锁暂时去掉。

    void DisplayAllData( const CSomeClass& mData )  
    {  
        CSomeClass& refData = const_cast< CSomeClass &>(mData) ;  
        refData.DisplayMembers ( ) ;   
    }  

    另外:const_cast也可用于指针

    void DisplayAllData( const CSomeClass* pData )  
    {  
        CSomeClass*  pCastedData = const_cast< CSomeClass *>( pData) ;  
        pCastedData ->DisplayMembers ( ) ;   
    } 

    C++类型转换符存在的问题:

    static_cast的用途可用C风格类型转换进行处理,且更简单。

    例:

    double dPi = 3.14 ;  
    int num1 = static_cast<int>(dPi) ;  
    int num2 = (int)dPi ;  
      
    CDerived* pDerived1 = static_cast<CDerived*>(pBase) ;  
    CDerived* pDerived2 = (CDerived*)pBase ;  

    故,Bjarne Stroustrup说:“由于static_cast如此拙劣且难以输入,因此您在使用它之前很可能会三思。这很不错,因为类型转换在现代C++中是最容易避免的。”

    因此,在现代C++中,除dynamic_cast外的类型转换都是可以避免的。

    仅当需要满足遗留应用程序需求时,才需要使用其它类型转换运算符。在这种情况下,程序员通常倾向于使用C风格类型转换而不是使用C++类型转换运算符。

    重要的是,应尽量避免使用类型转换,而一旦使用类型转换,务必要知道幕后发生的情况。

    关于隐式转换:

    例:

    复制代码
    #include <iostream>  
      
    using namespace std ;  
      
    class A  
    {  
        int m_nA ;  
    };  
    class B  
    {  
        int m_nB;  
    };  
    class C : public A, public B  
    {  
        int m_nC;  
    };  
      
    int main(void)  
    {  
        C* pC = new C ;  
        B* pB = dynamic_cast<B*>(pC) ;  
        A* pA = dynamic_cast<A*>(pC) ;  
           
        if ( pC==pB )  
            cout << “equal” << endl ;  
        else  
            cout << “not equal” << endl ;  
      
        if ( (int)pC == (int)pB )  
            cout << “equal” <<endl ;  
        else  
            cout << “not equal” << endl ;  
      
        return 0 ;  
    }  
    //程序输出如下:  
    //equal  
    //not equal  
    复制代码

    if ( pC == pB )这里两端数据类型不同,比较时需要进行隐式类型转换。( pC == pB )相当于:pC == (C*)pB ;

    pB实际上指向的地址是对象C中的子类B的部分,从地址上跟pC不一样,所以直接比较地址数值的时候是不相同的。故 (int)pC 与(int)pB 不同。

    但是:(C*)pB相当于static_cast<C*>(pB)

    它们计算了父子类指针转换的偏移量,并将之转换到正确的地址(c里面有m_a,m_b,转换为B*指针后指到m_b处)

    [请参考这里——C++对象模型简介]

    【在C++中,涉及相关指针的强制类型转换,并不是不改变指针值,有时(涉及多重继承时)会根据需要改变底层值。reinterpret_cast才是只改变解释方式,不改变底层值。】

    【注意】C++中的隐式类型转换的方式和static_cast的转换行为类似。(只是static_cast对于不相关指针的转换无能为力)

  • 相关阅读:
    Oracle第三方ado.net数据提供程序
    HTML5实战 文摘 第二章 HTML5用于创建表单的输入小部件 数据绑定以及数据验证
    reactjs & antd & redux 使用心得
    HTML5实战 文摘 第一章 从文档到应用的转变
    css的高级选择器
    <!DOCTYPE html> 是什么,它的作用是什么
    Nginx调优
    java enum 枚举简单用法
    简谈java解析HTML(org.jsoup.nodes.Document)
    jquery EasyUI tree 加载远程数据 java实现
  • 原文地址:https://www.cnblogs.com/xiangtingshen/p/11064315.html
Copyright © 2020-2023  润新知