C++之dynamic_cast、static_cast、const_cast、reinterpret_cast的用法和区别
簡述
C++中有四個類型轉(zhuǎn)換符,旨在嚴(yán)格限制允許的類型轉(zhuǎn)換,使轉(zhuǎn)換更規(guī)范。這四個轉(zhuǎn)換符分別是:
- dynamic_cast
- static_cast
- const_cast
- reinterpret_cast
可以根據(jù)目的選擇一個適合的運算符,而不是使用通用的類型轉(zhuǎn)換。讓編譯器能夠檢查程序的行為是否與設(shè)計者想法吻合。
接下來看看每個類型轉(zhuǎn)換符的用法以及它們之間的區(qū)別。
dynamic_cast
之前在 “C++之 RTTI”中講到過dynamic_cast,dynamic_cast是動態(tài)轉(zhuǎn)換,使用該轉(zhuǎn)換符時會自動去檢查轉(zhuǎn)換類型,以及轉(zhuǎn)換是否合法。它的用途是,使得能夠在類層次結(jié)構(gòu)中進(jìn)行向上轉(zhuǎn)換(由于是 is-a關(guān)系,這樣的類型轉(zhuǎn)換是安全的),而不允許其他轉(zhuǎn)換。
語法為:
dynamic_cast<type-name> (expression)
舉個栗子:
一個基類 Base(必須要是虛基類,帶有虛函數(shù)),一個繼承于Base 的派生類 A,那么
也就是說,dynamic_cast不能從多態(tài)性的虛基類強制到某個派生類或者兄弟類。dynamic_cast要求多態(tài)性的操作對象。
如果轉(zhuǎn)換不合法,將會返回空指針,就比如上面那句不成立的轉(zhuǎn)化,返回一個空指針。
需要注意的是:編譯器不能讀由 void所指向的存儲提供任何保證。這也就意味著dynamic_cast不能從 void觸發(fā)進(jìn)行強制轉(zhuǎn)換,因為它必須去查看對象,以便確定其類型,對于這種情況就需要 static_cast了。
缺點:這是為了保證轉(zhuǎn)換的合法性,dynamic_cast會帶來一點運行時的額外開銷。
static_cast
靜態(tài)轉(zhuǎn)換static_cast,和dynamic_cast不同的是,它不需要檢查被強制轉(zhuǎn)換的對象。
語法為:
static_cast<type-name> (expression)
僅當(dāng) type_name 可被隱式轉(zhuǎn)換為 expression 所屬的類型或 expression 可被隱式轉(zhuǎn)換為 type_name 所屬的類型時,上述轉(zhuǎn)換才是合法的,否則將會出錯。
比如說:A 是 B 的基類,而 C 是一個無關(guān)的類,那么從 A 到 B 的轉(zhuǎn)換,從 B 到 A 的轉(zhuǎn)換都是合法的,而從A到 C 轉(zhuǎn)換是不允許的。
第一種轉(zhuǎn)換是合法的,因為向上轉(zhuǎn)換可以顯示地進(jìn)行。第二種轉(zhuǎn)換是從基類指針到派生類指針,在不進(jìn)行顯示類型轉(zhuǎn)換的情況下,將無法進(jìn)行。但是由于無需進(jìn)行類型轉(zhuǎn)換,便可以進(jìn)行另一個方向的類型轉(zhuǎn)換,因此使用 static_cast 來進(jìn)行向下轉(zhuǎn)換是合法的。
也就是說,可以從常規(guī)基類強制,不能從虛基類強制。比如 A 如果是 B 的常規(guī)基類,沒有虛函數(shù),這樣是可以向下轉(zhuǎn)換的,如果 A 是B 的虛基類,就不能轉(zhuǎn)換。
const_cast
const_cast運算符用于執(zhí)行只有一種用途的類型轉(zhuǎn)換,即改變值為 const 或 volatile,其語法也是一樣的:
const_cast<type-name> (expression)
注意:這里的type-name和expression類型必須相同,除了 const 和 volatile 特征(有或無)可以不同。
比如 A 和 B 兩個類:
第一個類型轉(zhuǎn)換使得*pA成為一個可用于修改 bar 的對象值的指針,它刪除 const 標(biāo)簽,第二個類型轉(zhuǎn)換是非法的,因為它同時嘗試將類型從 const A * 改為 const B *.
const_cast 的用途,有時候可能需要這樣一個值,它在大多數(shù)時候是常量,而有時候又是可以修改的,在這種情況下,可以將這個值聲明為 const,并在需要修改它的時候,使用 const_cast 。這也可以通過通用類型轉(zhuǎn)換來實現(xiàn),但通用轉(zhuǎn)換也可能同時改變類型:
A bar; const A * pBar = &bar;A * pA = (A *)(pBar); //合法 B * pB = (B *)(pBar); //合法由于編程時可能無意間同時改變類型和常量特征,因此使用 const_cast運算符更安全。
但是,const_cast并不是萬能的,它可以修改指向一個值的指針,但是修改 const 值的結(jié)果是不確定的,來看個示例:
#include <iostream>using namespace std;void change(const int * pt,int n) {int * pc;pc = const_cast<int *>(pt);*pc += n; }int main() {int pop1 = 100;const int pop2 = 50;cout << "pop1 = " << pop1 << " pop2 = " << pop2 << endl;change(&pop1,20);change(&pop2,20);cout << "pop1 = " << pop1 << " pop2 = " << pop2 << endl;return 0; }輸出結(jié)果:
pop1 = 100 pop2 = 50 pop1 = 120 pop2 = 50可以看到,由于 pop2被聲明為 const,因此編譯器可能禁止修改它。所以 const_cast 可用來刪除 const 的特征,但僅當(dāng)指向的值不是 const 時才可行。
reinterpret_cast
reinterpret_cast用于天生危險的類型轉(zhuǎn)換,reinterpret中文含義就是“重新詮釋”,它可以用于不同類型之間的轉(zhuǎn)換,也就是說可以將數(shù)據(jù)以二進(jìn)制存在形式的重新解釋。但并不是所有類型都可以轉(zhuǎn)換的。
語法:reinterpret_cast<type-name> (expression)
示例:
struct dat{ short a; short b; }; long value = 0xA224B118; dat * pd = reinterpret_cast<dat *>(&value); cout << pd->a;通常這樣的轉(zhuǎn)換適用于依賴于實現(xiàn)的底層編程技術(shù),是不可移植的。例如,不同系統(tǒng)在存儲多字節(jié)整型時,可能以不同順序存儲其中的字節(jié)。
然而,需要注意的是reinterpret_cast運算符并不支持所有的類型轉(zhuǎn)換,例如,可以將指針類型轉(zhuǎn)換為足以存儲指針表示的整型,但不能將指針轉(zhuǎn)換為更小的整型或浮點型。另一個限制是,不能將函數(shù)指針轉(zhuǎn)換為數(shù)據(jù)指針,反之亦然。
什么情況下可以用到這個轉(zhuǎn)換符:
- 從指針類型到一個足夠大的整數(shù)類型
- 從整數(shù)類型或者枚舉類型到指針類型
- 從一個指向函數(shù)的指針到另一個不同類型的指向函數(shù)的指針
- 從一個指向?qū)ο蟮闹羔樀搅硪粋€不同類型的指向?qū)ο蟮闹羔?/li>
- 從一個指向類函數(shù)成員的指針到另一個指向不同類型的函數(shù)成員的指針
- 從一個指向類數(shù)據(jù)成員的指針到另一個指向不同類型的數(shù)據(jù)成員的指針
參考資料《c++程序設(shè)計語言》、《C++編程思想》
總結(jié)
以上是生活随笔為你收集整理的C++之dynamic_cast、static_cast、const_cast、reinterpret_cast的用法和区别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++之 RTTI
- 下一篇: C++设计模式--适配器模式