C++ 四種顯式類型轉換

顯式類型轉換

reinterpret_cast<new_type>(EXPression)顯式轉換
const_cast<new_type>(EXPression)      顯式轉換
static_cast<new_type>(EXPression)     顯式轉換
dynamic_cast<new_type>(EXPression)    顯式轉換
功能: 將EXPression表達式的值轉換爲 new_type類型的值。
1 前三種類型的轉換是在編譯時期 實現轉換的,
    最後一個是在運行時期 進行類型轉換的,而且返回轉換成功與否標誌,這是傳統的類型轉換所不具有的功能


double   d=3.2;
int i= d; //隱式轉換double變量d 爲int 變量, i=3
假若使用C++顯式類型轉換 static_cast(exp)函數作以上一樣的事,就可讓他人知道這樣的double 到 int 類型的轉換,是有意這麼作的,
並不是疏忽大意所致。

double   d=3.2;
int i = static_cast<int>(d);//顯式轉換

A reinterpret_cast 類型轉換函數將一個類型的指針,轉換爲另外一個類型的指針。這種轉換不用改變指針變量值數據存放格式(不改變指針變量值),只需在編譯時從新解釋指針的類型就能夠作到。reinterpret_cast 能夠將指針轉換爲一個整形數(隱式轉換),但不能用於非指針類型的轉換,即便這樣作也不會經過編譯
    1> 用顯式的reinterpret_cast 將基本類型或一個類的指針,轉換爲另外一個類型或類的指針
        //基本類型指針的類型轉換
        double d=9.3;
        double* pd = &d;
        int *pi = reinterpret_cast<int* >(pd); //至關於隱式轉換 int* pi  = (int* )pd;        
    2>
        //不相關的類的指針的類型轉換
        class A{}; class B{};
        A* pa = new A;
        B* pb = reinterpret_cast<B* >(pa); // 至關於隱式轉換 B* pb = (B*)pa;

    3>    指針轉換爲整數
        long j = reinterpret_cast<long>(pi); //至關於隱式轉換 long j = (long)pi;

    4>    嘗試將int 類型的變量轉換爲double 類型,因爲並不是指針類型轉換,所以轉換不成功.
        //企圖轉換非指針變量
        int i=8;
        double dl = reinterpret_cast<double>(i); //不能編譯經過
        //企圖轉換 const 指針爲 void * 指針
        const int*  pci - 0;
        void*  pv = reinterpret_cast<void* >(pci); //不能編譯經過
        
B  const_cast 類型轉換函數用於去除指針變量的常量屬性,將它轉換爲一個對應指針類型的普通變量。反過來,也能夠將一個很是量的指針變量轉換爲一個常指針變量。這種轉換是在編譯期間作出的類型更改。
    1> 將int 類型的常指針便利pci 轉換爲int 指針變量,將類A的常指針便利pca 轉換爲類A的普通指針變量,將類A的常指針變量pca轉換爲類A的普通指針變量
        const int* pci = 0;
        int *pj =  const_cast<int* >(pci); //至關於隱式轉換 int * pj  = (int* )pci;
        const A* pca = new A;
        A *pa  = const_cast<A*>(pca);      //至關於隱式轉換 A* pa  = (A*)pca;
    2> 基於安全考慮,const_cast 沒法將非指針的常變量轉換爲普通變量
        const int i = 0;
        const_cast<int>(i); //去除變量i的常屬性,不能編譯經過
    3>將普通指針變量pi 轉換爲常指針變量,但不能將非指針的普通變量轉換爲常變量。而隱式轉換則容許
        int * pi = 0;  //至關於隱式轉換 const int* pcj = (int*)pi;
        const int* pcj = const_cast<const int* >(pi);
        
        int i =0;
        const int cj = const_cast<const int>(i); //非指針轉換,不能編譯經過
        const int ck = (const int)i; // 隱式轉換, 可經過編譯
        該運算符用來修改類型的const或volatile屬性。除了const 或volatile修飾以外, type_id和expression的類型是同樣的。
    常量指針被轉化成很是量指針,而且仍然指向原來的對象;
    常量引用被轉換成很是量引用,而且仍然指向原來的對象;常量對象被轉換成很是量對象。
    volatile和const類型,舉例以下所示。
    class B
    {
    public:    
        int m_iNum;    
    }
    void foo()
    {
        const B b1;    
        b1.m_iNum = 100; //comile error    
        B b2 = const_cast<B>(b1);    
        b2. m_iNum = 200; //fine    
    }
上面的代碼編譯時會報錯,由於b1是一個常量對象,不能對它進行改變;
使用const_cast把它轉換成一個很是量對象,就能夠對它的數據成員任意改變。注意:b1和b2是兩個不一樣的對象。

C  static_cast 主要用於基本類型之間  和具備繼承關係的類型之間的轉換,這種轉換通常會更改變量的內部表示方式,所以static_cast應用於指針類型轉換,沒有太大意義,即便容許指針類型轉換,也不及reinterpret_cast解釋效率高
static_cast類型轉換用於相關類型之間的轉換,諸如:在同一個類的繼承層次關係中,向上或向下轉換;枚舉類型與整數類型之間的轉換;浮點類型與指數類型之間的轉換。在這4中類型轉換中,static_cast是最接近C-style的了。html

該運算符把expression轉換爲type-id類型,但沒有運行時類型檢查來保證轉換的安全性。它主要有以下幾種用法:
    (1)用於類層次結構中基類和派生類之間指針或引用的轉換
    進行上行轉換(把派生類的指針或引用轉換成基類表示)是安全的
    進行下行轉換(把基類的指針或引用轉換爲派生類表示),因爲沒有動態類型檢查,因此是不安全的
    (2)用於基本數據類型之間的轉換,如把int轉換成char。這種轉換的安全也要開發人員來保證
    (3)把空指針轉換成目標類型的空指針
    (4)把任何類型的表達式轉換爲void類型
    注意:static_cast不能轉換掉expression的const、volitale或者__unaligned屬性。
c++

        1> // 基本類型轉換
            int i=0;
            double d = static_cast<double>(i);  //至關於隱式轉換 double d =(double)i;
            int j = static_cast<int>(d);        //至關於隱式轉換 int j = (int)d;
        2> //轉換繼承類的對象爲基類對象
            class Base{};
            class Derived : public Base{};
            Derived d;
            Base b = static_cast<Base >(d);   //至關於隱式轉換 Base b = (Base)d;
        3>  以下將繼承類與基類的指針進行相互轉換,都能編譯經過,但基類指針轉換爲繼承類指針,具備必定的危害性.
            // 繼承類指針 轉換爲基類指針
            Derived* pd = new Derived;
            Base* pb = static_cast<Base* >(pd); //至關於隱式轉換 Base* pb = (Derived*)pd;
            // 基類指針轉換爲繼承類指針
            Base* pb = new Base;
            Derived* pd = static_cast<Derived* >(pb); //至關於隱式轉換 Derived* pd = (Dervived*)pb;
        4>  如下代碼嘗試用static_cast 轉換基本數據類型的指針,將繼承類對象轉換爲基類對象或  轉換無繼承關係的類的指針,都不能編譯經過.
            class A{};
            class B{};
            int *pi = 0;
            double *pd = static_cast<double* >(pi); //企圖int*  轉換爲 double* ,  不能編譯經過
            //
            Base b;
            Derived d = static_cast<Derived>(b); //企圖繼承類對象轉換爲基類對象,不能編譯經過

            //
            A a;
            B b = static_cast<B>(a);   //企圖轉換無繼承關係的類, 不能編譯經過
            
            A * pa = NULL;
            B* pb =  static_cast<B*>(pa); // 企圖轉換無繼承關係的類的指針,不能編譯經過

        
D dynamic_cast 與 靜態static_cast 相對, 是動態的轉換。這種轉換是在運行時進行轉換分析的,並不是在編譯時期進行。
    dynamic_cast 只能在繼承類對象的指針之間 或 引用之間 進行類型轉換進行轉換時,會根據當前運行對象的運行時類型信息(RTTI),判斷類型對象之間的轉換是否合法。dynamic_cast的指針轉換失敗,可經過是否爲NULL指針檢測;  引用轉換失敗,則拋出一個bad_cast異常。express

  用法:dynamic_cast<type_id> (expression)
    該運算符把expression轉換成type_id類型的對象。type_id必須是類的指針、引用或者void*;
    若是type_id是類指針類型,那麼expression也必須是一個指針,若是type_id是一個引用,那麼expression也必須是一個引用。
    dynamic_cast主要用於類層次間的上行轉換和下行轉換,還能夠用於類之間的交叉轉換。
    在類層次間進行上行轉換時,dynamic_cast和static_cast的效果是同樣的;
    在進行下行轉換時,dynamic_cast具備類型檢查的功能,比static_cast更安全。
安全

        1> dynamic_cast 將繼承類指針或引用轉換爲  基類指針或引用, 並對沒有繼承關係, 但被轉換的類具備虛函數的對象指針進行轉換,都可編譯經過。
            class Base{};
            class Derived: public Base{};
            //繼承類指針轉換爲基類指針
            Derived* pd = new Derived();
            Base* pb = dynamic_cast<Base* >(pd);
            if(!pb)
                printf("dynamic_cast 類型轉換失敗\n");    
            else
                printf("dynamic_cast 類型轉換成功\n");    
            //有繼承關係的引用之間轉換
            Derived d;
            Base& b = dynamic_cast<Base& >(d);
            
            //沒有繼承關係,但被轉換的類有虛函數
            class A {virtual ~A(){}}; // 有虛函數
            class B{};
            A* pa = new A;
            B* pb = dynamic_cast<B* >(pa); //有虛函數的對象指針,能夠轉換
            if(!pb)
                printf("dynamic_cast 類型轉換失敗\n");    
            else
                printf("dynamic_cast 類型轉換成功\n");        
        2> 以下代碼嘗試將非指針的繼承對象轉換爲 基類對象, 對無繼承關係(且沒有虛函數)的對象指針進行轉換, 基本類型指針轉換  以及基類指針轉換爲繼承類指針,均不能編譯經過
            class A{};  //沒有虛函數
            class B{virtual ~B(){}};
            //繼承類轉換爲基類對象, 不能編譯經過
            Derived d;
            Base b = dynamic_cast<Base>(d);
            
            //無繼承關係,且A 無虛函數, A類對象指針轉換, 不能編譯經過
            A* pa = new A;
            B* pb = dynamic_cast<B* >(pa);
            
            // 基本類型之間轉換(無繼承關係), 不能經過
            int* i=0;
            int  j = dynamic_cast<int* >(i);

            //基類指針轉換爲繼承類指針, 不能編譯經過
            Base*   pb = new Base;
            Derived *pd = dynamic_cast<Derived* >(pb);

        3> dynamic_cast 不僅是應用於類型轉換,一般利用它作運行時對象類型檢查的特性,在程序中檢測當前內存對象的類型信息。ide

class B
{
public:
   int m_iNum;
    virtual void foo();
};
class D:public B
{
  public:
    char *m_szName[100];
};
void func(B *pb)
{
    D *pd1 = static_cast<D *>(pb);
    D *pd2 = dynamic_cast<D *>(pb);
}
在上面的代碼段中,若是pb指向一個D類型的對象,pd1和pd2是同樣的,而且對這兩個指針執行D類型的任何操做都是安全的;
    可是,若是pb指向的是一個B類型的對象,那麼pd1將是一個指向該對象的指針,對它進行D類型的操做將是不安全的(如訪問m_szName),
    而pd2將是一個空指針。
    另外要注意:B要有虛函數,不然會編譯出錯;static_cast則沒有這個限制。
    這是因爲運行時類型檢查須要運行時類型信息,而這個信息存儲在類的虛函數表(
    關於虛函數表的概念,詳細可見<Inside c++ object model>)中,只有定義了虛函數的類纔有虛函數表,
    沒有定義虛函數的類是沒有虛函數表的。函數

另外,dynamic_cast還支持交叉轉換,以下所示。
    class A
    {
    public:
        int m_iNum;
        virtual void f(){}
    };
    class B:public A
    {
        
    };
    class D:public A
    {
        
    };
    void foo()
    {    
        B *pb = new B;    
        pb->m_iNum = 100;    
        D *pd1 = static_cast<D *>(pb); //compile error    
        D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL    
        delete pb;    
    }
    在函數foo中,使用static_cast進行轉換是不被容許的,將在編譯時出錯,而使用dynamic_cast轉換則是容許的,結果是空指針。
    zongjiegoogle

在寫代碼中常常會有不少的隱式類型轉換或顯式類型轉換。spa

對於隱式的類型轉換主要是放生在賦值的時候,講變量賦值給不一樣類型的變量的時候就會發生類型轉換,若是是寬化轉換(即從佔字節少的類型向佔字節多的 類型轉換),這個時候是不會出現丟失數據的。若是是窄化轉換(從佔字節多的類型向佔字節少的類型轉換),這個時候就頗有可能會出現丟失數據,或者數據錯誤 (如從有符號向無符號轉換,就可能會出現各類沒法想象的問題)。。。因此這種狀況應該儘可能避免。.net

對於C風格顯式轉換,就是強制轉換,可能會形成數據解釋錯誤,也是很不安全的。指針

在C++中有四種類型轉換:

static_cast <new_type> (expression) 靜態轉換

靜態轉換相似於C風格顯式轉換,可是會判斷轉換類型之間的關係,若是轉換類型之間沒有任何關係,則不可轉換,編譯器會報錯。(不相關類型之間不能夠發生轉換).

dynamic_cast <new_type> (expression) 動態轉換

動態轉換有兩個約束條件:其一是要求new_type爲指針或引用,其二是下行轉換時要求基類是多態的(基類中包含至少一個虛函數)。

動態轉換支持上行轉換和下行轉換,可是對於不安全的下行轉換,會返回NULL,提升安全性(上行轉換:子類轉化爲父類,下行轉換:父類轉化爲子類)。

reinterpret_cast <new_type> (expression) 重解釋轉換

重解釋轉換則是任何兩個類型之間均可以轉換,是最不安全的一種類型轉換,儘可能不要用。

const_cast <new_type> (expression) 常量向很是量轉換

將常量轉換爲很是量,這個轉換並不轉換原常量自己,只是它返回的結果爲很是量了

http://blog.csdn.net/coding_hello/article/details/2211466

http://www.xuebuyuan.com/1554696.html

http://www.2cto.com/kf/201411/353737.html

http://blog.csdn.net/thesys/article/details/5651713https://www.google.com.hk/search?q=ttp://blog.csdn.net/pongba/archive/2004/09/01/90642.aspx&ie=utf-8&oe=utf-8&gws_rd=cr&ei=tWTLVM7UJMTU8gXN5IGwBAhttp://blog.csdn.net/pongba/article/details/90642http://blog.csdn.net/pongba/article/details/2544894http://blog.csdn.net/pongba/article/list/2http://blog.csdn.net/pongba/article/list/2http://blog.csdn.net/pongba/article/list/2

相關文章
相關標籤/搜索