static_cast-Konvertierung
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.
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-
Abgeleitetist ein vollständiger Klassentyp. -
Basisist eine Basisklasse vonAbgeleitet. - cv1 ist nicht stärker cv-qualifiziert als cv2.
-
Basisist eine virtuelle Basisklasse vonAbgeleitet. -
Basisist eine Basisklasse einer virtuellen Basisklasse vonAbgeleitet. - Keine gültige Standardkonvertierung von „Zeiger auf
Abgeleitet“ zu „Zeiger aufBasis“ existiert.
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) |
|
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
Die explizite Konvertierung ist wie folgt definiert
|
(seit C++17) |
- Konvertierung von lvalue zu rvalue
- Konvertierung von Array zu Zeiger
- Konvertierung von Funktion zu Zeiger
- Nullzeiger-Konvertierung
- Null-Member-Zeiger-Konvertierung
- Boolesche Konvertierung
| (seit C++17) |
|
a) Ein Wert eines Scope-Enumerationstyps kann in einen Ganzzahl- oder Fließkommatyp konvertiert werden.
|
(seit C++11) |
- 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.
|
d) Ein prvalue vom Fließkommatyp kann explizit in jeden anderen Fließkommatyp konvertiert werden.
|
(seit C++23) |
Basis“ kann explizit in den Typ „Zeiger auf cv2 Abgeleitet“ konvertiert werden, wenn alle folgenden Bedingungen erfüllt sind-
Abgeleitetist ein vollständiger Klassentyp. -
Basisist eine Basisklasse vonAbgeleitet. - cv1 ist nicht stärker cv-qualifiziert als cv2.
Abgeleitet, das das Objekt vom Typ Basis umschließt, auf das Ausdruck zeigt.-
Basisist eine virtuelle Basisklasse vonAbgeleitet. -
Basisist eine Basisklasse einer virtuellen Basisklasse vonAbgeleitet. - Keine gültige Standardkonvertierung von „Zeiger auf
Abgeleitet“ zu „Zeiger aufBasis“ existiert.
Abgeleitet zeigt, ist das Verhalten undefiniert.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-
Abgeleitetist ein vollständiger Klassentyp. -
Basisist eine Basisklasse vonAbgeleitet. - cv1 ist nicht stärker cv-qualifiziert als cv2.
Basis.Basis vom Typ T“ zu „Zeiger auf Member von Abgeleitet vom Typ T“ existiert, ist das Programm ill-formed.Basis ist, ist das Verhalten undefiniert.T“ konvertiert werden, wenn T ein Objekttyp ist und cv1 nicht stärker cv-qualifiziert ist als cv2.
|
(bis C++17) |
|
(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);
|
(seit C++11) |
- sonst ein prvalue.
- ↑ Diese Art von static_cast wird verwendet, um Move-Semantik in std::move zu implementieren.
- ↑ 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
[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]