Menu
Coddy logo textTech

Classes Abstratas

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 60 de 104.

Uma classe abstrata é qualquer classe que contenha pelo menos uma função virtual pura. Como ela possui uma interface incompleta, você não pode criar objetos de uma classe abstrata diretamente - ela existe exclusivamente para ser herdada.

class Shape {
public:
    virtual double area() = 0;      // Virtual pura - torna Shape abstrata
    virtual double perimeter() = 0; // Outra função virtual pura
    
    void printInfo() {              // Método regular - possui implementação
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;
};

Shape s;  // Erro: não é possível instanciar uma classe abstrata

Classes abstratas podem conter uma mistura de funções virtuais puras (sem implementação), funções virtuais regulares (com implementação padrão) e funções não virtuais. Isso permite que você defina um comportamento comum, ao mesmo tempo em que exige que as classes derivadas implementem funcionalidades específicas.

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 todas as funções virtuais puras
c.printInfo();      // Usa o printInfo() herdado, chama o area() de Circle

Uma classe derivada deve implementar todas as funções virtuais puras para se tornar concreta (instanciável). Se ela deixar qualquer uma sem implementação, ela mesma permanecerá abstrata. Este mecanismo garante que cada classe concreta em sua hierarquia forneça a funcionalidade exigida.

challenge icon

Desafio

Fácil

Vamos construir um sistema de player de mídia que demonstra como classes abstratas definem contratos para diferentes tipos de mídia. Você criará uma classe base abstrata que estabelece o que cada player de mídia deve fazer e, em seguida, implementará players concretos para conteúdo de áudio e vídeo.

Você organizará seu código em três arquivos:

  • MediaPlayer.h: Defina uma classe abstrata MediaPlayer que serve como modelo para todos os tipos de mídia. Sua classe abstrata deve ter:
    • Um membro protegido std::string title
    • Um membro protegido int duration (em segundos)
    • Um construtor que inicializa ambos os valores
    • Um método virtual puro play() — cada tipo de mídia será reproduzido de forma diferente
    • Um método virtual puro getMediaType() retornando uma std::string
    • Um método regular (não virtual) showInfo() que imprime: <title> (<duration>s) - Type: <mediaType> — este método deve chamar getMediaType() para obter o tipo
    • Um destrutor virtual
  • Players.h: Implemente dois players de mídia concretos que herdam de MediaPlayer:

    AudioPlayer:

    • Um membro privado std::string artist
    • Um construtor que recebe title, duration e artist
    • Implemente play() para imprimir: Playing audio: <title> by <artist>
    • Implemente getMediaType() para retornar "Audio"

    VideoPlayer:

    • Um membro privado std::string resolution
    • Um construtor que recebe title, duration e resolution
    • Implemente play() para imprimir: Playing video: <title> in <resolution>
    • Implemente getMediaType() para retornar "Video"
  • main.cpp: Leia quatro entradas (cada uma em uma linha separada):
    1. Título da faixa de áudio
    2. Duração do áudio (inteiro)
    3. Título do vídeo
    4. Duração do vídeo (inteiro)

    Crie um AudioPlayer com o artista "Unknown Artist" e um VideoPlayer com a resolução "1080p". Armazene ambos em um array de ponteiros MediaPlayer*.

    Percorra o array e, para cada player, primeiro chame showInfo(), depois chame play(). Imprima uma linha em branco entre cada item de mídia. Limpe seus objetos alocados dinamicamente quando terminar.

Por exemplo, com as entradas 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

Observe como o método showInfo() é definido uma vez na classe base abstrata, mas chama o método virtual puro getMediaType() — isso demonstra como classes abstratas podem misturar implementações concretas com métodos que as classes derivadas devem fornecer. Lembre-se de usar a palavra-chave override em todos os métodos sobrescritos.

Folha de consulta

Uma classe abstrata contém pelo menos uma função virtual pura e não pode ser instanciada diretamente. Ela existe para ser herdada e definir uma interface para classes derivadas.

Definindo uma Classe Abstrata

Use = 0 para declarar uma função virtual pura:

class Shape {
public:
    virtual double area() = 0;      // Função virtual pura
    virtual double perimeter() = 0; // Torna Shape abstrata
    
    void printInfo() {              // Método regular com implementação
        std::cout << "Area: " << area() << std::endl;
    }
    
    virtual ~Shape() = default;     // Destrutor virtual
};

Classes abstratas podem conter:

  • Funções virtuais puras (sem implementação)
  • Funções virtuais regulares (com implementação padrão)
  • Funções não virtuais

Implementando Classes Concretas

Uma classe derivada deve implementar todas as funções virtuais puras para se tornar instanciável:

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: todas as funções virtuais puras implementadas
c.printInfo();      // Método herdado chama o area() de Circle

Se uma classe derivada não implementar todas as funções virtuais puras, ela permanecerá abstrata e não poderá ser instanciada.

Experimente você mesmo

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

int main() {
    // Ler as entradas
    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: Criar um AudioPlayer com o artista "Unknown Artist"
    
    // TODO: Criar um VideoPlayer com a resolução "1080p"
    
    // TODO: Armazenar ambos em um array de ponteiros MediaPlayer*
    
    // TODO: Percorrer o array e para cada player:
    //       1. Chamar showInfo()
    //       2. Chamar play()
    //       3. Imprimir uma linha em branco entre cada item de mídia
    
    // TODO: Limpar os objetos alocados dinamicamente
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos