Menu
Coddy logo textTech

Klasy abstrakcyjne

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 60 z 104.

Klasa abstrakcyjna to każda klasa zawierająca co najmniej jedną czysto wirtualną funkcję. Ponieważ ma niekompletny interfejs, nie możesz bezpośrednio tworzyć obiektów klasy abstrakcyjnej — istnieje ona wyłącznie po to, by po niej dziedziczyć.

class Shape {
public:
    virtual double area() = 0;      // Czysto wirtualna — sprawia, że Shape jest klasą abstrakcyjną
    virtual double perimeter() = 0; // Kolejna funkcja czysto wirtualna
    
    void printInfo() {              // Zwykła metoda — ma implementację
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // Błąd: nie można utworzyć instancji klasy abstrakcyjnej

Klasy abstrakcyjne mogą zawierać funkcje czysto wirtualne (bez implementacji), zwykłe funkcje wirtualne (z domyślną implementacją) oraz funkcje niewirtualne. Dzięki temu możesz definiować wspólne zachowanie, jednocześnie wymagając od klas pochodnych implementacji określonych funkcjonalności.

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 implementuje wszystkie czysto wirtualne funkcje
c.printInfo();      // Używa odziedziczonej funkcji printInfo(), wywołuje funkcję area() klasy Circle

Klasa pochodna musi implementować wszystkie czysto wirtualne funkcje, aby stać się klasą konkretną (możliwą do utworzenia instancji). Jeśli pozostawi którąkolwiek z nich niezaimplementowaną, sama pozostanie abstrakcyjna. Ten mechanizm gwarantuje, że każda klasa konkretna w hierarchii zapewnia wymaganą funkcjonalność.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system odtwarzacza multimediów, który pokazuje, jak klasy abstrakcyjne definiują kontrakty dla różnych typów mediów. Utworzysz abstrakcyjną klasę bazową, która określa, co musi robić każdy odtwarzacz multimediów, a następnie zaimplementujesz konkretne odtwarzacze treści audio i wideo.

Rozmieścisz swój kod w trzech plikach:

  • MediaPlayer.h: Zdefiniuj abstrakcyjną klasę MediaPlayer, która będzie wzorcem dla wszystkich typów mediów. Twoja klasa abstrakcyjna powinna mieć:
    • Chronione pole std::string title
    • Chronione pole int duration (w sekundach)
    • Konstruktor inicjalizujący obie wartości
    • Czysto wirtualną metodę play(): każdy typ mediów będzie odtwarzany inaczej
    • Czysto wirtualną metodę getMediaType(), która zwraca std::string
    • Zwykłą (niewirtualną) metodę showInfo(), która wyświetla: <title> (<duration>s) - Type: <mediaType>. Ta metoda powinna wywoływać getMediaType(), aby uzyskać typ
    • Wirtualny destruktor
  • Players.h: Zaimplementuj dwa konkretne odtwarzacze multimediów dziedziczące po MediaPlayer:

    AudioPlayer:

    • Prywatne pole std::string artist
    • Konstruktor przyjmujący tytuł, czas trwania i wykonawcę
    • Zaimplementuj play(), aby wyświetlała: Playing audio: <title> by <artist>
    • Zaimplementuj getMediaType(), aby zwracała "Audio"

    VideoPlayer:

    • Prywatne pole std::string resolution
    • Konstruktor przyjmujący tytuł, czas trwania i rozdzielczość
    • Zaimplementuj play(), aby wyświetlała: Playing video: <title> in <resolution>
    • Zaimplementuj getMediaType(), aby zwracała "Video"
  • main.cpp: Odczytaj cztery dane wejściowe (każdą w osobnym wierszu):
    1. Tytuł utworu audio
    2. Czas trwania audio (liczba całkowita)
    3. Tytuł wideo
    4. Czas trwania wideo (liczba całkowita)

    Utwórz obiekt AudioPlayer z wykonawcą "Unknown Artist" oraz obiekt VideoPlayer z rozdzielczością "1080p". Zapisz oba w tablicy wskaźników MediaPlayer*.

    Przejdź pętlą przez tablicę i dla każdego odtwarzacza najpierw wywołaj showInfo(), a następnie play(). Wyświetl pusty wiersz między poszczególnymi elementami multimedialnymi. Po zakończeniu zwolnij dynamicznie zaalokowane obiekty.

Na przykład dla danych wejściowych Summer Vibes, 180, Nature Documentary i 3600:

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

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

Zauważ, że metoda showInfo() jest zdefiniowana raz w abstrakcyjnej klasie bazowej, ale wywołuje czysto wirtualną metodę getMediaType(). Pokazuje to, że klasy abstrakcyjne mogą łączyć konkretne implementacje z metodami, które muszą dostarczyć klasy pochodne. Pamiętaj, aby użyć słowa kluczowego override we wszystkich nadpisywanych metodach.

Spróbuj swoich sił

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

int main() {
    // Wczytaj dane wejściowe
    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: Utwórz AudioPlayer z wykonawcą "Unknown Artist"
    
    // TODO: Utwórz VideoPlayer o rozdzielczości "1080p"
    
    // TODO: Umieść oba obiekty w tablicy wskaźników MediaPlayer*
    
    // TODO: Przejdź przez tablicę i dla każdego odtwarzacza:
    //       1. Wywołaj showInfo()
    //       2. Wywołaj play()
    //       3. Wypisz pustą linię między elementami multimedialnymi
    
    // TODO: Zwolnij dynamicznie zaalokowane obiekty
    
    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online