Udostępnij za pośrednictwem


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

Hierarchia klas pokazano wiele wystąpień

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

ClassHierarchyVirtualBaseClasses — grafika

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

Hierarchia klas pokazano zduplikowane klasy podstawowe

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);
}
  

Zobacz też

Informacje

Operatory odlewania

Słów kluczowych języka C++