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

Convierte de forma segura punteros y referencias a clases hacia arriba, hacia abajo y lateralmente a lo largo de la jerarquía de herencia.

Contenidos

Sintaxis

dynamic_cast< tipo-destino >( expresión )
target-type - puntero a tipo de clase completo, referencia a tipo de clase completo, o puntero a void (opcionalmente calificado-cv)
expression - lvalue (hasta C++11) glvalue (desde C++11) de un tipo de clase completo si target-type es una referencia, prvalue de un puntero a tipo de clase completo si target-type es un puntero

Explicación

Para facilitar la descripción, " expresión o el resultado es una referencia a T " significa que "es un glvalue de tipo T " , lo cual sigue la convención de decltype (desde C++11) .

Solo las siguientes conversiones pueden realizarse con dynamic_cast , excepto cuando dichas conversiones eliminen constancia (o volatilidad).

1) Si el tipo de expression es exactamente target-type o una versión menos calificada cv de target-type , el resultado es el valor de expression con tipo target-type . En otras palabras, dynamic_cast puede utilizarse para agregar constancia . Una conversión implícita y static_cast también pueden realizar esta conversión.
2) Si target-type es "puntero a (posiblemente calificado con cv) Base " y el tipo de expression es "puntero a (posiblemente calificado con cv) Derived " tal que Base es una clase base de Derived , el resultado es
  • un valor de puntero nulo si expression es un valor de puntero nulo, o
  • un puntero al Base subobjeto único del objeto Derived apuntado por expression en caso contrario. En otras palabras, dynamic_cast puede usarse para upcast de punteros, de derivado a base. Una conversión implícita y static_cast también pueden realizar esta conversión.
3) Si target-type es "referencia a (posiblemente calificada cv) Base " y el tipo de expression es "(posiblemente calificada cv) Derived " tal que Base es una clase base de Derived , el resultado es el subobjeto único Base del objeto Derived referido por expression . En otras palabras, dynamic_cast puede usarse para upcast referencias, de derivada a base. Una conversión implícita y static_cast también pueden realizar esta conversión.
4) Si expression es un valor de puntero nulo de un tipo polimórfico , el resultado es el valor de puntero nulo de target-type .
5) En caso contrario, expression debe ser un puntero o referencia a un objeto de tipo polimórfico dentro de su tiempo de vida o dentro de su período de construcción o destrucción cuyo tipo sea similar al tipo de expression (de lo contrario el comportamiento es indefinido)
a) Si expression es un puntero a (posiblemente calificado con cv) void , el resultado es un puntero al objeto más derivado apuntado por expression .
b) De lo contrario, se aplica una verificación en tiempo de ejecución para determinar si el objeto apuntado/referido por expression puede convertirse al tipo Target , apuntado o referido por target-type :
i) Si, en el objeto más derivado apuntado/referido por expression , expression apunta/se refiere a un subobjeto de clase base pública de un objeto Target , y si solo un objeto de tipo Target se deriva del subobjeto apuntado/referido por expression , el resultado apunta/se refiere a ese objeto Target . En otras palabras, dynamic_cast puede usarse para downcast punteros/referencias, de base a derivada.
ii) En caso contrario, si expression apunta/se refiere a un subobjeto de clase base pública del objeto más derivado, y el tipo del objeto más derivado tiene una clase base unívoca y pública de tipo Target , el resultado apunta/se refiere al subobjeto Target del objeto más derivado. En otras palabras, dynamic_cast puede utilizarse para realizar crosscast (o side-cast) de punteros/referencias, entre dos tipos derivados de la misma base.
iii) De lo contrario, la verificación en tiempo de ejecución falla.
  • Si target-type es un tipo puntero, el resultado es el valor de puntero nulo de target-type .
  • Si target-type es un tipo referencia, se lanza una excepción de un tipo que coincidiría con un handler de tipo std::bad_cast .

Cuando dynamic_cast se utiliza en un constructor o destructor (directa o indirectamente), y la expresión se refiere al objeto que actualmente está en construcción/destrucción, el objeto se considera el objeto más derivado. Si el tipo-destino no es un puntero o referencia a la propia clase del constructor/destructor o a una de sus bases, el comportamiento es indefinido.

Similar a otras expresiones de conversión, el resultado es:

  • un lvalue si target-type es un tipo referencia
  • un rvalue si target-type es un tipo puntero
(hasta C++11)
  • un lvalue si target-type es un tipo referencia a lvalue ( expression debe ser un lvalue)
  • un xvalue si target-type es un tipo referencia a rvalue ( expression puede ser lvalue o rvalue (hasta C++17) debe ser un glvalue (los prvalues son materializados ) (desde C++17) de un tipo clase completo)
  • un prvalue si target-type es un tipo puntero
(desde C++11)

Notas

Un downcast también puede realizarse con static_cast , que evita el costo de la verificación en tiempo de ejecución, pero solo es seguro si el programa puede garantizar (mediante otra lógica) que el objeto apuntado por expression es definitivamente Derived .

Algunas formas de dynamic_cast dependen de la identificación de tipos en tiempo de ejecución (RTTI), es decir, información sobre cada clase polimórfica en el programa compilado. Los compiladores normalmente tienen opciones para deshabilitar la inclusión de esta información.

Palabras clave

dynamic_cast

Ejemplo

#include <iostream>
struct V
{
    virtual void f() {} // debe ser polimórfico para usar dynamic_cast verificado en tiempo de ejecución
};
struct A : virtual V {};
struct B : virtual V
{
    B(V* v, A* a)
    {
        // conversiones durante la construcción (ver la llamada en el constructor de D abajo)
        dynamic_cast<B*>(v); // bien definido: v de tipo V*, V base de B, resulta en B*
        dynamic_cast<B*>(a); // comportamiento indefinido: a tiene tipo A*, A no es base de 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; // el objeto más derivado
    A& a = d; // upcast, dynamic_cast puede usarse, pero no es necesario
    [[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(); // seguro de llamar
    }
    Base* b2 = new Derived;
    if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // seguro de llamar
    }
    delete b1;
    delete b2;
}

Salida:

downcast from b2 to d successful

Informes de defectos

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.

DR Se aplica a Comportamiento publicado Comportamiento correcto
CWG 1269 C++11 la verificación en tiempo de ejecución no se realizaba para
expression s xvalue si target-type es un tipo de referencia a rvalue
se realiza
CWG 2861 C++98 expression podría apuntar/referirse a un objeto de acceso restringido al tipo el comportamiento no está definido en este caso

Referencias

  • Estándar C++23 (ISO/IEC 14882:2024):
  • 7.6.1.7 Dynamic cast [expr.dynamic.cast]
  • Estándar C++20 (ISO/IEC 14882:2020):
  • 7.6.1.6 Dynamic cast [expr.dynamic.cast]
  • Estándar C++17 (ISO/IEC 14882:2017):
  • 8.2.7 Conversión dinámica [expr.dynamic.cast]
  • Estándar C++14 (ISO/IEC 14882:2014):
  • 5.2.7 Dynamic cast [expr.dynamic.cast]
  • Estándar C++11 (ISO/IEC 14882:2011):
  • 5.2.7 Dynamic cast [expr.dynamic.cast]
  • Estándar C++98 (ISO/IEC 14882:1998):
  • 5.2.7 Dynamic cast [expr.dynamic.cast]
  • Estándar C++03 (ISO/IEC 14882:2003):
  • 5.2.7 Dynamic cast [expr.dynamic.cast]

Véase también