1. 程式人生 > >C++ 型別轉換(Casting Operators)

C++ 型別轉換(Casting Operators)

   在C++中,經常會涉及到型別轉換,雖說一般情況下不建議型別轉換,但有時候還是避免不了。轉換的時候,可能一般都直接使用C語言風格的轉換(直接強制轉換),但這樣做可能很不安全,容易造成資料丟失(如int-> char),記憶體訪問違規。

   下面講一講C++的幾個轉換操作符,常見的有這麼幾個:static_cast, dynamic_cast, const_cast,reinterpret_cast。這裡所講的幾乎都是參考MSDN,地址如下:

   ms-help://MS.MSDNQTR.v90.chs/dv_vclang/html/16240348-26bc-4f77-8eab-57253f00ce52.htm

1、static_cast

    語法形式:

   static_cast <type-id> ( expression)

   該操作符把expression轉換成type-id的型別,這裡面沒有型別檢查,所以它的安全性不能得到保證。

   1,static_cast可以用於轉換基類指標到派生類指標,進行上行轉換(把子類的指標或引用轉換成基類指標)是安全,進行下行轉換(基類指標或引用轉成子類指標)是不安全的。

   2,用於基本資料型別之間的轉換,如把int轉成char,int轉成enum,這種轉換的安全性只能由開發人員來保證,因為int轉char可能會導致資料丟失,從而造成邏輯錯誤。

   3,static_cast可以轉換空指標到目標型別的空指標。

   4,static_cast可以把任何型別轉換成void型別,目標型別可以包含const,volatile,或__unaligned屬性。

   5,static_cast不能轉換掉const,volatile,或__unaligned屬性。

   6,如果要用來轉換類指標,如果類A與類B之間沒有任何關係,那麼會報編譯錯誤。

2、dynamic_cast

    語法形式:

   dynamic_cast <type-id> ( expression)

   把expression轉換成type-id型別,type-id必須是一個類的指標、類的引用或者void*,如果type-id是一個指標,那麼expression必須是一個指標,如果type-id是引用,那麼expression必須是一個引用。

   dynamic_cast主要用於類層次之間的上行轉換和下行轉換,還可以用於類之間的交叉轉換(Cross)。

   dynamic_cast必須用於有繼承關係的類之間,如果兩個類指標之間沒有任何關係,則會報編譯錯誤。

    在VisualC++ 2005中,當type-id不是所轉型別的指標的話,dynamic_cast不會再拋異常,它會返回0。

   在類層次之間進行上行轉換時,dynamic_cast和static_cast的效果是一樣的,但在進行下行轉換時,dynamic_cast具有型別檢查功能,比static_cast更安全。(如果基類指標根本就不是指向子類,dynamic_cast返回NULL,而static_cast照樣能轉換成功,此時是不安全的)。

   我們一起來看一下下面這段程式碼:

    //dynamic_cast_1.cpp
    // compilewith: /c
    class B {};
    class C :public B { };
    class D :public C { };

    void f(D*pd) {
     C* pc =dynamic_cast<C*>(pd);  // ok: C is a direct base class
                                  // pc points to C subobject of pd
      B* pb =dynamic_cast<B*>(pd);  // ok: B is an indirect base class
                                  // pb points to B subobject of pd
    }

    voidfunc(B *pb){
       D *pd1 =static_cast<D *>(pb);
       D *pd2 =dynamic_cast<D *>(pb);
    }

   在上面的程式碼中,如果pb指向一個D型別的物件,pd1和pd2是一樣的,並且對這兩個指標執行D型別的任何操作都是安全的,但是,如果pb指向的是一個B型別的物件,那麼static_cast也能轉換成功,那麼用pd1(D型別)去訪問D型別的一些方法時,可能就會出異常,而對於dynicma_cast,它就會返回一個NULL,表示轉換不成功,注意了,這個函式是有效能開銷的,因為它要進行型別檢查等操作。

   另外,對於dynamic_cast,B型別需要有虛擬函式,否則編譯要出錯(這種情況必須是下行轉換,即從上向下轉換),因為dynamic_cast會進行執行時型別檢查,而這個資訊儲存在類的虛擬函式表中,只有定義了虛擬函式的類才會有虛擬函式表,沒有定義虛數的類是沒有虛擬函式表的,所以編譯就會出錯,而對於static_cast則沒有限制,因為它不進行執行時型別檢查。

   dynamic_cast還支援交叉轉換:

    classA
    {
   public:
    intm_iNum;
    virtual voidf(){}
    };

    classB:public A{};
    classD:public A{};
 
    voidfoo()
    {
       B *pb = newB;
      pb->m_iNum = 100;
       D *pd1 =static_cast<D *>(pb); //copileerror
       D *pd2 =dynamic_cast<D *>(pb); //pd2 isNULL
       deletepb;
    }

   在函式foo中,使用static_cast進行轉換是不被允許的,將在編譯時出錯;而使用dynamic_cast的轉換則是允許的,結果是空指標。

3、const_cast

    語法形式:

   const_cast <type-id> ( expression)

   該運算子用來修改型別的constg或volatile屬性。除了const或volatile修飾之外,type-id和expression的型別是一樣的。

   這個用得最多的就是常量指標轉換成非常量指標,常量引用轉換成非常量引用,並且仍是指向原來物件或仍是原來物件的引用。

    舉個例子:

    classB
    {
      public:
       intm_iNum;
    }
    voidfoo()
    {
       const Bb1;
       b1.m_iNum =100; //comile error
       B b2 =const_cast<B>(b1);
       b2. m_iNum =200; //fine
    }

   上面的程式碼編譯時會報錯,因為b1是一個常量物件,不能對它進行改變;使用const_cast把它轉換成一個常量物件,就可以對它的資料成員任意改變。注意:b1和b2是兩個不同的物件。

4、reinterpret_cast

    語法形式:

   reinterpret_cast <type-id> (expression )

   type-id必須是一個指標、引用、算術型別、函式指標或者成員指標。它可以將char* 轉成int*,類A的指標轉成類B的指標,這樣的轉換是不安全的。reinperpre_cast不能去掉const,volatile或__unaligned屬性。它可以將一個NULL指標轉換成目標型別的NULL指標。

 

   //expre_reinterpret_cast_Operator.cpp
    // compilewith: /EHsc
    #include<iostream>

    // Returns ahash code based on an address
    unsignedshort Hash( void *p ) {
      unsigned intval = reinterpret_cast<unsigned int>(p );
      return (unsigned short )( val ^ (val >>16));
    }

    usingnamespace std;
    int main(){
      inta[20];
      for ( int i= 0; i < 20; i++ )
         cout<< Hash( a + i )<< endl;
    }

相關推薦

C++ 型別轉換Casting Operators

   在C++中,經常會涉及到型別轉換,雖說一般情況下不建議型別轉換,但有時候還是避免不了。轉換的時候,可能一般都直接使用C語言風格的轉換(直接強制轉換),但這樣做可能很不安全,容易造成資料丟失(如int-> char),記憶體訪問違規。    下面講一講C++的幾個

java資料型別型別轉換必須清楚

資料型別分類: 主要分為 基本型別、引用型別兩大類;   基本型別 轉換原則  型別轉換主要在在 賦值、方法呼叫、算術運算 三種情況下發生。  另外還有是直接數的賦值:先通過直接數判斷其型別,然後基本原則和上面談到的賦值

JS幾種資料型別轉換最全

一、轉為字串:使用 .toString或者String。 1、 .toString()方法:注意,不可以轉null和underfined //轉為字串-->toString方法 var bool=true; console.log(bool.toString()); //注意,toSt

go學習筆記-型別轉換Type Conversion

型別轉換(Type Conversion) 型別轉換用於將一種資料型別的變數轉換為另外一種型別的變,基本格式 type_name(expression) type_name 為型別,expression 為表示式。 示例 func testCov() { var a = 20 var

Struts2學習筆記十二 型別轉換Type Conversion

null引用處理 我們知道,我們在Action中定義屬性時並沒有對他們進行初始化,那麼也就是Struts2在對請求引數進行型別轉換時,我們的Action屬性可能還是null。那麼框架會自動將這些null的屬性例項化一個預設的物件(在學習Parameters攔截器時已經看過原

C++的型別轉換Type Casting

C++的型別轉換包括了兩類,隱式轉換和顯式轉換。 隱式轉換常見於兩種情況,一種是基礎型別運算時,自動從低精度型別向高精度型別轉換,如char轉int、int轉double等。 int a = 100; double b = a / 4.0; 另一種情況是物件之間賦值,

強制型別轉換C++學習筆記 13

無論是強制轉換或是自動轉換,都只是為了本次運算的需要而對變數的資料長度進行臨時性轉換,這並不改變該變數的型別。 一、 C語言中強制型別轉換的一般形式為: (資料型別)表示式 例1: 求x與2進行取餘運算。 (int) x % 2 因為取餘運算的運算元必須是整數,如果x是實數

C++字元型別轉換BSTR、_bstr_t、CString、char *、LPCTSTR轉換

1、CString轉BSTR BSTR bstr; CString strSql;  bstr = strSql.AllocSysString(); …  SysFreeString(bstrText); // 用完釋放&

C++強制型別轉換dynamic_cast,static_cast, const_cast, reinterpret_cast

[toc] C++同時提供了4種新的強制型別轉換形式(通常稱為新風格的或C++風格的強制轉 型):const_cast(expression)、dynamic_cast(expression)、 reinterpret_cast(expression)和 st

C++字串的型別轉換std::string, std::wstring, c-string

一、std::string與std::wstring共有篇(c++11新添) 1)string(wstring) to numerical value | string(wstring)轉化成數值

類的自動轉化和強制型別轉換C++

可以將類定義成與基本型別或另一個類相關,使得從一種型別轉換為另一種型別是有意義的。 當一個類的建構函式中,有隻有接受一個引數的建構函式,這個建構函式就能作為轉換函式。 #pragma once #ifndef STONEWT_H_ #define STONEWT

C++字元型別轉換BSTR、_bstr_t與CString、char *轉換

1、CString轉BSTR BSTR bstr; CString strSql;  bstr = strSql.AllocSysString(); …  SysFreeString(bstrText

LBS——座標型別轉換C#

座標型別轉換 座標轉化 座標模型 WGS84座標系:即地球座標系,國際上通用的座標系。裝置一般包含GPS晶片或者北斗晶片獲取的經緯度為WGS84地理座標系,谷歌地圖採用的是WGS84地理座標系(中國範圍除外); GCJ02座標系:即火星座標系,是

[C++] 過載運算子與型別轉換2——函式呼叫運算子和型別轉換運算子

1、這兩個應該是C++中比較高階的用法了。 一、函式呼叫運算子   1、過載函式呼叫運算子(),必須是成員函式,一個類可以定義多個不同版本的呼叫運算子,相互之間應該在引數數量或者型別上有所區別。   2、定義了呼叫運算子的類的物件稱作 函式物件;函式

15 More Effectic C++ ——條款21/22過載防止隱式型別轉換/使用複合操作符

1 看不見的隱式型別轉換 當建構函式只有一個,編譯器會利用建構函式進行隱式型別轉換。如下面所示: class UInt { public: UInt(); UInt(int value); } UInt a = 0, b(0), c = 1; // 隱式轉換:int變成UI

Swift-型別轉換Type Casting十七

前言 型別轉換 可以判斷例項的型別,也可以將例項看作是父類或者子類的例項。 型別轉換 在 Swift 中使用 is 和 as 操作符實現,當然也包括後面加歎號 ! 的強制展開和後面加問號 ? 的可選型別。這兩個操作符提供了一種簡單達意的方式去檢查值的型別或是

C#基礎資料型別與位元組陣列記憶體中的資料格式相互轉換BitConverter 類

在某種通訊協議中(如 Modbus),可能需要把一些基本的資料型別記憶體中的表示形式轉換成以位元組陣列的形式,方便傳送。C/C++中可以利用指標等操作完成,但C#中沒有指標,咋辦呢?可以用BitConverter類啊。 1,把double型別轉換成byte陣列,float型別的話,在1234.5678後加

C#/.NET整數的三種強制型別轉換int、Convert.ToInt32、int.Parse()的區別總結

1.(int) 適合簡單資料型別之間的轉換,C#的預設整型是int32(不支援bool型)。 2. int.Parse(string sParameter) 是個建構函式,引數型別只支援string型別,Parse就是把String型別轉換成int,char,doubl

[C++]隱式類型別轉換

C++ primer 中有這麼一句話:可以用單個實參來呼叫的建構函式定義了從形參型別到該型別的一個隱式轉換。 這麼解釋: 比如有個類A的物件a的成員函式的引數應該是類A的物件,但是把一個別的型別B的物件b傳進去了,而且這個物件b的型別恰好是A的單引數建構函式

Java種的基本資料型別轉換自動、強制、提升

Java種的8大基本資料型別,以及它們所佔記憶體大小和範圍 1、自動型別轉換 自動型別轉換是指:數字表示範圍小的資料型別可以自動轉換成範圍大的資料型別。 如: long l = 100; int i = 200; long ll = i; 具體自動轉換如如下圖所示: