隱式類型轉(zhuǎn)換:
C++的隱式轉(zhuǎn)換發(fā)生在以下四種情況:
- 在混合類型的算術(shù)表達(dá)式中哩盲。
- 在表達(dá)式賦值中挨摸。
- 表達(dá)式傳給函數(shù)時镇饮,實(shí)參轉(zhuǎn)換為形參的類型广鳍。
- 函數(shù)返回表達(dá)式時轉(zhuǎn)換成返回值類型。
顯式類型轉(zhuǎn)換:
- 被稱為“強(qiáng)制類型轉(zhuǎn)換”(cast)
- C風(fēng)格:(type-id)
- C++風(fēng)格:
static_cast
蝶溶、dynamic_cast
嗜历、reinterpret_cast
、和const_cast
1. static_cast
- 用法:
static_cast < type-id > ( expression )
- 通常用于轉(zhuǎn)換數(shù)值類型抖所,進(jìn)行非多態(tài)的類型轉(zhuǎn)換梨州。
- 在轉(zhuǎn)換時不進(jìn)行類型檢查,在編譯時進(jìn)行類型檢查田轧,如果轉(zhuǎn)換不成功則編譯錯誤暴匠,因此不安全。
// static_cast_Operator.cpp
// compile with: /LD
class B {};
class D : public B {};
void f(B* pb, D* pd) {
D* pd2 = static_cast<D*>(pb); // Down
// Not safe, D can have fields
// and methods that are not in B.
B* pb2 = static_cast<B*>(pd); // Up
// Safe conversion, D always contains all of B.
}
- 與 dynamic_cast 不同傻粘,pb 的 static_cast 轉(zhuǎn)換不執(zhí)行運(yùn)行時檢查每窖。 由 pb 指向的對象可能不是 D 類型的對象,在這種情況下使用 *pd2 會是災(zāi)難性的弦悉。 例如窒典,調(diào)用 D 類(而非 B 類)的成員函數(shù)可能會導(dǎo)致訪問沖突。
2. dynamic_cast
- 用法:
dynamic_cast < type-id > ( expression )
- 用于指針和引用稽莉。不同類型的指針和引用之間的轉(zhuǎn)換瀑志。
-
注意:
dynamic_cast
在幫助你瀏覽繼承層次上是有限制的。它不能被用于缺乏虛函數(shù)的類型上污秆。也即如果想將基類指針轉(zhuǎn)換為派生類指針劈猪,如果基類不是虛類則無法實(shí)現(xiàn)。 - 被用于安全地沿著類的繼承關(guān)系向下進(jìn)行類型轉(zhuǎn)換良拼。這就是說战得,你能用dynamic_cast把指向基類的指針或引用轉(zhuǎn)換成指向其派生類或其兄弟類的指針或引用,而且你能知道轉(zhuǎn)換是否成功将饺。
- 向上轉(zhuǎn)換和static_cast作用一樣贡避。不要求虛基類痛黎。
- 支持同一個基類的不同派生類指針之間的轉(zhuǎn)換予弧。而
static_cast
則會報錯刮吧。 - 失敗的轉(zhuǎn)換將返回空指針(當(dāng)對指針進(jìn)行類型轉(zhuǎn)換時)或者拋出異常(當(dāng)對引用進(jìn)行類型轉(zhuǎn)換時)。例子如下掖蛤。
// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
virtual void Test(){}
};
class D : public B {};
void f(B* pb) {
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
- 如果
pb
確實(shí)指向 D 類型的對象杀捻,則pd1
和pd2
將獲取相同的值。 如果pb == 0
蚓庭,它們也將獲取相同的值致讥。 - 如果
pb
指向 B 類型的對象,而非指向完整的 D 類器赞,則dynamic_cast
足以判斷返回零垢袱。 但是,static_cast
依賴于程序員的斷言港柜,即pb
指向 D 類型的對象请契,因而只是返回指向那個假定的 D 對象的指針。
3. reinpreter_cast
- 用法:
reinpreter_cast<type-id> (expression)
-
type-id
必須是一個指針夏醉、引用爽锥、算術(shù)類型、函數(shù)指針或者成員指針畔柔。 - 它可以把一個指針轉(zhuǎn)換成一個整數(shù)氯夷,也可以把一個整數(shù)轉(zhuǎn)換成一個指針(先把一個指針轉(zhuǎn)換成一個整數(shù),在把該整數(shù)轉(zhuǎn)換成原類型的指針靶擦,還可以得到原先的指針值)腮考。
- 比較底層的轉(zhuǎn)換,在非相關(guān)的類型之間轉(zhuǎn)換玄捕。操作結(jié)果只是簡單的從一個指針到別的指針的值的二進(jìn)制拷貝秸仙。在類型之間指向的內(nèi)容不做任何類型的檢查和轉(zhuǎn)換。
reinpreter_cast
是特意用于底層的強(qiáng)制轉(zhuǎn)型桩盲,導(dǎo)致實(shí)現(xiàn)依賴(就是說寂纪,不可移植)的結(jié)果。
4. const_cast
- 用法:
const_cast<type_id> (expression)
- 該運(yùn)算符用來修改類型的
const
或volatile
屬性赌结。除了const
或volatile
修飾之外捞蛋,type_id
和expression
的類型是一樣的。 - 常量指針被轉(zhuǎn)化成非常量指針柬姚,并且仍然指向原來的對象拟杉;常量引用被轉(zhuǎn)換成非常量引用,并且仍然指向原來的對象量承;常量對象被轉(zhuǎn)換成非常量對象搬设。
關(guān)于多態(tài)的類指針轉(zhuǎn)換
- 向上轉(zhuǎn)換:派生類指針轉(zhuǎn)為基類指針穴店。
- 向下轉(zhuǎn)換:基類指針轉(zhuǎn)換為派生類指針。
見下面這個例子:
class A {
public:
A() {
a = 0;
}
private:
int a;
};
class B : public A {
public:
B() {
b = 0;
}
private:
int b;
};
int main() {
A *pa1, *pa2, *pa3, *pa4;
B *pb1, *pb2, *pb3;
A a1;
pa1 = &a1;
B b1;
pb1 = &b1;
// 首先拿穴,對于指針直接指向?qū)ο螅? pa2 = &b1; // Correct 指針pa直接指向B中A有的一部分
pb2 = &a1; // Error 需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換來縮小pb指針的范圍
// error: invalid conversion from 'A*' to 'B*'
// 指針之間的轉(zhuǎn)換
pa3 = dynamic_cast<A*>(pb3); // Up Correct 見上泣洞,使得指針能夠正常工作
pb3 = dynamic_cast<B*>(pa4); // Down Error
// error: cannot dynamic_cast 'pa4' (of type 'class A*') to type 'class B*' (source type is not polymorphic)
// 由于類A不是虛基類,不能將其指針pa轉(zhuǎn)換為類B的指針默色,因?yàn)轭怋的指針能夠?qū)中沒有的內(nèi)容進(jìn)行操作球凰,直接轉(zhuǎn)換則不能做到。若A為虛基類腿宰,B是對A中方法的重寫呕诉,則能夠正確轉(zhuǎn)換
return 0;
}
例子:
- 此轉(zhuǎn)換類型稱為“向上轉(zhuǎn)換”,因?yàn)樗鼘⒃陬悓哟谓Y(jié)構(gòu)上的指針吃度,從派生的類移到該類派生的類甩挫。 向上轉(zhuǎn)換是一種隱式轉(zhuǎn)換。
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
}
- 此轉(zhuǎn)換類型稱為“向下轉(zhuǎn)換”椿每,因?yàn)樗鼘⒃陬悓哟谓Y(jié)構(gòu)下的指針伊者,從給定的類移到該類派生的類。
class B {virtual void f();};
class D : public B {virtual void f();};
void f() {
B* pb = new D; // unclear but ok
B* pb2 = new B;
D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D
D* pd2 = dynamic_cast<D*>(pb2); // pb2 points to a B not a D
}
參考閱讀
static_cast, dynamic_cast, const_cast探討
static_cast 運(yùn)算符
dynamic_cast 運(yùn)算符