Menu
Coddy logo textTech

Kompozycja a dziedziczenie

Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 76 z 104.

Projektując relacje między klasami, masz dwie główne możliwości: dziedziczenie („jest”) i kompozycję („ma”). Wybór odpowiedniego podejścia znacząco wpływa na elastyczność i łatwość utrzymania kodu.

Dziedziczenie tworzy silne powiązanie między klasami. Obiekt Car, który dziedziczy po Vehicle, jest trwale związany z tą relacją:

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

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

Kompozycja osadza obiekty jako składowe, tworząc bardziej elastyczną relację. Car ma Engine, zamiast być silnikiem:

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

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

Główną zaletą kompozycji jest elastyczność. Możesz łatwo wymieniać komponenty, zmieniać zachowanie w czasie działania programu lub łączyć wiele możliwości bez ograniczeń sztywnej hierarchii klas. W większości przypadków nowoczesne projektowanie w C++ opiera się na kompozycji zamiast dziedziczenia.

Używaj dziedziczenia, gdy występuje rzeczywista relacja „jest czymś” i potrzebujesz polimorfizmu. Używaj kompozycji, gdy chcesz ponownie wykorzystać funkcjonalność lub gdy relację lepiej opisują określenia „ma” lub „używa”.

challenge icon

Wyzwanie

Łatwy

Zbudujmy symulator systemu komputerowego, który pokazuje, kiedy używać kompozycji zamiast dziedziczenia. Zamodelujesz komputer, który ma komponenty (kompozycja), zamiast być komponentem, pokazując, jak kompozycja zapewnia elastyczność wymiany części w czasie działania programu.

Rozmieścisz swój kod w trzech plikach:

  • Components.h: Zdefiniuj poszczególne komponenty, z których może składać się komputer.

    Utwórz klasę CPU z prywatnymi polami std::string model i int cores. Zdefiniuj konstruktor przyjmujący obie wartości, metodę process(), która wyświetla CPU [model] processing with [cores] cores, oraz metodę getModel().

    Utwórz klasę Memory z prywatnym polem int sizeGB. Zdefiniuj konstruktor, metodę load(), która wyświetla Loading data into [sizeGB]GB RAM, oraz metodę getSize().

    Utwórz klasę Storage z prywatnymi polami std::string type (takimi jak "SSD" lub "HDD") oraz int capacityGB. Zdefiniuj konstruktor, metodę read(), która wyświetla Reading from [capacityGB]GB [type], oraz metody pobierające wartości obu pól.

  • Computer.h: Zdefiniuj klasę Computer, która łączy komponenty za pomocą kompozycji.

    Klasa Computer powinna mieć prywatne obiekty składowe: CPU, Memory i Storage. Użyj listy inicjalizacyjnej konstruktora, aby zainicjalizować te komponenty na podstawie parametrów.

    Zaimplementuj następujące metody:

    • boot(): wyświetla Booting computer..., a następnie wywołuje load() dla pamięci, read() dla pamięci masowej oraz process() dla procesora, każdą z tych metod w osobnym wierszu
    • specs(): wyświetla specyfikację komputera w następującym formacie:
      Computer Specs:
      - CPU: [model] ([cores] cores)
      - RAM: [size]GB
      - Storage: [capacity]GB [type]
  • main.cpp: Wczytaj sześć danych wejściowych (każdą w osobnym wierszu):
    1. Nazwa modelu procesora (ciąg znaków)
    2. Liczba rdzeni procesora (liczba całkowita)
    3. Rozmiar pamięci w GB (liczba całkowita)
    4. Typ pamięci masowej (ciąg znaków, np. "SSD")
    5. Pojemność pamięci masowej w GB (liczba całkowita)
    6. Polecenie: "boot" albo "specs"

    Utwórz obiekty komponentów, a następnie utwórz obiekt Computer za pomocą kompozycji. W zależności od polecenia wywołaj boot() albo specs().

Na przykład, dla danych wejściowych Intel i7, 8, 16, SSD, 512 i boot:

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

Dla danych wejściowych AMD Ryzen, 6, 32, HDD, 1000 i specs:

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

Zwróć uwagę, że klasa Computer nie dziedziczy po żadnym komponencie. Ona je zawiera. Ta relacja „ma” oznacza, że możesz łatwo tworzyć komputery z różnymi zestawami komponentów, a nawet wymieniać komponenty później, jeśli dodasz metody ustawiające. Ta elastyczność jest kluczową zaletą kompozycji w porównaniu z dziedziczeniem.

Spróbuj swoich sił

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

using namespace std;

int main() {
    // Wczytaj dane wejściowe
    string cpuModel;
    getline(cin, cpuModel);  // Nazwa modelu CPU (może zawierać spacje)
    
    int cpuCores;
    cin >> cpuCores;  // Liczba rdzeni CPU
    
    int memorySize;
    cin >> memorySize;  // Rozmiar pamięci w GB
    
    string storageType;
    cin >> storageType;  // Typ nośnika danych (np. "SSD")
    
    int storageCapacity;
    cin >> storageCapacity;  // Pojemność nośnika danych w GB
    
    string command;
    cin >> command;  // Polecenie: "boot" lub "specs"

    // TODO: Utwórz obiekty komponentów (CPU, Memory, Storage)
    
    // TODO: Utwórz obiekt Computer z użyciem kompozycji
    
    // TODO: W zależności od polecenia wywołaj boot() lub specs()

    return 0;
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator C++ online