dynamic_cast<type-id> (expression)
這個表達(dá)式將
expression
轉(zhuǎn)換為一個
type-id
類型的對象。
Type-id
必須是一個指針、指向一個已經(jīng)定義類的類型或一個指向
VOID
的指針。
Expression
的類型必須是一個指針,如果
type-id
是一個指針;當(dāng)
type-id
是一個引用的時候必須是一個左值。
如果
type-id
是一個到
expression
類的直接或間接的模棱兩可的指針,結(jié)果是一個到
type-id
類型的子對象:
class B { ... };
class C : public B { ... };
class D : public C { ... };
?
void f(D* pd)
{
?? C* pc = dynamic_cast<C*>(pd);?? // ok: C
是一個直接的基類
???????????????????????????????? // pc
指向
pd
的
C
子對象
?
?? B* pb = dynamic_cast<B*>(pd);?? // ok: B
是一個間接的基類
???????????????????????????
?????// pb
指向
pd
的
B
子對象
?? ...
}
這個類型轉(zhuǎn)換叫做向上轉(zhuǎn)型,因?yàn)樗鼘⒁粋€指針在其繼承層次向上轉(zhuǎn)型,即從一個繼承類到其基類。向上轉(zhuǎn)型是隱式轉(zhuǎn)換。
如果
type-id
是一個
void*
,運(yùn)行時檢查將決定表達(dá)式的實(shí)際類型。結(jié)果是一個到
expression
指向的完整對象。例如:
class A { ... };
?
class B { ... };
?
void f()
{
?? A* pa = new A;
?? B* pb = new B;
?? void* pv = dynamic_cast<void*>(pa);
?? // pv
指向一個
A
類型的對象
?? ...
?? pv = dynamic_cast<void*>(pb);
?? // pv
指向一個
B
類型的對象
}
如果
type-id
不是
void*
,運(yùn)行時檢查指向
expression
的對象能否轉(zhuǎn)換為指向
type-id
類型的對象。
如果
expression
類型是
type-id
的基類,運(yùn)行時檢查是否
expression
實(shí)際是一個指向
type-id
類型的完整對象,如果是,結(jié)果返回指向
type-id
類型的完整對象,否則返回
NULL
。例如:
class B { ... };
class D : public B { ... };
void f()
{
?? B* pb = new D;???????????????????? // unclear but ok
?? B* pb2 = new B;
?? D* pd = dynamic_cast<D*>(pb);????? // ok: pb
實(shí)際指向
D
?? ...
?? D* pd2 = dynamic_cast<D*>(pb2);?? // pb2
實(shí)際指向
B
而不是
D
?????????
??????????????????????????//
轉(zhuǎn)換失敗,
pd2
是
NULL
?? ...
}
向下類型轉(zhuǎn)換之所以這么說是因?yàn)槠鋸念惱^承層次的父類向子類轉(zhuǎn)換。
在多重繼承的情況,可能導(dǎo)致二義性。看一下下面的類繼承層次:
指向類型D的指針轉(zhuǎn)換為B或C都正常,但如果從D轉(zhuǎn)換到A將會怎么樣來?這個結(jié)果導(dǎo)致轉(zhuǎn)換的二義性錯誤;為了結(jié)果這個問題,你可以指向兩次明確的轉(zhuǎn)型,例如:
void f()
{
?? D* pd = new D;
?? A* pa = dynamic_cast<A*>(pd);??? ??//
錯誤:二義性
?? B* pb = dynamic_cast<B*>(pd);????? //
首先轉(zhuǎn)換到
B
?? A* pa2 = dynamic_cast<A*>(pb);?? // ok:
明確的
}
在使用虛基類的時候就導(dǎo)致更復(fù)雜的模糊;看下面的類層次圖:
在這個繼承層次中,A是虛基類。假定一個類E的實(shí)例并且一個指向A子對象的指針,一次到B的dynamic_cast會由于不明確性導(dǎo)致失敗,你必須首先轉(zhuǎn)換到適當(dāng)?shù)膶哟危缓笤傧蛏限D(zhuǎn)換到確定的層次,一直按照這種方式直到到達(dá)正確的B對象。
看下面的類層次圖:
假定一個類型E的對象和一個指向D子對象的指針,從D子對象導(dǎo)航到左上A子對象,必須執(zhí)行三個轉(zhuǎn)換。從D到E的dynamic_cast的轉(zhuǎn)換,然后一個從E到B的轉(zhuǎn)換(可以是dynamic_cast或者隱式轉(zhuǎn)換),最終是從B到A的轉(zhuǎn)換,例如:
void f(D* pd)
{
?? E* pe = dynamic_cast<E*>(pd);//
這里的
D
實(shí)際上是
E
類型的對象
?? B* pb = pe;????? // upcast, implicit conversion
?? A* pa = pb;????? // upcast, implicit conversion
}
dynamic_cast
操作能執(zhí)行交叉轉(zhuǎn)換,使用上面相同的類層次,從
B
子對象到
D
子對象轉(zhuǎn)換是可能的,只要完整的對象是
E
。
由于交叉轉(zhuǎn)換,從
D
指針到左上角
A
子對象的指針是可行的;首先從
D
到
B
的交叉轉(zhuǎn)換,然后隱式從
B
到
A
的轉(zhuǎn)換。例如:
void f(D* pd)
{
?? B* pb = dynamic_cast<B*>(pd);????? // cross cast
?? A* pa = pb;?????????????? ???// upcast, implicit conversion
}
一個
NULL
指針值通過
dynamic_cast
轉(zhuǎn)換到一個
NULL
指針。
當(dāng)使用
dynamic_cast <
type-id
> (
expression
)
時,
如果
expression
不能安全的轉(zhuǎn)換到
type-id
,運(yùn)行時檢查導(dǎo)致轉(zhuǎn)型失敗,例如:
class A { ... };
?
class B { ... };
?
void f()
{
?? A* pa = new A;
?? B* pb = dynamic_cast<B*>(pa);????? // fails, not safe;
??????????????????????????????????? // B not derived from A
?? ...
}
轉(zhuǎn)換失敗的指針類型是
NULL
指針。失敗的引用類型轉(zhuǎn)換拋出
bad_cast_exception
異常;如果
expression
沒有指向或引用一個有效的對象將拋出
__non_rtti_object
異常。