Поделиться через


оператор dynamic_cast

Преобразование операнд expression к объекту типа type-id.

dynamic_cast < type-id > ( expression )

Заметки

type-id должны быть указатель или ссылку на ранее типу заданного класса или "указателю значение null".Тип expression если должен быть указателем type-id если указатель или l-значение type-id ссылка.

См. static_cast описание различий между статическим и динамическим преобразованиями приведения, и когда каждое соответствующее использовать.

2 Критические изменения в расширениях функциональности dynamic_cast в управляемом коде:

  • dynamic_cast к указателю к базовому типу положенного в упакован перечисления завершится ошибкой во время выполнения, возвращая 0 вместо преобразованного указателя.

  • dynamic_cast больше не вызывает исключение, когда type-id внутренний указатель на тип значения, приведение терпя ошибкой во время выполнения.Приведение указателя теперь будет возвращено значение 0, то вместо вызова.

If type-id указатель на точно выраженному доступному прямо или косвенному базовому классу expressionуказатель на уникальный subobject типа type-id результат.Примеры.

// 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
}

Этот тип конвертации называется "upcast", так как он перемещает указатель вверх в иерархии класса, производного класса к классу он является производным от.Upcast неявное преобразование.

If type-id void* проверка среды выполнения делается определить фактический тип expression.Результат указатель к общему указанный объект к которым следуют expression.Примеры.

// 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
}

If type-id не void* проверка среды выполнения делается ли объект на указал expression может быть преобразовано к типу, указанному в by type-id.

Если тип expression базовый класс типа type-idпроверка среды выполнения выполняется, чтобы определить, expression фактически точки до полного объекту типа type-id.Если это значение равно true, то результат указатель к общему объекту типа type-id.Примеры.

// 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
}

Этот тип конвертации называется "образования производных типов", так как он перемещает указатель вниз по иерархии классов из заданного класса в класс, производный от него.

В случае множественного наследования, вставляются возможности неоднозначности.Рассмотрим иерархию классов, показанной на следующем рисунке.

Для типов среды CLR dynamic_cast результаты в этом никак-op, если преобразование может быть выполнено неявно или MSIL isinst инструкция, которая выполняет проверку и возвращает динамический nullptr при сбое преобразования.

Следующий пример использует dynamic_cast определить, является ли класс экземпляр заданного типа.

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

Иерархия классов, указывающий множественное наследование

Иерархия класса, демонстрирующая множественное наследование

Указатель на объект типа D может быть безопасно приводится к B OR C.Однако, если D приводит для указания A объект, для которого экземпляр A привело к?Это может привести к неоднозначной ошибке приведения.Чтобы обойти эту проблему, можно запустить 2 точно выраженных приведения.Примеры.

// 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
}

Дальнейшие неоднозначности можно вставить при использовании виртуальных базовых классов.Рассмотрим иерархию классов, показанной на следующем рисунке.

Иерархия классов, указывающий виртуальных базовых классов

График ClassHierarchyVirtualBaseClasses

В этой иерархии A виртуального базового класса.См. Виртуальные базовые классы для определения виртуального базового класса.Получив экземпляр класса E и указатель на A subobject, a dynamic_cast к указателю на B завершится ошибкой из-за неоднозначности.Необходимо сначала привести обратно к общему E объект, после чего работает в резервное копирование способа иерархия, выраженном в точно образом, для достижения правильного B объект.

Рассмотрим иерархию классов, показанной на следующем рисунке.

Базовые классы повторяющиеся отображения иерархии классов

Иерархия класса, демонстрирующая копии базовых классов

Получив объект типа E и указатель на D subobject, переходить от D subobject к левейшему A subobject, 3 преобразования.Можно выполнить a dynamic_cast преобразование D указатель на E указатель, затем преобразование ( dynamic_cast или неявное преобразование) E В Bи, наконец, неявное преобразование из B В A.Примеры.

// 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 оператор может также использоваться для выполнения перекрестное "приведение". Использование ту же иерархию класса, например приведение указателя, например от B в subobject D subobject, пока общий объект типа E.

Изучение перекрестное, фактически можно сделать приведения преобразование из указателя в D на указатель на левейшему A в subobject только 2 шагах.Можно выполнять перекрестные привоженный из D В Bпосле этого неявное преобразование из B В A.Примеры.

// 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
}

Значение указателя null преобразован в значение нулевого указателя целевого типа by dynamic_cast.

При использовании dynamic_cast < type-id > ( expression ), если expression не удалось безопасно быть преобразовано в тип type-idпроверка среды выполнения вызывает приведение завершается неудачей.Примеры.

// 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
}

Значение приведения к типу указателя сбоя указатель null.Приведение к ссылочному типу возникает исключение a сбоя исключение bad_cast.   If expression не указывает на допустимый или не ссылается на объект, a __non_rtti_object исключение.

См. ИД типа описание __non_rtti_object исключение.

Пример

Следующий пример создает указатель базового класса (структуры a) на объект (структуре c#).Это, а также факт там виртуальные функции, включает полиморфизм среды выполнения.

Образец также вызывает функцию non-виртуального в иерархии.

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

См. также

Ссылки

Операторы приведения

Ключевые слова C++