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 abstrataClasses 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 CircleUma 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.
Desafio
FácilVamos 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 abstrataMediaPlayerque 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 umastd::string - Um método regular (não virtual)
showInfo()que imprime:<title> (<duration>s) - Type: <mediaType>— este método deve chamargetMediaType()para obter o tipo - Um destrutor virtual
- Um membro protegido
Players.h: Implemente dois players de mídia concretos que herdam deMediaPlayer: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"
- Um membro privado
main.cpp: Leia quatro entradas (cada uma em uma linha separada):- Título da faixa de áudio
- Duração do áudio (inteiro)
- Título do vídeo
- Duração do vídeo (inteiro)
Crie um
AudioPlayercom o artista"Unknown Artist"e umVideoPlayercom a resolução"1080p". Armazene ambos em um array de ponteirosMediaPlayer*.Percorra o array e, para cada player, primeiro chame
showInfo(), depois chameplay(). 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 1080pObserve 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 CircleSe 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;
}
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
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico