dynamic_cast
conversion
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).
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
Basesubobjeto único del objetoDerivedapuntado 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.
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.
Target
, apuntado o referido por
target-type
:
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.
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.
- 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:
|
(hasta C++11) |
|
(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
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]