Menu
Coddy logo textTech

Komposition vs. Vererbung

Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy. Lektion 76 von 104.

Beim Entwerfen von Beziehungen zwischen Klassen hast du zwei Hauptoptionen: Vererbung („ist-ein“) und Komposition („hat-ein“). Die Wahl des richtigen Ansatzes wirkt sich erheblich auf die Flexibilität und Wartbarkeit deines Codes aus.

Vererbung erzeugt eine enge Kopplung zwischen Klassen. Ein Car, das von Vehicle erbt, ist dauerhaft an diese Beziehung gebunden:

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

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

Komposition bettet Objekte als Mitglieder ein und schafft dadurch eine flexiblere Beziehung. Ein Car hat einen Engine, anstatt ein Motor zu sein:

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

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

Der entscheidende Vorteil der Komposition ist ihre Flexibilität. Du kannst Komponenten problemlos austauschen, das Verhalten zur Laufzeit ändern oder mehrere Fähigkeiten kombinieren, ohne durch eine starre Klassenhierarchie eingeschränkt zu sein. Beim modernen C++-Design wird in den meisten Fällen die Komposition der Vererbung vorgezogen.

Verwende Vererbung, wenn eine echte „is-a“-Beziehung besteht und du Polymorphismus benötigst. Verwende Komposition, wenn du Funktionalität wiederverwenden möchtest oder wenn sich die Beziehung besser als „has-a“ oder „uses-a“ beschreiben lässt.

challenge icon

Aufgabe

Einfach

Erstellen wir einen Computersystem-Simulator, der demonstriert, wann Komposition anstelle von Vererbung verwendet werden sollte. Du modellierst einen Computer, der Komponenten hat (Komposition), anstatt selbst eine Komponente zu sein, und zeigst damit, wie Komposition die Flexibilität bietet, Teile zur Laufzeit auszutauschen.

Du verteilst deinen Code auf drei Dateien:

  • Components.h: Definiere die einzelnen Komponenten, die ein Computer enthalten kann.

    Erstelle eine CPU-Klasse mit einem privaten std::string model und int cores. Stelle einen Konstruktor bereit, der beide Werte entgegennimmt, eine process()-Methode, die CPU [model] processing with [cores] cores ausgibt, sowie eine getModel()-Methode.

    Erstelle eine Memory-Klasse mit einem privaten int sizeGB. Stelle einen Konstruktor bereit, eine load()-Methode, die Loading data into [sizeGB]GB RAM ausgibt, sowie eine getSize()-Methode.

    Erstelle eine Storage-Klasse mit einem privaten std::string type (zum Beispiel „SSD“ oder „HDD“) und int capacityGB. Stelle einen Konstruktor, eine read()-Methode, die Reading from [capacityGB]GB [type] ausgibt, sowie Getter-Methoden für beide Felder bereit.

  • Computer.h: Definiere eine Computer-Klasse, die Komposition verwendet, um Komponenten zu kombinieren.

    Dein Computer sollte private Memberobjekte haben: eine CPU, einen Memory und einen Storage. Verwende die Initialisierungsliste des Konstruktors, um diese Komponenten anhand von Parametern zu initialisieren.

    Implementiere diese Methoden:

    • boot(): gibt Booting computer... aus und ruft anschließend load() für den Speicher, read() für den Speicher und process() für die CPU auf, jeweils in einer eigenen Zeile
    • specs(): gibt die Spezifikationen des Computers in diesem Format aus:
      Computer Specs:
      - CPU: [model] ([cores] cores)
      - RAM: [size]GB
      - Storage: [capacity]GB [type]
  • main.cpp: Lies sechs Eingaben ein (jeweils in einer eigenen Zeile):
    1. CPU-Modellname (String)
    2. Anzahl der CPU-Kerne (Ganzzahl)
    3. Speichergröße in GB (Ganzzahl)
    4. Speichertyp (String, z. B. „SSD“)
    5. Speicherkapazität in GB (Ganzzahl)
    6. Ein Befehl: entweder „boot“ oder „specs“

    Erstelle die Komponentenobjekte und anschließend mithilfe von Komposition ein Computer-Objekt. Rufe abhängig vom Befehl entweder boot() oder specs() auf.

Beispielsweise mit den Eingaben Intel i7, 8, 16, SSD, 512 und boot:

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

Mit den Eingaben AMD Ryzen, 6, 32, HDD, 1000 und specs:

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

Beachte, dass die Computer-Klasse von keiner Komponente erbt. Sie enthält sie. Diese „hat-eine“-Beziehung bedeutet, dass du problemlos Computer mit unterschiedlichen Komponentenkombinationen erstellen oder Komponenten später sogar austauschen könntest, wenn du Setter-Methoden hinzufügen würdest. Diese Flexibilität ist der entscheidende Vorteil von Komposition gegenüber Vererbung.

Probier es selbst

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

using namespace std;

int main() {
    // Eingaben lesen
    string cpuModel;
    getline(cin, cpuModel);  // CPU-Modellname (kann Leerzeichen enthalten)
    
    int cpuCores;
    cin >> cpuCores;  // Anzahl der CPU-Kerne
    
    int memorySize;
    cin >> memorySize;  // Speichergröße in GB
    
    string storageType;
    cin >> storageType;  // Speichertyp (z. B. "SSD")
    
    int storageCapacity;
    cin >> storageCapacity;  // Speicherkapazität in GB
    
    string command;
    cin >> command;  // Befehl: "boot" oder "specs"

    // TODO: Komponentenobjekte erstellen (CPU, Memory, Storage)
    
    // TODO: Ein Computer-Objekt mittels Komposition erstellen
    
    // TODO: Basierend auf dem Befehl entweder boot() oder specs() aufrufen

    return 0;
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-C++-Compiler