共用方式為


dynamic_cast 運算子

將轉換運算元expression物件的型別type-id。

dynamic_cast < type-id > ( expression )

備註

type-id必須是指標或預先定義的類別型別的參考 」 或 「 是 」 指向 void"。 哪種expression必須是一個指標,如果type-id就是指標,值 (l-value) 顯示type-id的參考。

請參閱 static_cast 如需說明的靜態和動態轉換轉換之間,以及適用於使用時的差異。

有兩個重大變更的行為, dynamic_cast在 managed 程式碼:

  • dynamic_cast指標的 boxed 列舉的基礎型別將無法在執行階段,傳回 0,而非已轉換的指標。

  • dynamic_cast將不會再發生例外狀況時type-id是成實值型別,無法在執行階段型別轉換具有內部指標。 轉型會立即傳回 0 的指標值,而不擲回。

如果type-id是模稜兩可存取直接或間接基底類別的指標, expression,唯一的子物件型別的指標type-id是結果。 例如:

// dynamic_cast_1.cpp
// compile with: /c
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
}

這種類型的轉換稱為 「 向上轉型",因為它衍生自類別衍生類別從移動的指標,類別階層架構中向上。 向上轉型是隱含轉換。

如果type-id是 void * 來決定的實際型別進行執行階段檢查expression。 結果是完整所指向的物件指標expression。 例如:

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = new B;
   void* pv = dynamic_cast<void*>(pa);
   // pv now points to an object of type A

   pv = dynamic_cast<void*>(pb);
   // pv now points to an object of type B
}

如果type-id不是 void * 的執行階段檢查撤銷狀態,如果指向物件,請參閱expression可以轉換成所指的型別type-id。

如果型別expression基底類別型別的type-id,執行階段檢查撤銷狀態,看看是否expression實際上會指向完整的物件型別的type-id。 如果這種情況,則結果將是完整的物件型別的指標type-id。 例如:

// dynamic_cast_3.cpp
// compile with: /c /GR
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
}

這種類型的轉換稱為向下 「 轉換 」 因為指標下移類別階層架構,從指定的類別,類別衍生自它。

在多個繼承的情況下,會產生模稜兩可的可能性。 請考慮下圖所示的類別階層架構。

對於 CLR 型別, dynamic_cast會執行任何作業如果轉換可以隱含地執行或 MSIL isinst指令時,它會執行動態檢查,並傳回nullptr如果轉換失敗。

以下範例使用dynamic_cast來判斷類別是否為特定型別的執行個體:

// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;

void PrintObjectType( Object^o ) {
   if( dynamic_cast<String^>(o) )
      Console::WriteLine("Object is a String");
   else if( dynamic_cast<int^>(o) )
      Console::WriteLine("Object is an int");
}

int main() {
   Object^o1 = "hello";
   Object^o2 = 10;

   PrintObjectType(o1);
   PrintObjectType(o2);
}

顯示多重繼承的類別階層架構

顯示多重繼承的類別階層架構

變數的指標型別的物件, D就可以安全地轉換成B或C。 不過,如果D轉換為指向A物件時,哪一個執行個體的A可能會造成嗎? 這會造成模稜兩可的轉型時發生錯誤。 若要解決這個問題,您可以執行兩個模稜兩可的轉換 (cast)。 例如:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   D* pd = new D;
   B* pb = dynamic_cast<B*>(pd);   // first cast to B
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
}

當您使用虛擬基底類別,可以引進了進一步的語意模糊。 請考慮下圖所示的類別階層架構。

顯示虛擬基底類別的類別階層架構

ClassHierarchyVirtualBaseClasses 圖形

在此階層中, A虛擬基底類別。 請參閱虛擬基底類別虛擬基底類別的定義。 執行個體的類別E和變數的指標, A子物件, dynamic_cast指標的B會因模稜兩可失敗。 您必須先轉換為完整的E物件,然後處理模稜兩可的方式,達到正確的備份階層架構中, B物件。

請考慮下圖所示的類別階層架構。

類別階層架構顯示重複基底類別

顯示重複基底類別的類別階層架構

指定型別的物件E和變數的指標, D子物件,從瀏覽D到最左邊的子物件A subobject,可以製作三種轉換。 您可以執行dynamic_cast換算D指標E指標,然後轉換 (不論是哪一dynamic_cast或隱含轉換) 從E到B,和最後一個隱含轉換從B到A。 例如:

// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   E* pe = dynamic_cast<E*>(pd);
   B* pb = pe;   // upcast, implicit conversion
   A* pa = pb;   // upcast, implicit conversion
}

dynamic_cast運算子也可用來執行 「 交叉轉換 」。 使用相同的類別階層架構,則可能要轉型的指標,例如,從B subobject 到D subobject,前提是完整的物件屬於型別E。

考慮交叉轉換 (cast),則實際上可能進行轉換,從變數的指標, D最左邊指標的A在兩個步驟中的子物件。 您可以執行從轉換的十字形D到B,然後從隱含轉換B到A。 例如:

// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   B* pb = dynamic_cast<B*>(pd);   // cross cast
   A* pa = pb;   // upcast, implicit conversion
}

Null 指標值會轉換成時發現 null 指標值的目的型別,藉由dynamic_cast。

當您使用dynamic_cast < type-id > ( expression ),如果expression無法安全地轉換成型別type-id,執行階段檢查導致失敗的轉型。 例如:

// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = dynamic_cast<B*>(pa);   // fails at runtime, not safe;
   // B not derived from A
}

失敗的型別轉換為指標型別值為 null 指標。 失敗的轉型為參考型別擲回 bad_cast 例外狀況。如果expression不會指向或參考有效的物件, __non_rtti_object在擲回例外狀況。

請參閱 typeid 如需說明**__non_rtti_object**例外狀況。

範例

下列範例會建立基底類別 (struct),物件的指標 (結構 C)。 這點,再加上的事實那里虛擬函式,可讓執行階段多型。

這個範例也會呼叫階層架構中的非虛擬的函式。

// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#include <stdio.h>
#include <iostream>

struct A {
    virtual void test() {
        printf_s("in A\n");
   }
};

struct B : A {
    virtual void test() {
        printf_s("in B\n");
    }

    void test2() {
        printf_s("test2 in B\n");
    }
};

struct C : B {
    virtual void test() {
        printf_s("in C\n");
    }

    void test2() {
        printf_s("test2 in C\n");
    }
};

void Globaltest(A& a) {
    try {
        C &c = dynamic_cast<C&>(a);
        printf_s("in GlobalTest\n");
    }
    catch(std::bad_cast) {
        printf_s("Can't cast to C\n");
    }
}

int main() {
    A *pa = new C;
    A *pa2 = new B;

    pa->test();

    B * pb = dynamic_cast<B *>(pa);
    if (pb)
        pb->test2();

    C * pc = dynamic_cast<C *>(pa2);
    if (pc)
        pc->test2();

    C ConStack;
    Globaltest(ConStack);

   // will fail because B knows nothing about C
    B BonStack;
    Globaltest(BonStack);
}
  

請參閱

參考

轉型運算子

C + + 關鍵字