Namespaces
Variants

dynamic_cast conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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

Содержание

Синтаксис

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

Объяснение

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

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

1) Если тип expression точно соответствует target-type или является менее cv-квалифицированной версией target-type , результатом будет значение expression с типом target-type . Другими словами, dynamic_cast может использоваться для добавления константности . Неявное преобразование и static_cast также могут выполнять это преобразование.
2) Если target-type является "указателем на (возможно cv-квалифицированный) Base " и тип expression является "указателем на (возможно cv-квалифицированный) Derived " таким образом, что Base является базовым классом Derived , результатом будет
  • нулевое значение указателя, если expression является нулевым указателем, или
  • указатель на уникальный Base подобъект объекта Derived , на который указывает expression в противном случае. Другими словами, dynamic_cast может использоваться для повышающего преобразования указателей, от производного к базовому. Неявное преобразование и static_cast также могут выполнять это преобразование.
3) Если target-type является «ссылкой на (возможно cv-квалифицированный) Base », а тип expression — «(возможно cv-квалифицированный) Derived », причём Base является базовым классом для Derived , результатом будет уникальный Base подобъект объекта Derived , на который ссылается expression . Другими словами, dynamic_cast может использоваться для upcast ссылок — от производного класса к базовому. Неявное преобразование и static_cast также могут выполнять это преобразование.
4) Если expression является нулевым указателем полиморфного типа, результат представляет собой нулевое значение указателя типа target-type .
5) В противном случае, expression должен быть указателем или ссылкой на объект полиморфного типа в течение его времени жизни или в течение периода его конструирования или разрушения, тип которого подобен типу expression (в противном случае поведение не определено)
a) Если expression является указателем на (возможно cv-квалифицированный) void , результат представляет собой указатель на наиболее производный объект , на который указывает expression .
b) В противном случае применяется проверка во время выполнения, чтобы определить, может ли объект, на который указывает/на который ссылается expression , быть преобразован в тип Target , на который указывает или на который ссылается target-type :
i) Если в наиболее производном объекте, на который указывает/на который ссылается expression , expression указывает/ссылается на открытый базовый подобъект объекта Target , и если только один объект типа Target является производным от подобъекта, на который указывает/на который ссылается expression , результат указывает/ссылается на этот объект Target . Другими словами, dynamic_cast может использоваться для понижающего преобразования указателей/ссылок, от базового к производному.
ii) В противном случае, если expression указывает/ссылается на подобъект публичного базового класса наиболее производного объекта, и тип наиболее производного объекта имеет однозначный и публичный базовый класс типа Target , результат указывает/ссылается на подобъект Target наиболее производного объекта. Другими словами, dynamic_cast может использоваться для кросс-каста (или side-cast) указателей/ссылок между двумя типами, производными от одного базового класса.
iii) В противном случае проверка во время выполнения завершается неудачей.
  • Если target-type является типом указателя, результатом будет нулевое значение указателя типа target-type .
  • Если target-type является ссылочным типом, выбрасывается исключение типа, соответствующего обработчику типа std::bad_cast .

Когда dynamic_cast используется в конструкторе или деструкторе (напрямую или косвенно), и expression ссылается на объект, который в настоящее время конструируется/уничтожается, этот объект считается наиболее производным объектом. Если target-type не является указателем или ссылкой на собственный класс конструктора/деструктора или один из его базовых классов, поведение не определено.

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

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

Примечания

Приведение к производному типу также может быть выполнено с помощью static_cast , что позволяет избежать затрат на проверку во время выполнения, но это безопасно только если программа может гарантировать (с помощью другой логики), что объект, на который указывает expression , точно является 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 Applied to Behavior as published Correct behavior
CWG 1269 C++11 проверка во время выполнения не выполнялась для xvalue
expression s если target-type является типом rvalue-ссылки
выполняется
CWG 2861 C++98 expression мог указывать/ссылаться на объект с недоступным типом поведение в этом случае не определено

Ссылки

  • Стандарт C++23 (ISO/IEC 14882:2024):
  • 7.6.1.7 Динамическое приведение типов [expr.dynamic.cast]
  • Стандарт C++20 (ISO/IEC 14882:2020):
  • 7.6.1.6 Динамическое приведение типа [expr.dynamic.cast]
  • Стандарт C++17 (ISO/IEC 14882:2017):
  • 8.2.7 Динамическое приведение типов [expr.dynamic.cast]
  • Стандарт C++14 (ISO/IEC 14882:2014):
  • 5.2.7 Динамическое приведение типа [expr.dynamic.cast]
  • Стандарт C++11 (ISO/IEC 14882:2011):
  • 5.2.7 Динамическое приведение типов [expr.dynamic.cast]
  • Стандарт C++98 (ISO/IEC 14882:1998):
  • 5.2.7 Динамическое приведение типа [expr.dynamic.cast]
  • Стандарт C++03 (ISO/IEC 14882:2003):
  • 5.2.7 Динамическое приведение типа [expr.dynamic.cast]

Смотрите также