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

Convertit de manière sécurisée les pointeurs et références vers des classes vers le haut, vers le bas et latéralement le long de la hiérarchie d'héritage.

Table des matières

Syntaxe

dynamic_cast< type-cible >( expression )
target-type - pointeur vers un type de classe complet, référence vers un type de classe complet, ou pointeur vers void (éventuellement qualifié cv)
expression - lvalue (jusqu'à C++11) glvalue (depuis C++11) d'un type de classe complet si target-type est une référence, prvalue d'un pointeur vers un type de classe complet si target-type est un pointeur

Explication

Pour faciliter la description, « expression ou le résultat est une référence à T » signifie que « c'est une glvalue de type T » , ce qui suit la convention de decltype (depuis C++11) .

Seules les conversions suivantes peuvent être effectuées avec dynamic_cast , sauf lorsque ces conversions supprimeraient la constance (ou la volatilité).

1) Si le type de expression est exactement target-type ou une version moins qualifiée cv de target-type , le résultat est la valeur de expression avec le type target-type . Autrement dit, dynamic_cast peut être utilisé pour ajouter la constance . Une conversion implicite et static_cast peuvent également effectuer cette conversion.
2) Si target-type est « pointeur vers (éventuellement qualifié cv) Base » et que le type de expression est « pointeur vers (éventuellement qualifié cv) Derived » tel que Base est une classe de base de Derived , le résultat est
  • une valeur de pointeur nul si expression est une valeur de pointeur nul, ou
  • un pointeur vers le Base sous-objet unique de l'objet Derived pointé par expression sinon. En d'autres termes, dynamic_cast peut être utilisé pour effectuer un upcast de pointeurs, de la classe dérivée vers la classe de base. Une conversion implicite et static_cast peuvent également effectuer cette conversion.
3) Si target-type est « référence vers (éventuellement qualifié cv) Base » et que le type de expression est « (éventuellement qualifié cv) Derived » tel que Base est une classe de base de Derived , le résultat est le sous-objet Base unique de l'objet Derived désigné par expression . Autrement dit, dynamic_cast peut être utilisé pour effectuer un upcast de références, de la classe dérivée vers la classe de base. Une conversion implicite et static_cast peuvent également réaliser cette conversion.
4) Si expression est une valeur de pointeur nul d'un type polymorphe , le résultat est la valeur de pointeur nul de target-type .
5) Sinon, expression doit être un pointeur ou une référence vers un objet de type polymorphe durant sa durée de vie ou durant sa période de construction ou de destruction dont le type est similaire au type de expression (sinon le comportement est indéfini)
a) Si expression est un pointeur vers (éventuellement qualifié cv) void , le résultat est un pointeur vers l' objet le plus dérivé pointé par expression .
b) Sinon, une vérification à l'exécution est appliquée pour déterminer si l'objet pointé/référencé par expression peut être converti vers le type Target , pointé ou référencé par target-type :
i) Si, dans l'objet le plus dérivé pointé/référé par expression , expression pointe/se réfère à un sous-objet de classe de base publique d'un objet Target , et si un seul objet de type Target est dérivé du sous-objet pointé/référé par expression , le résultat pointe/se réfère à cet objet Target . En d'autres termes, dynamic_cast peut être utilisé pour effectuer un downcast de pointeurs/références, de la base vers la dérivée.
ii) Sinon, si expression pointe/réfère à un sous-objet de classe de base publique de l'objet le plus dérivé, et que le type de l'objet le plus dérivé possède une classe de base non ambiguë et publique de type Target , le résultat pointe/réfère au sous-objet Target de l'objet le plus dérivé. Autrement dit, dynamic_cast peut être utilisé pour effectuer un crosscast (ou side-cast) des pointeurs/références, entre deux types dérivés de la même base.
iii) Sinon, la vérification à l'exécution échoue.
  • Si target-type est un type pointeur, le résultat est la valeur de pointeur nul de target-type .
  • Si target-type est un type référence, une exception d'un type qui correspondrait à un gestionnaire de type std::bad_cast est levée.

Lorsque dynamic_cast est utilisé dans un constructeur ou un destructeur (directement ou indirectement), et que expression fait référence à l'objet actuellement en cours de construction/destruction, l'objet est considéré comme l'objet le plus dérivé. Si target-type n'est pas un pointeur ou une référence vers la propre classe du constructeur/destructeur ou l'une de ses bases, le comportement est indéfini.

Similaire à d'autres expressions de cast, le résultat est :

  • une lvalue si target-type est un type référence
  • une rvalue si target-type est un type pointeur
(jusqu'à C++11)
  • une lvalue si target-type est un type référence lvalue ( expression doit être une lvalue)
  • une xvalue si target-type est un type référence rvalue ( expression peut être lvalue ou rvalue (jusqu'à C++17) doit être une glvalue (les prvalues sont matérialisées ) (depuis C++17) d'un type classe complet)
  • une prvalue si target-type est un type pointeur
(depuis C++11)

Notes

Un downcast peut également être effectué avec static_cast , ce qui évite le coût de la vérification à l'exécution, mais cela n'est sûr que si le programme peut garantir (par une autre logique) que l'objet pointé par expression est définitivement Derived .

Certaines formes de dynamic_cast reposent sur l' identification du type à l'exécution (RTTI), c'est-à-dire des informations sur chaque classe polymorphe dans le programme compilé. Les compilateurs disposent généralement d'options pour désactiver l'inclusion de ces informations.

Mots-clés

dynamic_cast

Exemple

#include <iostream>
struct V
{
    virtual void f() {} // doit être polymorphe pour utiliser dynamic_cast vérifié à l'exécution
};
struct A : virtual V {};
struct B : virtual V
{
    B(V* v, A* a)
    {
        // casts pendant la construction (voir l'appel dans le constructeur de D ci-dessous)
        dynamic_cast<B*>(v); // bien défini : v de type V*, V base de B, donne B*
        dynamic_cast<B*>(a); // comportement indéfini : a a le type A*, A n'est pas une 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; // l'objet le plus dérivé
    A& a = d; // upcast, dynamic_cast peut être utilisé, mais inutile
    [[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(); // sûr d'appeler
    }
    Base* b2 = new Derived;
    if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // sûr d'appeler
    }
    delete b1;
    delete b2;
}

Sortie :

downcast from b2 to d successful

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement corrigé
CWG 1269 C++11 la vérification à l'exécution n'était pas effectuée pour les
expression s xvalue si target-type est un type de référence rvalue
effectuée
CWG 2861 C++98 expression pouvait pointer/référencer un objet inaccessible par le type le comportement est indéfini dans ce cas

Références

  • Norme C++23 (ISO/IEC 14882:2024) :
  • 7.6.1.7 Dynamic cast [expr.dynamic.cast]
  • Norme C++20 (ISO/CEI 14882:2020) :
  • 7.6.1.6 Conversion dynamique [expr.dynamic.cast]
  • Norme C++17 (ISO/IEC 14882:2017) :
  • 8.2.7 Conversion dynamique [expr.dynamic.cast]
  • Norme C++14 (ISO/IEC 14882:2014) :
  • 5.2.7 Conversion dynamique [expr.dynamic.cast]
  • Norme C++11 (ISO/CEI 14882:2011) :
  • 5.2.7 Conversion dynamique [expr.dynamic.cast]
  • Norme C++98 (ISO/CEI 14882:1998) :
  • 5.2.7 Conversion dynamique [expr.dynamic.cast]
  • Norme C++03 (ISO/IEC 14882:2003) :
  • 5.2.7 Dynamic cast [expr.dynamic.cast]

Voir aussi