C++-Programmierung: Typumwandlung

Alte Seite
Diese Seite gehört zum alten Teil des Buches und wird nicht mehr gewartet. Die Inhalte sollen in das neue Buch einfließen: C++-Programmierung/ Inhaltsverzeichnis.
Eine aktuelle Seite zum gleichen Thema ist unter C++-Programmierung/ Nützliches/ Casts verfügbar.

Grundlagen

Bearbeiten

Wie 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

Bearbeiten

Implizite 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

Bearbeiten

Bisweilen 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

Bearbeiten

C 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

Bearbeiten

Mit 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

Bearbeiten

Merke: 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

Bearbeiten

Merke: 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

Bearbeiten

Merke: 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

Bearbeiten

Die 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.