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