Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: pekfos
Programowanie obiektowe, C++

Dziedziczenie

[lekcja] 11. O dziedziczeniu.

Wprowadzenie

Bardzo często, tworząc wiele powiązanych klas, można zauważyć, że wiele elementów się powtarza. Gdyby "wyrzucić przed nawias" powtarzające się metody i zmienne, otrzymamy dużo krótszy i bardziej funkcjonalny kod. Do tego właśnie służy dziedziczenie: do łączenia klas, by "wyrzucony przed nawias", powtarzający się kod łączyć z poszczególnymi klasami.

Dziedziczenie

Dziedziczenie, jak sama nazwa wskazuje, pozwala jednej klasie odziedziczyć coś (zmienne, metody) po drugiej. Klasę dziedziczącą nazywamy klasą pochodną, a klasę, po której klasa pochodna dziedziczy, nazywamy klasą bazową. (Klasa pochodna pochodzi od bazowej).
C/C++
class Bazowa
{
};

class Pochodna
    : typ_dziedziczenia Bazowa
{
};
Są 3 typy dziedziczenia: publiczne (
public
), chronione (
protected
) i prywatne (
private
). Różnią się dostępem do odziedziczonych składowych w klasie pochodnej:

Dziedziczenie publiczne

Dziedziczenie publiczne jest najczęściej stosowane. Składowe publiczne klasy bazowej są odziedziczone jako publiczne, a składowe chronione jako chronione.

Dziedziczenie chronione

W dziedziczeniu chronionym składowe publiczne są dziedziczone jako chronione, a składowe chronione jako chronione.

Dziedziczenie prywatne

Dziedziczenie prywatne jest domyślne (gdy nie jest podany typ dziedziczenia). Składowe publiczne są dziedziczone jako prywatne, a chronione jako prywatne.

We wszystkich sposobach dziedziczenia, składowe prywatne klasy bazowej są dziedziczone jako prywatne, ale klasa pochodna nie ma do nich dostępu. Aby klasa pochodna miała dostęp do prywatnych składowych klasy bazowej, musi być zaprzyjaźniona z klasą bazową.
Operator
=
 nie jest dziedziczony.
C/C++
/*
                         +-----------------------------------+
                         |        sposób dziedziczenia       |
                         +-----------+-----------+-----------+
                         |  public   | protected |  private  |
+------------+-----------+===========+===========+===========+
|            |  public   #  public   | protected |  private  |
| widoczność +-----------+-----------+-----------+-----------+
|  w klasie  | protected # protected | protected |  private  |
|  bazowej   +-----------+-----------+-----------+-----------+
|            |  private  #     -*    |     -*    |     -*    |
+------------+-----------+-----------+-----------+-----------+

* - niedostępne, jeśli nie ma przyjaźni

*/

class Bazowa
{
    int prywatna;
protected:
    int chroniona;
public:
    int publiczna;
};

class PochodnaPublic
    : public Bazowa
{
public:
    void f()
    {
        //prywatna = 0; //brak dostepu
        chroniona = 0; //chroniona
        publiczna = 0; //publiczna
    }
};

class PochodnaProtected
    : protected Bazowa
{
    void f()
    {
        //prywatna = 0; //brak dostepu
        chroniona = 0; //chroniona
        publiczna = 0; //chroniona
    }
};

class PochodnaPrivate
    : private Bazowa
{
    void f()
    {
        //prywatna = 0; //brak dostepu
        chroniona = 0; //prywatna
        publiczna = 0; //prywatna
    }
};

int main()
{
    PochodnaPublic ppu;
   
    //ppu.prywatna = 0; //prywatna
    //ppu.chroniona = 0; //chroniona
    ppu.publiczna = 0; //publiczna
   
    PochodnaProtected ppro;
   
    //ppro.prywatna = 0; //prywatna
    //ppro.chroniona = 0; //chroniona
    //ppro.publiczna = 0; //chroniona
   
    PochodnaPrivate ppri;
   
    //ppri.prywatna = 0; //prywatna
    //ppri.chroniona = 0; //prywatna
    //ppri.publiczna = 0; //prywatna
}

Używanie odziedziczonych składowych

Odziedziczonych składowych można używać tak, jak tych zdefiniowanych bezpośrednio w klasie pochodnej. Można też jawnie określać, która klasa zawiera składową, do której chcemy się odwołać:
C/C++
class Baza
{
protected:
    int x;
};

class Pochodna
    : public Baza
{
    int x; //Przesłania x z Bazowej
   
public:
    void f()
    {
        x = 1; // x z Pochodnej
        Baza::x = 2; //x z Bazowej
    }
};

Inicjalizacja odziedziczonych składowych

By zainicjalizować odziedziczoną część obiektu, wywołujemy w konstruktorze klasy pochodnej konstruktor klasy bazowej:
C/C++
class Bazowa
{
    int x;
public:
    Bazowa( int a )
        : x( a )
    { }
};

class Pochodna
    : public Bazowa
{
public:
    Pochodna( int a )
        : Bazowa( a ) //Jawne wywołanie konstruktora na liście inicjalizacyjnej
    { }
};

Przykład

C/C++
#include <iostream>

class B
{
public:
    int x;
   
    B( int a )
        : x( a )
    { }
   
    void Bx()
    {
        std::cout << "B: " << x << std::endl;
    }
};

class P
    : public B
{
public:
    int x;
   
    P( int a, int b )
        : B( a )
        , x( b ) //wywołujemy konstruktor klasy bazowej
    { }
   
    void Px()
    {
        std::cout << "P: " << x << std::endl;
    }
};

int main()
{
    P p( 1, 2 );
    p.Bx(); //odziedziczone po B
    p.Px();
    std::cout << "---" << std::endl;
    p.x = 0; //modyfikuje x z P
    p.Bx();
    p.Px();
    std::cout << "---" << std::endl;
    p.B::x = 8; //modyfikuje x z B
    p.Bx();
    p.Px();
}
B: 1
P: 2
---
B: 1
P: 0
---
B: 8
P: 0
Poprzedni dokument Następny dokument
Polimorfizm Konwersja w górę i rzutowanie w dół