Operator dynamic_cast
Konwertuje argument expression do obiektu typu type-id.
dynamic_cast < type-id > ( expression )
Uwagi
type-id Musi być wskaźnik lub odwołanie do typu uprzednio zdefiniowane klasy lub "wskaźnik do void".Typ expression musi być wskaźnik, jeśli type-id jest wskaźnikiem lub l wartość, jeśli type-id jest odwołanie.
Zobacz static_cast o wyjaśnienie różnicy między konwersje odlewania statycznych i dynamicznych i kiedy należy używać każdego.
Istnieją dwie podziału zmiany w zachowaniu dynamic_cast w kodzie zarządzanym:
dynamic_castdo wskaźnik podstawowy typ boxed enum zakończy się niepowodzeniem w czasie wykonywania, zamiast przekonwertowanych wskaźnik wartość 0.
dynamic_castnie jest już wygeneruje wyjątek podczas type-id jest wnętrza wskaźnik na wartość typu z wytopu, braku w czasie wykonywania.Obsada teraz zwróci wartość 0 wskaźnik zamiast rzuca.
Jeśli type-id jest wskaźnikiem do jednoznaczne dostępne bezpośredniego lub pośredniego klasa podstawowa expression, wskaźnik do unikatowych podobiektów typu type-id jest wynikiem.Na przykład:
// 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
}
Ten rodzaj konwersji jest nazywany "rozszerzające", ponieważ będzie przenoszony z klasy, który jest pochodną klasy dziedziczącej wskaźnik w górę hierarchii klas.Rzutowanie rozszerzające jest niejawna konwersja.
Jeśli type-id jest void *, dokonuje się rzeczywisty typ wyboru run-time expression.Wynik jest wskaźnik do kompletnego obiektu wskazywanej przez expression.Na przykład:
// 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
}
Jeśli type-id nie jest void *, aby zobaczyć, jeśli obiekt wskazywanej przez dokonywana jest kontrola run-time expression można konwertować na typ wskazywanej przez type-id.
Jeśli typ expression jest klasa podstawowa typu type-id, aby sprawdzić, czy dokonywana jest kontrola run-time expression faktycznie wskazuje kompletnego obiektu typu type-id.Jeśli to PRAWDA, wynik jest wskaźnik do kompletnego obiektu typu type-id.Na przykład:
// 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
}
Ten typ konwersji nazywa "rzutowania", ponieważ jej przesuwa kursor w dół hierarchii klas, z danej klasy, do klasy uzyskane z niego.
W przypadkach wielokrotne dziedziczenie możliwości niejednoznaczności są wprowadzane.Należy wziąć pod uwagę hierarchia klas pokazano na poniższym rysunku.
Dla typów CLR dynamic_cast w wyniku zerowa, jeśli można wykonać konwersji niejawnie lub MSIL isinst instrukcji, która wykonuje dynamiczne sprawdzanie i zwraca nullptr Jeśli konwersja nie powiedzie się.
Następujące przykładowe zastosowania dynamic_cast do ustalenia, czy klasa jest wystąpienie określonego typu:
// 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);
}
Hierarchia klas, pokazywanie wielokrotne dziedziczenie
Wskaźnik do obiektu typu D może być bezpiecznie oddanych do B lub C.Jednakże jeśli D jest rzutowany wskaż A obiekt, którego wystąpienie A spowodowałoby?Spowodowałoby to błąd odlewania niejednoznaczne.Aby obejść ten problem, można wykonać dwa jednoznaczne poświaty.Na przykład:
// 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
}
Mogą zostać wprowadzone dalsze niejasności, korzystając z wirtualnej klasy podstawowej.Należy wziąć pod uwagę hierarchia klas pokazano na poniższym rysunku.
Hierarchia klas wykazujące wirtualne klasy podstawowej
W tej hierarchii A jest klasą bazową wirtualnych.Zobacz Wirtualnych podstawowych klas dla definicji wirtualne klasy podstawowej.Biorąc pod uwagę instancji klasy E i wskaźnik do A podobiektów, dynamic_cast do wskaźnika do B nie powiedzie się z powodu niejednoznaczności.Musi być najpierw oddanych do kompletnego E obiekt, a następnie przechodzić do hierarchii, kopie zapasowe w jednoznaczny sposób do osiągnięcia właściwego B obiektu.
Należy wziąć pod uwagę hierarchia klas pokazano na poniższym rysunku.
Pokazywanie duplikat klasy hierarchii klas podstawowych
Podany obiekt typu E i wskaźnik do D podobiektów do przejścia z D podobiektów do większości po lewej stronie A subobject, można dokonać konwersji trzy.Można wykonać dynamic_cast konwersji z D wskaźnik, aby E wskaźnik, a następnie konwersji (albo dynamic_cast lub niejawna konwersja) z E do Bi ostatecznie niejawna konwersja z B do A.Na przykład:
// 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 Operator może być stosowane również do wykonywania "cross cast". Przy użyciu tej samej hierarchii klas, jest możliwe do oddania wskaźnik, na przykład z B subobject do D subobject, jak długo kompletnego obiektu jest typu E.
Biorąc pod uwagę krzyż poświaty, jest rzeczywiście możliwe wykonać konwersję z wskaźnik do D na wskaźnik do większości po lewej stronie A podobiektów w tylko z dwóch kroków.Można przeprowadzić przeładunku, rzutowanie z D do B, następnie niejawna konwersja z B do A.Na przykład:
// 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
}
Wartość wskaźnika null jest konwertowany na wartość null wskaźnika typu miejsca docelowego przez dynamic_cast.
Kiedy używać dynamic_cast < type-id > ( expression ), jeśli expression nie może być bezpiecznie konwertowane na wpisz type-id, wyboru run-time powoduje oddanych do awarii.Na przykład:
// 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
}
Wartość Nieudane oddanych do typu wskaźnik jest wskaźnik zerowy.Nieudane oddanych, aby odwołać się za rzuca typu bad_cast wyjątek. Jeśli expression nie punktu lub odwołać prawidłowym obiektem __non_rtti_object jest wyjątek.
Zobacz typeid o wyjaśnienie __non_rtti_object wyjątku.
Przykład
Poniższy przykład tworzy wskaźnik klasy bazowej (struct A) do obiektu (struct C).To plus fakt, że są funkcje wirtualnych, polimorfizmu w czasie wykonywania.
Próbka również wywołuje funkcję wirtualnych w hierarchii.
// 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);
}