Menu
Coddy logo textTech

Composition ou héritage

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy. Leçon 76 sur 104.

Lors de la conception des relations entre les classes, vous avez deux options principales : l’héritage (« is-a ») et la composition (« has-a »). Choisir la bonne approche a un impact considérable sur la flexibilité et la maintenabilité de votre code.

L’héritage crée un couplage étroit entre les classes. Une Car qui hérite de Vehicle est définitivement liée à cette relation :

class Vehicle {
public:
    virtual void start() { std::cout << "Starting vehicle\n"; }
};

class Car : public Vehicle {
public:
    void start() override { std::cout << "Starting car\n"; }
};

La composition intègre des objets en tant que membres, créant ainsi une relation plus flexible. Une Car possède un Engine plutôt que d’être un moteur :

class Engine {
public:
    void start() { std::cout << "Engine running\n"; }
};

class Car {
private:
    Engine engine;  // Car A un Engine
public:
    void start() { engine.start(); }
};

Le principal avantage de la composition est la flexibilité. Vous pouvez facilement remplacer des composants, modifier le comportement lors de l’exécution ou combiner plusieurs fonctionnalités sans les contraintes d’une hiérarchie de classes rigide. La conception moderne en C++ privilégie la composition à l’héritage dans la plupart des cas.

Utilise l’héritage lorsqu’il existe une véritable relation « is-a » et que tu as besoin de polymorphisme. Utilise la composition lorsque tu veux réutiliser des fonctionnalités ou lorsque la relation est mieux décrite comme « has-a » ou « uses-a ».

challenge icon

Défi

Facile

Construisons un simulateur de système informatique qui montre quand utiliser la composition plutôt que l’héritage. Vous modéliserez un ordinateur qui a des composants (composition) plutôt que d’être un composant, afin de montrer comment la composition offre la flexibilité de remplacer les éléments au moment de l’exécution.

Vous organiserez votre code sur trois fichiers :

  • Components.h : définissez les composants individuels qu’un ordinateur peut contenir.

    Créez une classe CPU avec un std::string model privé et un int cores privé. Fournissez un constructeur qui accepte ces deux valeurs, une méthode process() qui affiche CPU [model] processing with [cores] cores, ainsi qu’une méthode getModel().

    Créez une classe Memory avec un int sizeGB privé. Fournissez un constructeur, une méthode load() qui affiche Loading data into [sizeGB]GB RAM, ainsi qu’une méthode getSize().

    Créez une classe Storage avec un std::string type privé (comme "SSD" ou "HDD") et un int capacityGB. Fournissez un constructeur, une méthode read() qui affiche Reading from [capacityGB]GB [type], ainsi que des méthodes d’accès pour les deux champs.

  • Computer.h : définissez une classe Computer qui utilise la composition pour combiner les composants.

    Votre Computer doit posséder comme membres privés des objets : un CPU, une Memory et un Storage. Utilisez la liste d’initialisation du constructeur pour initialiser ces composants à partir des paramètres.

    Implémentez ces méthodes :

    • boot() : affiche Booting computer..., puis appelle load() sur la mémoire, read() sur le stockage et process() sur le CPU, chacun sur une ligne distincte
    • specs() : affiche les spécifications de l’ordinateur au format suivant :
      Computer Specs:
      - CPU: [model] ([cores] cores)
      - RAM: [size]GB
      - Storage: [capacity]GB [type]
  • main.cpp : lisez six entrées (chacune sur une ligne distincte) :
    1. Nom du modèle du CPU (chaîne de caractères)
    2. Nombre de cœurs du CPU (entier)
    3. Taille de la mémoire en Go (entier)
    4. Type de stockage (chaîne de caractères, par exemple "SSD")
    5. Capacité du stockage en Go (entier)
    6. Une commande : soit "boot", soit "specs"

    Créez les objets composants, puis créez un Computer en utilisant la composition. Selon la commande, appelez soit boot(), soit specs().

Par exemple, avec les entrées Intel i7, 8, 16, SSD, 512 et boot :

Booting computer...
Loading data into 16GB RAM
Reading from 512GB SSD
CPU Intel i7 processing with 8 cores

Avec les entrées AMD Ryzen, 6, 32, HDD, 1000 et specs :

Computer Specs:
- CPU: AMD Ryzen (6 cores)
- RAM: 32GB
- Storage: 1000GB HDD

Remarquez que la classe Computer n’hérite d’aucun composant. Elle les contient. Cette relation « a-un » signifie que vous pourriez facilement créer des ordinateurs avec différentes combinaisons de composants, ou même remplacer les composants ultérieurement si vous ajoutiez des méthodes d’affectation. Cette flexibilité constitue le principal avantage de la composition par rapport à l’héritage.

Essayez vous-même

#include <iostream>
#include <string>
#include "Computer.h"

using namespace std;

int main() {
    // Lire les entrées
    string cpuModel;
    getline(cin, cpuModel);  // Nom du modèle de CPU (peut contenir des espaces)
    
    int cpuCores;
    cin >> cpuCores;  // Nombre de cœurs CPU
    
    int memorySize;
    cin >> memorySize;  // Taille de la mémoire en Go
    
    string storageType;
    cin >> storageType;  // Type de stockage (p. ex., "SSD")
    
    int storageCapacity;
    cin >> storageCapacity;  // Capacité de stockage en Go
    
    string command;
    cin >> command;  // Commande : "boot" ou "specs"

    // TODO: Créer les objets composants (CPU, Memory, Storage)
    
    // TODO: Créer un objet Computer en utilisant la composition
    
    // TODO: Selon la commande, appeler soit boot() soit specs()

    return 0;
}
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur C++ en ligne