C++-Programmierung: Typumwandlung
Eine aktuelle Seite zum gleichen Thema ist unter C++-Programmierung/ Nützliches/ Casts verfügbar.
Grundlagen
BearbeitenWie Sie aus dem Abschnitt Variablen und Konstanten wissen, wird der Typ einer Variablen bei ihrer Deklaration ein für allemal festgelegt. Gelegentlich ist es jedoch notwendig, einen Wert (implizit oder explizit) von einem Typ in einen anderen zu konvertieren. Hierfür gibt es verschiedene Verfahren der Typumwandlung (cast).
Implizite Typumwandlung
BearbeitenImplizite Casts werden vom Compiler automatisch vorgenommen, z.B. um bei einer arithmetischen Operation die Typen der beiden Operanden einander anzugleichen. Auch bei Funktionsaufrufen:
int f(float);
int x = f(1); // konvertiert 1 nach float, um f aufrufen zu können
Explizite Typumwandlung
BearbeitenBisweilen muss ein Cast explizit verlangt werden. Im Beispiel
int a = 3, b = 4;
float x = a/b;
erhält x
den Wert 0, weil die Division zweier Ganzzahlen eine Ganzzahl liefert und den Nachkommateil abschneidet. Sie könnten das Problem lösen, indem Sie eine temporäre float
-Variable einführen und damit die Fließkomma-Division erzwingen:
int a = 3, b = 4;
float fa = a;
float x = fa/b; // jetzt wird x = 0.75 zugewiesen
Das lässt sich ohne die temporäre Variable eleganter schreiben, entweder in der „klassischen“ Cast-Notation (C-style cast)
float x = (float)a/b;
oder gleichwertig in der funktionalen Notation (function-style cast)
float x = float(a)/b;
Zeiger und Casts: Achtung
BearbeitenC erlaubt explizite Casts zwischen beliebigen Zeigern:
int i = 1;
int *ip = &i;
float *fp = (float*)ip;
Dieses Konstrukt ist auch in C++ völlig legal. Aber vielleicht ahnen Sie es bereits: Mit dem auf diese Weise „produzierten“ Zeiger fp
lässt sich nicht viel anfangen, weil die Typen int
und float
eine völlig verschiedene interne Darstellung besitzen. Im Sinne einer weitgehenden Kompatibilität mit C akzeptiert der C++-Compiler solche Casts zwar, von ihrer Verwendung wird aber dringend abgeraten!
Cast-Operatoren
BearbeitenMit der Übernahme beliebiger Zeiger-Casts aus C hatten sich die C++-Entwickler eine schwere Hypothek aufgeladen. Der C++-Standard stellt deshalb vier verschiedene Cast-Operatoren bereit, dank derer auf die riskanten C-Casts verzichtet werden kann. Die Namen der Operatoren deuten an, welchem Zweck der Cast jeweils dient.
static_cast
BearbeitenMerke: Verändert die Daten selbst.
static_cast<Typ>(ausdruck)
bewirkt dasselbe wie (Typ)ausdruck
, sofern eine implizite Umwandlung existiert. Anderenfalls akzeptiert es der Compiler nicht. In unserem Beispiel können Sie schreiben
float x = static_cast<float>(a)/b;
const_cast
BearbeitenMerke: Verändert nichts, erlaubt dem Compiler aber eine Adresse, an der konstante Daten stehen, immer zu verwenden, wenn die Daten nicht geändert werden. Das heißt also auch, wenn eigentlich konstante Daten ausgeschlossen wurden.
const_cast<Typ>(ausdruck)
bewirkt dasselbe wie (Typ)ausdruck
, sofern sich der angegebene Typ
und der Typ von ausdruck
höchstens um ein const
unterscheiden. Achtung: Wenn Sie auf diese Art das const
-Attribut „wegzaubern“, heißt das noch lange nicht, dass die Variable dann „unfallfrei“ verändert werden kann. Der Compiler könnte z. B. alle const
-Objekte in einem speziellen Read-Only-Speicherbereich anlegen, wo Schreibzugriffe grundsätzlich verboten sind. Solche Casts dienen ausschließlich dazu, konstante Referenzen oder Zeiger auf konstante Daten an Funktionen zu übergeben, welche eigentlich das gleiche in der nichtkonstanten Variante erwarten. Bitte beachten Sie, dass so etwas nur gemacht werden darf, wenn Sie wissen, dass innerhalb der Funktion nichts an den Daten geändert wird, wenn doch, ist das Programm fehlerhaft und sein Verhalten undefiniert.
reinterpret_cast
BearbeitenMerke: Verändert die Art, wie Daten an einer bestimmten Adresse gelesen („interpretiert“) werden.
Dieser Cast ist sehr hardwarenah und sollte daher nur in hardwarenahem Programmcode nötig sein. reinterpret_cast<Typ*>(ausdruck)
macht dasselbe wie (Typ*)ausdruck
und sollte deshalb mit äußerster Vorsicht benutzt werden.
dynamic_cast
BearbeitenDie drei bisher besprochenen Cast-Operatoren werden sämtlich zur Compilezeit ausgeführt. Im Zusammenhang mit Klassen tritt aber häufig das Problem auf, zur Laufzeit zu entscheiden, welcher exakten Klasse ein Objekt angehört bzw. ob eine gewisse Operation mit diesem Objekt durchgeführt werden darf. Hierauf werden wir im Kapitel Vererbung noch ausführlich eingehen.