Assignment Chef icon Assignment Chef
All German tutorials

Programming lesson

C++ Vererbung und Polymorphie: Drachen zähmen mit Vererbungshierarchien – Ein Tutorial zu COWCOP3504C Lab 07

In diesem Tutorial lernst du, wie du in C++ mithilfe von Vererbung und Polymorphie eine Drachenklasse erstellst – inspiriert von CowLab 07. Wir bauen auf einer Cow-Klasse auf, leiten Dragon und IceDragon ab und zeigen, wie dynamische Typabfragen und virtuelle Methoden funktionieren.

C++ Vererbung Polymorphie C++ Dragon Klasse C++ IceDragon C++ Cow Klasse C++ dynamic_cast C++ virtuelle Methoden C++ C++17 CMake COWCOP3504C Lab 07 cowsay C++ Vererbungshierarchie C++ C++ für Studenten OOP C++ Tutorial C++ Drachen Beispiel Feuer spucken C++

Einführung: Vererbung in C++ – Mehr als nur Kühe

Stell dir vor, du entwickelst ein Spiel wie Clash of Clans oder eine KI-gesteuerte Kreaturenwelt: Jede Kreatur hat Grundfähigkeiten, aber Drachen können Feuer spucken, Eisdrachen nicht. Genau hier kommt die Vererbung ins Spiel. In diesem Tutorial lernst du, wie du mit C++ Vererbung und Polymorphie eine Hierarchie aus Cow, Dragon und IceDragon aufbaust – ganz wie im Lab 07 der COWCOP3504C. Keine Sorge, wir lösen nicht die ganze Aufgabe, sondern zeigen dir die entscheidenden Konzepte.

1. Die Basis: Cow-Klasse

Bevor wir zu feuerspeienden Drachen kommen, brauchen wir eine Basisklasse. Die Cow-Klasse speichert einen Namen und ein Bild (ASCII-Art). In C++ sieht eine einfache Cow-Klasse so aus:

// Cow.h
#ifndef COW_H
#define COW_H

#include <string>

class Cow {
public:
    Cow(const std::string& name);
    std::string getName() const;
    std::string getImage() const;
    virtual void setImage(const std::string& image);

private:
    std::string name_;
    std::string image_;
};

#endif

Beachte: setImage ist virtual. Das ist der Schlüssel zur Polymorphie – abgeleitete Klassen können diese Methode überschreiben. Warum virtual? Damit später, wenn wir einen Cow-Zeiger auf ein Dragon-Objekt haben, die richtige Methode aufgerufen wird.

Die Implementierung ist simpel:

// Cow.cpp
#include "Cow.h"

Cow::Cow(const std::string& name) : name_(name) {}

std::string Cow::getName() const { return name_; }

std::string Cow::getImage() const { return image_; }

void Cow::setImage(const std::string& image) { image_ = image; }

2. Dragon-Klasse: Von der Kuh zum Drachen

Ein Drache ist eine spezielle Kuh – er erbt alle Eigenschaften, kann aber zusätzlich Feuer spucken. In C++ leiten wir Dragon von Cow ab:

// Dragon.h
#ifndef DRAGON_H
#define DRAGON_H

#include "Cow.h"

class Dragon : public Cow {
public:
    Dragon(const std::string& name, const std::string& image);
    bool canBreatheFire() const;
};

#endif

Der Konstruktor ruft den Cow-Konstruktor auf und setzt das Bild. Die Methode canBreatheFire() gibt für einen normalen Drachen immer true zurück. In der Implementierung:

// Dragon.cpp
#include "Dragon.h"

Dragon::Dragon(const std::string& name, const std::string& image)
    : Cow(name) {
    setImage(image);
}

bool Dragon::canBreatheFire() const {
    return true;
}

Spannend wird es, wenn wir später durch Polymorphie herausfinden, ob ein Cow-Zeiger auf einen Drachen zeigt. Dafür nutzen wir dynamic_cast – wie die HeiferGenerator-Klasse es tut.

3. IceDragon: Ein eisiger Untertyp

IceDragon erbt von Dragon und überschreibt canBreatheFire(), um false zurückzugeben. Kein Feuer, aber dafür Eis – cool, oder?

// IceDragon.h
#ifndef ICEDRAGON_H
#define ICEDRAGON_H

#include "Dragon.h"

class IceDragon : public Dragon {
public:
    IceDragon(const std::string& name, const std::string& image);
    bool canBreatheFire() const;
};

#endif

Implementierung:

// IceDragon.cpp
#include "IceDragon.h"

IceDragon::IceDragon(const std::string& name, const std::string& image)
    : Dragon(name, image) {}

bool IceDragon::canBreatheFire() const {
    return false;
}

Beachte: Der IceDragon-Konstruktor ruft den Dragon-Konstruktor auf, der wiederum den Cow-Konstruktor aufruft. Die Vererbungskette ist: Cow → Dragon → IceDragon.

4. Polymorphie in Aktion: Der HeiferGenerator

Die bereitgestellte HeiferGenerator-Klasse erzeugt eine Liste von Cow-Zeigern, die auf verschiedene Objekte zeigen: Cow, Dragon, IceDragon. Mit dynamic_cast prüft sie, ob ein Cow-Zeiger tatsächlich auf einen Dragon zeigt:

Dragon* HeiferGenerator::getDragonPointer(Cow* candidate) {
    Dragon* dragon = dynamic_cast<Dragon*>(candidate);
    return dragon; // nullptr, wenn es kein Dragon ist
}

Das ist mächtig: Du kannst eine Liste von „Kühen“ durchgehen und nur bei Drachen eine Extra-Meldung ausgeben. Genau das passiert im cowsay-Programm: Wenn der Nutzer -n dragon wählt, wird der Cow-Zeiger per dynamic_cast in einen Dragon-Zeiger umgewandelt und canBreatheFire() aufgerufen.

5. CMakeLists.txt: C++17 einstellen

Damit alles funktioniert, musst du in deiner CMakeLists.txt die Sprache auf C++17 setzen:

cmake_minimum_required(VERSION 3.10)
project(cowsay)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(cowsay cowsay.cpp Cow.cpp Dragon.cpp IceDragon.cpp HeiferGenerator.cpp)

Warum C++17? Weil dynamic_cast und andere Features ab C++11 stabil sind, aber C++17 bringt nützliche Erweiterungen wie std::string_view (optional). Dein Professor verlangt es – also halten wir uns dran.

6. Typische Fehler vermeiden

  • Vergiss virtual nicht: Wenn setImage nicht virtual ist, wird bei einem Cow-Zeiger auf Dragon die Cow-Version aufgerufen – das Bild wird nicht gesetzt.
  • Konstruktorverkettung: IceDragon muss den Dragon-Konstruktor aufrufen, nicht direkt Cow. Sonst fehlt die Initialisierung der Dragon-Ebene.
  • dynamic_cast nur bei Polymorphie: Du brauchst mindestens eine virtuelle Methode (hier setImage), damit der Cast funktioniert. Ohne virtual ist dynamic_cast undefiniert.

7. Ausblick: Vererbung im echten Leben

Vererbung begegnet dir überall: In Spiele-Engines wie Unity (MonoBehaviour → PlayerController), in GUI-Frameworks (QWidget → QPushButton) oder in KI-Modellen (BaseModel → GPT4). Sogar in der Finanzwelt: Ein Basisklasse „Asset“ und abgeleitete „Stock“, „Bond“ etc. Mit diesem Tutorial hast du die Grundlagen verstanden – und kannst jetzt deine eigenen Drachen (oder Kühe) programmieren.

Zusammenfassung

  • Erstelle eine Basisklasse Cow mit virtueller Methode.
  • Leite Dragon ab und füge canBreatheFire() hinzu.
  • Leite IceDragon von Dragon ab und überschreibe die Methode.
  • Nutze dynamic_cast für Typabfragen.
  • Setze C++17 in CMakeLists.txt.

Jetzt bist du bereit, das Lab zu meistern. Viel Erfolg – und lass die Drachen fliegen!