Spec-Zone.ru › C++

dynamic_cast преобразование

Безопасно преобразует указатели и ссылки на классы вверх, вниз и вбок по иерархии наследования.

Синтаксис

dynamic_cast< тип-цели >( выражение )
тип-цели - указатель на полный тип класса, ссылка на полный тип класса или указатель на (необязательно с квалификаторами cv) void
выражение - lvalue(до C++11)glvalue(с C++11) полного типа класса, если тип-цели — ссылка, prvalue указателя на полный тип класса, если тип-цели — указатель

Если преобразование успешно, dynamic_cast возвращает значение типа тип-цели. Если преобразование терпит неудачу и тип-цели — тип указателя, оно возвращает нулевой указатель этого типа. Если преобразование терпит неудачу и тип-цели — тип ссылки, оно выбрасывает исключение, соответствующее обработчику типа std::bad_cast.

Объяснение

Для удобства описания, «выражение или результат является ссылкой на T» означает, что «это glvalue типа T», что соответствует соглашению decltype.

Только следующие преобразования могут быть выполнены с помощью dynamic_cast, за исключением случаев, когда такие преобразования приведут к снятию константности (или изменчивости).

1) Если тип выражения точно равен тип-цели или является менее квалифицированной версией тип-цели, результат — значение выражения с типом тип-цели. (Другими словами, dynamic_cast может использоваться для добавления константности. Неявное преобразование и static_cast также могут выполнить это преобразование.)
2) Если значение выражения — нулевое значение указателя, результатом является нулевое значение указателя типа тип-цели.
3) Если тип-цели — указатель или ссылка на Base, а тип выражения — указатель или ссылка на Derived, где Base — уникальный, доступный базовый класс Derived, результат — указатель или ссылка на подобъект класса Base внутри объекта Derived, на который указывает или идентифицируется выражение. (Примечание: неявное преобразование и static_cast также могут выполнить это преобразование.)
4) Если выражение — указатель на полиморфный тип, а тип-цели — указатель на void, результатом является указатель на наиболее производный объект, на который указывает или к которому обращается выражение.
5) Если выражение — указатель или ссылка на полиморфный тип Base, а тип-цели — указатель или ссылка на тип Derived, выполняется проверка во время выполнения:
a) Исследуется наиболее производный объект, на который указывает/идентифицируется выражение. Если в этом объекте выражение указывает/идентифицирует общедоступный базовый класс Derived, и если только один объект типа Derived производен от подобъекта, на который указывает/идентифицируется выражение, то результатом преобразования является указатель/ссылка на этот объект Derived. (Это известно как «преобразование вниз».)
b) В противном случае, если выражение указывает/идентифицирует общедоступный базовый класс наиболее производного объекта и, одновременно, у наиболее производного объекта есть недвусмысленный общедоступный базовый класс типа Derived, результатом преобразования является указатель/ссылка на этот Derived (Это известно как «преобразование вбок».)
c) В противном случае проверка во время выполнения завершается неудачно. Если dynamic_cast используется для указателей, возвращается нулевое значение указателя типа тип-цели. Если оно использовалось для ссылок, выбрасывается исключение std::bad_cast.
6) Когда dynamic_cast используется в конструкторе или деструкторе (прямо или косвенно), и выражение ссылается на объект, который в настоящее время находится в процессе построения/разрушения, объект считается наиболее производным объектом. Если тип-цели не является указателем или ссылкой на собственный класс конструктора/деструктора или на один из его базовых классов, поведение является неопределённым.

Аналогично другим выражениям преобразования, результатом является:

  • lvalue, если тип-цели — тип ссылки
  • rvalue, если тип-цели — тип указателя
(до C++11)
  • lvalue, если тип-цели — тип lvalue-ссылки (выражение должно быть lvalue)
  • xvalue, если тип-цели — тип rvalue-ссылки (выражение может быть lvalue или rvalue(до C++17)должно быть glvalue (prvalue материализуются материализуются)(с C++17) полного типа класса)
  • prvalue, если тип-цели — тип указателя
(с C++11)

Примечания

  • Преобразование вниз также может быть выполнено с помощью static_cast, что позволяет избежать затрат на проверку во время выполнения, но оно безопасно только если программа может гарантировать (через какой-либо другой логический механизм), что объект, на который указывает выражение, определённо Derived.
  • Некоторые формы dynamic_cast полагаются на идентификацию типа во время выполнения (RTTI), то есть информацию о каждом полиморфном классе в скомпилированной программе. Компиляторы обычно имеют параметры для отключения включения этой информации.

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

dynamic_cast

Пример

#include <iostream>
 
struct V
{
    virtual void f() {} // must be polymorphic to use runtime-checked dynamic_cast
};
 
struct A : virtual V {};
 
struct B : virtual V
{
    B(V* v, A* a)
    {
        // casts during construction (see the call in the constructor of D below)
        dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B*
        dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B
    }
};
 
struct D : A, B
{
    D() : B(static_cast<A*>(this), this) {}
};
 
struct Base
{
    virtual ~Base() {}
};
 
struct Derived : Base
{
    virtual void name() {}
};
 
int main()
{
    D d; // the most derived object
    A& a = d; // upcast, dynamic_cast may be used, but unnecessary
 
    [[maybe_unused]]
    D& new_d = dynamic_cast<D&>(a); // downcast
    [[maybe_unused]]
    B& new_b = dynamic_cast<B&>(a); // sidecast
 
    Base* b1 = new Base;
    if (Derived* d = dynamic_cast<Derived*>(b1); d != nullptr)
    {
        std::cout << "downcast from b1 to d successful\n";
        d->name(); // safe to call
    }
 
    Base* b2 = new Derived;
    if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // safe to call
    }
 
    delete b1;
    delete b2;
}

Вывод:

downcast from b2 to d successful

Отчеты об ошибках

Следующие отчеты об ошибках, меняющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применимо к Поведение, как опубликовано Правильное поведение
CWG 1269 C++11 проверка во время выполнения не выполнялась для xvalue
выражений, если тип-цели — тип rvalue-ссылки
выполняется

См. также

  • const_cast
  • static_cast
  • reinterpret_cast
  • явное преобразование
  • неявные преобразования

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/dynamic_cast

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API