C++中static_cast和dynamic_cast強制類型轉換

來源:互聯網
上載者:User

標籤:指標   space   括弧   簡單   dynamic   rtt   返回   運算   繼承   

在C++標準中,提供了關於類型層次轉換中的兩個關鍵字static_cast和dynamic_cast。

一、static_cast關鍵字(編譯時間類型檢查)

用法:static_cast < type-id > ( expression ),該運算子把expression轉換為type-id類型,但沒有運行時類型檢查來保證轉換的安全性,它主要有如下幾種用法:

(1)用於基礎資料型別 (Elementary Data Type)之間的轉換,如把int轉換為char,把int轉換成enum,但這種轉換的安全性需要開發人員自己保證(這可以理解為保證資料的精度,即程式員能不能保證自己想要的程式安全),如在把int轉換為char時,如果char沒有足夠的位元位來存放int的值(int>127或int<-127時),那麼static_cast所做的只是簡單的截斷,及簡單地把int的低8位複製到char的8位中,並直接拋棄高位。

(2)把null 指標轉換成目標類型的null 指標

(3)把任何類型的運算式類型轉換成void類型

(4)用於類階層中父類和子類之間指標和引用的轉換。

對於以上第(4)點,存在兩種形式的轉換,即上行轉換(子類到父類)和下行轉換(父類到子類)。對於static_cast,上行轉換時安全的,而下行轉換時不安全的,為什麼呢?因為static_cast的轉換時粗暴的,它僅根據類型轉換語句中提供的資訊(角括弧中的類型)來進行轉換,這種轉換方式對於上行轉換,由於子類總是包含父類的所有資料成員和函數成員,因此從子類轉換到父類的指標對象可以沒有任何顧慮的訪問其(指父類)的成員。而對於下行轉換為什麼不安全,是因為static_cast只是在編譯時間進行類型堅持,沒有運行時的類型檢查,具體原理在dynamic_cast中說明。

二、dynamic_cast關鍵字(運行時類型檢查)

(作為四個內部類型轉換操作符之一的dynamic_cast和傳統的C風格的強制類型轉換有著巨大的差別。除了dynamic_cast以外的轉換,其行為的都是在編譯期就得以確定的,轉換是否成功,並不依賴被轉換的對象。而dynamic_cast則不然。在這裡,不再討論其他三種轉換和C風格的轉換。
首先,dynamic_cast依賴於RTTI資訊,其次,在轉換時,dynamic_cast會檢查轉換的source對象是否真的可以轉換成target類型,這種檢查不是文法上的,而是真實情況的檢查。
先看RTTI相關部分,通常,許多編譯器都是通過vtable找到對象的RTTI資訊的,這也就意味著,如果基類沒有虛方法,也就無法判斷一個基類指標變數所指對象的真實類型, 這時候,dynamic_cast只能用來做安全的轉換,例如從衍生類別指標轉換成基類指標.而這種轉換其實並不需要dynamic_cast參與.
也就是說,dynamic_cast是根據RTTI記載的資訊來判斷類型轉換是否合法的.)

用法:同static_cast

dynamic_cast主要用於類階層中父類和子類之間指標和引用的轉換,由於具有運行時類型檢查,因此可以保證下行轉換的安全性,何為安全性?即轉換成功就返迴轉換後的正確類型指標,如果轉換失敗,則返回NULL,之所以說static_cast在下行轉換時不安全,是因為即使轉換失敗,它也不返回NULL。

對於上行轉換,dynamic_cast和static_cast是一樣的。

對於下行轉換,說到下行轉換,有一點需要瞭解的是在C++中,一般是可以用父類指標指向一個子類對象,如parent* P1 = new Children(); 但這個指標只能訪問父類定義的資料成員和函數,這是C++中的靜態聯翩,但一般不定義指向父類對象的子類類型指標,如Children* P1 = new parent;這種定義方法不符合生活習慣,在程式設計上也很麻煩。這就解釋了也說明了,在上行轉換中,static_cast和dynamic_cast效果是一樣的,而且都比較安全,因為向上轉換的對象一般是指向子類對象的子類類型指標;而在下行轉換中,由於可以定義就不同了指向子類對象的父類類型指標,同時static_cast只在編譯時間進行類型檢查,而dynamic_cast是運行時類型檢查,則需要視情況而定。下面通過代碼進行說明

class Base{    virtual void fun(){}};class Derived:public Base{};

由於需要進行向下轉換,因此需要定義一個父類類型的指標Base *P,但是由於子類繼承與父類,父類指標可以指向父類對象,也可以指向子類對象,這就是重點所在。如果 P指向的確實是子類對象,則dynamic_cast和static_cast都可以轉換成功,如下所示:

Base *P = new Derived();Derived *pd1 = static_cast<Derived *>(P);Derived *pd2 = dynamic_cast<Derived *>(P);

以上轉換都能成功。

 

但是,如果 P 指向的不是子類對象,而是父類對象,如下所示:

Base *P = new Base;Derived *pd3 = static_cast<Derived *>(P);Derived *pd4 = dynamic_cast<Derived *>(P);

在以上轉換中,static_cast轉換在編譯時間不會報錯,也可以返回一個子類對象指標(假想),但是這樣是不安全的,在運行時可能會有問題,因為子類中包含父類中沒有的資料和函數成員,這裡需要理解轉換的字面意思,轉換是什嗎?轉換就是把對象從一種類型轉換到另一種類型,如果這時用 pd3 去訪問子類中有但父類中沒有的成員,就會出現訪問越界的錯誤,導致程式崩潰。而dynamic_cast由於具有運行時類型檢查功能,它能檢查P的類型,由於上述轉換是不合理的,所以它返回NULL。

 

三、總結

C++中層次類型轉換中無非兩種:上行轉換和下行轉換

對於上行轉換,static_cast和dynamic_cast效果一樣,都安全;

對於下行轉換:你必須確定要轉換的資料確實是目標類型的資料,即需要注意要轉換的父類類型指標是否真的指向子類對象,如果是,static_cast和dynamic_cast都能成功;如果不是static_cast能返回,但是不安全,可能會出現訪問越界錯誤,而dynamic_cast在運行時類型檢查過程中,判定該過程不能轉換,返回NULL。

註:

虛函數對於dynamic_cast轉換的作用

  為何使用dynamic_cast轉換類指標時,需要虛函數呢。

Dynamic_cast轉換是在運行時進行轉換,運行時轉換就需要知道類對象的資訊(繼承關係等)。

如何在運行時擷取到這個資訊——虛函數表。

  C++物件模型中,對象執行個體最前面的就是虛函數表指標,

通過這個指標可以擷取到該類對象的所有虛函數,包括父類的。

因為衍生類別會繼承基類的虛函數表,所以通過這個虛函數表,我們就可以知道該類對象的父類,在轉換的時候就可以用來判斷對象有無繼承關係。

  所以虛函數對於正確的基類指標轉換為子類指標是非常重要的。

C++中static_cast和dynamic_cast強制類型轉換

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.