Menu
Coddy logo textTech

Abstrakte Klassen

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 60 von 104.

Eine abstrakte Klasse ist jede Klasse, die mindestens eine rein virtuelle Funktion enthält. Da sie über eine unvollständige Schnittstelle verfügt, kannst du keine Objekte einer abstrakten Klasse direkt erstellen – sie existiert ausschließlich dazu, von ihr zu erben.

class Shape {
public:
    virtual double area() = 0;      // Rein virtuell - macht Shape abstrakt
    virtual double perimeter() = 0; // Eine weitere rein virtuelle Funktion
    
    void printInfo() {              // Reguläre Methode - hat Implementierung
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // Fehler: abstrakte Klasse kann nicht instanziiert werden

Abstrakte Klassen können eine Mischung aus rein virtuellen Funktionen (ohne Implementierung), regulären virtuellen Funktionen (mit Standardimplementierung) und nicht virtuellen Funktionen enthalten. Dadurch kannst du gemeinsames Verhalten definieren und gleichzeitig von abgeleiteten Klassen verlangen, bestimmte Funktionalität zu implementieren.

class Circle : public Shape {
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double area() override { return 3.14159 * radius * radius; }
    double perimeter() override { return 2 * 3.14159 * radius; }
};

Circle c(5.0);      // OK: Circle implementiert alle rein virtuellen Funktionen
c.printInfo();      // Verwendet die geerbte printInfo(), ruft Circle's area() auf

Eine abgeleitete Klasse muss alle rein virtuellen Funktionen implementieren, um konkret (instanziierbar) zu werden. Wenn sie eine davon nicht implementiert, bleibt sie selbst abstrakt. Dieser Mechanismus stellt sicher, dass jede konkrete Klasse in deiner Hierarchie die erforderliche Funktionalität bereitstellt.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Mediaplayer-System, das zeigt, wie abstrakte Klassen Verträge für verschiedene Medientypen definieren. Du erstellst eine abstrakte Basisklasse, die festlegt, was jeder Mediaplayer tun muss, und implementierst anschließend konkrete Player für Audio- und Videoinhalte.

Du wirst deinen Code auf drei Dateien verteilen:

  • MediaPlayer.h: Definiere eine abstrakte Klasse MediaPlayer, die als Vorlage für alle Medientypen dient. Deine abstrakte Klasse sollte Folgendes enthalten:
    • Ein geschütztes std::string title-Member
    • Ein geschütztes int duration-Member (in Sekunden)
    • Einen Konstruktor, der beide Werte initialisiert
    • Eine rein virtuelle play()-Methode: Jeder Medientyp wird anders abgespielt
    • Eine rein virtuelle getMediaType()-Methode, die einen std::string zurückgibt
    • Eine reguläre (nicht virtuelle) showInfo()-Methode, die Folgendes ausgibt: <title> (<duration>s) - Type: <mediaType>. Diese Methode sollte getMediaType() aufrufen, um den Typ abzurufen
    • Einen virtuellen Destruktor
  • Players.h: Implementiere zwei konkrete Mediaplayer, die von MediaPlayer erben:

    AudioPlayer:

    • Ein privates std::string artist-Member
    • Einen Konstruktor, der title, duration und artist entgegennimmt
    • Implementiere play(), sodass Folgendes ausgegeben wird: Playing audio: <title> by <artist>
    • Implementiere getMediaType(), sodass "Audio" zurückgegeben wird

    VideoPlayer:

    • Ein privates std::string resolution-Member
    • Einen Konstruktor, der title, duration und resolution entgegennimmt
    • Implementiere play(), sodass Folgendes ausgegeben wird: Playing video: <title> in <resolution>
    • Implementiere getMediaType(), sodass "Video" zurückgegeben wird
  • main.cpp: Lies vier Eingaben ein (jeweils in einer eigenen Zeile):
    1. Titel des Audiotitels
    2. Audiodauer (Ganzzahl)
    3. Videotitel
    4. Videodauer (Ganzzahl)

    Erstelle einen AudioPlayer mit dem Künstler "Unknown Artist" und einen VideoPlayer mit der Auflösung "1080p". Speichere beide in einem Array aus MediaPlayer*-Zeigern.

    Durchlaufe das Array und rufe für jeden Player zuerst showInfo() und anschließend play() auf. Gib zwischen den einzelnen Medienelementen eine Leerzeile aus. Räume die dynamisch angelegten Objekte anschließend auf.

Zum Beispiel mit den Eingaben Summer Vibes, 180, Nature Documentary und 3600:

Summer Vibes (180s) - Type: Audio
Playing audio: Summer Vibes by Unknown Artist

Nature Documentary (3600s) - Type: Video
Playing video: Nature Documentary in 1080p

Beachte, dass die Methode showInfo() einmal in der abstrakten Basisklasse definiert wird, aber die rein virtuelle Methode getMediaType() aufruft. Dies zeigt, wie abstrakte Klassen konkrete Implementierungen mit Methoden kombinieren können, die von abgeleiteten Klassen bereitgestellt werden müssen. Denke daran, bei allen überschriebenen Methoden das Schlüsselwort override zu verwenden.

Probier es selbst

#include <iostream>
#include <string>
#include "MediaPlayer.h"
#include "Players.h"

int main() {
    // Eingaben lesen
    std::string audioTitle;
    int audioDuration;
    std::string videoTitle;
    int videoDuration;
    
    std::getline(std::cin, audioTitle);
    std::cin >> audioDuration;
    std::cin.ignore();
    std::getline(std::cin, videoTitle);
    std::cin >> videoDuration;
    
    // TODO: Erstelle einen AudioPlayer mit Künstler "Unknown Artist"
    
    // TODO: Erstelle einen VideoPlayer mit Auflösung "1080p"
    
    // TODO: Speichere beide in einem Array von MediaPlayer*-Zeigern
    
    // TODO: Durchlaufe das Array und für jeden Player:
    //       1. Rufe showInfo() auf
    //       2. Rufe play() auf
    //       3. Gib eine leere Zeile zwischen jedem Medienelement aus
    
    // TODO: Räume dynamisch allozierte Objekte auf
    
    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler