Übungsaufgaben zu Exception

Praktische Aufgabe

Im Notebook zu Exceptions wurde das Konzept von Exceptions in C++ erläutert: Diese dienen dazu, bei Ausnahmesituationen den normalen Programmablauf zu unterbrechen und optional eine Fehlerbehandlung zu starten.

Dafür muss zunächst definiert werden, welche Art von Fehlermeldung geworfen werden soll. Hierfür ist es möglich, von std::exception erbende Klassen zu erstellen, es existieren aber auch schon einige standardmäßig in C++. Daraufhin wird im Abschnitt, bei dem ein Fehler auftreten könnte, mittels throw eine Instanz jener Exception erzeugt und an die aufrufende Funktion übergeben. Bei vielen bereits vorhandenen Klassen wie beispielsweise den elementaren Datentypen sind diese Maßnahmen schon implementiert, sodass nur noch auf die korrekte Behandlung dieser eventuell auftretenden Exceptions geachtet werden muss.

Dafür wird, falls vorhanden, der den Funktionsaufruf umschließende catch-Block mit dem passenden Typ einer Exception aufgerufen. Wenn der Fehler behebbar ist, sollten entsprechende Schritte eingeleitet werden, andernfalls ist oft eine Ausgabe der Fehlermeldung mit what hilfreich. Existiert kein passendes catch, bricht die Ausführung des Programms ebenfalls mit der Ausgabe einer Fehlermeldung ab.

Unten finden Sie die Codebasis auf dem Stand der letzten Übung zu Containerklassen, die nun am Ende erweitert wird. Es soll eine Exception geworfen werden, falls zwischen gewünschtem Start und Ziel keine Verbindung besteht. In diesem Fall wird aktuell in Train::vGoTo(...) eine einfache Fehlermeldung über die Konsole ausgegeben. Diese Aufgabe soll im Folgenden eine Exception übernehmen:

Erstellen einer TrainException Klasse

Um das oben beschriebene Verhalten zu erreichen, soll die Klasse TrainException erstellt werden, welche von std::exception erbt. Zunächst müssen dafür die beiden Libraries <exception> und <stdlib.h> inkludiert werden. Außerdem verfügt diese Klasse als Membervariable über einen Shared Pointer auf den Bahnhof, der angefahren werden soll, um im weiteren Verlauf dessen Namen auszugeben.

Ansonsten wenden Sie dieselben Konzepte an, die Sie bisher beim Erstellen von Klassen und Vererbungsstrukturen erlernt haben; insbesondere also Konstruktor, Destruktor und passende Zugriffsspezifizierer.

Ausgabe der Fehlermeldung

Zur Realisierung der Ausgabe implementieren Sie die Methode TrainException::vExplain(), die auf der Konsole ausgibt, welchen Bahnhof der Zug anfahren wollte und dass das nicht möglich ist, da keine Verbindung existiert

Integration der Exception in den Programmablauf

Werfen Sie nun anstelle der einfachen Fehlermeldung im else-Zweig von Train::vGoTo(...) eine TrainException, der der Shared Pointer im Konstruktor übergeben wird. Führen Sie nun die Testaufrufe innnerhalb eines try-catch Blockes durch, der im Fehlerfall TrainException::vExplain() der geworfenen Exception aufruft.

zum Lösungsvorschlag

#include <iostream>
#include <string>
#include <memory>
#include <vector>
class Station
{
    private:
        std::string p_sName;
        std::vector<std::shared_ptr<Station>> p_pNeighbors;
    
    public:
        Station(std::string station);
    
        void vAddNeighbor(std::shared_ptr<Station> neighbor);
        std::string getName() const;
        void vPrintNeighbors() const;
        bool isNeighbor(std::shared_ptr<Station> request) const;
};
Station::Station(std::string station) : p_sName(station)
{}
// falls request ein bekannter Nachbar ist: returnt 1, sonst 0
bool Station::isNeighbor(std::shared_ptr<Station> request) const
{
    // falls request in p_pNeighbors:
    if(std::find(p_pNeighbors.begin(), p_pNeighbors.end(), request) != p_pNeighbors.end()) {
        return 1;
    }
    
    // sonst:
    return 0;
}
void Station::vPrintNeighbors() const
{
    std::cout << std::endl << "Folgende Bahnhoefe koennen von " << p_sName << " aus angefahren werden: ";
    for (auto n : p_pNeighbors) {
        std::cout << n->getName() << ", ";
    }
}
std::string Station::getName() const
{
    return p_sName;
}
void Station::vAddNeighbor(std::shared_ptr<Station> neighbor)
{
    p_pNeighbors.push_back(neighbor);
}
class Train
{
    private:
        static inline int p_iIDCounter = 0;
        const int p_iID = p_iIDCounter++;
    
        std::shared_ptr<Station> p_pIsAt = nullptr;
    protected:
        float p_fDelay = 0;
    
    public:
        Train() = default;
        virtual ~Train() = 0;
        
        virtual void vPrintProperties(std::ostream& ausgabe) const;
    
        void vGoTo(std::shared_ptr<Station> to);
};
Train::~Train()
{
    std::cout << "Aufruf des rein virtuellen Destruktors" << std::endl;
}
void Train::vPrintProperties(std::ostream& ausgabe) const
{
    ausgabe << "ID: " << p_iID << std::endl;
    
    //ausgabe << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl; -> jetzt in PassengerTrain
    ausgabe << "momentane Verspaetung: " << p_fDelay << " Minuten"<< std::endl;
}
class PassengerTrain : public Train
{
    public:
        PassengerTrain() = default;
        PassengerTrain(int p_iPassengerCounter);
        virtual ~PassengerTrain() = default;
        
        void vPrintProperties(std::ostream& ausgabe) const override;
        float fStation(int passengersIn, int passengersOut);
    
    private:
        int p_iPassengerCounter = 0;

};
PassengerTrain::PassengerTrain(int passengers) : Train(), p_iPassengerCounter(passengers)
{
    std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
void PassengerTrain::vPrintProperties(std::ostream& ausgabe) const
{
    Train::vPrintProperties(ausgabe);
    ausgabe << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl;
}
// 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 PassengerTrain::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;
}
class FreightTrain : public Train
{
    private:
        float p_fChargeQuantity = 0.0;
        std::string p_sChargeType = "default";
        
    public:
        FreightTrain() = default;
        FreightTrain(float chargeQuantity, std::string chargeType);
        
        //void vPrintProperties() const;
        void vPrintProperties(std::ostream& ausgabe) const override;

        void vLoadCharge(float amount);
};
FreightTrain::FreightTrain(float chargeQuantity, std::string chargeType) : Train(), p_fChargeQuantity(chargeQuantity), p_sChargeType(chargeType)
{}
void FreightTrain::vPrintProperties(std::ostream& ausgabe) const
{
    Train::vPrintProperties(ausgabe);
    ausgabe << "Ladung: " << p_fChargeQuantity << " " << p_sChargeType << std::endl;
}
// abladen: amount < 0
void FreightTrain::vLoadCharge(float amount)
{ 
    if (p_fChargeQuantity + amount < 0)
    {
        std::cout << "Es kann nicht mehr abgeladen werden als geladen ist. Abbruch." << std::endl;
        return;
    }

    p_fChargeQuantity += amount;
    std::cout << "Es wurden " << amount << " " << p_sChargeType;
    
    
    if (amount > 0)
    {
        std::cout << " aufgeladen.";
    }
    else
    {
        std::cout << " abgeladen.";
    }
    
    std::cout << " Es befinden sich nun " << p_fChargeQuantity << " " << p_sChargeType << " auf dem Zug." << std::endl;
}
#define OPERATOR operator<<

std::ostream & OPERATOR(std::ostream& out, const Train& train)
{
    train.vPrintProperties(out);
    return out;
}

#undef OPERATOR 
//TrainException.h
//hier: Klasse TrainException implementieren
//TrainException.cpp
//hier: Konstruktor implementieren
//TrainException.cpp
//hier: Destruktor implementieren
//TrainException.cpp
//hier: vExplain(...) implementieren
void Train::vGoTo(std::shared_ptr<Station> to)
{
    if((p_pIsAt==nullptr) || (p_pIsAt->isNeighbor(to)))
    {
        p_pIsAt = to;
        std::cout << "Zug ist nach " << p_pIsAt->getName() << " gefahren." << std::endl;
    }
    else
    {
        std::cout << "Der Zug kann nicht nach " << to->getName() << " fahren: Es gibt keine Verbindung." << std::endl;
    }
    
    /*
    // Fahre nur, wenn Zug im Anfangszustand, oder das Ziel und die aktuelle Haltestelle verbunden sind:
    if((p_sIsAt==nullptr) || (p_sIsAt->getDestination() == to))
    {
        p_sIsAt = to;
        std::cout << "Zug ist nach " << p_sIsAt->getName() << " gefahren." << std::endl;
    }
    else
    {
        std::cout << "Der Zug kann nicht nach " << to->getName() << " fahren: Es gibt keine Verbindung." << std::endl;
    }
    */
}
// Test

std::unique_ptr<PassengerTrain> aTrain;
aTrain =  std::make_unique<PassengerTrain>();

auto bTrain = std::make_unique<FreightTrain>(2, "tons of wood");

std::cout << std::endl << "Eigenschaften 'aTrain':" << std::endl;
std::cout << *aTrain;

std::cout << std::endl << "Eigenschaften 'bTrain':" << std::endl;
std::cout << *bTrain;

// alter Test: gleiches Verhalten wie in 04_smartpointer
/*
auto berlin = std::make_shared<Station>("Berlin");
auto hamburg = std::make_shared<Station>("Hamburg");
auto frankfurt = std::make_shared<Station>("Frankfurt");

berlin->vAddNeighbor(hamburg);
hamburg->vAddNeighbor(berlin);

aTrain->vGoTo(berlin);
aTrain->vGoTo(hamburg);
aTrain->vGoTo(frankfurt);
*/

// neu: Strecken"netz"
auto berlin = std::make_shared<Station>("Berlin");
auto hamburg = std::make_shared<Station>("Hamburg");
auto frankfurt = std::make_shared<Station>("Frankfurt");
auto koeln = std::make_shared<Station>("Koeln");
auto muenchen = std::make_shared<Station>("Muenchen");

berlin->vAddNeighbor(hamburg);
berlin->vAddNeighbor(frankfurt);
    
hamburg->vAddNeighbor(berlin);
hamburg->vAddNeighbor(koeln);

// Strecke nur in eine Richtung
koeln->vAddNeighbor(frankfurt);

frankfurt->vAddNeighbor(koeln);
frankfurt->vAddNeighbor(berlin);
frankfurt->vAddNeighbor(muenchen);

muenchen->vAddNeighbor(frankfurt);

// Zeige Liste der bekannten Nachbarn
berlin->vPrintNeighbors();
hamburg->vPrintNeighbors();
koeln->vPrintNeighbors();
frankfurt->vPrintNeighbors();
muenchen->vPrintNeighbors();




std::cout<< "\n\n\nZuege fahren lassen: \n\n";

aTrain->vGoTo(berlin);
aTrain->vGoTo(hamburg);
aTrain->vGoTo(koeln);
aTrain->vGoTo(hamburg); // Fehlermeldung: keine Verbindung

Eigenschaften 'aTrain':
ID: 0
momentane Verspaetung: 0 Minuten
Anzahl Passagiere: 0

Eigenschaften 'bTrain':
ID: 1
momentane Verspaetung: 0 Minuten
Ladung: 2 tons of wood

Folgende Bahnhoefe koennen von Berlin aus angefahren werden: Hamburg, Frankfurt, 
Folgende Bahnhoefe koennen von Hamburg aus angefahren werden: Berlin, Koeln, 
Folgende Bahnhoefe koennen von Koeln aus angefahren werden: Frankfurt, 
Folgende Bahnhoefe koennen von Frankfurt aus angefahren werden: Koeln, Berlin, Muenchen, 
Folgende Bahnhoefe koennen von Muenchen aus angefahren werden: Frankfurt, 


Zuege fahren lassen: 

Zug ist nach Berlin gefahren.
Zug ist nach Hamburg gefahren.
Zug ist nach Koeln gefahren.
Der Zug kann nicht nach Hamburg fahren: Es gibt keine Verbindung.

Lösungsvorschlag zur Implementierung

zur Aufgabenstellung

#include <iostream>
#include <string>
#include <memory>
#include <vector>
#include <exception>
#include <stdlib.h>
class Station
{
    private:
        std::string p_sName;
        std::vector<std::shared_ptr<Station>> p_pNeighbors;
    
    public:
        Station(std::string station);
        virtual ~Station() = default;
        void vAddNeighbor(std::shared_ptr<Station> neighbor);
        std::string getName() const;
        void vPrintNeighbors() const;
        bool isNeighbor(std::shared_ptr<Station> request) const;
};
Station::Station(std::string station) : p_sName(station)
{}
// falls request ein bekannter Nachbar ist: returnt 1, sonst 0
bool Station::isNeighbor(std::shared_ptr<Station> request) const
{
    // falls request in p_pNeighbors:
    if(std::find(p_pNeighbors.begin(), p_pNeighbors.end(), request) != p_pNeighbors.end()) {
        return 1;
    }
    
    // sonst:
    return 0;
}
void Station::vPrintNeighbors() const
{
    std::cout << std::endl << "Folgende Bahnhoefe koennen von " << p_sName << " aus angefahren werden: ";
    for (auto n : p_pNeighbors) {
        std::cout << n->getName() << ", ";
    }
}
std::string Station::getName() const
{
    return p_sName;
}
void Station::vAddNeighbor(std::shared_ptr<Station> neighbor)
{
    p_pNeighbors.push_back(neighbor);
}
class Train
{
    private:    
        static inline int p_iIDCounter = 0;
        const int p_iID = p_iIDCounter++;
    
        std::shared_ptr<Station> p_pIsAt = nullptr;
    protected:
        float p_fDelay = 0;
    
    public:
        Train() = default;
        virtual ~Train() = 0;
        
        virtual void vPrintProperties(std::ostream& ausgabe) const;
        void vGoTo(std::shared_ptr<Station> to);
        std::shared_ptr<Station> getIsAt();
};
std::shared_ptr<Station> Train::getIsAt()
{
    return p_pIsAt;
}
Train::~Train()
{
    std::cout << "Aufruf des rein virtuellen Destruktors" << std::endl;
}
void Train::vPrintProperties(std::ostream& ausgabe) const
{
    ausgabe << "ID: " << p_iID << std::endl;
    
    //ausgabe << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl; -> jetzt in PassengerTrain
    ausgabe << "momentane Verspaetung: " << p_fDelay << " Minuten"<< std::endl;
}
class PassengerTrain : public Train
{
    public:
        PassengerTrain() = default;
        PassengerTrain(int p_iPassengerCounter);
        virtual ~PassengerTrain() = default;
        
        void vPrintProperties(std::ostream& ausgabe) const override;
        float fStation(int passengersIn, int passengersOut);
    
    private:
        int p_iPassengerCounter = 0;

};
PassengerTrain::PassengerTrain(int passengers) : Train(), p_iPassengerCounter(passengers)
{
    std::cout << "Aufruf des Nicht-Standardkonstruktors" << std::endl;
}
void PassengerTrain::vPrintProperties(std::ostream& ausgabe) const
{
    Train::vPrintProperties(ausgabe);
    ausgabe << "Anzahl Passagiere: " << p_iPassengerCounter << std::endl;
}
// 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 PassengerTrain::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;
}
class FreightTrain : public Train
{
    private:
        float p_fChargeQuantity = 0.0;
        std::string p_sChargeType = "default";
        
    public:
        FreightTrain() = default;
        FreightTrain(float chargeQuantity, std::string chargeType);
        
        //void vPrintProperties() const;
        void vPrintProperties(std::ostream& ausgabe) const override;

        void vLoadCharge(float amount);
};
FreightTrain::FreightTrain(float chargeQuantity, std::string chargeType) : Train(), p_fChargeQuantity(chargeQuantity), p_sChargeType(chargeType)
{}
void FreightTrain::vPrintProperties(std::ostream& ausgabe) const
{
    Train::vPrintProperties(ausgabe);
    ausgabe << "Ladung: " << p_fChargeQuantity << " " << p_sChargeType << std::endl;
}
// abladen: amount < 0
void FreightTrain::vLoadCharge(float amount)
{ 
    if (p_fChargeQuantity + amount < 0)
    {
        std::cout << "Es kann nicht mehr abgeladen werden als geladen ist. Abbruch." << std::endl;
        return;
    }

    p_fChargeQuantity += amount;
    std::cout << "Es wurden " << amount << " " << p_sChargeType;
    
    
    if (amount > 0)
    {
        std::cout << " aufgeladen.";
    }
    else
    {
        std::cout << " abgeladen.";
    }
    
    std::cout << " Es befinden sich nun " << p_fChargeQuantity << " " << p_sChargeType << " auf dem Zug." << std::endl;
}
#define OPERATOR operator<<

std::ostream & OPERATOR(std::ostream& out, const Train& train)
{
    train.vPrintProperties(out);
    return out;
}

#undef OPERATOR 
class TrainException : std::exception
{
    private:
        std::shared_ptr<Station> p_pDestination;
    
    public:
        TrainException(std::shared_ptr<Station> destination);
        virtual ~TrainException();
        void vExplain(); // ganz unten
};
TrainException::TrainException(std::shared_ptr<Station> destination) : p_pDestination(destination)
{}
TrainException::~TrainException()
{}
void TrainException::vExplain()
{
    std::cout << "Der Zug versuchte nach " << p_pDestination->getName() << " zu fahren. Nicht moeglich, da keine Verbindung vorhanden. Ende." << std::endl;
}
void Train::vGoTo(std::shared_ptr<Station> to)
{
    if((p_pIsAt==nullptr) || (p_pIsAt->isNeighbor(to)))
    {
        p_pIsAt = to;
        std::cout << "Zug ist nach " << p_pIsAt->getName() << " gefahren." << std::endl;
    }
    else
    {
        throw TrainException(to);
        std::cout << "Der Zug kann nicht nach " << to->getName() << " fahren: Es gibt keine Verbindung." << std::endl;
    }
}
// Test

std::shared_ptr<PassengerTrain> aTrain;
aTrain =  std::make_shared<PassengerTrain>();

auto bTrain = std::make_shared<FreightTrain>(2, "tons of wood");

std::cout << std::endl << "Eigenschaften 'aTrain':" << std::endl;
std::cout << *aTrain;

std::cout << std::endl << "Eigenschaften 'bTrain':" << std::endl;
std::cout << *bTrain;

// neu: Strecken"netz"
auto berlin = std::make_shared<Station>("Berlin");
auto hamburg = std::make_shared<Station>("Hamburg");
auto frankfurt = std::make_shared<Station>("Frankfurt");
auto koeln = std::make_shared<Station>("Koeln");
auto muenchen = std::make_shared<Station>("Muenchen");


berlin->vAddNeighbor(hamburg);
berlin->vAddNeighbor(frankfurt);
    
hamburg->vAddNeighbor(berlin);
hamburg->vAddNeighbor(koeln);

// Strecke nur in eine Richtung
koeln->vAddNeighbor(frankfurt);

frankfurt->vAddNeighbor(koeln);
frankfurt->vAddNeighbor(berlin);
frankfurt->vAddNeighbor(muenchen);

muenchen->vAddNeighbor(frankfurt);

// Zeige Liste der bekannten Nachbarn
berlin->vPrintNeighbors();
hamburg->vPrintNeighbors();
koeln->vPrintNeighbors();
frankfurt->vPrintNeighbors();
muenchen->vPrintNeighbors();

Eigenschaften 'aTrain':
ID: 0
momentane Verspaetung: 0 Minuten
Anzahl Passagiere: 0

Eigenschaften 'bTrain':
ID: 1
momentane Verspaetung: 0 Minuten
Ladung: 2 tons of wood

Folgende Bahnhoefe koennen von Berlin aus angefahren werden: Hamburg, Frankfurt, 
Folgende Bahnhoefe koennen von Hamburg aus angefahren werden: Berlin, Koeln, 
Folgende Bahnhoefe koennen von Koeln aus angefahren werden: Frankfurt, 
Folgende Bahnhoefe koennen von Frankfurt aus angefahren werden: Koeln, Berlin, Muenchen, 
Folgende Bahnhoefe koennen von Muenchen aus angefahren werden: Frankfurt, 
try
{
    std::cout<< "\n\n\nZuege fahren lassen: \n\n";

    aTrain->vGoTo(berlin);
    aTrain->vGoTo(hamburg);
    aTrain->vGoTo(koeln);
    aTrain->vGoTo(hamburg); // Fehlermeldung: keine Verbindung
}

catch(TrainException &e)
{
    e.vExplain();
}



Zuege fahren lassen: 

Zug ist nach Berlin gefahren.
Zug ist nach Hamburg gefahren.
Zug ist nach Koeln gefahren.
Error: 

Verständnisfragen

Unterschiedliche Ausgabe

Warum wird mit der Implementierung von Train::vGoTo() im Lösungsvorschlag bei einem fehlerhaften Aufruf der Inhalt der Exception ausgegeben, nicht aber die normale Ausgabe in der Zeile darunter (die in der vorherigen Implementierung ausgeführt wurde)?

Abbruch

Welches Verhalten erwarten Sie von den unten aufgeführten Methodenaufrufen? Wie könnte erreicht werden, dass auch bei einzelnen fehlerhaften Aufrufen von Train::vGoTo() die darauf folgenden Anweisungen ausgeführt werden?

try
{
    std::cout<< "\n\n\nZuege fahren lassen: \n\n";

    aTrain->vGoTo(berlin);
    aTrain->vGoTo(hamburg);
    aTrain->vGoTo(frankfurt);
    aTrain->vGoTo(koeln);
    aTrain->vGoTo(frankfurt);
    aTrain->vGoTo(hamburg);
    aTrain->vGoTo(berlin);
}

catch(TrainException &e)
{
    e.vExplain();
}

Lösungsvorschläge zu den Verständnisfragen

Unterschiedliche Ausgaben

Nach dem Werfen einer Exception mittels throw wird die fehlerhafte Funktion verlassen, bis die Exception durch ein passendes catch abgefangen wird. Bei einander aufrufenden Funktionen geschieht das so lange, wie die Exception unbehandelt bleibt, d.h. es können durch eine Exception auch mehrere Funktionen verlassen werden. Wenn schließlich die eigentliche main-Methode des Programms verlassen werden soll, bricht die Ausführung des Programms mit der Ausgabe dieser Exception ab.

Abbruch

Da keine direkte Verbindung von Hamburg nach Frankfurt besteht, würde die Ausführung bei der aktuellen Implementierung an dieser Stelle abbrechen, da eine Exception geworfen und der catch-Block ausgeführt wird. Um dieses Verhalten zu verhindern, könnte jeder Aufruf von Train::vGoTo() in einem separaten try-catch Block stattfinden, was allerdings schnell unübersichtlich wird:

std::cout<< "\n\n\nZuege fahren lassen: \n\n";

try{aTrain->vGoTo(berlin); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(hamburg); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(frankfurt); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(koeln); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(frankfurt); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(hamburg); } 
catch(TrainException &e) { e.vExplain();}

try{aTrain->vGoTo(berlin); } 
catch(TrainException &e) { e.vExplain();}