operatore di dynamic_cast
converte l'operando expression a un oggetto di tipo type-id.
dynamic_cast < type-id > ( expression )
Note
type-id deve essere un puntatore o un riferimento a un tipo definito nella classe o “a un puntatore a void„.il tipo di expression deve essere un puntatore se type-id è un puntatore, o un l-value se type-id è un riferimento.
vedere " tipo2 " per una spiegazione della differenza tra le conversioni statiche e dinamiche cast di e è appropriato utilizzare ciascuno.
Esistono due modifiche sostanziali nel comportamento di dynamic_cast nel codice gestito:
dynamic_cast a un puntatore al tipo sottostante boxed un enum non verrà eseguito in fase di esecuzione, restituendo 0 anziché un puntatore convertito.
dynamic_cast ulteriori non genererà un'eccezione type-id è un puntatore interno a un tipo di valore, con il cast in cui ha esito negativo in fase di esecuzione.Il cast ora restituirà i 0 valori di puntatore anziché generare un'eccezione.
se type-id è un puntatore a una classe base diretta o indiretta accessibile ambigue di expression, un puntatore al sotto-oggetto univoco di tipo type-id è il risultato.Di seguito è riportato un esempio:
// 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
}
Questo tipo di conversione viene chiamato un “eseguire l'upcast„ perché sposta un puntatore alla gerarchia di classi, da una classe derivata a una classe derivata da.Un eseguire l'upcast è una conversione implicita.
se type-id è il void*, un controllo di runtime non viene eseguito per determinare il tipo effettivo di expression.Il risultato è un puntatore all'oggetto completo puntato in near expression.Di seguito è riportato un esempio:
// 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 non è a void*, un controllo di runtime non viene eseguito per verificare se l'oggetto puntasse da expression può essere convertito nel tipo puntato in near type-id.
se il tipo di expression è una classe base del tipo di type-id, un controllo di runtime non viene eseguito per verificare se expression in realtà punti a un oggetto completo del tipo di type-id.In questo caso, il risultato è un puntatore a un oggetto completo del tipo di type-id.Di seguito è riportato un esempio:
// 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
}
Questo tipo di conversione viene chiamato “un downcast„ perché riduce una gerarchia di classi del puntatore, da una determinata classe a una classe derivata da.
Nei casi di ereditarietà multipla, le opportunità di ambiguità vengono introdotti.Si consideri la gerarchia di classi illustrato nella figura che segue.
per i tipi CLR, dynamic_cast risultati nell'una o a un privi op se la conversione può essere eseguita in modo implicito, o un codice MSIL isinst istruzione, che esegue un controllo dinamico e restituisce nullptr se la conversione non riesce.
Di seguito viene utilizzato un esempio dynamic_cast per determinare se una classe è un'istanza di tipo specifico:
// 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);
}
Ereditarietà multipla di rappresentazione della gerarchia di classi
Un puntatore a un oggetto di tipo D in modo sicuro possibile eseguire il cast su B o C.tuttavia, se D viene eseguito il cast per indicare A oggetto, di cui istanza A risulterebbe?Questa operazione comporterebbe un errore ambiguo del cast.Per aggirare questo problema, è possibile eseguire due cast inequivocabili.Di seguito è riportato un esempio:
// 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
}
Ulteriori ambiguità possono essere provocati quando si utilizzano le classi di base virtuali.Si consideri la gerarchia di classi illustrato nella figura che segue.
gerarchia di classi che mostra le classi di base virtuali
Nella gerarchia, A è una classe base virtuale.vedere classi di base virtuali per la definizione di una classe base virtuale.Fornita un'istanza di classe E e un puntatore a A sotto-oggetto, a dynamic_cast un puntatore a B avrà esito negativo a causa di ambiguità.È innanzitutto necessario eseguire il cast del completo E oggetto, quindi utilizzare il backup della modalità la gerarchia, in modo non ambiguo, per ottenere il corretto B oggetto.
Si consideri la gerarchia di classi illustrato nella figura che segue.
Classi di base duplicati di rappresentazione della gerarchia di classi
Dato un oggetto di tipo E e un puntatore a D sotto-oggetto, spostarsi da l D sotto-oggetto perestremità sinistra A il sotto-oggetto, tre conversioni può essere eseguito.È possibile eseguire un oggetto dynamic_cast conversione da D puntatore a un oggetto E puntatore, quindi una conversione (spostandosi dynamic_cast né una conversione implicita) da E in Be infine una conversione implicita da B in A.Di seguito è riportato un esempio:
// 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 l'operatore può essere utilizzato per eseguire un “cast della croce.„ Utilizzando la stessa gerarchia di classi, è possibile eseguire il cast di un puntatore, ad esempio, da B il sotto-oggetto D sotto-oggetto, finché l'oggetto completo è di tipo E.
Mentre i cast della croce, in realtà è possibile effettuare la conversione da un puntatore a D a un puntatore perestremità sinistra A sotto-oggetto a solo due passaggi.È possibile eseguire una croce eseguito il cast da D in B, quindi una conversione implicita da B in A.Di seguito è riportato un esempio:
// 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 valore di puntatore null viene convertito al valore di puntatore null del tipo di destinazione da dynamic_cast.
Quando si utilizzano dynamic_cast < type-id > ( expression )se, expression impossibile in modo sicuro essere convertito nel tipo type-id, il controllo runtime determina il cast non riesca.Di seguito è riportato un esempio:
// 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
}
Il valore di un cast non riuscito a un tipo di puntatore rappresenta il puntatore null.Un cast con un tipo di riferimento genera un'eccezione eccezione del bad_cast. se expression non indica o non fa riferimento a un oggetto valido, a __non_rtti_object l'eccezione viene generata un'eccezione.
vedere typeid per una spiegazione di __non_rtti_object eccezione.
Esempio
Nell'esempio seguente viene creato il puntatore della classe base (struct In), un oggetto (struct C).In questo modo, più il fatto che è funzioni virtuali, eseguire il polimorfismo runtime.
Viene inoltre chiama una funzione non virtuale nella gerarchia.
// 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);
}