Einleitung
C++ Typkonvertierungen
Automatische Typkonvertierungen (Promotions)
Kommen wir nun zu einem recht heiklen Thema, der Typkonvertierung (Typumwandlung). Mittels Typkonvertierung kann der ursprüngliche Datentyp, z.B. einer Variable, einer Konstante oder eines Ausdrucks (im Folgenden Datum genannt), in einen anderen Datentyp konvertiert werden. Wie Sie in der Zwischenzeit bereits erfahren haben, wird bei Operationen mit ungleichen Datentypen, soweit wie möglich, eine automatische Typkonvertierung durch den Compiler vorgenommen, da Operatoren nur Daten mit gleichen Datentypen verarbeiten können. Wir werden uns in dieser Lektion ansehen, wie Sie explizit solche Typkonvertierungen durchführen und wie die automatische Typkonvertierung arbeitet.
|
|
Fangen mit der 'alten' Form der Typkonvertierung an. Diese Form sollten Sie aber in Zukunft so gut wie nicht mehr benützen. Sie enthält keinerlei Sicherheitsabfragen (d.h. die Datentypen können beliebig umgewandelt werden) und wird hier nur der Vollständigkeit halber aufgeführt.
Der Datentyp eines Datums kann mit folgenden Anweisungen explizit in einen anderen Datentyp überführt werden:
| (DTYP) datum DTYP (datum) |
DTYP ist der neue Datentyp, in den das datum konvertiert werden soll.
Bei der Konvertierung eines Gleitkommawertes in eine Ganzzahl werden die Nachkommastellen abgeschnitten, es erfolgt keine Rundung. Beachten Sie dies bitte bei Ihren Berechnungen.
|
// Ausgangszustand short var1 = 10; short var2 = 4; double result1, result2; // Berechnung: double(10) / double(4) // = 10.0 / 4.0 // = 2.5 result1 = (double)var1 / (double)var2; // Berechnung: double(10 / 4) // = double(2) // = 2.0 result2 = double(10 / 4); |
Oben sehen Sie ein Beispiel mit der 'alten' Typkonvertierung. Wie Sie dem Beispiel auch entnehmen können, ist es nicht immer gleichgültig, wann Sie ein Datum konvertieren. Im Beispiel liefert die Division von Ganzzahlen ebenfalls eine Ganzzahl, auch wenn Sie diese anschließend in eine Gleitkommazahl umwandeln.
C++ kennt folgende (neuen) Typkonvertierungen, die Sie in Zukunft einsetzen sollten, wenn Sie schon Daten konvertieren müssen:
| const_cast<DTYP>(datum) static_cast<DTYP>(datum) dynamic_cast<DTYP>(datum) reinterpret_cast<DTYP>(datum) |
DTYP ist auch hier der neue Datentyp, in den der Ausdrucks ARG konvertiert werden soll. Jede dieser Typkonvertierung wird für ganz spezielle Konvertierungen eingesetzt.
Der const_cast Operator dient dazu, den const oder volatile Modifizierer von einem Datentyp zu entfernen (volatile wird später noch erklärt). Dabei darf sich der neue Datentyp vom Ursprungsdatentyp nur durch den Modifizierer const oder volatile unterscheiden. Alle anderen Konvertierungen führen zu einem Fehler beim Übersetzen des Programms. Als Ergebnis liefert const_cast den auf DTYP konvertierten Ausdruck. Die erste Zuweisung im Beispiel liefert einen Fehler, da ein Zeiger auf einen konstanten Text nicht einem Zeiger auf einen veränderlichen Text direkt zugewiesen werden kann. Wie's trotzdem geht, ist in der darunter stehenden Anweisung dargestellt, hier wird der const-Modifizierer entfernt.
|
// Zeiger auf konstante Zeichen const char *pConst = "Text"; // Zeiger auf veränderbare Zeichen char *pVar // Das schlägt fehl! pVar = pConst; // Aber so geht's pVar = const_cast<char*>(pConst); |
|
|
Der static_cast Operator wird eingesetzt, um zwischen Ganzzahl-Datentypen und Gleitkomma-Datentypen zu konvertieren. Die erste Anweisung im Beispiel konvertiert ein long-Datum in ein char-Datum. Beachten Sie hierbei bitte, dass nur das niederwertigste Byte übernommen wird, der Rest wird verworfen. Ebenfalls eingesetzt wird der static_cast Operator um einen void-Zeiger (Zeiger ohne bestimmtem Datentyp) in einen beliebigen anderen Zeiger (Zeiger mit bestimmtem Datentyp) zu konvertieren. So konvertiert die letzte Anweisung des Beispiels den void-Zeiger pVal in den int-Zeiger pVar.
|
// Konvertierung von long nach char long longVar = ..; char charVar = static_cast<char>(longVar); // void-Zeiger-Konvertierung void *pVal = ..; int *pVar = static_cast<int*>(pVal); |
Außerdem kann der static_cast Operator noch eine Ganzzahl in einen enum-Wert konvertieren. Allerdings müssen Sie dabei selber darauf achten, dass die zu konvertierende Ganzzahl innerhalb der in der enum-Anweisung definierten Konstanten liegt. Der enum-Datentyp werden später noch behandelt.
|
|
Typkonvertierungen mittels reinterpret_cast sind die fehlerträchtigsten, da sie in der Regel plattformabhängige Konvertierungen durchführen. Der reinterpret_cast Operator wird zum einen für die Konvertierung zwischen verschiedenen Zeigertypen und zum anderen für die Konvertierung von Ganzzahlen in Zeiger und umgekehrt eingesetzt.
|
// Definitionen cchar *pText = "Text"; void *pAny; const int CONST = 10; llong lVal; // Konvertierungen Zeiger nach long lVal = reinterpret_cast<long>((pText); // Konvertierung nach char-Zeiger pText = reinterpret_cast<char*>(CONST); /// Konvertierung zwischen Zeigern pText = reinterpret_cast<char*>(pAny); |
Der Konvertierungsoperator dynamic_cast wird später nach der Behandlung von abgeleiteten Klassen beschrieben, da er nur in diesem Zusammenhang von Bedeutung ist (sieh Lektion Typkonvertierungen auf Klassenzeiger) Er wird nur der Vollständigkeit wegen an dieser Stelle erwähnt.
Viele 'alltägliche' Typanpassungen kann der Compiler automatisch vornehmen, wenn dadurch keine Information verloren geht. Beachten Sie bitte, dass vor dem Ausführen einer Operation (und auch eine Zuweisung ist eine Operation) immer die Datentypen der Operanden angepasst werden. Die Anpassung erfolgt in der Weise, dass der 'kleinere' Datentyp auf den 'größeren' erweitert wird.
Ohne jetzt auf alle Einzelheiten einzugehen, die im Standard ca. 8 DIN-A4 Seiten belegen, gibt es folgende wichtige Konvertierungen.
Werte vom Datentyp char,, unsigned char, signed char, unsigned short und signed short können vom Compiler auf den Datentyp int erweitert werden, wenn dadurch der gesamte Wertebereich des Originaldatentyps abgedeckt wird. Ist dies nicht der Fall, so wird eine Anpassung auf einen unsigned int Datentyp versucht. Ebenfalls können enum und wchar_t Datentypen nach int bzw. long (sowohl signed als auch unsigned) umgewandelt werden. Und zum Schluss kann ein bool Wert noch in einen int Wert konvertiert werden, wobei für true gleich 1 und für false gleich 0 verwendet wird.
|
cchar var = 0x55; if (var == 0x80) // Konvertierung von var auf int! bool bVar = true; int nVar = bVar; // Konvertierung von bVar auf int |
EEin Wert vom Typ float kann bei Bedarf auf einen Wert vom Datentyp double konvertiert werden.
Ein Gleitkommawert kann in einen Ganzzahlwert konvertiert werden, wobei die Nachkommastellen einfach abgeschnitten werden. Kann der Ganzzahlwert nicht exakt als Gleitkommawert dargestellt werden, so ist die entsprechende Rundung vom Compiler abhängig.
Ein Zeiger eines beliebigen Datentyps kann immer in einen void--Zeiger (datentyp-loser Zeiger) konvertiert werden. Außerdem kann ein Zeiger auf eine abgeleitete Klasse stets in einen Zeiger auf die entsprechende Basisklasse konvertiert werden. Dieser Sachverhalt spielt später im Kurs noch eine wichtige Rolle.