operador dynamic_cast
convierte el operando expression a un objeto de type-idescrito.
dynamic_cast < type-id > ( expression )
Comentarios
type-id debe ser un puntero o una referencia a un tipo de clase previamente definido o un “puntero a null”.El tipo de expression debe ser un puntero si type-id es un puntero, o un valor l si type-id es una referencia.
Vea static_cast para obtener una explicación de la diferencia entre las conversiones estáticas y dinámicas del marco, y cuándo es adecuado utilizar cada uno.
Hay dos cambios importantes en el comportamiento de dynamic_cast en código administrado:
dynamic_cast a un puntero al tipo subyacente de una enumeración se producirá un error en tiempo de ejecución, devolviendo 0 en lugar de puntero convertido.
dynamic_cast producirá no más una excepción cuando type-id es un puntero interior a un tipo de valor, con la conversión errores en tiempo de ejecución.La conversión ahora devolverá los 0 valores de puntero en lugar de producir.
Si type-id es un puntero a una clase base directa o indirecta accesible clara de expression, un puntero al subobjeto único de type-id con tipo es el resultado.Por ejemplo:
// 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
}
Se llama a este tipo de conversión una “hacia arriba” porque mueve un puntero encima de una jerarquía de clases, una clase derivada a una clase que se deriva de.Una conversión es una conversión implícita.
Si type-id es void*, una comprobación en tiempo de ejecución se crea para determinar el tipo real de expression.El resultado es un puntero al objeto completo indicada por expression.Por ejemplo:
// 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 no es void*, una comprobación en tiempo de ejecución se crea para ver si el objeto indicada por expression se puede convertir al tipo indicada por type-id.
Si el tipo de expression es una clase base del tipo de type-id, una comprobación en tiempo de ejecución se crea para ver si los puntos de expression realmente un objeto completo del tipo de type-id.Si es true, el resultado es un puntero a un objeto completo del tipo de type-id.Por ejemplo:
// 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
}
Se llama a este tipo de conversión un “tipo” porque mueve un puntero hacia abajo una jerarquía de clases, una clase especificada a una clase derivada de ella.
En casos de herencia múltiple, las posibilidades de ambigüedad se introducen.Considere la jerarquía de clases mostrada en la ilustración siguiente.
Para los tipos de CLR, dynamic_cast produce cualquiera una instrucción una ausencia. Sys. si la conversión se puede realizar de forma implícita, o MSIL isinst , que realiza una comprobación dinámica y devuelve nullptr si la conversión.
El ejemplo siguiente utiliza dynamic_cast para determinar si una clase es una instancia de tipo determinado:
// 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);
}
jerarquía de clases que muestra herencia múltiple
Un puntero a un objeto de D escrito puede estar con seguridad convertido a B o a C.Sin embargo, ¿si D se convierte para señalar a A un objeto, que resultaría la instancia de A ?Esto produciría un error ambiguo del marco.Para obtener para este problema, puede realizar dos conversiones inequívocas.Por ejemplo:
// 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
}
Otras ambigüedades pueden presentarse al utilizar clases base virtuales.Considere la jerarquía de clases mostrada en la ilustración siguiente.
jerarquía de clases que muestra clases base virtuales
en esta jerarquía, A es una clase base virtual.Vea clases base virtuales para la definición de una clase base virtual.Proporciona una instancia de la clase E y un puntero al subobjeto de A , dynamic_cast a un puntero a B producirá un error debido a la ambigüedad.Primero debe convertir de nuevo a E el objeto completo, después funciona la copia de seguridad de la forma la jerarquía, de forma inequívoca, alcanzar el objeto correcto de B .
Considere la jerarquía de clases mostrada en la ilustración siguiente.
Clases base de duplicado de demostración de la jerarquía de clases
Dado un objeto de E escrito y un puntero al subobjeto de D , navegar de subobjeto de D el subobjeto de izquierda de A , tres conversiones pueden hacerse.Puede realizar una conversión del puntero de D a un puntero de E , entonces una conversión ( dynamic_cast o una conversión implícita) de E a By, finalmente una conversión implícita de dynamic_cast de B a A.Por ejemplo:
// 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
}
El operador de dynamic_cast también se puede utilizar para realizar una “conversión cruzada.” Utilizando la misma jerarquía de clases, es posible convertir un puntero, por ejemplo, del subobjeto de B el subobjeto de D , mientras el objeto completo es de Eescrito.
Mientras conversiones cruzadas, en realidad es posible realizar la conversión de un puntero a D a un puntero al subobjeto de izquierda de A exactamente en dos pasos.Puede realizar una conversión cruzada de D a B, entonces una conversión implícita de B a A.Por ejemplo:
// 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
}
Un valor de puntero null se convierte en el valor del puntero NULL del tipo de destino por dynamic_cast.
Cuando se utiliza dynamic_cast < type-id > ( expression ), si expression no se puede convertir con seguridad para escribir type-id, comprobación en tiempo de ejecución produce la conversión al error.Por ejemplo:
// 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
}
El valor de una conversión incorrecta al tipo de puntero es el puntero null.Una conversión incorrecta al tipo de referencia produce bad_cast Exception. Si expression no señala ni hace referencia a un objeto válido, se produce una excepción de __non_rtti_object .
Vea typeid para obtener una explicación de la excepción de __non_rtti_object .
Ejemplo
El ejemplo siguiente se crea la clase base (puntero struct A), un objeto (struct C).Ésta, más el hecho hay funciones virtuales, habilita el polimorfismo en tiempo de ejecución.
El ejemplo también llama a una función no virtual en la jerarquí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);
}