Übungsaufgaben zu Container

In diesem Kapitel haben Sie gelernt, was Container-Klassen sind und wie sie angewendet werden können. Im Folgenden gibt es einige praktische Übungen und Verständnisfragen, mit denen Sie überprüfen können, ob Sie das Gelernte korrekt anwenden können.

Praktische Aufgaben

In diesem Teil soll das Gelernte praktisch anwendet und somit das Train-Beispiel erweitert werden. Konkret werden Sie die Klasse Station aus den vorangegangen Aufgaben bearbeiten, sodass verschiedene Bahnhöfe miteinander verbunden werden.

Teil 1

Legen Sie in Station einen Vector p_pNeighbors vom Typ shared_ptr an, in dem benachbarte Stationen gespeichert werden.

Teil 2

Jetzt sollen verschiedene Funktionen implementiert werden. Schreiben Sie eine Funktion vAddNeighbor, die den Returntyp void hat, einen Nachbar zu dem aktuellen Bahnhof übergeben bekommt und ihn in dem Vector p_pNeighbors speichert. Um zu kontrollieren, dass Ihre Implementierung richtig ist, legen Sie ebenfalls eine Funktion vPrintNeighbors an, die den Vector ausgibt.

Teil 3

Zum Schluss legen Sie eine Funktion isNeighbor an, die überprüft, ob ein anderer Bahnhof mit dem aktuellen verbunden ist. Die Funktion soll 1 zurückgeben, wenn die Stationen miteinander verbunden sind und 0, wenn sie nicht verbunden sind.

Teil 4

Fügen Sie Ihre Implementierungen von Train, PassengerTrain und FreightTrain aus den vorherigen Aufgaben an passender Stelle ein. Die Funktion vSetStation ist für diese Aufgabe nicht relevant, kann also weggelassen werden. Compilieren Sie anschließend alles und führen Sie die main()-Funktion aus, um zu überprüfen, ob alles korrekt gemacht wurde.

zum Lösungsvorschlag

#include <iostream>
#include <string>
#include <memory>
#include <vector>
//Station.h
class Station{
    //hier Ihre Erweiterungen einfügen
    private:
    std::string p_sName;
     
    public:
    Station(std::string station);
    std::string getName() const;
}
//Station.cpp
//Konstruktor für Station
Station::Station(std::string station)
    : p_sName(station){
        
    }
//Getter-Funktion für p_sName
std::string Station::getName() const {
    return p_sName;
}
//hier: Funktion Station::vAddNeighbor 
//hier: Funktion Station::vPrintNeighbors 
//hier: Funktion Station::isNeighbor 
//hier: Train.h einfügen
//hier: Train.cpp
//Destruktor einfügen
//hier: Funktion Train::vGoto einfügen
//hier: Funktion Train::vPrintProperties einfügen
//hier: PassengerTrain.h einfügen
//hier: PassengerTrain.cpp
//Konstruktor einfügen
//hier: PassengerTrain::vPrintProperties einfügen
//hier: Funktion PassengerTrain::fStation einfügen
//hier: FreightTrain.h einfügen
//hier: FreightTrain.cpp
//Konstruktor einfügen
//hier: Funktion FreightTrain::vPrintProperties einfügen
//hier: Funktion FreightTrain::vLoadCharge einfügen
#define OPERATOR operator<< //Diese Zeile kann in jeder IDE weggelassen werden, sie ist nur für Jupyter notwendig

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

#undef OPERATOR //Diese Zeile kann in jeder IDE weggelassen werden, sie ist nur für Jupyter notwendig
// 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;

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

Lösungen

zur Aufgabenstellung

Hier finden Sie die Lösungen zu den Aufgaben zu Station. Bitte beachten Sie, dass es mehrere Möglichkeiten gibt, die Aufgaben zu lösen, hier wird lediglich eine Variante aufgezeigt. Solange Ihre Implementierung funktioniert wie gefordert, ist sie wahrscheinlich richtig!

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)
{}
bool Station::isNeighbor(std::shared_ptr<Station> request) const
{
    if(std::find(p_pNeighbors.begin(), p_pNeighbors.end(), request) != p_pNeighbors.end()) {
        return 1;
    }
    
    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);
}

Verständnisfragen

Dieser Teil ist eher theoretischer Natur. Er besteht aus 3 kleinen Aufgaben, bei denen Sie auf Fehlersuche in kleinen Codesnippets gehen sollen. Bitte führen Sie die unten aufgeführten include-Befehle als erstes aus, damit es nicht zu Zusatzfehlern kommt ;-).

#include <iostream>
#include <vector>
#include <map>
#include <array>
#include <string>
#include <iterator>

Aufgabe 1

Folgender vector wurde angelegt. Er soll die Zahlen 7, 7, 7, 256, 4 in dieser Reihenfolge beinhalten. Finden Sie die Fehler.

{
    vector<int> vec(3,7);
    vec.push_back(256);
    vec.insert(4,4);
    for(auto it: vec){
        cout << it << " ";
    }
}

Aufgabe 2

Es wurde ein Array angelegt mit 4 Elementen. An der vierten Stelle soll der Wert verändert werden. Warum funktioniert das nicht? Finden Sie den Fehler.

{
    std::array<float, 4> arr = {1.1, 2.2, 3.3};
    arr.at(4) = 4.4;
    for(auto i: arr){
        std::cout << i << " ";
    }
}

Aufgabe 3

In der Folgenden Map soll das gefundene Element ausgegeben werden. Wenn die gesuchte Person (hier: Ernst Schmachtenberg) nicht in dieser Map gespeichert ist, soll eine Meldung erscheinen. Finden Sie die Fehler.
Zusatz: Warum ist eine Map nicht geeignet, um Vor- und Nachnamen zueinander zu speichern?

{
    std::map<std::string, std::string> people;
    people["Schmachtenberg"] = "Ernst";
    people["Rüdiger"] = "Ulrich";
    people["Lankes"] = "Stefan";
    people["Sauer"] = "Dirk";
    people["Monti"] = "Antonello";
    
    auto wanted = people.find("Ernst");
    
    if(wanted != people.end()){
        std::cout << wanted->first << ", " << wanted->second;
    } else {
        std::cout << "Person not found.";
    }
}
Person not found.

Lösungen

Lösung 1

Die erste 4 in dem insert-Befehl ist kein Iterator, dementsprechend wird nicht die passende Sstelle zurück geliefert. Mögliche Lösungen wären, entweder vec.insert(vec.end(), 4) oder vec.push_back(4) zu benutzen. Alternativ kann man den ganzen vector auch von vornherein mit den korrekten Werten initialisieren. Zusätzlich fehlt das 'std::' vor vector<int> bei der Initialisierung und vor cout. Diesen Fehler könnte man auch durch die Zeile using namespace std vor den geschweiften Klammern beheben, dies ist aber keine gängige Praxis (mehr).

Lösung 2

Hier sollten Sie sich an den Satz "Array index starts at 0" erinnern (Dieser Satz ist i.A. gültig, es gibt aber einige wenige Ausnahmen, wie Sie vielleicht aus Matlab etc. wissen). Um auf die vierte Stelle des Arrays zuzugreifen, wird der Index 3 benutzt. Korrekt würde der Befehl also lauten arr.at(3) = 4.4.

Lösung 3

Wenn find() den Iterator end() liefert, heißt das, dass kein Eintrag mit diesem Schlüssel in der Map existiert. Der erste Fehler ist also, dass es in der if-Bedingung != statt == heißen müsste (oder die beiden Anweisungen getauscht werden müssten). Der zweite Fehler ist, dass Key (deutsch: Schlüssel) und Value (deutsch: Wert) in der Funktion verwechselt wurden. Es wurde also nach dem Wert gesucht und nicht nach dem Schlüssel. Richtig ist also auto wanted = people.find("Schmachtenberg");.