Menu
Coddy logo textTech

Classi astratte

Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 60 di 104.

Una classe astratta è una classe che contiene almeno una funzione virtuale pura. Poiché ha un'interfaccia incompleta, non puoi creare direttamente oggetti di una classe astratta: esiste esclusivamente per essere ereditata.

class Shape {
public:
    virtual double area() = 0;      // Puramente virtuale - rende Shape astratta
    virtual double perimeter() = 0; // Un'altra funzione puramente virtuale
    
    void printInfo() {              // Metodo ordinario - ha un'implementazione
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // Errore: impossibile creare un'istanza di una classe astratta

Le classi astratte possono contenere una combinazione di funzioni virtuali pure (senza implementazione), funzioni virtuali normali (con implementazione predefinita) e funzioni non virtuali. Questo ti permette di definire comportamenti comuni, richiedendo al contempo alle classi derivate di implementare funzionalità specifiche.

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 implementa tutte le funzioni virtuali pure
c.printInfo();      // Usa la funzione ereditata printInfo(), chiama area() di Circle

Una classe derivata deve implementare tutte le funzioni virtuali pure per diventare concreta (istanziabile). Se ne lascia qualcuna non implementata, rimane astratta. Questo meccanismo garantisce che ogni classe concreta nella tua gerarchia fornisca le funzionalità richieste.

challenge icon

Sfida

Facile

Creiamo un sistema di riproduzione multimediale che mostra come le classi astratte definiscono i contratti per diversi tipi di contenuti multimediali. Creerai una classe base astratta che stabilisce cosa deve fare ogni lettore multimediale, quindi implementerai lettori concreti per contenuti audio e video.

Organizzerai il codice in tre file:

  • MediaPlayer.h: definisci una classe astratta MediaPlayer che funge da modello per tutti i tipi di contenuti multimediali. La classe astratta deve avere:
    • Un membro protetto std::string title
    • Un membro protetto int duration (in secondi)
    • Un costruttore che inizializza entrambi i valori
    • Un metodo virtuale puro play(): ogni tipo di contenuto multimediale verrà riprodotto in modo diverso
    • Un metodo virtuale puro getMediaType() che restituisce un std::string
    • Un metodo normale (non virtuale) showInfo() che stampa: <title> (<duration>s) - Type: <mediaType>. Questo metodo deve chiamare getMediaType() per ottenere il tipo
    • Un distruttore virtuale
  • Players.h: implementa due lettori multimediali concreti che ereditano da MediaPlayer:

    AudioPlayer:

    • Un membro privato std::string artist
    • Un costruttore che accetta titolo, durata e artista
    • Implementa play() per stampare: Playing audio: <title> by <artist>
    • Implementa getMediaType() per restituire "Audio"

    VideoPlayer:

    • Un membro privato std::string resolution
    • Un costruttore che accetta titolo, durata e risoluzione
    • Implementa play() per stampare: Playing video: <title> in <resolution>
    • Implementa getMediaType() per restituire "Video"
  • main.cpp: leggi quattro input (ciascuno su una riga separata):
    1. Titolo della traccia audio
    2. Durata dell'audio (intero)
    3. Titolo del video
    4. Durata del video (intero)

    Crea un AudioPlayer con artista "Unknown Artist" e un VideoPlayer con risoluzione "1080p". Memorizzali entrambi in un array di puntatori MediaPlayer*.

    Scorri l'array e, per ogni lettore, chiama prima showInfo(), poi chiama play(). Stampa una riga vuota tra ogni contenuto multimediale. Al termine, libera gli oggetti allocati dinamicamente.

Per esempio, con gli input Summer Vibes, 180, Nature Documentary e 3600:

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

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

Nota come il metodo showInfo() è definito una sola volta nella classe base astratta, ma chiama il metodo virtuale puro getMediaType(). Questo dimostra come le classi astratte possano combinare implementazioni concrete con metodi che le classi derivate devono fornire. Ricordati di usare la parola chiave override per tutti i metodi sovrascritti.

Provalo tu

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

int main() {
    // Leggi i dati in ingresso
    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: Crea un AudioPlayer con l'artista "Unknown Artist"
    
    // TODO: Crea un VideoPlayer con risoluzione "1080p"
    
    // TODO: Memorizza entrambi in un array di puntatori MediaPlayer*
    
    // TODO: Scorri l'array e, per ogni player:
    //       1. Chiama showInfo()
    //       2. Chiama play()
    //       3. Stampa una riga vuota tra un elemento multimediale e l'altro
    
    // TODO: Libera gli oggetti allocati dinamicamente
    
    return 0;
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore C++ online