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).
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.
class Bazowa
{
int prywatna;
protected:
int chroniona;
public:
int publiczna;
};
class PochodnaPublic
: public Bazowa
{
public:
void f()
{
chroniona = 0;
publiczna = 0;
}
};
class PochodnaProtected
: protected Bazowa
{
void f()
{
chroniona = 0;
publiczna = 0;
}
};
class PochodnaPrivate
: private Bazowa
{
void f()
{
chroniona = 0;
publiczna = 0;
}
};
int main()
{
PochodnaPublic ppu;
ppu.publiczna = 0;
PochodnaProtected ppro;
PochodnaPrivate ppri;
}
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ć:
class Baza
{
protected:
int x;
};
class Pochodna
: public Baza
{
int x;
public:
void f()
{
x = 1;
Baza::x = 2;
}
};
Inicjalizacja odziedziczonych składowych
By zainicjalizować odziedziczoną część obiektu, wywołujemy w konstruktorze klasy pochodnej konstruktor klasy bazowej:
class Bazowa
{
int x;
public:
Bazowa( int a )
: x( a )
{ }
};
class Pochodna
: public Bazowa
{
public:
Pochodna( int a )
: Bazowa( a )
{ }
};
Przykład
#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 )
{ }
void Px()
{
std::cout << "P: " << x << std::endl;
}
};
int main()
{
P p( 1, 2 );
p.Bx();
p.Px();
std::cout << "---" << std::endl;
p.x = 0;
p.Bx();
p.Px();
std::cout << "---" << std::endl;
p.B::x = 8;
p.Bx();
p.Px();
}
B: 1
P: 2
---
B: 1
P: 0
---
B: 8
P: 0