zoukankan      html  css  js  c++  java
  • reinterpret

    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对于不相关指针的转换无能为力)

  • 相关阅读:
    POJ 1953 World Cup Noise
    POJ 1995 Raising Modulo Numbers (快速幂取余)
    poj 1256 Anagram
    POJ 1218 THE DRUNK JAILER
    POJ 1316 Self Numbers
    POJ 1663 Number Steps
    POJ 1664 放苹果
    如何查看DIV被设置什么CSS样式
    独行DIV自适应宽度布局CSS实例与扩大应用范围
    python 从入门到精通教程一:[1]Hello,world!
  • 原文地址:https://www.cnblogs.com/wangsicongde/p/7599288.html
Copyright © 2011-2022 走看看