opérateur de dynamic_cast
convertit l'opérande expression à un objet de type type-id.
dynamic_cast < type-id > ( expression )
Notes
type-id doit être un pointeur ou une référence à un type défini précédemment de classe ou un « pointeur vers void ».Le type d' expression doit être un pointeur si type-id est un pointeur, ou une l-value si type-id est une référence.
Consultez static_cast pour plus d'informations sur la différence entre les conversions statiques et dynamiques de casting, et lorsqu'il convient d'utiliser chacun.
Il existe deux nouveautés du comportement d' dynamic_cast dans le code managé :
dynamic_cast vers un pointeur vers le type sous-jacent d'un enum boxed échoue au moment de l'exécution, en retournant 0 au lieu du pointeur converti.
dynamic_cast ne lèvera plus une exception lorsque type-id est un pointeur intérieur à un type valeur, le cast manquant au moment de l'exécution.Le cast retourne maintenant les 0 valeurs de type pointeur au lieu de lever.
Si type-id est un pointeur vers une classe de base directe ou indirecte accessible non équivoque d' expression, un pointeur vers l'unique sous-objet du type type-id est le résultat.Par exemple :
// 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
}
Ce type de conversion est appelé « upcast » parce qu'il se déplace un pointeur vers le haut d'une hiérarchie de classes, d'une classe dérivée à une classe qu'elle est dérivée de.un upcast est une conversion implicite.
si type-id est void*, un contrôle à l'exécution est fait pour déterminer le type réel d' expression.Le résultat est un pointeur vers l'objet complet sur lequel pointe expression.Par exemple :
// 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
}
Si type-id n'est pas void*, un contrôle à l'exécution est fait pour voir si l'objet sur lequel pointe expression peut être convertie dans le type sur lequel pointe type-id.
Si le type d' expression est une classe de base du type d' type-id, un contrôle à l'exécution est fait pour vérifier si les points d' expression réellement à un objet complet du type d' type-id.Si c'est le cas, le résultat est un pointeur vers un objet complet du type d' type-id.Par exemple :
// 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
}
Ce type de conversion est appelé « cast aval » parce qu'il se déplace un pointeur vers le bas d'une hiérarchie de classes, d'une classe donnée à une classe dérivée d'elle.
En cas d'héritage multiple, des possibilités de l'ambiguïté sont ajoutées.Examinez la hiérarchie de classes affichée dans l'illustration suivante.
Pour les types CLR, les résultats d' dynamic_cast dans l'ou dans l'autre un une absence d'opération si la conversion peut être effectuée implicitement, ou une instruction MSIL isinst , qui exécute un contrôle dynamique et retourne nullptr si la conversion échoue.
L'exemple suivant utilise dynamic_cast pour déterminer si une classe est une instance de type particulier :
// 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);
}
Héritage multiple d'apparence de la hiérarchie de classes
Un pointeur vers un objet de type D peut être sans risque casté à B ou à C.Toutefois, si D est castée pour indiquer A un objet, que l'instance d' A résulterait ?Cela conduirait une erreur ambiguë de casting.Pour contourner ce problème, vous pouvez effectuer deux casts non ambigus.Par exemple :
// 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
}
D'autres ambiguïtés peuvent être appliquées lorsque vous utilisez les classes de base virtuelle.Examinez la hiérarchie de classes affichée dans l'illustration suivante.
Hiérarchie de classes en affichant les classes de base virtuelle
dans cette hiérarchie, A est une classe de base virtuelle.Consultez Classes de base virtuelle pour la définition d'une classe de base virtuelle.En fonction d'une instance de classe E et un pointeur au sous-objet d' A , dynamic_cast à un pointeur vers B échoue en raison de l'ambiguïté.Vous devez d'abord effectuer un cast vers E l'objet complet, puis adaptez votre sauvegarde de méthode la hiérarchie, de manière non équivoque, pour atteindre l'objet approprié de B .
Examinez la hiérarchie de classes affichée dans l'illustration suivante.
Classes de base en double d'apparence de la hiérarchie de classes
Étant donné un objet de type E et un pointeur au sous-objet d' D , pour naviguer du sous-objet d' D au sous-objet de gauche d' A , trois conversions peuvent être effectuées.Vous pouvez effectuer une conversion d' dynamic_cast du pointeur d' D à un pointeur d' E , une conversion ( dynamic_cast ou une conversion implicite) d' E à B, et enfin une conversion implicite d' B à A.Par exemple :
// 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
}
L'opérateur d' dynamic_cast peut également être utilisé pour exécuter « un cast croisé ». À l'aide de la même hiérarchie de classes, il est possible de convertir un pointeur, par exemple, du sous-objet d' B au sous-objet d' D , tant que l'objet complet est de type E.
Conformément à les casts croisés, il est en fait possible d'effectuer la conversion d'un pointeur vers D à un pointeur du sous-objet de gauche d' A dans seulement deux étapes.Vous pouvez effectuer un cast croisé d' D à B, une conversion implicite d' B à A.Par exemple :
// 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
}
Une valeur de pointeur null est convertie à la valeur du pointeur null pour le type de destination par dynamic_cast.
Lorsque vous utilisez dynamic_cast < type-id > ( expression ), si expression ne peut pas être sans risque converti en type type-id, le contrôle à l'exécution entraîne un cast de l'échec.Par exemple :
// 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
}
La valeur d'un cast en type pointeur est le pointeur null.Un cast en type référence lève exception de bad_cast. Si expression n'indique pas ou ne référence pas d'objet valide, une exception d' __non_rtti_object est levée.
Consultez typeid pour obtenir une explication de l'exception d' __non_rtti_object .
Exemple
L'exemple suivant crée la classe de base (pointeur struct A), un objet (struct C).Ce, plus le fait plusieurs fonctions virtuelles, active le polymorphisme d'exécution.
l'exemple appelle également une fonction non virtuelle dans la hiérarchie.
// 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);
}