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

Konvertiert sicher Zeiger und Referenzen auf Klassen aufwärts, abwärts und seitwärts entlang der Vererbungshierarchie.

Inhaltsverzeichnis

Syntax

dynamic_cast< Zieltyp >( Ausdruck )
target-type - Zeiger auf vollständigen Klassentyp, Referenz auf vollständigen Klassentyp oder Zeiger auf (optional cv-qualifizierten) void
expression - Lvalue (bis C++11) Glvalue (seit C++11) eines vollständigen Klassentyps, wenn target-type eine Referenz ist; Prvalue eines Zeigers auf vollständigen Klassentyp, wenn target-type ein Zeiger ist

Erklärung

Zur Vereinfachung der Beschreibung bedeutet „ expression oder das Ergebnis ist eine Referenz auf T “, dass „es ein Glvalue vom Typ T ist“ , was der Konvention von decltype (seit C++11) folgt.

Nur die folgenden Konvertierungen können mit dynamic_cast durchgeführt werden, außer wenn solche Konvertierungen Constness entfernen würden (oder Volatilität).

1) Wenn der Typ von expression exakt target-type oder eine weniger cv-qualifizierte Version von target-type ist, dann ist das Ergebnis der Wert von expression mit dem Typ target-type . Mit anderen Worten, dynamic_cast kann verwendet werden, um Constness hinzuzufügen . Eine implizite Konvertierung und static_cast können diese Konvertierung ebenfalls durchführen.
2) Wenn target-type "Zeiger auf (möglicherweise cv-qualifiziertes) Base " ist und der Typ von expression "Zeiger auf (möglicherweise cv-qualifiziertes) Derived " ist, sodass Base eine Basisklasse von Derived ist, dann ist das Ergebnis
  • ein Nullzeigerwert, wenn expression ein Nullzeigerwert ist, oder
  • ein Zeiger auf das eindeutige Base Subobjekt des Derived -Objekts, auf das expression zeigt, andernfalls. Mit anderen Worten, dynamic_cast kann verwendet werden, um Zeiger upzucasten , von abgeleitet zu basis. Eine implizite Konvertierung und static_cast können diese Konvertierung ebenfalls durchführen.
3) Wenn target-type "Referenz auf (möglicherweise cv-qualifiziertes) Base " ist und der Typ von expression "(möglicherweise cv-qualifiziertes) Derived " ist, sodass Base eine Basisklasse von Derived ist, dann ist das Ergebnis das eindeutige Base -Subobjekt des Derived -Objekts, auf das durch expression verwiesen wird. Mit anderen Worten kann dynamic_cast verwendet werden, um Referenzen upzucasten , von abgeleiteter zu Basisklasse. Eine implizite Konvertierung und static_cast können diese Konvertierung ebenfalls durchführen.
4) Wenn expression ein Nullzeigerwert eines polymorphen Typs ist, dann ist das Ergebnis der Nullzeigerwert von target-type .
5) Andernfalls muss expression ein Zeiger oder eine Referenz auf ein Objekt polymorphen Typs innerhalb seiner Lebensdauer oder innerhalb seiner Konstruktions- oder Destruktionsphase sein, dessen Typ ähnlich zum Typ von expression ist (andernfalls ist das Verhalten undefiniert)
a) Wenn expression ein Zeiger auf (möglicherweise cv-qualifiziertes) void ist, dann ist das Ergebnis ein Zeiger auf das am meisten abgeleitete Objekt , auf das expression zeigt.
b) Andernfalls wird eine Laufzeitprüfung durchgeführt, um festzustellen, ob das Objekt, auf das/das durch expression gezeigt/verwiesen wird, in den Typ Target konvertiert werden kann, auf den/das durch target-type gezeigt/verwiesen wird:
i) Wenn im am meisten abgeleiteten Objekt, auf das/das durch expression gezeigt/verwiesen wird, expression auf ein öffentliches Basisklassen-Subobjekt eines Target -Objekts zeigt/verweist, und wenn nur ein Objekt vom Typ Target von dem Subobjekt abgeleitet ist, auf das/das durch expression gezeigt/verwiesen wird, zeigt/verweist das Ergebnis auf dieses Target -Objekt. Mit anderen Worten, dynamic_cast kann verwendet werden, um Zeiger/Referenzen abwärts zu konvertieren , von Basis zu abgeleitet.
ii) Andernfalls, wenn expression auf ein öffentliches Basisklassen-Subobjekt des vollständig abgeleiteten Objekts zeigt/verweist und der Typ des vollständig abgeleiteten Objekts eine eindeutige und öffentliche Basisklasse vom Typ Target besitzt, zeigt/verweist das Ergebnis auf das Target -Subobjekt des vollständig abgeleiteten Objekts. Mit anderen Worten, dynamic_cast kann verwendet werden, um Crosscasting (oder Side-Casting) von Zeigern/Referenzen zwischen zwei Typen durchzuführen, die von derselben Basis abgeleitet sind.
iii) Andernfalls schlägt die Laufzeitprüfung fehl.
  • Wenn target-type ein Zeigertyp ist, ist das Ergebnis der Nullzeigerwert von target-type .
  • Wenn target-type ein Referenztyp ist, wird eine Ausnahme eines Typs ausgelöst, der zu einem Handler vom Typ std::bad_cast passen würde.

Wenn dynamic_cast in einem Konstruktor oder Destruktor verwendet wird (direkt oder indirekt) und expression auf das Objekt verweist, das sich gerade im Konstruktions-/Destruktionsprozess befindet, wird das Objekt als das am stärksten abgeleitete Objekt betrachtet. Wenn target-type kein Zeiger oder keine Referenz auf die eigene Klasse des Konstruktors/Destruktors oder eine seiner Basisklassen ist, ist das Verhalten undefiniert.

Ähnlich wie bei anderen Umwandlungsausdrücken ist das Ergebnis:

  • ein Lvalue, falls target-type ein Referenztyp ist
  • ein Rvalue, falls target-type ein Zeigertyp ist
(bis C++11)
  • ein Lvalue, falls target-type ein Lvalue-Referenztyp ist ( expression muss ein Lvalue sein)
  • ein Xvalue, falls target-type ein Rvalue-Referenztyp ist ( expression kann Lvalue oder Rvalue sein (bis C++17) muss ein Glvalue sein (Prvalues werden materialisiert ) (seit C++17) eines vollständigen Klassentyps)
  • ein Prvalue, falls target-type ein Zeigertyp ist
(seit C++11)

Hinweise

Ein Downcast kann auch mit static_cast durchgeführt werden, was die Kosten der Laufzeitprüfung vermeidet, aber nur sicher ist, wenn das Programm garantieren kann (durch andere Logik), dass das Objekt, auf das expression zeigt, definitiv Derived ist.

Einige Formen von dynamic_cast basieren auf Laufzeit-Typinformation (RTTI), also Informationen über jede polymorphe Klasse im kompilierten Programm. Compiler bieten typischerweise Optionen zum Deaktivieren der Einbindung dieser Informationen.

Schlüsselwörter

dynamic_cast

Beispiel

#include <iostream>
struct V
{
    virtual void f() {} // muss polymorph sein, um dynamische Typumwandlung zur Laufzeit zu verwenden
};
struct A : virtual V {};
struct B : virtual V
{
    B(V* v, A* a)
    {
        // Typumwandlungen während der Konstruktion (siehe Aufruf im Konstruktor von D unten)
        dynamic_cast<B*>(v); // wohldefiniert: v vom Typ V*, V Basis von B, ergibt B*
        dynamic_cast<B*>(a); // undefiniertes Verhalten: a hat Typ A*, A keine Basis von 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; // das am meisten abgeleitete Objekt
    A& a = d; // Upcast, dynamic_cast könnte verwendet werden, aber unnötig
    [[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(); // sicher aufzurufen
    }
    Base* b2 = new Derived;
    if (Derived* d = dynamic_cast<Derived*>(b2); d != nullptr)
    {
        std::cout << "downcast from b2 to d successful\n";
        d->name(); // sicher aufzurufen
    }
    delete b1;
    delete b2;
}

Ausgabe:

downcast from b2 to d successful

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrigiertes Verhalten
CWG 1269 C++11 die Laufzeitprüfung wurde nicht für xvalue
expression s durchgeführt, wenn target-type ein Rvalue-Referenztyp ist
durchgeführt
CWG 2861 C++98 expression könnte auf ein typunzugängliches Objekt zeigen/verweisen das Verhalten ist in diesem Fall undefiniert

Referenzen

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

Siehe auch