Operator dynamic_castdynamic_cast Operator

Konwertuje operand expression na obiekt typu type-id .Converts the operand expression to an object of type type-id.

SkładniaSyntax

dynamic_cast < type-id > ( expression )

UwagiRemarks

type-idMusi być wskaźnikiem lub odwołaniem do wcześniej zdefiniowanego typu klasy lub "wskaźnikiem do void".The type-id must be a pointer or a reference to a previously defined class type or a "pointer to void". Typ elementu expression musi być wskaźnikiem, jeśli type-id jest wskaźnikiem lub l-wartością, jeśli type-id jest odwołaniem.The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

Zobacz static_cast , aby uzyskać wyjaśnienie różnic między konwersjami statycznymi a dynamicznymi, i kiedy jest on właściwy do użycia.See static_cast for an explanation of the difference between static and dynamic casting conversions, and when it is appropriate to use each.

Istnieją dwie zmiany w zachowaniu dynamic_cast w kodzie zarządzanym:There are two breaking changes in the behavior of dynamic_cast in managed code:

  • dynamic_cast na wskaźnik do podstawowego typu wyliczenia w ramce będzie kończyć się niepowodzeniem w czasie wykonywania, zwracając 0 zamiast przekonwertowanego wskaźnika.dynamic_cast to a pointer to the underlying type of a boxed enum will fail at runtime, returning 0 instead of the converted pointer.

  • dynamic_cast nie będzie już type-id zgłaszać wyjątku, gdy jest wskaźnikiem wewnętrznym do typu wartości, a rzutowanie kończy się niepowodzeniem w czasie wykonywania.dynamic_cast will no longer throw an exception when type-id is an interior pointer to a value type, with the cast failing at runtime. Rzutowanie będzie teraz zwracało 0 wartość wskaźnika zamiast zgłaszania.The cast will now return the 0 pointer value instead of throwing.

Jeśli type-id jest wskaźnikiem do nieniejednoznacznej dostępnej bezpośredniej lub pośredniej klasy bazowej expression , wskaźnik do unikatowego podobiektu typu type-id jest wynikiem.If type-id is a pointer to an unambiguous accessible direct or indirect base class of expression, a pointer to the unique subobject of type type-id is the result. Na przykład:For example:

// 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 typ konwersji nazywa się "przerzutem", ponieważ przenosi wskaźnik do hierarchii klas z klasy pochodnej do klasy, z której pochodzi.This type of conversion is called an "upcast" because it moves a pointer up a class hierarchy, from a derived class to a class it is derived from. Rzutowanie jest niejawną konwersją.An upcast is an implicit conversion.

Jeśli type-id jest wartością void *, jest przeprowadzane sprawdzanie czasu wykonania w celu określenia rzeczywistego typu expression .If type-id is void*, a run-time check is made to determine the actual type of expression. Wynik jest wskaźnikiem do kompletnego obiektu wskazywanego przez expression .The result is a pointer to the complete object pointed to by expression. Na przykład:For example:

// 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 wartość nie jest równa void *, sprawdzanie czasu wykonywania jest wykonywane w celu sprawdzenia, czy obiekt wskazywany przez expression można przekonwertować na typ wskazywany przez type-id .If type-id is not void*, a run-time check is made to see if the object pointed to by expression can be converted to the type pointed to by type-id.

Jeśli typ expression jest klasą bazową typu type-id , wykonywane jest sprawdzanie w czasie wykonywania, aby zobaczyć expression , czy faktycznie wskazuje na kompletny obiekt typu type-id .If the type of expression is a base class of the type of type-id, a run-time check is made to see if expression actually points to a complete object of the type of type-id. Jeśli wartość jest równa true, wynik jest wskaźnikiem do kompletnego obiektu typu type-id .If this is true, the result is a pointer to a complete object of the type of type-id. Na przykład:For example:

// 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 nosi nazwę "downcast", ponieważ przesuwa wskaźnik w dół hierarchii klas, z danej klasy do klasy pochodnej.This type of conversion is called a "downcast" because it moves a pointer down a class hierarchy, from a given class to a class derived from it.

W przypadku wielokrotnego dziedziczenia są wprowadzane możliwości niejednoznaczności.In cases of multiple inheritance, possibilities for ambiguity are introduced. Rozważmy hierarchię klas pokazaną na poniższym rysunku.Consider the class hierarchy shown in the following figure.

W przypadku typów CLR dynamic_cast w programie powstaje wartość No-op, jeśli konwersja może zostać wykonana niejawnie lub instrukcji MSIL isinst , która wykonuje dynamiczne sprawdzanie i zwraca, nullptr Jeśli konwersja nie powiedzie się.For CLR types, dynamic_cast results in either a no-op if the conversion can be performed implicitly, or an MSIL isinst instruction, which performs a dynamic check and returns nullptr if the conversion fails.

Poniższy przykład używa dynamic_cast do określenia, czy Klasa jest wystąpieniem określonego typu:The following sample uses dynamic_cast to determine if a class is an instance of particular type:

// 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, która pokazuje wielokrotne dziedziczenieClass hierarchy that shows multiple inheritance
Hierarchia klas, która pokazuje wielokrotne dziedziczenieClass hierarchy that shows multiple inheritance

Wskaźnik do obiektu typu D może być bezpiecznie rzutowany na B lub C .A pointer to an object of type D can be safely cast to B or C. Jeśli jednak D rzutowanie wskazuje na A obiekt, którego wystąpienie A miałoby wynik?However, if D is cast to point to an A object, which instance of A would result? Spowoduje to niejednoznaczny błąd rzutowania.This would result in an ambiguous casting error. Aby obejść ten problem, można wykonać dwa niejednoznaczne rzuty.To get around this problem, you can perform two unambiguous casts. Na przykład:For example:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A {virtual void f();};
class D : public B, public C {virtual void f();};

void f() {
   D* pd = new D;
   A* pa = dynamic_cast<A*>(pd);   // C4540, ambiguous cast fails at runtime
   B* pb = dynamic_cast<B*>(pd);   // first cast to B
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous
}

Dalsze niejasności można wprowadzać w przypadku używania wirtualnych klas bazowych.Further ambiguities can be introduced when you use virtual base classes. Rozważmy hierarchię klas pokazaną na poniższym rysunku.Consider the class hierarchy shown in the following figure.

Hierarchia klas, która pokazuje wirtualne klasy bazoweClass hierarchy that shows virtual base classes
Hierarchia klas, która pokazuje wirtualne klasy bazoweClass hierarchy that shows virtual base classes

W tej hierarchii, A jest wirtualną klasą bazową.In this hierarchy, A is a virtual base class. Wystąpienie klasy E i wskaźnik do A podobiektu, dynamic_cast do wskaźnika do B nie powiedzie się z powodu niejednoznaczności.Given an instance of class E and a pointer to the A subobject, a dynamic_cast to a pointer to B will fail due to ambiguity. Najpierw należy wykonać rzutowanie do kompletnego E obiektu, a następnie wykonać kopię zapasową hierarchii w sposób niejednoznaczny, aby dotrzeć do prawidłowego B obiektu.You must first cast back to the complete E object, then work your way back up the hierarchy, in an unambiguous manner, to reach the correct B object.

Rozważmy hierarchię klas pokazaną na poniższym rysunku.Consider the class hierarchy shown in the following figure.

Hierarchia klas, która pokazuje zduplikowane klasy bazoweClass hierarchy that shows duplicate base classes
Hierarchia klas, która pokazuje zduplikowane klasy bazoweClass hierarchy that shows duplicate base classes

Mając obiekt typu E i wskaźnik do D podobiektu, aby nawigować z D podobiektu do obiektu podobiektu z lewej strony A , można wykonać trzy konwersje.Given an object of type E and a pointer to the D subobject, to navigate from the D subobject to the left-most A subobject, three conversions can be made. Można wykonać dynamic_cast konwersję ze D wskaźnika do E wskaźnika, a następnie konwersję (albo dynamic_cast niejawną konwersję) z E do i na B końcu niejawną konwersję z B na A .You can perform a dynamic_cast conversion from the D pointer to an E pointer, then a conversion (either dynamic_cast or an implicit conversion) from E to B, and finally an implicit conversion from B to A. Na przykład:For example:

// 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 Operatora można także użyć do wykonania "rzutowanie krzyżowe".The dynamic_cast operator can also be used to perform a "cross cast." Korzystając z tej samej hierarchii klas, można rzutować wskaźnik, na przykład, z B podobiektu do D podobiektu, o ile kompletny obiekt jest typu E .Using the same class hierarchy, it is possible to cast a pointer, for example, from the B subobject to the D subobject, as long as the complete object is of type E.

Biorąc pod uwagę rzutowanie krzyżowe, można w rzeczywistości wykonać konwersję ze wskaźnika do D wskaźnika do podobiektu znajdującego się po lewej stronie A w zaledwie dwóch krokach.Considering cross casts, it is actually possible to do the conversion from a pointer to D to a pointer to the left-most A subobject in just two steps. Można wykonać rzutowanie krzyżowe z D do B , a następnie niejawną konwersję z B na A .You can perform a cross cast from D to B, then an implicit conversion from B to A. Na przykład:For example:

// 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 o wartości null jest konwertowana na wartość wskaźnika o wartości null typu docelowego przez dynamic_cast .A null pointer value is converted to the null pointer value of the destination type by dynamic_cast.

dynamic_cast < type-id > ( expression )Jeśli używasz, jeśli expression nie można bezpiecznie skonwertować do typu type-id , sprawdzenie w czasie wykonywania powoduje niepowodzenie rzutowania.When you use dynamic_cast < type-id > ( expression ), if expression cannot be safely converted to type type-id, the run-time check causes the cast to fail. Na przykład:For example:

// 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ść nieudanego rzutowania na typ wskaźnika jest wskaźnikiem o wartości null.The value of a failed cast to pointer type is the null pointer. Rzutowanie na typ referencyjny nie powiodło się, zgłasza wyjątek bad_cast.A failed cast to reference type throws a bad_cast Exception. Jeśli nie expression wskazuje lub nie odwołuje się do prawidłowego obiektu, __non_rtti_object zostanie zgłoszony wyjątek.If expression does not point to or reference a valid object, a __non_rtti_object exception is thrown.

Aby typeid uzyskać wyjaśnienie wyjątku, zobacz typeid __non_rtti_object .See typeid for an explanation of the __non_rtti_object exception.

PrzykładExample

Poniższy przykład tworzy wskaźnik klasy bazowej (struct A) do obiektu (struktura C).The following sample creates the base class (struct A) pointer, to an object (struct C). Jest to również funkcja wirtualna, która umożliwia korzystanie z polimorfizmu w czasie wykonywania.This, plus the fact there are virtual functions, enables runtime polymorphism.

Przykład wywołuje również funkcję niewirtualną w hierarchii.The sample also calls a non-virtual function in the hierarchy.

// 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);
}
in C
test2 in B
in GlobalTest
Can't cast to C

Zobacz takżeSee also

Operatory rzutowaniaCasting Operators
Słowa kluczoweKeywords