Namespaces
Variants

static_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 zwischen Typen unter Verwendung einer Kombination aus impliziten und benutzerdefinierten Konvertierungen.

Inhaltsverzeichnis

Syntax

static_cast< target-type  >( expression  )

Gibt einen Wert vom Typ target-type zurück.

Erklärung

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

1) Wenn expression ein Lvalue vom Typ " cv1 Base " ist und target-type "Referenz auf cv2 Derived " ist, referenziert das Ergebnis das Objekt vom Typ Derived , das expression umschließt, wenn alle folgenden Bedingungen erfüllt sind:
  • Derived ist ein vollständiger Klassentyp.
  • Base ist eine Basisklasse von Derived .
  • cv1 ist keine stärkere CV-Qualifikation als cv2 .
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm fehlerhaft:
Wenn expression tatsächlich kein Basisklassen-Subobjekt eines Objekts vom Typ Derived ist, ist das Verhalten undefiniert.
struct B {};
struct D : B { B b; };
D d;
B& br1 = d;
B& br2 = d.b;
static_cast<D&>(br1); // OK, L-Wert bezeichnet das ursprüngliche "d"-Objekt
static_cast<D&>(br2); // UB: Das "b"-Subobjekt ist kein Basisklassen-Subobjekt
2) Wenn target-type "Rvalue-Referenz auf Derived " ist und expression ein Xvalue vom Typ "(möglicherweise cv-qualifiziert) Base " ist, sodass Base eine Basisklasse von Derived ist, dann sind das Ergebnis und die Einschränkungen einer solchen Konvertierung dieselben wie bei der " Base -Lvalue-zu- Derived -Referenz"-Konvertierung.
3) Wenn target-type ein Rvalue-Referenztyp ist und der referenzierte Typ referenzkompatibel mit dem Typ von expression ist, konvertiert static_cast den Wert von Glvalue, Klassen-Prvalue oder Array-Prvalue (bis C++17) jedem Lvalue (seit C++17) expression zu einem Xvalue, der sich auf dasselbe Objekt wie der Ausdruck oder auf dessen Basisklassen-Subobjekt bezieht (abhängig von target-type ). [1]
Wenn target-type eine unzugängliche oder mehrdeutige Basis des Typs von expression ist, ist das Programm fehlerhaft.
Wenn expression ein Bitfeld -Lvalue ist, wird es zunächst in einen Prvalue des zugrundeliegenden Typs konvertiert.
(seit C++11)
4) Wenn target-type der (möglicherweise cv-qualifizierte) void ist, hat die Konvertierung kein Ergebnis. In diesem Fall ist expression ein verworfenen Wert Ausdruck .
5) Andernfalls kann expression explizit zu target-type konvertiert werden, falls

die Deklaration target-type temp ( expression  ) ; für eine erfundene temporäre Variable temp wohlgeformt ist.

Der Effekt einer solchen expliziten Konvertierung ist derselbe wie das Ausführen der Deklaration und Initialisierung und dann die Verwendung von temp als Ergebnis der Konvertierung. Die expression  wird als ein Lvalue (bis C++11) ein Glvalue (seit C++11) verwendet genau dann, wenn die Initialisierung sie als ein Lvalue (bis C++11) ein Glvalue (seit C++11) verwendet.

(bis C++17)

eine der folgenden Bedingungen erfüllt ist:

  • Es gibt eine implizite Konvertierungssequenz von expression zu target-type .
  • Die Overload Resolution für eine Direct-Initialization eines Objekts oder einer Referenz vom Typ target-type aus expression würde mindestens eine viable Funktion finden.
  • target-type ist ein Aggregate Type mit einem ersten Element x und es gibt eine implizite Konvertierungssequenz von expression zum Typ von x .
(seit C++20)

Die explizite Konvertierung ist wie folgt definiert:

  • Falls target-type ein Referenztyp ist, ist der Effekt derselbe wie das Ausführen der Deklaration und Initialisierung target-type temp ( expression  ) ; für eine erfundene temporäre Variable temp und dann die Verwendung von temp als Ergebnis der Konvertierung.
  • Andernfalls wird das Ergebnisobjekt direkt aus expression  initialisiert.
(seit C++17)
6) Andernfalls, falls die Konvertierung von expression zu target-type eine Umkehrung einer Standardkonvertierungssequenz ist und die Konvertierungssequenz keine der folgenden Konvertierungen enthält, kann die Konvertierung durch static_cast durchgeführt werden:
(seit C++17)
Wenn ein Programm static_cast verwendet, um die Umkehrung einer fehlerhaften Standardkonvertierungssequenz durchzuführen, ist es fehlerhaft.
7) Andernfalls werden Lvalue-zu-Rvalue-, Array-zu-Zeiger- und Funktion-zu-Zeiger-Konvertierungen auf expression angewendet. Nach diesen Konvertierungen können nur die folgenden Konvertierungen durch static_cast durchgeführt werden:
a) Ein Wert eines scoped enumeration -Typs kann in einen Integer- oder Gleitkommatyp konvertiert werden.
  • Wenn target-type (möglicherweise cv-qualifiziert) bool ist, ist das Ergebnis false , wenn der ursprüngliche Wert von expression null ist, und true für alle anderen Werte.
  • Wenn target-type ein integraler Typ außer (möglicherweise cv-qualifiziert) bool ist, bleibt der Wert unverändert, wenn der ursprüngliche Wert von expression durch target-type dargestellt werden kann. Andernfalls ist der resultierende Wert unspezifiziert.
(bis C++20)
  • Wenn target-type ein integraler Typ ist, ist das Ergebnis dasselbe wie bei der Konvertierung in den zugrunde liegenden Typ der Enumeration und dann in target-type .
(seit C++20)
  • Wenn target-type ein Gleitkommatyp ist, ist das Ergebnis dasselbe wie bei der Konvertierung vom ursprünglichen Wert zu target-type .
(seit C++11)
b) Ein Wert eines ganzzahligen oder Aufzählungstyps kann in jeden vollständigen Aufzählungstyp konvertiert werden.
  • Wenn target-type einen festen zugrundeliegenden Typ hat, wird expression zunächst durch integral promotion oder integral conversion bei Bedarf in diesen Typ konvertiert und anschließend in target-type .
  • Wenn target-type keinen festen zugrundeliegenden Typ hat, bleibt der Wert von expression unverändert, wenn der ursprüngliche Wert within the range of the enumeration values ist, andernfalls ist das Verhalten undefiniert.
c) Ein Wert eines Gleitkommatyps kann ebenfalls in jeden vollständigen Aufzählungstyp konvertiert werden. Das Ergebnis entspricht dem Konvertieren des ursprünglichen Werts von expression zuerst in den zugrundeliegenden Typ von target-type und dann in target-type selbst.
d) Ein Prvalue eines Gleitkommatyps kann explizit in jeden anderen Gleitkommatyp konvertiert werden.
  • Wenn der Quellwert von expression exakt in target-type dargestellt werden kann, ändert er sich nicht.
  • Andernfalls, wenn der Quellwert von expression zwischen zwei darstellbaren Werten von target-type liegt, ist das Ergebnis der Konvertierung eine implementierungsdefinierte Auswahl eines dieser Werte. [2]
  • Andernfalls ist das Verhalten undefiniert.
(since C++23)
e) Ein Rvalue (bis C++11) Ein Prvalue (seit C++11) vom Typ "Zeiger auf cv1 Base " kann explizit in den Typ "Zeiger auf cv2 Derived " konvertiert werden, wenn alle folgenden Bedingungen erfüllt sind:
  • Derived ist ein vollständiger Klassentyp.
  • Base ist eine Basisklasse von Derived .
  • cv1 ist keine stärkere CV-Qualifizierung als cv2 .
Wenn expression ein Null-Zeigerwert ist, dann ist das Ergebnis ein Null-Zeigerwert vom Typ target-type . Andernfalls ist das Ergebnis ein Zeiger auf das Objekt vom Typ Derived , das das Objekt vom Typ Base umschließt, auf das expression zeigt.
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm fehlerhaft:
  • Base ist eine virtuelle Basisklasse von Derived .
  • Base ist eine Basisklasse einer virtuellen Basisklasse von Derived .
  • Keine gültige Standardkonvertierung von "Zeiger auf Derived " zu "Zeiger auf Base " existiert.
Wenn expression kein Nullzeigerwert ist und nicht tatsächlich auf ein Basisklassen-Subobjekt eines Objekts vom Typ Derived zeigt, ist das Verhalten undefiniert.
f) Ein Rvalue (bis C++11) Ein Prvalue (seit C++11) vom Typ "Zeiger auf Mitglied von Derived vom Typ cv1 T " kann explizit in den Typ "Zeiger auf Mitglied von Base vom Typ cv2 T " konvertiert werden, wenn alle folgenden Bedingungen erfüllt sind:
  • Derived ist ein vollständiger Klassentyp.
  • Base ist eine Basisklasse von Derived .
  • cv1 ist keine stärkere CV-Qualifizierung als cv2 .
Wenn expression ein Null-Memberzeigerwert ist, ist das Ergebnis ein Null-Memberzeigerwert vom Typ target-type . Andernfalls ist das Ergebnis ein Zeiger auf das ursprüngliche (möglicherweise indirekte) Mitglied der Klasse Base .
Falls keine gültige Standardkonvertierung von "Zeiger auf Member von Base vom Typ T " zu "Zeiger auf Member von Derived vom Typ T " existiert, ist das Programm fehlerhaft.
Wenn expression kein Null-Memberzeigerwert ist und das bezeichnete Member kein (möglicherweise indirektes) Member der Klasse Base ist, ist das Verhalten undefiniert.
g) Ein Rvalue (bis C++11) Ein Prvalue (seit C++11) vom Typ "Zeiger auf cv1 void " kann explizit in den Typ "Zeiger auf cv2 T " konvertiert werden, wenn T ein Objekttyp ist und cv1 keine stärkere CV-Qualifizierung als cv2 darstellt.
  • Wenn Ausdruck ein Nullzeigerwert ist, ist das Ergebnis ein Nullzeigerwert vom Typ Zieltyp .
  • Wenn der Ausdruck die Adresse A eines Bytes im Speicher repräsentiert und A die Ausrichtungsanforderung von T erfüllt, dann repräsentiert der resultierende Zeigerwert ebenfalls A .
  • Das Ergebnis jeder anderen solchen Zeigerkonvertierung ist nicht spezifiziert.
  • Wenn Ausdruck das Ergebnis einer vorherigen Konvertierung von einem Objekt vom Typ "Zeiger auf cv3 T " ist, hat das Ergebnis den ursprünglichen Wert.
(bis C++17)
  • Wenn Ausdruck die Adresse A eines Bytes im Speicher repräsentiert, aber A die Ausrichtungsanforderung von T nicht erfüllt, dann ist der resultierende Zeigerwert nicht spezifiziert.
  • Andernfalls, wenn Ausdruck auf ein Objekt a zeigt und es ein Objekt b vom Typ T (unter Ignorierung der CV-Qualifizierung) gibt, das zeigerinterkonvertierbar (siehe unten) mit a ist, dann ist das Ergebnis ein Zeiger auf b .
  • Andernfalls wird der Zeigerwert durch die Konvertierung nicht verändert.
(seit C++17)

Wie bei allen Umwandlungsausdrücken ist das Ergebnis:

  • ein lvalue, wenn target-type ein lvalue reference type ist oder ein rvalue reference to function type (seit C++11) ;
  • ein xvalue, falls target-type eine Rvalue-Referenz auf Objekttyp ist;
(since C++11)
  • ein prvalue andernfalls.
  1. Diese Art von static_cast wird verwendet, um Move-Semantik in std::move zu implementieren.
  2. Falls IEEE-Arithmetik unterstützt wird, ist das Standardrundungsverfahren "Round to Nearest".

Zeiger-interkonvertierbare Objekte

Zwei Objekte a und b sind zeigerinterkonvertierbar wenn:

  • sie dasselbe Objekt sind, oder
  • eines ein Union-Objekt und das andere ein nicht-statisches Datenelement dieses Objekts ist, oder
  • eines ein Standard-Layout Klassenobjekt und das andere das erste nicht-statische Datenelement dieses Objekts oder irgendein Basisklassen-Subobjekt dieses Objekts ist, oder
  • ein Objekt c existiert, sodass a und c zeigerinterkonvertierbar sind, und c und b zeigerinterkonvertierbar sind.
union U { int a; double b; } u;
void* x = &u;                        // Der Wert von x ist „Zeiger auf u“
double* y = static_cast<double*>(x); // Der Wert von y ist „Zeiger auf u.b“
char* z = static_cast<char*>(x);     // Der Wert von z ist „Zeiger auf u“

Hinweise

Basis-zu-abgeleitet-Konvertierungen ( Downcasts ) mit static_cast führen keine Laufzeitprüfungen durch, um sicherzustellen, dass der dynamische Typ des gezeigten/referenzierten Objekts Derived ist, und können nur sicher verwendet werden, wenn diese Voraussetzung durch andere Mittel gewährleistet ist, wie beispielsweise bei der Implementierung von statischem Polymorphismus . Sichere Downcasts können mit dynamic_cast durchgeführt werden.

static_cast kann auch verwendet werden, um Funktionsüberladungen zu disambiguieren, indem eine Funktion-zu-Zeiger-Konvertierung zu einem spezifischen Typ durchgeführt wird, wie in

std::for_each(files.begin(), files.end(),
              static_cast<std::ostream&(*)(std::ostream&)>(std::flush));

Schlüsselwörter

static_cast

Beispiel

#include <iostream>
#include <vector>
struct B
{
    int m = 42;
    const char* hello() const
    {
        return "Hello world, this is B!\n";
    }
};
struct D : B
{
    const char* hello() const
    {
        return "Hello world, this is D!\n";
    }
};
enum class E { ONE = 1, TWO, THREE };
enum EU { ONE = 1, TWO, THREE };
int main()
{
    // 1. statischer Downcast
    D d;
    B& br = d; // Upcast durch implizite Konvertierung
    std::cout << "1) " << br.hello();
    D& another_d = static_cast<D&>(br); // Downcast
    std::cout << "1) " << another_d.hello();
    // 3. Lvalue zu Xvalue
    std::vector<int> v0{1, 2, 3};
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v0);
    std::cout << "3) nach Move, v0.size() = " << v0.size() << '\n';
    // 4. Ausdruck mit verworfenem Wert
    static_cast<void>(v2.size());
    // 5. Initialisierungskonvertierung
    int n = static_cast<int>(3.14);
    std::cout << "5) n = " << n << '\n';
    std::vector<int> v = static_cast<std::vector<int>>(10);
    std::cout << "5) v.size() = " << v.size() << '\n';
    // 6. Umkehrung der impliziten Konvertierung
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "6) *ni = " << *ni << '\n';
    // 7a. Scoped Enum zu int
    E e = E::TWO;
    int two = static_cast<int>(e);
    std::cout << "7a) " << two << '\n';
    // 7b. int zu Enum, Enum zu anderem Enum
    E e2 = static_cast<E>(two);
    [[maybe_unused]]
    EU eu = static_cast<EU>(e2);
    // 7f. Zeiger auf Member-Upcast
    int D::*pm = &D::m;
    std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n';
    // 7g. void* zu beliebigem Objektzeiger
    void* voidp = &e;
    [[maybe_unused]]
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

Ausgabe:

1) Hallo Welt, dies ist B!
1) Hallo Welt, dies ist D!
3) nach Verschiebung, v0.size() = 0
5) n = 3
5) v.size() = 10
6) *ni = 3
7a) 2
7f) 42

Fehlerberichte

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

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 137 C++98 die Konstanz und Volatilität von
Zeigern auf void konnten weggecastet werden
CV-Qualifizierungen können in
solchen Fällen nicht weggecastet werden
CWG 427 C++98 Downcast könnte mit Direktinitialisierung mehrdeutig sein wählt in diesem Fall Downcast aus
CWG 439 C++98 beim Konvertieren eines "Zeigers auf Objekt" zu "Zeiger auf
void " und zurück zu sich selbst konnte der Wert nur erhalten
bleiben, wenn der Ergebnistyp dieselbe CV-Qualifizierung hat
CV-Qualifizierung
kann unterschiedlich sein
CWG 1094 C++98 die Konvertierung von Gleitkommawerten
zu Aufzählungswerten war nicht spezifiziert
spezifiziert
CWG 1320 C++11 die Konvertierung von scoped enumeration
Werten zu bool war nicht spezifiziert
spezifiziert
CWG 1412 C++98 das Ergebnis der Konvertierung von
"Zeiger auf
void " zu "Zeiger auf Objekt" war unklar
klargestellt
CWG 1447 C++11 die Konvertierung von Bitfeldern zu Rvalue-Referenzen
war nicht spezifiziert (Referenzen können nicht an Bitfelder gebunden werden)
spezifiziert
CWG 1766 C++98 die Konvertierung von Ganzzahl- oder Aufzählungswerten zu Aufzählungswerten
ergab ein nicht spezifiziertes Ergebnis, wenn expression außerhalb des Bereichs liegt
das Verhalten ist
in diesem Fall undefiniert
CWG 1832 C++98 die Konvertierung von Ganzzahl- oder Aufzählungswerten zu
Aufzählungswerten erlaubte, dass target-type unvollständig sein konnte
nicht erlaubt
CWG 2224 C++98 die Konvertierung von einem Member vom Basistyp zu
seinem vollständigen Objekt vom abgeleiteten Klassentyp war gültig
das Verhalten ist
in diesem Fall undefiniert
CWG 2254 C++11 ein Standard-Layout-Klassenobjekt ohne Datenelemente
war zeigerinterkonvertierbar mit seiner ersten Basisklasse
es ist zeigerinterkonvertierbar
mit jeder seiner Basisklassen
CWG 2284 C++11 ein Nicht-Standard-Layout-Union-Objekt und ein nicht-statisches Datenelement
dieses Objekts waren nicht zeigerinterkonvertierbar
sie sind es
CWG 2310 C++98 für Basis-zu-abgeleitet Zeigerkonvertierungen und
abgeleitet-zu-Basis Zeiger-zu-Member-Konvertierungen
konnte der abgeleitete Klassentyp unvollständig sein
muss vollständig sein
CWG 2338 C++11 die Konvertierung zu Aufzählungstypen mit festem zugrundeliegendem Typ
führte zu undefiniertem Verhalten, wenn expression außerhalb des Bereichs liegt
zuerst zum zugrundeliegenden Typ
konvertieren (kein undefiniertes Verhalten)
CWG 2499 C++11 eine Standard-Layout-Klasse könnte eine nicht-zeigerinterkonvertierbare
Basisklasse haben, obwohl alle Basis-Subobjekte dieselbe Adresse haben
hat sie nicht
CWG 2718 C++98 für Basis-zu-abgeleitet Referenzkonvertierungen
konnte der abgeleitete Klassentyp unvollständig sein
muss vollständig sein
CWG 2882 C++98 es war unklar, ob static_cast < void > ( expr ) versucht,
eine implizite Konvertierungssequenz von expr zu void zu bilden
kein Versuch in diesem Fall

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 7.6.1.9 Static cast [expr.static.cast]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 7.6.1.8 Static cast [expr.static.cast]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 8.2.9 Static cast [expr.static.cast]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 5.2.9 Static cast [expr.static.cast]
  • C++11-Standard (ISO/IEC 14882:2011):
  • 5.2.9 Static cast [expr.static.cast]
  • C++98 Standard (ISO/IEC 14882:1998):
  • 5.2.9 Static cast [expr.static.cast]
  • C++03-Standard (ISO/IEC 14882:2003):
  • 5.2.9 Static cast [expr.static.cast]

Siehe auch