home

11. Abend, Klassen Übung mit Lösung


class CD { // öffentliche Schnittstelle der Klasse // CD public: // mit folgenden Funktionen // können wir die Datenelemente // jeweils setzen void setInterpret(const string& interpret); void setTitle(const string& title); void setLength(long length); // diese Funktion gibt die // Daten der CD aus void display(); // Datenelemente im private-Teil verstecken private: string m_interpret; string m_title; double m_length;
}; // wichtig ! Semikolon nicht vergessen

Übung

Schreibe die Methoden "setLength" und "display" der Klasse CD so um, dass m_length nach dem Aufruf der Funktion setLength die Länge als Minute.Sekunden speichert und auch so ausgibt :
---------------------------
Title     : Viva Las Vegas
Interpret : Elvis Presley
Laenge    : 35.30
Um in der Funktion "display" die Ausgabe für double Zahlen so einzurichten, dass sie zwei Nachkommastellen ausgibt, musst du die Datei <iomanip> includieren. Du kannst dann folgenden Aufruf machen :
cout << fixed << setprecision(2);
Siehe hierfür auch im Buch das Beispiel auf Seite 268 an.

Lösung


///////////////////////////////////////////////// void CD::setLength(long length) { // pro Minute 60 Sekunden long min = length / 60; // der Rest sind die Sekunden long sec = length % 60; m_length = (double)min + (double)sec / 100.0; }

Die eigentliche Berechnung ist relativ einfach. Ausgehend davon, dass length die Anzahl Sekunden für die ganze CD sind, ist die Berechnung der Minuten einfach.
Da wir die Nachkommastellen als Sekunden verwenden wollen und nicht als Bruchteile von Minuten müssen wir die Sekunden mit dem Modulo-operator berechnen. Eigentlich ist die Verwendung des doubles m_length nicht ganz korrekt, denn 3.5 Minuten sind eigentlich 3 Minuten und 30 Sekunden. Trotzdem ist für unser Vorhaben diese Anwendung möglich.

Wichtig sind vor allem die Datentypen in dieser Funktion. Die Anzahl der Minuten und Sekunden kann man problemlos als longs abbilden. Das Problem ist danach die Berechnung von m_length. Folgende Berechnung führt zum falschen Ergebnis :


long min = length / 60; long sec = length % 60;
m_length = min + sec / 100;
Während die Minuten korrekt sind, bleiben die Sekunden 0. Die Sekunden sind als Ganzzahl gespeichert und haben maximal 60 als Wert. Wird eine Ganzzahl, die kleiner als 100 ist durch 100 geteilt, muss das Ergebnis 0 betragen, wir arbeiten ja mit Ganzzahlen. Durch eine kleine Änderung können wir dem Compiler aber klarmachen, dass wir mit doubles rechnen wollen :

long min = length / 60; long sec = length % 60;
m_length = min + sec / 100.0;
Zuerst wird die Division durchgeführt, denn auch in C++ gelten die normalen Rechenregeln. Da aber der Wert 100.0 vom Compiler als double interpretiert wird, wird die Variable sec implizit zum double gewandelt un die Division liefert einen double als Ergebnis. Zum Beispiel 0.3. Dieser double-Wert wird dann mit der Variable min addiert. Hierfür wird die Variable auch implizit zu einem double wert gewandelt und schon haben wir das erwünschte Ergebnis.
In der Lösung oben habe ich diese impliziten Typumwandlungen explizit gemacht. Dadurch wird genauer aufgezeigt was passiert und das Verhalten vom Programmierer gesteuert.
Die Ausgabe ist ziemlich einfach, denn m_length den geünschten Wert bereits enthält muss man ihn nur ausgeben. Mit der setprecision-Geschichte steuern wir die Ausgabe.

///////////////////////////////////////////////// void CD::display() { cout << fixed << setprecision(2); cout << "---------------------------" << endl; cout << "Title : " << m_title << endl; cout << "Interpret : " << m_interpret << endl; cout << "Laenge : " << m_length << endl; } /////////////////////////////////////////////////

Übung

Ändere die Klasse CD so, dass sie anstatt des doubles oder longs für die Länge eine Struktur CDLength verwendet.
Definiere in der Datei CD.h eine Struktur CDLength mit den Elementen Minutes und Seconds. Ändere danach den Datentypen des Datenelementes m_length von double auf CDLength.
Schreibe nun die Funktion "setLength(long length)" so um, dass sie die Minuten und Sekunden berechnet und im Datenelement m_length speichert.
Ändere nun auch die Funktion "display" so, dass sie die Elemente der Struktur m_length einzeln ausgibt, etwa so :

--------------------------- Title : Viva Las Vegas Interpret : Elvis Presley Laenge : 35 min 30 sec

#ifndef CD_H #define CD_H #include <string> // wir verwenden in dieser // Datei nur die string-Klasse using std::string; struct CDLength { long Minutes; long Secondes; }; // Schlüsselwort class gefolgt // vom Klassennamen class CD { // öffentliche Schnittstelle der Klasse // CD public: // mit folgenden Funktionen // können wir die Datenelemente // jeweils setzen void setInterpret(const string& interpret); void setTitle(const string& title); void setLength(long length); // diese Funktion gibt die // Daten der CD aus void display(); // Datenelemente im private-Teil verstecken private: string m_interpret; string m_title; CDLength m_length; }; #endif
Diese Lösung abstrahiert korrekt die Laenge einer CD mit einer Struktur. Da wir im Moment wirklich nur Minuten und Sekunden zusammen-"packen" wollen, genügt eine Klasse mit zwei öffentlichen (public) Datenelementen. Darum können wir uns ganz wenig Schreibarbeit sparen und verwenden das Schlüsselwort struct anstelle von class um CDLength zu definieren.
Übrigens haben wir CDLength speziell definiert um die Länge von CD's zu verwalten. Eigentlich könnten wir diese Struktur ein wenig allgemeiner definieren und sie ganz einfach Length nennen.
Die Funktion setLength wird dadurch ein wenig einfacher :

///////////////////////////////////////////////// void CD::setLength(long length) { // pro Minute 60 Sekunden long min = length / 60; // der Rest sind die Sekunden long sec = length % 60; m_length.Minutes = min; m_length.Secondes = sec; } /////////////////////////////////////////////////
Und hier die Ausgabe-Funktion:

///////////////////////////////////////////////// void CD::display() { cout << "---------------------------" << endl; cout << "Title : " << m_title << endl; cout << "Interpret : " << m_interpret << endl; cout << "Laenge : " << m_length.Minutes << " min " << m_length.Secondes << " sec" << endl; } /////////////////////////////////////////////////
Beachte, dass bei der zweitletzten Zeile kein Semikolon am Ende der Zeile steht. Die Zeile wurde einfach umgebrochen, es könnte aber auch alles auf einer Zeile stehen.

Übung

Du bist ein junger Mensch und interessierst dich möglicherweise für Autos. Möglicherweise vergleichst Du manchmal die Fahrzeuge Deiner Kollegen mit Deinem. Nimm an Du willst eine Datenbank haben von allen Autos Deiner Kollegen.
Schreibe eine Klasse Auto.
Abstrahiere das ein Auto so, wie es Dir für die geschilderte Problemstellung richtig erscheint. Füge also einige Datenelemente in Deine Klasse ein und gib der Klasse auch ein Verhalten indem du einige Methoden definierst, sicher um die Datenelemente zu setzen wie setPS(long ps) etc. Schreibe auch eine Methode display() um die Daten anzuzeigen.
Definiere die Klasse in einer eigenen Header und Quellcodedatei (z.B. Auto.h, Auto.cpp).

Schreibe eine Methode "staerker" : bool staerker(Auto* anderesAuto) in der Klasse Auto.
Diese Funktion soll die PS Zahl (m_PS) mit der PS-Zahl des anderen Autos vergleichen und true zurückgeben falls die eigene PS-Zahl grösser ist als die des anderenAutos.

Lösung

Hier das Projekt mit den Lösungen.