Was sind die richtigen Verwendungszwecke von:
static_cast
(Typ)Wert
Typ(Wert)
Wie kann man entscheiden, was in welchen Fällen zu verwenden ist?
static_cast
ist der erste Cast, den Sie versuchen sollten zu benutzen. Es macht Dinge wie implizite Konvertierungen zwischen Typen (wie int
zu float
, oder Zeiger zu void*
), und es kann auch explizite Konvertierungsfunktionen (oder implizite) aufrufen. In vielen Fällen ist die explizite Angabe von static_cast
nicht notwendig, aber es ist wichtig zu beachten, dass die T(something)
Syntax äquivalent zu (T)something
ist und vermieden werden sollte (mehr dazu später). Ein T(something, something_else)
ist jedoch sicher und ruft garantiert den Konstruktor auf.
static_cast
kann auch durch Vererbungshierarchien casten. Es ist unnötig, wenn man nach oben castet (in Richtung einer Basisklasse), aber wenn man nach unten castet, kann es verwendet werden, solange es nicht durch virtuelle
Vererbung castet. Es führt jedoch keine Überprüfung durch, und es ist ein undefiniertes Verhalten, wenn static_cast
eine Hierarchie hinunter zu einem Typ gecastet wird, der nicht tatsächlich der Typ des Objekts ist.
const_cast
kann verwendet werden, um const
zu einer Variablen zu entfernen oder hinzuzufügen; kein anderer C++-Cast ist in der Lage, ihn zu entfernen (nicht einmal reinterpret_cast
). Es ist wichtig zu beachten, dass das Ändern eines ehemals const
-Wertes nur dann undefiniert ist, wenn die ursprüngliche Variable const
ist; wenn Sie es benutzen, um das const
von einer Referenz auf etwas zu entfernen, das nicht mit const
deklariert wurde, ist es sicher. Dies kann zum Beispiel beim Überladen von Mitgliedsfunktionen auf der Basis von const
nützlich sein. Es kann auch verwendet werden, um const
zu einem Objekt hinzuzufügen, z.B. um eine Überladung einer Mitgliedsfunktion aufzurufen.
const_cast
funktioniert auch ähnlich bei volatile
, obwohl das weniger üblich ist.
dynamic_cast
wird ausschließlich für die Behandlung von Polymorphismus verwendet. Man kann einen Zeiger oder eine Referenz auf einen polymorphen Typ auf einen beliebigen anderen Klassentyp casten (ein polymorpher Typ hat mindestens eine virtuelle Funktion, deklariert oder geerbt). Sie können damit nicht nur nach unten casten, sondern auch seitwärts oder sogar in eine andere Kette. Der dynamic_cast
sucht das gewünschte Objekt und gibt es, wenn möglich, zurück. Wenn es nicht möglich ist, wird nullptr
im Falle eines Zeigers zurückgegeben, oder std::bad_cast
im Falle einer Referenz geworfen.
dynamic_cast
hat allerdings einige Einschränkungen. Es funktioniert nicht, wenn es mehrere Objekte desselben Typs in der Vererbungshierarchie gibt (der sogenannte "gefürchtete Diamant") und Sie keine "virtuelle" Vererbung verwenden. Es kann auch nur durch öffentliche Vererbung gehen - es wird immer scheitern, durch geschützte
oder private
Vererbung zu gehen. Dies ist jedoch selten ein Problem, da solche Formen der Vererbung selten sind.
reinterpret_cast
ist der gefährlichste Cast und sollte sehr sparsam verwendet werden. Es wandelt einen Typ direkt in einen anderen um - wie z.B. das Casting eines Zeigers in einen anderen, oder das Speichern eines Zeigers in einem int
, oder alle möglichen anderen unangenehmen Dinge. Im Großen und Ganzen ist die einzige Garantie, die man mit reinterpret_cast
bekommt, dass man normalerweise genau den gleichen Wert erhält, wenn man das Ergebnis zurück in den ursprünglichen Typ castet (aber nicht, wenn der Zwischentyp kleiner ist als der ursprüngliche Typ). Es gibt auch eine Reihe von Konvertierungen, die reinterpret_cast
nicht durchführen kann. Es wird hauptsächlich für besonders seltsame Konvertierungen und Bitmanipulationen verwendet, wie z.B. das Umwandeln eines Rohdatenstroms in tatsächliche Daten oder das Speichern von Daten in den niedrigen Bits eines Zeigers auf ausgerichtete Daten.
C-style cast und function-style cast sind Casts unter Verwendung von (type)object
bzw. type(object)
und sind funktional gleichwertig. Sie sind definiert als die erste der folgenden Möglichkeiten, die erfolgreich ist:
const_cast
static_cast
(allerdings ohne Berücksichtigung von Zugriffsbeschränkungen)static_cast
(siehe oben), dann const_cast
reinterpret_cast
reinterpret_cast
, dann const_cast
Es kann daher in einigen Fällen als Ersatz für andere Casts verwendet werden, kann aber extrem gefährlich sein, weil es in einen reinterpret_cast
übergehen kann, und letzteres sollte bevorzugt werden, wenn ein explizites Casting erforderlich ist, es sei denn, Sie sind sicher, dass static_cast
erfolgreich sein wird oder reinterpret_cast
scheitern wird. Selbst dann sollten Sie die längere, explizitere Option in Betracht ziehen.
Casts im C-Stil ignorieren auch die Zugriffskontrolle, wenn sie einen static_cast
durchführen, was bedeutet, dass sie die Möglichkeit haben, eine Operation durchzuführen, die kein anderer Cast kann. Das ist allerdings nur eine Spielerei und meiner Meinung nach nur ein weiterer Grund, Casts im C-Stil zu vermeiden.
Verwenden Sie dynamic_cast
für die Umwandlung von Zeigern/Referenzen innerhalb einer Vererbungshierarchie.
Verwenden Sie static_cast
für gewöhnliche Typkonvertierungen.
Verwenden Sie reinterpret_cast
für die Neuinterpretation von Bitmustern auf niedriger Ebene. Mit äußerster Vorsicht zu verwenden.
Verwenden Sie const_cast
für das Weggießen von const/volatile
. Vermeiden Sie dies, es sei denn, Sie sind gezwungen, eine const-inkorrekte API zu benutzen.
Beantwortet dies Ihre Frage?
Ich habe reinterpret_cast
noch nie benutzt und frage mich, ob es nicht nach schlechtem Design riecht, wenn ich auf einen Fall stoße, der es braucht. In der Codebasis, an der ich arbeite, wird dynamic_cast
häufig verwendet. Der Unterschied zu static_cast
ist, dass dynamic_cast
eine Laufzeitüberprüfung durchführt, die (sicherer) oder nicht (mehr Overhead) das sein kann, was man will (siehe msdn).