Podczas implementacji klas, często możemy zauważyć, że część cech składowych klasy można wykorzystać także w innych klasach.
Weźmy pod lupę klasę Computer. Jeżeli chcielibyśmy utworzyć klasy: Laptop, PC, Tablet, to część metod oraz składowych klasy musielibyśmy powielić.
class Computer {
public:
void turnOn();
void powerOff();
void restart();
private:
Processor processor_;
Drive drive_;
Motherboard motherboard_;
GraphicsCard graphics_card_;
Memory memory_;
};class Laptop {
public:
void turnOn();
void powerOff();
void restart();
void display();
void getUserInput();
private:
Processor processor_;
Drive drive_;
Motherboard motherboard_;
GraphicsCard graphics_card_;
Memory memory_;
Screen screen_;
Keyboard keyboard_;
};class Tablet {
public:
void turnOn();
void powerOff();
void restart();
void display();
void getUserInput();
private:
Processor processor_;
Drive drive_;
Motherboard motherboard_;
GraphicsCard graphics_card_;
Memory memory_;
Screen screen_;
};class Computer {
public:
void turnOn();
void powerOff();
void restart();
protected:
Processor processor_;
Drive drive_;
Motherboard motherboard_;
GraphicsCard graphics_card_;
Memory memory_;
};
class Laptop : public Computer {
public:
void display();
void getUserInput();
private:
Screen screen_;
Keyboard keyboard_;
};
class Tablet : public Computer {
public:
void display();
void getUserInput();
private:
Screen screen_;
};Klasa, po której dziedziczymy, nazywają się klasą bazową (base class).
Klasa, która dziedziczy nazywa się klasą pochodną (derived class).
Inaczej, klasa, po której dziedziczymy to rodzic (parent class).
Klasa, która dziedziczy to dziecko (child class).
void display();
void getUserInput();Załóżmy, że dodajemy klasę Screen. Klasa ta wyświetla na bieżąco interfejs użytkownika.
Chcemy też stworzyć klasę reprezentującą ekran dotykowy - TouchScreen, który również umożliwia odczyt akcji od użytkownika i ich wyświetlanie.
class Screen {
public:
void display();
private:
void process();
Monitor monitor_;
};class TouchScreen {
public:
void display();
void getUserInput();
private:
void process();
void displayKeyboard();
Monitor monitor_;
};class Screen {
public:
void display();
private:
void process();
Monitor monitor_;
};class TouchScreen : public Screen {
public:
void getUserInput();
private:
void displayKeyboard();
};class Screen {
public:
void display();
private:
void process();
Monitor monitor_;
};
class TouchScreen : public Screen {
public:
void getUserInput();
private:
void displayKeyboard();
};
class Computer {
public:
void turnOn();
void powerOff();
void restart();
protected:
Processor processor_;
Drive drive_;
Motherboard motherboard_;
GraphicsCard graphics_card_;
Memory memory_;
};
class Laptop : public Computer,
public Screen {
Keyboard keyboard_;
public:
void getUserInput();
};
class Tablet : public Computer,
public TouchScreen {
};Wielodziedziczenie to dziedziczenie z kliku klas bazowych.
Wybór implementacji zależy od programisty.
Nie zawsze wielodziedziczenie będzie lepszym rozwiązaniem.
Należy się zawsze zastanowić czy dziedziczenie po konkretnej klasie uprości nam program i czy nie będzie powodować żadnych komplikacji w dalszym procesie rozbudowy naszego programu.
Najwyżej trzeba będzie refaktoryzować program ;)
struct Bird {
fly();
makeSound();
};
struct Penguin {
swim();
makeSound();
};
// Hummingbird is the type of bird which makes so little sound so it
// can be said that it makes no sound.
struct Hummingbird {
fly();
};Jeżeli spróbujemy teraz uprościć klasę poprzez dziedziczenie pojawi się problem:
struct Bird {
fly();
makeSound();
};
struct Penguin : public Bird {
fly(); // But I can't fly!
swim();
makeSound();
};
struct Hummingbird : public Bird {
fly();
makeSound(); // But I don't make sound!
};Jeszcze bardziej utrudnimy sytuację, gdy w przyszłości dodamy sobie kolejne klasy jak Struś. Zawsze przed implementacją musimy się zastanowić jak podzielić odpowiedzialność na poszczególne klasy, aby uniknąć podobnych problemów.
Poczytajcie o zasadzie Liskov Substitution Principle (LSP). Mówi ona jak powinno / nie powinno się projektować kodu obiektowego. Ta zasada została złamana w ostatnim przykładzie.
Możecie też poczytać o wszystkich zasadach SOLID.