Różnice między klasami abstrakcyjnymi a interfejsami

W programowaniu obiektowym w C++ kluczowe jest zrozumienie, jak projektować hierarchię klas. Do tworzenia wzorców zachowań używamy klas abstrakcyjnych oraz interfejsów (które w C++ są po prostu specyficzną formą klasy abstrakcyjnej).

1. Klasa Abstrakcyjna (Tożsamość: "IS-A")

Klasa abstrakcyjna w C++ to taka, która posiada przynajmniej jedną czystą funkcję wirtualną (zapisaną jako = 0).

  • Brak instancji: Nie można utworzyć obiektu takiej klasy (np. Urzadzenie u; wywoła błąd).
  • Dziedziczenie: Klasa pochodna musi nadpisać czyste funkcje wirtualne, aby można było stworzyć jej obiekty.
  • Pola i Metody: Może posiadać zwykłe zmienne (pola) oraz metody z gotowym kodem, które będą wspólne dla wszystkich dzieci.
  • Słowo kluczowe virtual i override: Używamy virtual w bazie i (opcjonalnie, ale zalecane) override w klasie pochodnej, by uniknąć błędów.

2. Interfejs (Umiejętność: "CAN-DO")

W C++ nie ma słowa interface. Interfejs to po prostu klasa, która posiada tylko i wyłącznie czyste funkcje wirtualne i nie ma żadnych pól (zmiennych).

  • Wielokrotne dziedziczenie: C++ pozwala jednej klasie dziedziczyć po wielu innych klasach. Pozwala to "składać" obiekt z wielu umiejętności.
  • Kontrakt: Implementując interfejs, klasa obiecuje, że dostarczy kod dla wszystkich jego funkcji.

Kod z lekcji

Ten kod pokazuje różnicę: Urządzenie (baza) vs Sterowanie (umiejętność).

Podsumowanie

Głównym celem lekcji było zrozumienie, że w programowaniu obiektowym nie liczy się tylko "pisanie kodu", ale projektowanie relacji między obiektami.

1. Zapamiętaj różnicę (Złota zasada)

  • Klasa Abstrakcyjna to fundament. Mówi nam, czym obiekt JEST (relacja IS-A). Używamy jej, gdy obiekty mają wspólne cechy i logikę (np. każde urządzenie ma model i stan włączenia).
  • Interfejs (Klasa czysto abstrakcyjna) to kontrakt. Mówi nam, co obiekt POTRAFI (relacja CAN-DO). Używamy go, by nadać umiejętność klasom, które nie muszą być ze sobą spokrewnione (np. pilotem możemy sterować telewizorem, ale i inteligentną roletą).

2. Szybkie porównanie techniczne

Cecha Klasa Abstrakcyjna Interfejs (w C++)
Definicja Zawiera przynajmniej jedną funkcję = 0. Zawiera tylko funkcje = 0.
Pola (dane) Może posiadać zmienne (np. string model). Nie posiada pól (brak stanu).
Dziedziczenie Klasa pochodna dziedziczy tożsamość. Klasa implementuje zachowanie.
Cel Unikanie powtarzania kodu (wspólna baza). Elastyczność i polimorfizm.

3. Słowa kluczowe – Twoi sprzymierzeńcy

  • virtual – "Hej, ta funkcja może być inna w przyszłości (w klasach pochodnych)".
  • = 0 – "Ta funkcja nie ma tutaj sensu, musisz ją napisać w konkretnej klasie".
  • override – "Sprawdź mnie, kompilatorze! Chcę nadpisać funkcję z bazy i nie chcę zrobić literówki".

4. Dlaczego to robimy?

Dzięki stosowaniu tych struktur nasz kod jest:

  1. Rozszerzalny: Możemy dodać nową klasę (np. Projektor), nie zmieniając ani jednej linii kodu w funkcjach obsługujących urządzenia.
  2. Bezpieczny: Kompilator pilnuje, byśmy nie zapomnieli o ważnych funkcjach (np. uruchomieniu urządzenia).
  3. Czytelny: Od razu widzimy, jakie urządzenia mamy w systemie i które z nich obsługują sterowanie pilotem.

💡 Ostatnia myśl:

"Klasa abstrakcyjna to geny, które dostajemy po rodzicach. Interfejs to certyfikat ukończenia kursu – nie ważne, kim jesteś, ważne, że umiesz to, co jest na dyplomie."