Operador de dynamic_cast
Converte o operando expression a um objeto do tipo type-id.
dynamic_cast < type-id > ( expression )
Comentários
O type-id deve ser um ponteiro ou uma referência a um tipo de classe definida anteriormente ou um "ponteiro para void".O tipo de expression deve ser um ponteiro se type-id é um ponteiro ou um valor de l se type-id é uma referência.
Consulte static_cast para obter uma explicação da diferença entre conversões de elenco estáticas e dinâmicas, e quando é apropriado usar cada uma.
Há duas alterações significativas no comportamento do dynamic_cast em código gerenciado:
dynamic_castum ponteiro para o tipo subjacente de um processador in a box enum falhará em tempo de execução, retornando 0 em vez do ponteiro convertido.
dynamic_castNão há mais lançará uma exceção quando type-id é um ponteiro interior para um tipo de valor, com a projeção falhando em tempo de execução.A projeção retornará o valor do ponteiro 0 em vez de gerar.
Se type-id é um ponteiro para uma inequívoca acessível direta ou indireta classe base de expression, um ponteiro para os objetos filho específicos exclusivo do tipo type-id é o resultado.Por exemplo:
// 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
}
Este tipo de conversão é chamado de "elevação" porque ele move um ponteiro para cima uma hierarquia de classes, de uma classe derivada para uma classe que é derivado.Uma elevação é uma conversão implícita.
Se type-id é void *, é feita uma verificação de tempo de execução para determinar o tipo real de expression.O resultado é um ponteiro para o objeto completo apontado por expression.Por exemplo:
// 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
}
Se type-id não é void *, é feita uma verificação de tempo de execução para ver se o objeto apontado pelo expression pode ser convertido para o tipo apontado por type-id.
Se o tipo de expression é uma classe base do tipo de type-id, é feita uma verificação de tempo de execução para ver se expression , na verdade, aponta para um objeto completo do tipo de type-id.Se isso for verdadeiro, o resultado é um ponteiro para um objeto completo do tipo de type-id.Por exemplo:
// 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
}
Esse tipo de conversão é denominado um "lançamento decrescente" porque ele move um ponteiro para baixo de uma hierarquia de classes, de uma determinada classe para uma classe derivado dele.
Em casos de herança múltipla, possibilidades de ambigüidade são introduzidas.Considere a hierarquia de classe mostrada na figura a seguir.
Para tipos CLR, dynamic_cast resulta em um não-operacional, se a conversão pode ser realizada implicitamente ou um MSIL isinst as instruções, que executa uma verificação dinâmica e retorna nullptr se a conversão falhar.
O seguinte exemplo usa dynamic_cast para determinar se uma classe é uma instância de tipo específico:
// 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);
}
Hierarquia de classes, mostrando várias heranças
Um ponteiro para um objeto do tipo D pode ser convertida com segurança para B ou C.No entanto, se D é um conversão para apontar para um A object, qual instância do A resultaria?Isso resultaria em um erro de elenco ambíguo.Para resolver esse problema, você pode executar duas projeções inequívoca.Por exemplo:
// 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
}
Podem ser introduzidas ambigüidades ainda mais quando você usa classes base virtuais.Considere a hierarquia de classe mostrada na figura a seguir.
Hierarquia de classes, mostrando as Classes Base virtuais
Nessa hierarquia, A é uma classe base virtual.Consulte Classes Base virtuais para a definição de uma classe base virtual.Dada uma instância da classe E e um ponteiro para o A objetos filho específicos, um dynamic_cast para um ponteiro para B falharão devido à ambigüidade.Você deve primeiramente converter para o completo E de objeto, em seguida, trabalhar à sua maneira de fazer backup de hierarquia, de maneira inequívoca, para alcançar o correto B objeto.
Considere a hierarquia de classe mostrada na figura a seguir.
Classes Base do mostrando duplicata de hierarquia de classe
Dado um objeto do tipo E e um ponteiro para o D objetos filho específicos, para navegar de um a D objetos filho específicos para a extrema esquerda A subobject, três conversões podem ser feitas.Você pode realizar uma dynamic_cast a conversão da D ponteiro para um E ponteiro, em seguida, uma conversão (qualquer um dos dynamic_cast ou uma conversão implícita) de E para Be finalmente uma conversão implícita de B para A.Por exemplo:
// 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
}
O dynamic_cast operador também pode ser usado para executar uma "conversão cruzada". Usando a mesma hierarquia de classe, é possível converter um ponteiro, por exemplo, a partir do B subobject para o D subobject, desde que o objeto completo é do tipo E.
Considerar entre conversões, é realmente possível fazer a conversão de um ponteiro para D para um ponteiro para a extrema esquerda A objetos filho específicos em apenas duas etapas.Você pode executar uma cruz converter do D para B, em seguida, uma conversão implícita de B para A.Por exemplo:
// 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
}
Um valor de ponteiro nulo é convertido para o valor de ponteiro nulo do tipo de destino por dynamic_cast.
Quando você usa dynamic_cast < type-id > ( expression ), se expression não pode ser com segurança convertido no tipo type-id, a verificação de tempo de execução faz com que a conversão falhe.Por exemplo:
// 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
}
O valor de uma projeção com falha para o tipo de ponteiro é o ponteiro nulo.Uma projeção com falha para fazer referência a tipo lança um bad_cast exceção. Se expression não aponte para ou fazer referência a um objeto válido, um __non_rtti_object exceção é lançada.
Consulte typeid para obter uma explicação sobre o __non_rtti_object exceção.
Exemplo
O exemplo a seguir cria o ponteiro de classe base (A struct), a um objeto (struct C).Isso, mais o fato de lá são funções virtuais, ativa o polimorfismo tempo de execução.
O exemplo também chama uma função não-virtual na hierarquia.
// 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);
}