Namensräume
Varianten
Aktionen

static_cast-Konvertierung

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

Konvertiert zwischen Typen unter Verwendung einer Kombination aus impliziten und benutzerdefinierten Konvertierungen.

Inhalt

[bearbeiten] Syntax

static_cast<Zieltyp >(Ausdruck )

Gibt einen Wert vom Typ Zieltyp zurück.

[bearbeiten] Erklärung

Nur die folgenden Konvertierungen können mit static_cast durchgeführt werden, es sei denn, solche Konvertierungen würden constness (oder Volatilität) aufheben.

1) Wenn Ausdruck ein lvalue vom Typ „cv1 Basis“ ist und Zieltyp „Referenz auf cv2 Abgeleitet“ ist, verweist das Ergebnis auf das Objekt vom Typ Abgeleitet, das Ausdruck umschließt, wenn alle folgenden Bedingungen erfüllt sind
  • Abgeleitet ist ein vollständiger Klassentyp.
  • Basis ist eine Basisklasse von Abgeleitet.
  • cv1 ist nicht stärker cv-qualifiziert als cv2.
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm ill-formed
  • Basis ist eine virtuelle Basisklasse von Abgeleitet.
  • Basis ist eine Basisklasse einer virtuellen Basisklasse von Abgeleitet.
  • Keine gültige Standardkonvertierung von „Zeiger auf Abgeleitet“ zu „Zeiger auf Basis“ existiert.
Wenn Ausdruck tatsächlich kein Basisklassen-Unterobjekt eines Objekts vom Typ Abgeleitet 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, lvalue denoting the original “d” object
static_cast<D&>(br2); // UB: the “b” subobject is not a base class subobject
2) Wenn Zieltyp ein rvalue-Referenztyp zu Abgeleitet ist und Ausdruck ein xvalue vom Typ „(möglicherweise cv-qualifiziert) Basis“ ist, sodass Basis eine Basisklasse von Abgeleitet ist, sind das Ergebnis und die Einschränkungen einer solchen Konvertierung dieselben wie bei der Konvertierung „Basis-lvalue zu Abgeleitet-Referenz“.
3) Wenn Zieltyp ein rvalue-Referenztyp ist und der referenzierte Typ referenzkompatibel mit dem Typ von Ausdruck ist, konvertiert static_cast den Wert von glvalue, Klassen-prvalue oder Array-prvalue(bis C++17)jedem lvalue(seit C++17) Ausdruck zu einem xvalue, das auf dasselbe Objekt verweist wie der Ausdruck, oder auf dessen Basisklassen-Unterobjekt (abhängig von Zieltyp).[1]
Wenn Zieltyp eine inkoommnig oder ambigue Basis des Typs von Ausdruck ist, ist das Programm ill-formed.
Wenn Ausdruck ein lvalue eines Bitfeldes ist, wird es zuerst in ein prvalue des zugrunde liegenden Typs konvertiert.
(seit C++11)
4) Wenn Zieltyp (möglicherweise cv-qualifiziertes) void ist, hat die Konvertierung kein Ergebnis. In diesem Fall ist Ausdruck ein discarded-value expression.
5) Andernfalls kann Ausdruck explizit in Zieltyp konvertiert werden, wenn

die Deklaration Zieltyp temp(Ausdruck ); für eine erfundene temporäre Variable temp wohlgeformt ist.

Die Auswirkung einer solchen expliziten Konvertierung ist dieselbe wie die Durchführung der Deklaration und Initialisierung und anschließende Verwendung von temp als Ergebnis der Konvertierung. Ausdruck  wird genau dann als lvalue verwendet, wenn die Initialisierung ihn als lvalue verwendet (bis C++11) / als glvalue verwendet (seit C++11).

(bis C++17)

eine der folgenden Bedingungen erfüllt ist

  • Es gibt eine implizite Konvertierungssequenz von Ausdruck zu Zieltyp.
  • Die Überladungsauflösung für eine direkte Initialisierung eines Objekts oder einer Referenz vom Typ Zieltyp aus Ausdruck würde mindestens eine geeignete Funktion finden.
  • Zieltyp ist ein Aggregattyp mit einem ersten Element x, und es gibt eine implizite Konvertierungssequenz von Ausdruck zum Typ von x.
(seit C++20)

Die explizite Konvertierung ist wie folgt definiert

  • Wenn Zieltyp ein Referenztyp ist, ist die Auswirkung dieselbe wie die Durchführung der Deklaration und Initialisierung Zieltyp temp(Ausdruck ); für eine erfundene temporäre Variable temp und anschließende Verwendung von temp als Ergebnis der Konvertierung.
  • Andernfalls wird das Ergebnisobjekt direkt aus Ausdruck  initialisiert.
(seit C++17)
6) Andernfalls, wenn die Konvertierung von Ausdruck zu Zieltyp 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 ill-formed Standardkonvertierungssequenz durchzuführen, ist es ill-formed.
7) Andernfalls werden lvalue-zu-rvalue-, Array-zu-Zeiger- und Funktions-zu-Zeiger-Konvertierungen auf Ausdruck angewendet. Nach diesen Konvertierungen können nur die folgenden Konvertierungen durch static_cast durchgeführt werden
a) Ein Wert eines Scope-Enumerationstyps kann in einen Ganzzahl- oder Fließkommatyp konvertiert werden.
  • Wenn Zieltyp (möglicherweise cv-qualifiziertes) bool ist, ist das Ergebnis false, wenn der ursprüngliche Wert von Ausdruck Null ist, und true für alle anderen Werte.
  • Wenn Zieltyp ein Ganzzahltyp außer (möglicherweise cv-qualifiziertem) bool ist, bleibt der Wert unverändert, wenn der ursprüngliche Wert von Ausdruck durch Zieltyp dargestellt werden kann. Andernfalls ist der resultierende Wert nicht spezifiziert.
(bis C++20)
  • Wenn Zieltyp ein Ganzzahltyp ist, ist das Ergebnis dasselbe wie bei der Konvertierung in den zugrunde liegenden Typ der Aufzählung und dann in Zieltyp.
(seit C++20)
  • Wenn Zieltyp ein Fließkommatyp ist, ist das Ergebnis dasselbe wie bei der Konvertierung des ursprünglichen Werts in Zieltyp.
(seit C++11)
b) Ein Wert eines Ganzzahl- oder Aufzählungstyps kann in jeden vollständigen Aufzählungstyp konvertiert werden.
  • Wenn Zieltyp einen festen zugrunde liegenden Typ hat, wird Ausdruck zuerst durch Integral Promotion oder Integral Conversion, falls erforderlich, in diesen Typ konvertiert und dann in Zieltyp.
  • Wenn Zieltyp keinen festen zugrunde liegenden Typ hat, bleibt der Wert von Ausdruck unverändert, wenn der ursprüngliche Wert innerhalb des Bereichs der Aufzählungswerte liegt, andernfalls ist das Verhalten undefiniert.
c) Ein Wert eines Fließkommatyps kann auch in jeden vollständigen Aufzählungstyp konvertiert werden. Das Ergebnis ist dasselbe wie bei der Konvertierung des ursprünglichen Werts von Ausdruck zuerst in den zugrunde liegenden Typ von Zieltyp und dann in Zieltyp selbst.
d) Ein prvalue vom Fließkommatyp kann explizit in jeden anderen Fließkommatyp konvertiert werden.
  • Wenn der Quellwert von Ausdruck exakt in Zieltyp dargestellt werden kann, ändert er sich nicht.
  • Andernfalls, wenn der Quellwert von Ausdruck zwischen zwei darstellbaren Werten von Zieltyp liegt, ist das Ergebnis der Konvertierung eine implementierungsdefinierte Wahl eines dieser beiden Werte.[2]
  • Andernfalls ist das Verhalten undefiniert.
(seit C++23)
e) Ein prvalue vom Typ „Zeiger auf cv1 Basis“ kann explizit in den Typ „Zeiger auf cv2 Abgeleitet“ konvertiert werden, wenn alle folgenden Bedingungen erfüllt sind
  • Abgeleitet ist ein vollständiger Klassentyp.
  • Basis ist eine Basisklasse von Abgeleitet.
  • cv1 ist nicht stärker cv-qualifiziert als cv2.
Wenn Ausdruck ein Nullzeigerwert ist, ist das Ergebnis ein Nullzeigerwert vom Typ Zieltyp. Andernfalls ist das Ergebnis ein Zeiger auf das Objekt vom Typ Abgeleitet, das das Objekt vom Typ Basis umschließt, auf das Ausdruck zeigt.
Wenn eine der folgenden Bedingungen erfüllt ist, ist das Programm ill-formed
  • Basis ist eine virtuelle Basisklasse von Abgeleitet.
  • Basis ist eine Basisklasse einer virtuellen Basisklasse von Abgeleitet.
  • Keine gültige Standardkonvertierung von „Zeiger auf Abgeleitet“ zu „Zeiger auf Basis“ existiert.
Wenn Ausdruck kein Nullzeigerwert ist und nicht tatsächlich auf ein Basisklassen-Unterobjekt eines Objekts vom Typ Abgeleitet zeigt, ist das Verhalten undefiniert.
f) Ein prvalue vom Typ „Zeiger auf Member von Abgeleitet vom Typ cv1 T“ kann explizit in den Typ „Zeiger auf Member von Basis vom Typ cv2 T“ konvertiert werden, wenn alle folgenden Bedingungen erfüllt sind
  • Abgeleitet ist ein vollständiger Klassentyp.
  • Basis ist eine Basisklasse von Abgeleitet.
  • cv1 ist nicht stärker cv-qualifiziert als cv2.
Wenn Ausdruck ein Null-Member-Zeigerwert ist, ist das Ergebnis ein Null-Member-Zeigerwert vom Typ Zieltyp. Andernfalls ist das Ergebnis ein Zeiger auf das ursprüngliche (möglicherweise indirekte) Member der Klasse Basis.
Wenn keine gültige Standardkonvertierung von „Zeiger auf Member von Basis vom Typ T“ zu „Zeiger auf Member von Abgeleitet vom Typ T“ existiert, ist das Programm ill-formed.
Wenn Ausdruck kein Null-Member-Zeigerwert ist und das von ihm bezeichnete Member kein (möglicherweise indirektes) Member der Klasse Basis ist, ist das Verhalten undefiniert.
g) Ein prvalue vom Typ „Zeiger auf cv1 void“ kann explizit in den Typ „Zeiger auf cv2 T“ konvertiert werden, wenn T ein Objekttyp ist und cv1 nicht stärker cv-qualifiziert ist als cv2.
  • Wenn Ausdruck ein Nullzeigerwert ist, ist das Ergebnis ein Nullzeigerwert vom Typ Zieltyp.
  • Wenn der Ausdruck die Adresse A eines Bytes im Speicher darstellt und A die Alignmentanforderung von T erfüllt, dann stellt der resultierende Zeigerwert ebenfalls A dar.
  • 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 darstellt, aber A die Alignmentanforderung 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-Qualifikation) gibt, das mit a zeiger-interkonvertierbar ist (siehe unten), ist das Ergebnis ein Zeiger auf b.
  • Andernfalls bleibt der Zeigerwert durch die Konvertierung unverändert.
(seit C++17)

Wie bei allen Cast-Ausdrücken ist das Ergebnis

  • ein lvalue, wenn Zieltyp ein lvalue-Referenztyp ist oder ein rvalue-Referenztyp auf eine Funktion(seit C++11);
  • ein xvalue, wenn Zieltyp ein rvalue-Referenztyp auf ein Objekt ist;
(seit C++11)
  • sonst ein prvalue.
  1. Diese Art von static_cast wird verwendet, um Move-Semantik in std::move zu implementieren.
  2. Wenn IEEE-Arithmetik unterstützt wird, ist das Runden standardmäßig auf die nächste ganze Zahl gerundet.

[bearbeiten] Zeiger-interkonvertierbare Objekte

Zwei Objekte a und b sind zeiger-interkonvertierbar, wenn

  • sie dasselbe Objekt sind, oder
  • eins ein Union-Objekt ist und das andere ein nicht-statisches Datenelement dieses Objekts ist, oder
  • eins ein Standard-Layout-Klassenobjekt ist und das andere das erste nicht-statische Datenelement dieses Objekts oder irgendein Basisklassen-Unterobjekt dieses Objekts ist, oder
  • es ein Objekt c gibt, so dass a und c zeiger-interkonvertierbar sind, und c und b zeiger-interkonvertierbar sind.
union U { int a; double b; } u;
void* x = &u;                        // x's value is “pointer to u”
double* y = static_cast<double*>(x); // y's value is “pointer to u.b”
char* z = static_cast<char*>(x);     // z's value is “pointer to u”

[bearbeiten] Hinweise

Basis-zu-abgeleitete Konvertierungen (Downcasts) mit static_cast führen keine Laufzeitprüfungen durch, um sicherzustellen, dass der dynamische Typ des zeigenden/referenzierten Objekts Abgeleitet ist, und dürfen nur sicher verwendet werden, wenn diese Vorbedingung durch andere Mittel garantiert ist, z. B. bei der Implementierung von statischer Polymorphie. Sichere Downcasts können mit dynamic_cast durchgeführt werden.

static_cast kann auch zur Disambiguierung von Funktionsüberladungen verwendet werden, indem eine Funktions-zu-Zeiger-Konvertierung zu einem bestimmten Typ durchgeführt wird, wie in

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

[bearbeiten] Schlüsselwörter

static_cast

[bearbeiten] 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. static downcast
    D d;
    B& br = d; // upcast via implicit conversion
    std::cout << "1) " << br.hello();
    D& another_d = static_cast<D&>(br); // downcast
    std::cout << "1) " << another_d.hello();
 
    // 3. lvalue to xvalue
    std::vector<int> v0{1, 2, 3};
    std::vector<int> v2 = static_cast<std::vector<int>&&>(v0);
    std::cout << "3) after move, v0.size() = " << v0.size() << '\n';
 
    // 4. discarded-value expression
    static_cast<void>(v2.size());
 
    // 5. initializing conversion
    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. inverse of implicit conversion
    void* nv = &n;
    int* ni = static_cast<int*>(nv);
    std::cout << "6) *ni = " << *ni << '\n';
 
    // 7a. scoped enum to int
    E e = E::TWO;
    int two = static_cast<int>(e);
    std::cout << "7a) " << two << '\n';
 
    // 7b. int to enum, enum to another enum
    E e2 = static_cast<E>(two);
    [[maybe_unused]]
    EU eu = static_cast<EU>(e2);
 
    // 7f. pointer to member upcast
    int D::*pm = &D::m;
    std::cout << "7f) " << br.*static_cast<int B::*>(pm) << '\n';
 
    // 7g. void* to any object pointer
    void* voidp = &e;
    [[maybe_unused]]
    std::vector<int>* p = static_cast<std::vector<int>*>(voidp);
}

Ausgabe

1) Hello world, this is B!
1) Hello world, this is D!
3) after move, v0.size() = 0
5) n = 3
5) v.size() = 10
6) *ni = 3
7a) 2
7f) 42

[bearbeiten] Defect Reports

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 137 C++98 die Constness und Volatilität von
Zeigern auf void konnte weggelassen werden
cv-Qualifikationen können nicht sein
in solchen Fällen weggelassen
CWG 427 C++98 Downcast könnte bei direkter Initialisierung mehrdeutig sein wählt in diesem Fall Downcast aus
CWG 439 C++98 bei der Konvertierung eines „Zeigers auf Objekt“ zu „Zeiger auf
void“ und dann zurück zu sich selbst, konnte nur seine
Wertigkeit bewahren, wenn der Zieltyp die gleiche cv-Qualifikation hat
cv-Qualifikation
kann unterschiedlich sein
CWG 1094 C++98 die Konvertierung von Fließkommawerten
zu Aufzählungswerten war nicht spezifiziert
spezifiziert
CWG 1320 C++11 die Konvertierung von Scope-Aufzählungen
zu bool war nicht spezifiziert
spezifiziert
CWG 1412 C++98 das Ergebnis der Konvertierung von
„Zeiger auf
void“ zu „Zeiger auf Objekt“ war unklar
wurde 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ählungs-
werten ergab ein nicht spezifiziertes Ergebnis, wenn Ausdruck außerhalb des Bereichs liegt
Das Verhalten ist
in diesem Fall nicht definiert.
CWG 1832 C++98 die Konvertierung von Ganzzahl- oder Aufzählungswerten zu
Aufzählungswerten erlaubte, dass Zieltyp unvollständig ist
nicht erlaubt
CWG 2224 C++98 die Konvertierung von einem Member vom Basisklassentyp zu
seinem vollständigen Objekt vom abgeleiteten Klassentyp war gültig
Das Verhalten ist
in diesem Fall nicht definiert.
CWG 2254 C++11 ein Standard-Layout-Klassenobjekt ohne Datenelemente
war zeiger-interkonvertierbar zu seinem ersten Basis-
member
zu allen seinen Basisklassen
CWG 2284 C++11 ein nicht-Standard-Layout-Union-Objekt und ein nicht-statisches Daten-
member dieses Objekts waren nicht zeiger-interkonvertierbar
sie sind
CWG 2310 C++98 für Basis-zu-abgeleitete Zeigerkonvertierungen und
abgeleitete-zu-Basis-Zeiger-auf-Member-Konvertierungen,
konnte der abgeleitete Klassentyp unvollständig sein
muss vollständig sein
CWG 2338 C++11 die Konvertierung zu Aufzählungstypen mit festem zugrunde liegendem Typ
führte zu undefiniertem Verhalten, wenn Ausdruck außerhalb des Bereichs liegt
zuerst zum zugrunde liegenden Typ konvertieren
(kein undefiniertes Verhalten)
CWG 2499 C++11 eine Standard-Layout-Klasse könnte eine nicht-zeiger-interkonvertierbare
Basisklasse haben, obwohl alle Basis-Unterobjekte die gleiche Adresse haben
hat sie nicht
CWG 2718 C++98 für Basis-zu-abgeleitete Referenzkonvertierungen,
konnte der abgeleitete Klassentyp unvollständig sein
muss vollständig sein
CWG 2882 C++98 war unklar, ob static_cast<void>(expr) versucht,
eine implizite Konvertierungssequenz von expr zu void zu bilden
kein Versuch in diesem Fall

[bearbeiten] 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]

[bearbeiten] Siehe auch