Menu
Coddy logo textTech

Абстрактные классы

Часть раздела Объектно-ориентированное программирование путешествия по C++ на Coddy. Урок 60 из 104.

abstract class — это любой class, который содержит как минимум одну чистую виртуальную function. Поскольку у него неполный интерфейс, вы cannot создавать объекты abstract class напрямую — он существует исключительно для того, чтобы от него можно было унаследоваться (inherited).

class Shape {
public:
    virtual double area() = 0;      // Чисто виртуальная — делает Shape абстрактным
    virtual double perimeter() = 0; // Ещё одна чисто виртуальная функция
    
    void printInfo() {              // Обычный метод — имеет реализацию
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // Ошибка: нельзя создать экземпляр абстрактного класса

Классы abstract могут содержать сочетание чистых виртуальных functions (без implementation), обычных виртуальных functions (с implementation по умолчанию) и невиртуальных functions. Это позволяет define общее поведение, одновременно требуя от классов Derived реализовать определённую функциональность.

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 реализует все чисто виртуальные функции
c.printInfo();      // Использует унаследованный printInfo(), вызывает area() у Circle

Производный класс должен реализовать all чистые виртуальные функции, чтобы стать конкретным (доступным для создания экземпляров). Если он оставляет какие-либо функции нереализованными, он сам остаётся abstract. Этот механизм гарантирует, что каждый конкретный класс в вашей иерархии предоставляет требуемую функциональность.

challenge icon

Задание

Легко

Давайте создадим систему медиаплеера, демонстрирующую, как abstract классы определяют контракты для разных типов медиаданных. Вы создадите abstract базовый класс, устанавливающий, что должен делать каждый медиаплеер, а затем Implement конкретные плееры для аудио- и видеоконтента.

Вы организуете код в трёх файлах:

  • MediaPlayer.h: Declare abstract MediaPlayer class, который служит шаблоном для всех типов медиаданных. Ваш abstract class должен содержать:
    • защищённый член std::string title
    • защищённый член int duration (в секундах)
    • constructor, инициализирующий оба значения
    • чистый виртуальный метод play(): каждый тип медиаданных будет воспроизводиться по-своему
    • чистый виртуальный метод getMediaType(), возвращающий std::string
    • обычный (не виртуальный) метод showInfo(), который выводит: <title> (<duration>s) - Type: <mediaType>. Этот метод должен вызывать getMediaType(), чтобы получить тип
    • виртуальный destructor
  • Players.h: Implement два конкретных медиаплеера, которые наследуются от MediaPlayer:

    AudioPlayer:

    • закрытый член std::string artist
    • constructor, принимающий title, duration и artist
    • Implement play() для вывода: Playing audio: <title> by <artist>
    • Implement getMediaType() для возврата "Audio"

    VideoPlayer:

    • закрытый член std::string resolution
    • constructor, принимающий title, duration и resolution
    • Implement play() для вывода: Playing video: <title> in <resolution>
    • Implement getMediaType() для возврата "Video"
  • main.cpp: Считайте четыре входных значения (каждое в отдельной строке):
    1. название аудиотрека
    2. длительность аудиозаписи (целое число)
    3. название видео
    4. длительность видео (целое число)

    Create AudioPlayer с artist "Unknown Artist" и VideoPlayer с resolution "1080p". Сохраните оба объекта в array указателей MediaPlayer*.

    Пройдите в цикле по array и для каждого плеера сначала вызовите showInfo(), а затем play(). Выводите пустую строку между каждым медиаматериалом. После завершения освободите dynamically выделенные объекты.

Например, для входных данных Summer Vibes, 180, Nature Documentary и 3600:

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

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

Обратите внимание, как метод showInfo() определён один раз в abstract базовом class, но вызывает чистый виртуальный getMediaType(). Это демонстрирует, как abstract классы могут сочетать конкретные реализации с методами, которые производные классы должны предоставлять. Не забудьте использовать ключевое слово override для всех переопределённых методов.

Попробуйте сами

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

int main() {
    // Считать входные данные
    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: Создать AudioPlayer с артистом "Unknown Artist"
    
    // TODO: Создать VideoPlayer с разрешением "1080p"
    
    // TODO: Сохранить оба в массиве указателей MediaPlayer*
    
    // TODO: Пройти по массиву и для каждого плеера:
    //       1. Вызвать showInfo()
    //       2. Вызвать play()
    //       3. Вывести пустую строку между каждым медиаэлементом
    
    // TODO: Очистить динамически выделенные объекты
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C++