使用標准C++
的類型轉換符:static_cast
、dynamic_cast
、reinterpret_cast
和const_cast
。
static_cast
用法:static_cast<type_id> (expression)
該運算符把expression
轉換為type-id
類型,但沒有運行時類型檢查來保證轉換的安全性。它主要有如下幾種用法:
int
轉換成char
。這種轉換的安全也要開發人員來保證void
類型注意:
static_cast
不能轉換掉expression
的const
、volitale
或者__unaligned
屬性。
用法:dynamic_cast<type_id> (expression)
該運算符把expression
轉換成type_id
類型的對象。type_id
必須是類的指針、引用或者void*
;
有條件轉換,動態類型轉換,運行時類型安全檢查(轉換失敗返回NULL
):
1. 安全的基類和子類之間轉換。
2. 必須要有虛函數。
3. 相同基類不同子類之間的交叉轉換。但結果是NULL
。
如果type_id
是類指針類型,那麼expression
也必須是一個指針,如果type_id
是一個引用,那麼expression
也必須是一個引用。
dynamic_cast
主要用於類層次間的上行轉換和下行轉換,還可以用於類之間的交叉轉換。
在類層次間進行上行轉換時,dynamic_cast
和static_cast
的效果是一樣的;
在進行下行轉換時,dynamic_cast
具有類型檢查的功能,比static_cast
更安全。
dynamic_cast
只用於對象的指針和引用。當用於多態類型時,它允許任意的隱式類型轉換以及相反過程。不過,與static_cast
不同,在後一種情況裡(注:即隱式轉換的相反過程),dynamic_cast
會檢查操作是否有效。也就是說,它會檢查轉換是否會返回一個被請求的有效的完整對象。
檢測在運行時進行。如果被轉換的指針不是一個被請求的有效完整的對象指針,返回值為NULL
.
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
轉換則是允許的,結果是空指針。
用法:reinterpret_cast<type_id> (expression)
type-id
必須是一個指針、引用、算術類型、函數指針或者成員指針。它可以把一個指針轉換成一個整數,也可以把一個整數轉換成一個指針(先把一個指針轉換成一個整數, 在把該整數轉換成原類型的指針,還可以得到原先的指針值)。
這個操作符能夠在非相關的類型之間轉換。操作結果只是簡單的從一個指針到別的指針的值的二進制拷貝。在類型之間指向的內容不做任何類型的檢查和轉換。如果情況是從一個指針到整型的拷貝,內容的解釋是系統相關的,所以任何的實現都不是方便的。一個轉換到足夠大的整型能夠包含它的指針是能夠轉換回有效的指針的。
該運算符的用法比較多。
(static_cast .
與. reinterpret_cast
比較,見下面 )
該運算符平台移植性比較差。
用法:const_cast<type_id> (expression)
該運算符用來修改類型的const
或volatile
屬性。除了const
或volatile
修飾之外, type_id
和expression
的類型是一樣的。
它允許子類類型的指針轉換為父類類型的指針(這是一個有效的隱式轉換),同時,也能夠執行相反動作:轉換父類為它的子類。
這個轉換類型操縱傳遞對象的const
屬性,或者是設置或者是移除
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
是兩個不同的對象。
class B
{
...
};
class D : public B
{
...
};
void f(B* pb)
{
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
即dynamic_cast
可用於繼承體系中的向下轉型,即將基類指針轉換為派生類指針,比static_cast
更嚴格更安全。dynamic_cast
在執行效率上比static_cast
要差一些,但static_cast
在更寬上范圍內可以完成映射,這種不加限制的映射伴隨著不安全性。static_cast
覆蓋的變換類型除類層次的靜態導航以外,還包括無映射變換、窄化變換(這種變換會導致對象切片,丟失信息)、用VOID*
的強制變換、隱式類型變換等…
reinterpret_cast
是為了映射到一個完全不同類型的意思,這個關鍵詞在我們需要把類型映射回原有類型時用到它。我們映射到的類型僅僅是為了故弄玄虛和其他目的,這是所有映射中最危險的。(這句話是C++
編程思想中的原話)
static_cast 和 reinterpret_cast
操作符修改了操作數類型。它們不是互逆的; static_cast
在編譯時使用類型信息執行轉換,在轉換執行必要的檢測(諸如指針越界計算, 類型檢查). 其操作數相對是安全的。另一方面;reinterpret_cast
僅僅是重新解釋了給出的對象的比特模型而沒有進行二進制轉換, 例子如下:
int n=9;
double d=static_cast < double > (n);
上面的例子中, 我們將一個變量從 int
轉換到 double
。這些類型的二進制表達式是不同的。 要將整數 9 轉換到 雙精度整數 9,static_cast
需要正確地為雙精度整數 d
補足比特位。其結果為 9.0
。
而reinterpret_cast 的行為卻不同:
int n=9;
double d=reinterpret_cast<double & > (n);
這次, 結果有所不同. 在進行計算以後, d
包含無用值. 這是因為 reinterpret_cast
僅僅是復制 n
的比特位到 d
, 沒有進行必要的分析.
因此, 你需要謹慎使用 reinterpret_cast
.
補充:
(1)static_cast
:在功能上基本上與C
風格的類型轉換一樣強大,含義也一樣。它有功能上的限制。例如,你不能用static_cast
像用C
風格轉換一樣把struct
轉換成int
類型或者把double
類型轉換成指針類型。另外,static_cast
不能從表達式中去除const
屬性,因為另一個新的類型轉換符const_cast
有這樣的功能。
可以靜態決議出類型的轉換可能性,即使是在繼承體系中,即使包括了多重繼承和虛繼承,只要可以進行靜態決議就可以轉換成功
(2)const_cast
:用於類型轉換掉表達式的const
或volatile
屬性。通過使用const_cast
,你向人們和編譯器強調你通過類型轉換想做的只是改變一些東西的constness
或者volatieness
屬性。這個含義被編譯器所約束。如果你試圖使用const_cast
來完成修改constness
或者volatileness
屬性之外的事情,你的類型轉換將被拒絕。
(3)dynamic_cast
:它被用於安全地沿著類的繼承關系向下進行類型轉換。這就是說,你能用dynamic_cast
把指向基類的指針或引用轉換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉換是否成功。失敗的轉換將返回空指針(當對指針進行類型轉換時)或者拋出異常(當對引用進行類型轉換時)。
(4)reinterpret_cast
:使用這個操作符的類型轉換,其轉換結果幾乎都是執行期定義。因此,使用reinterpret_cast
的代碼很難移植。reinterpret_casts
的最普通的用途就是在函數指針類型之間進行轉換。
## C++的四種強制轉型形式每一種適用於特定的目的:
dynamic_cast
主要用於執行“安全的向下轉型(safe downcasting
)”,也就是說,要確定一個對象是否是一個繼承體系中的一個特定類型。它是唯一不能用舊風格語法執行的強制轉型,也是唯一可能有重大運行時代價的強制轉型。
static_cast
可以被用於強制隱型轉換(例如,non-const
對象轉型為 const
對象,int
轉型為 double
,等等),它還可以用於很多這樣的轉換的反向轉換(例如,void*
指針轉型為有類型指針,基類指針轉型為派生類指針),但是它不能將一個 const
對象轉型為 non-const
對象(只有 const_cast
能做到),它最接近於C-style
的轉換。
const_cast
一般用於強制消除對象的常量性。它是唯一能做到這一點的 C++
風格的強制轉型。
reinterpret_cast
是特意用於底層的強制轉型,導致實現依賴(implementation-dependent
)(就是說,不可移植)的結果,例如,將一個指針轉型為一個整數。這樣的強制轉型在底層代碼以外應該極為罕見。
------------------------------分割線------------------------------
C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm
讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm
讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm
讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm
將C語言梳理一下,分布在以下10個章節中: