Przejdź do głównej zawartości

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;
Instancja 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
}
Kolejność definicji

Definicję struktury Vehicle musimy umieścić przed definicjami struktur pochodnych.

Wykorzystanie​

Schemat utworzonych klas
Schemat utworzonych wyżej klas

Powyż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"
}

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;
Instancja 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
}
Kolejność definicji

Definicję struktury Vehicle musimy umieścić przed definicjami struktur pochodnych.

Wykorzystanie​

Schemat utworzonych klas
Schemat utworzonych wyżej klas

Powyż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"
}