Hier finden Sie eine Übungsaufgabe, um die gerade gelernten Konzepte einmal selbst zu verwenden, sowie einige Verständnisfragen.
Im Folgenden soll das gerade gelernte angewendet werden. Zu jedem Teil der Übungsaufgabe gibt es eine eingeklappte Lösung. Bevor Sie sich diese anschauen, sollten Sie versuchen, die gewünschte Funktionalität selbst zu implementieren. Die Lösungsvorschläge stellen eine mögliche Lösung für die Aufgaben dar, aber auch andere Ansätze können die Aufgaben lösen.
Die Teile der Aufgabe bauen aufeinander auf. Es kann notwendig sein, dass sie zwischen den Aufgabenteilen den Kernel neu starten (). Das gleiche gilt für die Lösungsvorschläge.
Erstellen Sie eine Klasse mit dem Name Train. Die Klasse
soll die Instanzvariablen p_iPassengerCounter
(int) und p_fDelay (float)
beinhalten.
Objekte dieser Klasse sollen sowohl über den Standardkonstruktor, als
auch über einen Nicht-Standardkonstriktor instanziiert werden können.
Bei Verwendung des Standard-Konstruktors sollen beide Werte
0 sein. Der Nicht-Standardkonstruktor soll die Möglichkeit
bieten, die Variable p_iPassengerCounter zu setzen.
Erstellen Sie anschließend mit beiden Konstruktoren je eine Instanz der Klasse.
Erweitern Sie Ihre Klasse um eine Methode, die die Instanzvariablen
ausgibt (void printPropierties()). Rufen Sie die Methode
für beide Instanzen auf.
Erstellen Sie eine Methode
float station(int passengersIn, int passengersOut). Die
Methode soll die Variable p_iPassengerCounter
aktualisieren. Der Rückgabewert der Methode soll die aufgebaute
(positive Zahl) oder abgebaute (negative Zahl) Verspätung in Minuten
sein. Dabei wird davon ausgegangen, dass ein aussteigender Passagier 5
Sekunden und ein einsteigender Passagier 10 Sekunden benötigt. Um keine
Verspätung aufzubauen, darf der Halt 2 Minuten dauern.
Außerdem soll die Verspätung in der Variable p_fDelay
aktualisiert werden. Die Verspätung soll aber nicht negativ sein
können.
Für den Fall, dass mehr Personen aussteigen sollen als es Passagiere
im Zug gibt, soll die Methode 0 returnen und die Anzahl der
Passagiere nicht verändern.
Zuletzt soll die Klasse ein static-Member erhalten, um
jedem erzeugten Zug eine eindeutige ID zuweisen zu können. Erweitern Sie
Ihrer Klasse dazu durch die Membervariablen
static p_idCounter und p_iID. Auch
printProperties() soll entsprechend angepasst werden.
Erstellen Sie zum Testen der Funktionalität einige Züge und lassen Sie sich die Eigenschaften ausgeben.
#include <iostream>
// Train.h
// hier: Klasse Train implementieren
// Train.cpp
// hier: Konstruktor implementieren
// Train.cpp
// hier: printProperties() implementieren
// Train.cpp
// hier: station(...) implementieren
// main.cpp
// hier: Instanzen erzeugen, Ausgabe
#include <iostream>
// Train.h
class Train
{
private:
int p_iPassengerCounter = 0;
float p_fDelay = 0;
public:
Train() = default;
Train(int passengers);
virtual ~Train() = default;
};
// Train.cpp
Train::Train(int passengers) : p_iPassengerCounter(passengers)
{
std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
// main.cpp
Train aTrain = Train();
Train bTrain = Train(20);
Aufruf des Nicht-Standardkonstruktors
#include <iostream>
// Train.h
class Train
{
private:
int p_iPassengerCounter = 0;
float p_fDelay = 0;
public:
Train() = default;
Train(int passengers);
virtual ~Train() = default;
void vPrintProperties() const;
}
// Train.cpp
Train::Train(int passengers) : p_iPassengerCounter(passengers)
{
std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
// Train.cpp
void Train::vPrintProperties() const
{
std::cout << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl;
std::cout << "momentane Verspaetung: " << p_fDelay << " Minuten"<< std::endl;
}
// main.cpp
Train aTrain = Train();
Train bTrain = Train(20);
std::cout << std::endl << "Eigenschaften 'aTrain':" << std::endl;
aTrain.vPrintProperties();
std::cout << std::endl << "Eigenschaften 'bTrain':" << std::endl;
bTrain.vPrintProperties();
Aufruf des Nicht-Standardkonstruktors
Eigenschaften 'aTrain':
Anzahl Passagiere: 0
momentane Verspaetung: 0 Minuten
Eigenschaften 'bTrain':
Anzahl Passagiere: 20
momentane Verspaetung: 0 Minuten
#include <iostream>
// Train.h
class Train
{
private:
int p_iPassengerCounter = 0;
float p_fDelay = 0;
static inline int p_iIDCounter = 0;
const int p_iID = p_iIDCounter++;
public:
Train() = default;
Train(int passengers);
virtual ~Train() = default;
void vPrintProperties() const;
float fStation(int passengersIn, int passengersOut);
}
// Train.cpp
Train::Train(int passengers) : p_iPassengerCounter(passengers)
{
std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
// Train.cpp
void Train::vPrintProperties() const
{
std::cout << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl;
std::cout << "momentane Verspaetung: " << p_fDelay << " Minuten"<< std::endl;
}
// Train.cpp
// gibt Änderung der Verspätung zurück und Verändert `delay` (aber delay >= 0)
/* Annahmen / Funktion
bei Haltestelle: 2 Minuten Zeit.
Pro einsteigender Passagier: 10 Sekunden
Pro aussteigender Passagier: 5 Sekunden
nicht parallel
alles >2 Minuten: neue Verspätung
*/
float Train::fStation(int passengersIn, int passengersOut)
{
// mehr Passagiere als Aussteigende? -> fehlerhafte Einhabe -> mache nichts
if (p_iPassengerCounter < passengersOut)
{
std::cout << "Es koennen nicht mehr Personen aussteigen als sich im Zug befinden" << std::endl;
return 0;
}
p_iPassengerCounter = p_iPassengerCounter + passengersIn - passengersOut;
// Rechnung in Sekunden, Umrechnung in Minuten spaeter
float secondsChange = 120 - passengersIn * 10 - passengersOut * 5;
p_fDelay = (p_fDelay - secondsChange < 0) ? 0 : (p_fDelay - secondsChange)/60;
return secondsChange/60;
}
// main.cpp
Train aTrain = Train();
Train bTrain = Train(20);
std::cout << std::endl << "Eigenschaften 'aTrain':" << std::endl;
aTrain.vPrintProperties();
std::cout << std::endl << "Eigenschaften 'bTrain':" << std::endl;
bTrain.vPrintProperties();
// ---
bTrain.fStation(15, 10);
std::cout << std::endl << "\n\n\nEigenschaften 'bTrain' nach 1. Halt:" << std::endl;
bTrain.vPrintProperties();
bTrain.fStation(3, 12);
std::cout << std::endl << "Eigenschaften 'bTrain' nach 2. Halt:" << std::endl;
bTrain.vPrintProperties();
Aufruf des Nicht-Standardkonstruktors
Eigenschaften 'aTrain':
Anzahl Passagiere: 0
momentane Verspaetung: 0 Minuten
Eigenschaften 'bTrain':
Anzahl Passagiere: 20
momentane Verspaetung: 0 Minuten
Eigenschaften 'bTrain' nach 1. Halt:
Anzahl Passagiere: 25
momentane Verspaetung: 1.33333 Minuten
Eigenschaften 'bTrain' nach 2. Halt:
Anzahl Passagiere: 16
momentane Verspaetung: 0 Minuten
#include <iostream>
// Train.h
class Train
{
private:
int p_iPassengerCounter = 0;
float p_fDelay = 0;
static inline int p_iIDCounter = 0;
const int p_iID = p_iIDCounter++;
public:
Train() = default;
Train(int passengers);
virtual ~Train() = default;
void vPrintProperties() const;
float fStation(int passengersIn, int passengersOut);
}
// Train.cpp
Train::Train(int passengers) : p_iPassengerCounter(passengers)
{
std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
// Train.cpp
void Train::vPrintProperties() const
{
std::cout << "ID: " << p_iID << std::endl;
std::cout << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl;
std::cout << "momentane Verspaetung: " << p_fDelay << " Minuten"<< std::endl;
}
// Train.cpp
// gibt Änderung der Verspätung zurück und Verändert `delay` (aber delay >= 0)
/* Annahmen / Funktion
bei Haltestelle: 2 Minuten Zeit.
Pro einsteigender Passagier: 10 Sekunden
Pro aussteigender Passagier: 5 Sekunden
nicht parallel
alles >2 Minuten: neue Verspätung
*/
float Train::fStation(int passengersIn, int passengersOut)
{
// mehr Passagiere als Aussteigende? -> fehlerhafte Einhabe -> mache nichts
if (p_iPassengerCounter < passengersOut)
{
std::cout << "Es koennen nicht mehr Personen aussteigen als sich im Zug befinden" << std::endl;
return 0;
}
p_iPassengerCounter = p_iPassengerCounter + passengersIn - passengersOut;
// Rechnung in Sekunden, Umrechnung in Minuten spaeter
float secondsChange = 120 - passengersIn * 10 - passengersOut * 5;
p_fDelay = (p_fDelay - secondsChange < 0) ? 0 : (p_fDelay - secondsChange)/60;
return secondsChange/60;
}
// main.cpp
Train aTrain = Train();
Train bTrain = Train(20);
Train cTrain = Train(52);
Train dTrain = Train(5);
std::cout << std::endl << "Eigenschaften 'aTrain':" << std::endl;
aTrain.vPrintProperties();
std::cout << std::endl << "Eigenschaften 'bTrain':" << std::endl;
bTrain.vPrintProperties();
std::cout << std::endl << "Eigenschaften 'cTrain':" << std::endl;
cTrain.vPrintProperties();
std::cout << std::endl << "Eigenschaften 'dTrain':" << std::endl;
dTrain.vPrintProperties();
Aufruf des Nicht-Standardkonstruktors
Aufruf des Nicht-Standardkonstruktors
Aufruf des Nicht-Standardkonstruktors
Eigenschaften 'aTrain':
ID: 0
Anzahl Passagiere: 0
momentane Verspaetung: 0 Minuten
Eigenschaften 'bTrain':
ID: 1
Anzahl Passagiere: 20
momentane Verspaetung: 0 Minuten
Eigenschaften 'cTrain':
ID: 2
Anzahl Passagiere: 52
momentane Verspaetung: 0 Minuten
Eigenschaften 'dTrain':
ID: 3
Anzahl Passagiere: 5
momentane Verspaetung: 0 Minuten
Train thisIsATrain = Train();
std::cout << thisIsATrain.p_iPassengerCounter << std::endl;
input_line_34:3:27: error: 'p_iPassengerCounter' is a private member of '__cling_N514::Train'
std::cout << thisIsATrain.p_iPassengerCounter << std::endl;
^
input_line_29:6:13: note: declared private here
int p_iPassengerCounter = 0;
^
Interpreter Error:
Was müsste im Code der Klasse geändert werden, um diese Fehlermeldung zu verhindern? Verändern Sie die entsprechende Stelle und beobachten Sie was mit der Fehlermeldung passiert.
Grundsätzlich vermeidet man es, Instanzvariablen zu lesen oder zu bearbeiten, wie es in diesem Beispiel versucht wird. Falls eine Membervariable von außen gelesen/bearbeitet werden soll, wie soll dies geschehen?
2. Führen Sie den letzen Block aus der Musterlösung mehrmals hintereinander aus, ohne den Kernel neu zu starten. Was können Sie beoachten? Wieso?
1.
Train müsste p_iPassengerCounter unter
public stehen. Da man versucht, dem Anwender einer Klasse
die Details der Implementierung zu verbergen, ist es nicht hilfreich,
alle Member public, also von außen zugänglich zu
machen.2. Lokale Variablen (hier: aTrain, bTrain, ....) werden bei jeder Ausführung überschrieben und neu erzeugt, 'p_idCounter' wird nicht zurückgesetzt -> 'p_ID' steigt