Typdefinitionen in C++
Ein Datentyp ist
- Eine endliche Menge von Werten zusammen mit
- eine Spezifikation der maschinellen Repräsentation dieser Werte sowie
- meistens verschiedenen Operationen zur Verarbeitung von Werten und Objekten des Datentyps alleine oder in Kombination mit Werten und Objekten anderer Datentypen und
- manchmal Namen für einige oder alle Werte des Datentyps.
So gibt es in C++ beispielsweise den Datentyp "bool" mit dem Wert "true" und dem Wert "false". Für diese Werte ist die Darstellung 1 bzw. 0 festgelegt. Es gibt verschiedene Operationen für diesen Datentyp, wie etwa die Möglichkeit der Ausgabe.
Nun kann ein C++ -Programm auch neue Datentypen definieren. Das kann durch eine Aufzählung der Namen der Werte des Datentyps geschehen. C++ weist dann automatisch eine Repräsentation durch aufsteigende Zahlen ab 0 zu.
Soll eine Lichtzeichensignalanlage durch ein Programm gesteuert oder simuliert werden, dann kann es beispielsweise sinnvoll sein, einen Datentyp für die verschiedenen möglichen Zustände eines Signals einzuführen. Dies kann geschehen, indem nach dem Schlüsselwort "enum" der Name des neuen Datentyps angegeben wird, dem dann in geschweiften Klammern die kommagetrennten Wertnamen folgen.
Die Wertnamen müssen nicht großgeschrieben werden, dies wird aber empfohlen, da es sich eingebürgert hat.
enum.cpp
#include <iostream>
#include <ostream>
enum ampelzustand { ROT, ROTGELB, GRUEN, GELB };
int main()
{ ampelzustand ampel( ROT );
std::cout << ampel << ROTGELB << '\n'; }std::cout
01
Dem hier definierten Datentyp fehlt aber noch einige Unterstützung, so etwa die Möglichkeit zum Weiterschalten des Zustandes oder zur Ausgabe der Werte anhand ihrer Wertnamen. Derzeit wird zur Ausgabe noch die zugrundeliegende Repräsentation der Werte durch Ganzzahlen verwendet.
Typsicherheit
Eine Umgebung unterstützt Typsicherheit, in dem sie Fehler aufgrund des Typs von Ausdrücken diagnostiziert. Das folgende Programm definiert einen Datentyp für Ampelzustände und einen Datentyp für Antworten. Eine Initialisierung eines Objektes des einen Typs mit einem Wert des anderen Typs wird als Fehler erkannt. Diese Typsicherheit hilft dem Programmierer bei der Entdeckung solcher Fehler.
safe.cpp
#include <iostream>
#include <ostream>
enum ampelzustand { ROT, ROTGELB, GRUEN, GELB };
enum antwort { JA, NEIN, VIELLEICHT };
int main()
{ ampelzustand ampel( NEIN ); }Diagnosen
"safe.cpp", line 6: error: a value of type "antwort" cannot be used to
initialize an entity of type "ampelzustand"
{ ampelzustand ampel( NEIN ); }
^
Operatorüberladungen in C++
Operatoren der Sprache C++ können für benutzerdefinierten Datentypen definiert werden. Dadurch wird der Operator überladen. Seine Bedeutung für die Datentypen der Programmiersprache wird nicht verändert.
In dem folgenden Beispiel wird ein Datentyp "zustand" definiert, dessen Werte die möglichen Zustände eines Lichtsignals sind.
Die Addition einer Zahl zu einem Ampelzustand soll bedeuten, daß der Ampelzustand um so viele Schritte weitergezählt wird, wie die Zahl angibt. Nach dem Zustand "GELB" soll wieder der Zustand "ROT" kommen.
Zunächst werden der Zahlenwert des Zustandes und die Zahl addiert. Das Ergebnis kann allerdings außerhalb des Bereichs von 0 bis 3 liegen. Die folgenden drei Zeilen berechnen daher den Rest der Division der Summe durch die Zahl der Zustände. Dies hat den gewünschten Effekt. (Die Berechnung des Restes kann man in C++ noch einfacher machen, die dafür notwendigen Sprachelemente wurden aber bisher noch nicht behandelt.)
In der Funktion "main" wird dann die Summe aus einem Zustand und einer Zahl berechnet. Da der Operator "+" für diesen Fall überladen wurde, wird dann die für diesen Fall soeben definierte Funktion aufgerufen.
operator.cpp
#include <iostream>
#include <ostream>
enum zustand { ROT, ROTGELB, GRUEN, GELB };
zustand operator+( const zustand l, int const i )
{ int const top( static_cast<int>( GELB ) + 1 );
double const summe( static_cast<int>( l )+ i );
double const quotient( summe / top );
double const frac( quotient - static_cast<int>( quotient ));
int const rest( frac * top + 0.5 );
return static_cast<zustand>( rest ); }
int main()
{ zustand x( ROT ); std::cout << x;
x = x + 1; std::cout << x;
x = x + 1; std::cout << x;
x = x + 1; std::cout << x;
x = x + 1; std::cout << x;
x = x + 1; std::cout << x;
x = x + 1; std::cout << x; std::cout << '\n'; }std::cout
0123012
Übungsfrage Warum läuft das Programm ohne Ende, wenn in der Operatordefinition das erste "static_cast<int>" weggelassen wird?
Übungsaufgabe Die definierte Überladung für den Operator "+" ist nicht kommutativ. Der Ausdruck "x + 1" hat eine andere Bedeutung als "1 + x". Ändern Sie das obige Beispielprogramm so ab, daß der Operator "+" der Addition einer Zahl zu einem Ampelzustand kommutativ ist.