Classes abstraites
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 60 sur 104.
Une classe abstraite est toute classe qui contient au moins une fonction virtuelle pure. Comme son interface est incomplète, vous ne pouvez pas créer directement des objets d’une classe abstraite : elle existe uniquement pour être héritée.
class Shape {
public:
virtual double area() = 0; // Virtuelle pure - rend Shape abstrait
virtual double perimeter() = 0; // Une autre fonction virtuelle pure
void printInfo() { // Méthode ordinaire - a une implémentation
std::cout << "Area: " << area() << std::endl;
}
virtual ~Shape() = default;
};
Shape s; // Erreur : impossible d'instancier une classe abstraiteLes classes abstraites peuvent contenir un mélange de fonctions virtuelles pures (sans implémentation), de fonctions virtuelles ordinaires (avec une implémentation par défaut) et de fonctions non virtuelles. Cela vous permet de définir un comportement commun tout en exigeant des classes dérivées qu’elles implémentent des fonctionnalités spécifiques.
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 implémente toutes les fonctions virtuelles pures
c.printInfo(); // Utilise printInfo() héritée, appelle area() de CircleUne classe dérivée doit implémenter toutes les fonctions virtuelles pures pour devenir concrète (instanciable). Si elle en laisse certaines non implémentées, elle reste elle-même abstraite. Ce mécanisme garantit que chaque classe concrète de votre hiérarchie fournit les fonctionnalités requises.
Défi
FacileConstruisons un système de lecteur multimédia qui montre comment les classes abstraites définissent des contrats pour différents types de médias. Vous allez créer une classe de base abstraite qui établit ce que chaque lecteur multimédia doit faire, puis implémenter des lecteurs concrets pour le contenu audio et vidéo.
Vous allez organiser votre code sur trois fichiers :
MediaPlayer.h: définir une classe abstraiteMediaPlayerqui sert de modèle pour tous les types de médias. Votre classe abstraite doit comporter :- Un membre protégé
std::string title - Un membre protégé
int duration(en secondes) - Un constructeur qui initialise les deux valeurs
- Une méthode virtuelle pure
play(): chaque type de média sera lu différemment - Une méthode virtuelle pure
getMediaType()qui renvoie unstd::string - Une méthode ordinaire (non virtuelle)
showInfo()qui affiche :<title> (<duration>s) - Type: <mediaType>. Cette méthode doit appelergetMediaType()pour obtenir le type - Un destructeur virtuel
- Un membre protégé
Players.h: implémenter deux lecteurs multimédias concrets qui héritent deMediaPlayer:AudioPlayer:- Un membre privé
std::string artist - Un constructeur prenant le titre, la durée et l’artiste
- Implémenter
play()pour afficher :Playing audio: <title> by <artist> - Implémenter
getMediaType()pour renvoyer"Audio"
VideoPlayer:- Un membre privé
std::string resolution - Un constructeur prenant le titre, la durée et la résolution
- Implémenter
play()pour afficher :Playing video: <title> in <resolution> - Implémenter
getMediaType()pour renvoyer"Video"
- Un membre privé
main.cpp: lire quatre entrées (chacune sur une ligne distincte) :- Titre de la piste audio
- Durée audio (entier)
- Titre de la vidéo
- Durée de la vidéo (entier)
Créer un
AudioPlayeravec l’artiste"Unknown Artist"et unVideoPlayeravec la résolution"1080p". Stocker les deux dans un tableau de pointeursMediaPlayer*.Parcourir le tableau et, pour chaque lecteur, appeler d’abord
showInfo(), puis appelerplay(). Afficher une ligne vide entre chaque élément multimédia. Libérer les objets alloués dynamiquement une fois terminé.
Par exemple, avec les entrées Summer Vibes, 180, Nature Documentary et 3600 :
Summer Vibes (180s) - Type: Audio
Playing audio: Summer Vibes by Unknown Artist
Nature Documentary (3600s) - Type: Video
Playing video: Nature Documentary in 1080pRemarquez comment la méthode showInfo() est définie une seule fois dans la classe de base abstraite, mais appelle la méthode virtuelle pure getMediaType(). Cela montre comment les classes abstraites peuvent combiner des implémentations concrètes avec des méthodes que les classes dérivées doivent fournir. N’oubliez pas d’utiliser le mot-clé override pour toutes les méthodes redéfinies.
Essayez vous-même
#include <iostream>
#include <string>
#include "MediaPlayer.h"
#include "Players.h"
int main() {
// Lire les entrées
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: Créer un AudioPlayer avec l'artiste "Unknown Artist"
// TODO: Créer un VideoPlayer avec la résolution "1080p"
// TODO: Stocker les deux dans un tableau de pointeurs MediaPlayer*
// TODO: Parcourir le tableau et pour chaque player :
// 1. Appeler showInfo()
// 2. Appeler play()
// 3. Afficher une ligne vide entre chaque élément multimédia
// TODO: Nettoyer les objets alloués dynamiquement
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesGénération et compilation en C++Fichiers d’en-tête et fichiers sourceEspaces de noms et portéeIntroduction à la POO en C++Classes et objetsLe pointeur « this »Méthodes (fonctions membres)Attributs (membres de données)Bases des constructeurs et destructeursRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d’instance et statiquesAccesseurs et mutateursFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d’accès de l’héritageOrdre d’appel des constructeurs et destructeursRedéfinition des méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif : hiérarchie des employés10Vue d’ensemble de la STL
Vue d’ensemble et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - fréquence des mots13Modèles de conception, partie 1
Introduction aux modèles de conceptionModèle SingletonFabrique et fabrique abstraiteModèle BuilderModèle ObserverModèle Strategy2Gestion de la mémoire
Mémoire de pile ou de tasPointeurs et référencesMémoire dynamique (new/delete)Pointeurs intelligents en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d’accès en C++Spécificateurs d’accès en profondeurMasquage de l’informationStruct vs classeClasses imbriquées et internesRécapitulatif - Système de gestion des dossiers étudiants8Polymorphisme
Polymorphisme à la compilation vs à l’exécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d’interfaces en C++Conversion dynamique et RTTIRécapitulatif - Calculateur de formes3Constructeurs et destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d’initialisation des constructeursConstructeurs déléguésApprofondissement des destructeursRègle des trois / cinq / zéroRécapitulatif - Classe String6Surcharge des opérateurs
Introduction à la surcharge des opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l’opérateur d’affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif – Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation des templatesTemplates variadiquesBases de SFINAE et des traits de typesRécapitulatif - Conteneur génériqueEntraînez-vous par vous-même : Compilateur C++ en ligne