Dziedziczenie
W tej lekcji pokażemy Ci jak współdzielić cechy różnych klas za pomocą dziedziczenia, tworząc hierarchię i tym samym zapobiec niepotrzebnym powtórzeniom.
Motywacja
Tworząc struktury, które odwzorowują elementy z prawdziwego świata, często natrafiamy na sytuację, w której dwie struktury mają wspólne cechy. Przykładowo, jeśli tworzymy grę o pojazdach, zawierajacą i samoloty ✈ i samochody 🚗, utworzylibyśmy następujące dwie struktury:
struct Car
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
bool is_cabrio;
};
struct Airplane
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
int number_of_engines; // liczba silników
std::string airlines_name; // nazwa linii lotniczych
};
Zwróć uwagę na zaznaczone linie kodu. Po krótkiej analizie tego kodu zauważymy, że obydwie struktury mają wspólne cechy:
- marka
- model
- rok produkcji
W dalszej części tej lekcji skorzystamy z dziedziczenia, by uwspólnić te elementy.
Struktura bazowa
Wyłoniliśmy już cechy tzw. struktury bazowej (bądź klasy bazowej - o tym w przyszłości). Utworzymy teraz strukturę, która będzie się składać tylko z nich:
struct Vehicle
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
};
Zauważ, że nazwałem strukturę Vehicle
(z ang. pojazd). Jest to struktura opisująca generalna formę pojazdu.
Utworzenie instancji tej struktury nie ma większego sensu:
Vehicle vehicle;
Vehicle
Powyższy zapis nie jest zabroniony. Nie spowoduje on błędu kompilacji. W przyszłości dowiemy się jak zablokować możliwość utworzenia klasy takiego obiektu, poznając tzw. konstruktory prywatne.
Zamiast tego, użyjemy jej, tworząc struktury Car
i Airplane
, by odziedziczyły one
jej cechy.
Struktury pochodne
Aby skorzystać z mechanizmu dziedziczenia, tworząc tzw. struktury pochodne podajemy po dwukropku strukturę bazową, w ten sposób:
struct Car : Vehicle
{
bool is_cabrio;
};
struct Airplane : Vehicle
{
int number_of_engines; // liczba silników
std::string airlines_name; // nazwa linii lotniczych
};
Zobacz cały kod
#include <string>
struct Vehicle
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
};
struct Car : Vehicle
{
bool is_cabrio;
};
struct Airplane : Vehicle
{
int number_of_engines; // liczba silników
std::string airlines_name; // nazwa linii lotniczych
};
int main()
{
// na razie pusto
}
Definicję struktury Vehicle
musimy umieścić przed definicjami struktur pochodnych.
Wykorzystanie
Schemat utworzonych wyżej klasPowyższy schemat pokazuje, że elementy odziedziczone ze struktury Vehicle
równierz znajdują
się w strukturze Car
i Airplane
.
Z tego powodu, tworząc samochód wewnątrz kodu, możemy śmiało korzystać z pól brand
, model
, production_year
,
tak jakby były one bezpośrednio w strukturze Car
:
Car ford;
ford.brand = "Ford";
ford.model = "Fiesta";
ford.production_year = 2010;
ford.is_cabrio = false;
Analogicznie z samolotem:
Airplane boeing;
boeing.brand = "Boeing";
boeing.model = "737";
boeing.production_year = 2010;
boeing.number_of_engines = 2;
boeing.airlines_name = "Air Canada";
Zobacz cały kod
#include <iostream>
#include <string>
struct Vehicle
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
};
struct Car : Vehicle
{
bool is_cabrio;
};
struct Airplane : Vehicle
{
int number_of_engines; // liczba silników
std::string airlines_name; // nazwa linii lotniczych
};
int main()
{
Car ford;
ford.brand = "Ford";
ford.model = "Fiesta";
ford.production_year = 2010;
ford.is_cabrio = false;
Airplane boeing;
boeing.brand = "Boeing";
boeing.model = "737";
boeing.production_year = 2010;
boeing.number_of_engines = 2;
boeing.airlines_name = "Air Canada";
std::cout << ford.brand << '\n'; // "Ford"
std::cout << boeing.brand << '\n'; // "Boeing"
}
Dziedziczenie metod
Podobnie jak składowe zmienne, dziedziczone są też metody klasy bazowej. Dodajmy do Vehicle
metodę
complete_name()
, która zwróci nam nazwę składającą się z brand
i model
:
struct Vehicle
{
// ...
std::string complete_name()
{
return brand + " " + model;
}
};
Następnie możemy użyć tej metody na instancji struktury Car
:
Car ford;
ford.brand = "Ford";
ford.model = "Fiesta";
std::cout << ford.complete_name(); // "Ford Fiesta"
Zobacz cały kod
#include <iostream>
#include <string>
struct Vehicle
{
std::string brand; // marka
std::string model;
int production_year; // rok produkcji
std::string complete_name()
{
return brand + " " + model;
}
};
struct Car : Vehicle
{
bool is_cabrio;
};
struct Airplane : Vehicle
{
int number_of_engines; // liczba silników
std::string airlines_name; // nazwa linii lotniczych
};
int main()
{
Car ford;
ford.brand = "Ford";
ford.model = "Fiesta";
ford.production_year = 2010;
ford.is_cabrio = false;
Airplane boeing;
boeing.brand = "Boeing";
boeing.model = "737";
boeing.production_year = 2010;
boeing.number_of_engines = 2;
boeing.airlines_name = "Air Canada";
std::cout << ford.complete_name() << '\n'; // "Ford Fiesta"
std::cout << boeing.complete_name() << '\n'; // "Boeing 737"
}