dynamic_cast 演算子
型 type-id のオブジェクトにオペランド expression を変換します。
dynamic_cast < type-id > ( expression )
解説
type-id は」無効にする前に定義されたクラス型または 「ポインターへのポインターまたは参照である必要があります。expression の種類は type-id が参照で type-id がポインターの場合または左辺値である必要がありますポインター。
それぞれの使用が適切である場合静的および動的キャストの変換の違いの詳細についてはstatic_cast を参照してください。
マネージ コードの dynamic_cast の動作に 2 個の大幅な変更が加えられています :
ボックス化された列挙型の基になる型へのポインターへの dynamic_cast は変換されたポインターではなく 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
}
このような変換はクラス階層の上にポインターを移動すると派生クラスからの派生クラスへのキャスト 「上向き」と呼びます。アップロード キャストは暗黙の型変換です。
void* type-id がの場合 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
}
void* type-id がである expression が指し示す type-id が指し示すオブジェクトが型に変換できるかどうかを確認するにはランタイム チェックが行われます。
expression の種類が type-id 型の基本クラスで表示するにはランタイム チェックがあるかどうか type-id の種類の完全な expression オブジェクトへのポインターの実際になります。これが true の場合結果は 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 は変換が暗黙的に実行できる場合または MSIL 命令 isinst 入力しいずれかの結果 dynamic_cast の変換に失敗した動的な検証を実行し操作を 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 に安全にキャストできます。ただしA に A のインスタンスが発生したオブジェクトを指すように D がキャストまたは。これはあいまいなキャストのエラーが発生します。この問題を回避するには次の 2 つが明確なキャストを実行できます。次に例を示します。
// 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
}
そのほかの型は仮想基本クラスを使用する場合に発生することがあります。次の図に示すクラスの階層構造を検討してください。
クラスの階層構造の仮想基本クラス
この階層構造ではA は仮想基本クラスです。仮想基本クラスの定義については 仮想基本クラス を参照してください。クラス Eポインターのインスタンスをdynamic_cast は B へのポインターに A のサブオブジェクトによりあいまいさが原因で失敗します。E の完全なオブジェクトにはまず次にキャストする方法をバックアップする B の正しいオブジェクトにアクセスするには階層の明確な方法でです。
次の図に示すクラスの階層構造を検討してください。
クラスの階層構造を表示する重複の基本クラス
Eポインター型のオブジェクトをD のサブオブジェクトから A の左端のサブオブジェクトに移動するに D のサブオブジェクトにより3 種類の変換を作成できます。D のポインターから E のポインターへの dynamic_cast の変換または変換 (dynamic_cast 暗黙の型変換)最終的に B から A への EB からへの暗黙の型変換を実行できます。次に例を示します。
// 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 の演算子を使用できます 「クロス キャストを実行できます」。同じクラスの階層構造を使用して完全なオブジェクトが E ポインター型である場合は B のサブオブジェクトの D のサブオブジェクトにキャストできます。
複数のキャストを考慮して実際のポインターへのポインター D は 2 ステップで A の左端のサブオブジェクトへの変換を行うことができます。D から B にキャストすると BA からへの暗黙の型変換を実行できます。次に例を示します。
// 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 ポインターの値は dynamic_cast によって変換先の型の null ポインター値に変換されます。
dynamic_cast < type-id > (expression) を使用するとtype-id を入力するに expression を安全に変換できない場合ランタイム チェックにはキャストは失敗します。次に例を示します。
// 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例外がスローされます。
__non_rtti_object の例外の詳細についてはtypeid を参照してください。
使用例
次の例では基本クラス (オブジェクト (C) 構造体の構造体 A) のポインターを作成します。多くのファクトとしてこれは仮想関数有効にします実行時のポリモーフィズムを示します。
このサンプルでは階層の非仮想関数を呼び出します。
// 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);
}