Dziedziczenie

Dokładnie

Posted by Mrozo on March 27, 2015

Dziedziczenie

Często w naszych programach istnieją bardzo podobne klasy, które różnią się jedynie małymi szczegółami. Dla przykładu: klasa Wojownik, Mag i Łucznik. Wszyscy będą mieli podobne atrybuty takie jak życie, poziom, nazwa itp. W ten sposób powstanie nam masa klas posiadających w wielu miejscach dokładnie taki sam kod, czego byśmy nie chcieli.

class Wojownik
{
private:
    string nazwa;
    int hp;
    int mp;
    int poziom;
    int sila;

public:
    void OkrzykBojowy()
    {
        cout << "Argh!";
    }

    void AtakMieczem()
    {
        //kod
    }

    //gettery i settery
};

class Lucznik
{
private:
    string nazwa;
    int hp;
    int mp;
    int poziom;
    int zrecznosc;

public:
    void OkrzykBojowy()
    {
        cout << "Argh!";
    }

    void AtakLukiem()
    {
        //kod
    }

    //gettery i settery
};

class Mag
{
private:
    string nazwa;
    int hp;
    int mp;
    int poziom;
    int silaWoli;

public:
    void OkrzykBojowy()
    {
        cout << "Argh!";
    }

    void MagicznyAtak()
    {
        //kod
    }

    //gettery i settery
};

Nie wygląda to imponująco, nie pisałem getterów, setterów i konstruktora a i tak kod wygląda na zbyt bardzo powtórzony i bezsensowny. Aby rozwiązać ten problem będziemy dziedziczyć klasę z innej klasy:

class Bohater
{
protected:
    string nazwa;
    int hp;
    int mp;
    int poziom;
public:
    void OkrzykBojowy()
    {
        cout << "Argh!";
    }

    //gettery i settery
};


class Wojownik : public Bohater
{
private:
    int sila;
public:
    void AtakMieczem()
    {
        //kod
    }
};

class Lucznik : public Bohater
{
private:
    int zrecznosc;
public:
    void AtakLukiem()
    {
        //kod
    }
};

class Mag : public Bohater
{
private:
    int silaWoli;
public:
    void MagicznyAtak()
    {
        //kod
    }
};

Operatorem dwukropka informujemy, że nasza nowa klasa po lewej stronie ma odziedziczyć cechy po tej z prawej strony. Public po dwukropku to typ dziedziczenia o czym za chwilę napiszę. Jeżeli w klasie pochodnej chcielibyśmy nieco zmodyfikować odziedziczoną metodę, piszemy ją na nowo a ona sama zostanie nadpisana.

Określanie dostępu do składników w klasie podstawowej

private:
zostaną odziedziczone, w klasi pochodnej dalej będą prywatne.

public i protected:
są bezpośrednio dostępne w klasie pochodnej. Protected znaczy, że dla wszystkich potomków tej klasy będzie on jak public, a dla reszty niedostępny czyli jak private.

Rodzaje dziedziczenia

public:
składniki public z klasy podstawowej mają w klasie pochodnej również public, protected również zostaną protected (nic się nie zmienia)

protected:
składniki public i protected są w klasie pochodnej zabezpieczone jako protected

private:
składniki public oraz protected są w klasie pochodnej od teraz private

Co nie jest dziedziczone

  • Konstruktor
  • Destruktor
  • Operator przypisania (=)

Konstruktor w klasie pochodnej

Konstruktor musimy napisać sami, ponieważ każda klasa pochodna różni się między sobą. Aby nie przepisywać od nowa atrybutów klasy podstawowej robimy coś takiego:

Bohater(string _nazwa, int _hp, int _mp, int _poziom) //konstruktor w klasie Bohater
    {
        nazwa = _nazwa;
        hp = _hp;
        mp = _mp;
        poziom = _poziom;
    }

Wojownik( string nazwa, int hp, int mp, int poziom, int _sila) : Bohater(nazwa, hp, mp, poziom) //konstruktor w klasie Wojownik
    {
        sila = _sila;
    }

Dodatkowo możemy ustawić wartości domyśle, które przyjmą się jeżeli sami nie wprowadzimy naszych podczas tworzenia obiektu: (tak można robić z każdym konstruktorem, w klasie podstawowej również)

Wojownik( string nazwa = "Wojo", int hp = 100, int mp = 20, int poziom = 1, int _sila = 20) : Bohater(nazwa, hp, mp, poziom)
    {
        sila = _sila;
    }

Dodatki

Do zaprezentowania dziedziczenia konstruktora w klasie pochodnej użyłem preambuły konstruktora, prościej listy inicjalizacyjnej.

Kompletny kod pliku main.cpp (click)