Dziedziczenie
Kon
o s
n truk
u tor
o y
y i
i d
e
d struk
u tor
o y
Programowanie obiektowe
1
Dziedziczenie to technika pozwalająca na definiowanie nowych klas przy wykorzystaniu klas wcześniej zdefiniowanych
Wyraża związki hierarchiczne między klasami (klasa nadrzędna - klasa podrzędna);
Specjalizuje lub generalizuje klasy;
osoba
klasa bazowa
Pr
P zykł
zy a
kł d
a :
d
dorosły
dziecko
klasy pochodne
każdy dorosły i każde dziecko jest osobą (generalizacja);
dorosły jest przypadkiem szczególnym osoby, podobnie jak dziecko (specjalizacja);
Programowanie obiektowe
2
Klasa pochodna:
dziedziczy wszystkie zmienne z sekcji „public” i „protected” klasy bazowej;
dziedziczy wszystkie funkcje z sekcji „public” i „protected” klasy bazowej;
do dostępnych składowych klasy bazowej można się odwoływać poprzez operator zakresu „::”;
W klasie pochodnej można także:
zdefiniować dodatkowe zmienne składowe;
zdefiniować dodatkowe funkcje składowe;
przedefiniować (zmienić) funkcje składowe odziedziczone z klasy bazowej ( polimorfizm);
Programowanie obiektowe
3
sekcja docelowa dla składowych
dziedziczonych
Postać ogólna dziedziczenia:
class Klasa_pochodna: sekcja Klasa_bazowa_1 [, Klasa_bazowa_N]
{
// nowe składowe
// funkcje odziedziczone nadpisane (przedefiniowane)
};
tzw. dziedziczenie wielobazowe
Programowanie obiektowe
4
Jeżeli w klasie bazowej i w klasie pochodnej są składniki o tej samej nazwie, wówczas w zakresie klasy pochodnej składnik z tej klasy zasłania odziedziczony składnik z klasy bazowej
Jeśli składnik klasy bazowej jest zasłonięty to odwołanie się do niego jes
e t
s m
o
m żl
ż iwe
e z
użyc
y i
c em
e
m oper
e a
r t
a ora
r
a zak
za r
k e
r s
e u
s (::)
Programowanie obiektowe
5
class osoba
{
int wiek;
char imię[20], nazwisko[30];
public:
vo
v id wczy
c
t
zy aj
a ();
void ustaw(int wiek, char *p_imię, char *p_nazwisko); void wypisz();
};
Programowanie obiektowe
6
Założenia rozszerzające dla klasy „dorosly”:
numer dowodu:
char *nr_dowodu;
pr
p yw
y a
w t
a ny
y dl
d a
l
a kla
kl sy
a
sy „do
d r
o osl
o y
sl ”
y ;
metody wczytaj, wypisz, ustaw:
dostępne publicznie;
odziedziczone z klasy bazowej;
Programowanie obiektowe
7
Klasa „dorosly”
klasa pochodna
klasa bazowa
class dorosly: public osoba
{
sekcja docelowa dla składowych
dziedziczonych
c
char * nr_dowodu;
public:
nowa składowa
void wczytaj ();
void wypisz ();
void ustaw(int wiek, char *p_imie, char *p_nazwisko, char *nr_dow);
};
metody odziedziczone ale przedefiniowane
Programowanie obiektowe
8
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna : public Klasa_bazowa;
Klasa_bazowa
Klasa_pochodna
// sekcja
// sekcja
// p
u
p b
u l
b ilc
i
// p
u
p b
u l
b ilc
i
// sekcja
// sekcja
// protected
// protected
// sekcja
// sekcja
// private
// private
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
Programowanie obiektowe
9
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna : protected Klasa_bazowa;
Klasa_bazowa
Klasa_pochodna
// sekcja
// sekcja
// p
u
p b
u l
b ilc
i
// p
u
p b
u l
b ilc
i
// sekcja
// sekcja
// protected
// protected
// sekcja
// sekcja
// pivate
// pivate
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
Programowanie obiektowe
10
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna : private Klasa_bazowa;
Klasa_bazowa
Klasa_pochodna
// sekcja
// sekcja
// public
// public
// sekcja
// sekcja
// protected
// protected
// sekcja
// sekcja
// private
// private
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
Programowanie obiektowe
11
Z zakresu klasy pochodnej do prywatnych składników klasy bazowej można sięgać tylko poprzez funkcje składowe klasy bazowej
Do składników protected i public klasy bazowej mamy dostęp bezpośred
e ni;
i
Dziedziczenie prywatne stosujemy wtedy, gdy chcemy aby nie było publicznego dostępu do odziedziczonych składników klasy bazowej;
Nie podlegają dziedziczeniu:
konstruktory
trzeba je zdefiniować w klasie pochodnej
destruktory
Programowanie obiektowe
12
Dziedziczenie jest techniką definiowania nowych klas;
Dziedziczenie jest jedną z najwspanialszych cech języków programowania obiektowego;
Umo
m żlilw
i ia
i :
oszczędność pracy,
tworzenie hierarchii klas (hierarchia wprowadza naturalne relacje między klasami),
tworzenie szablonów klas (klas ogólnych), tzn. klas przeznaczonych do dziedziczenia , np. szablon klasy „kolejka”) Programowanie obiektowe
13
Przykład hierarchii klas
samochód
„wywodzi się”
osobowy
ciężarowy
autobus
Fiat
VW
opel
Programowanie obiektowe
14
Zgodność typów:
class KlasaA
{
…
}
class KlasaB: public KlasaA
{
....
};
KlasaA a;
zmienne obiektowe (obiekty)
KlasaB b;
a = b; // ?
dozwolone, ale kopiuje się tylko tyle, ile jest w KlasaA b = a; // ?
niedozwolone
Programowanie obiektowe
15
Zgodność typów:
KlasaA *ap;
wskaźniki na obiekty
KlasaB *bp;
ap = bp;
// ?
poprawne (wystąpi polimorfizm)
niedozwolone
bp = ap;
// ?
bp = (KlasaB*) ap;
// ?
dozwolone (styl języka C)
bp = dynamic_cast<KlasaB*>(ap); // ?
dozwolone (styl języka C++)
Operator dynamic_cast zwraca 0 (dla wskaźników) lub zgłasza bad_cast (dla referencji), gdy rzutowanie się nie powiedzie; Programowanie obiektowe
16
pierwsza (najczęściej publiczna) funkcja składowa obiektu, o nazwie takiej samej jak nazwa klasy;
służy do inicjowania obiektów danej klasy, tzn. do nadawania wartości początkowych składnikom definiowanego (właśnie) obiektu (w trakcie deklaracji obiektu przydzielane jest dla niego miejsce w PAO);
metoda bezzwrotna ( nie można użyć nawet typu „void”! );
definiowany tak jak funkcja składowa:
we
w wn
w ąt
ą rz de
d kl
e a
kl r
a acj
a i
cj
i kla
kl sy
a
sy – do
d m
o yś
y l
ś n
l i
n e
i
e „in
i l
n iln
i e
n ”
e ;
poza deklaracją klasy:
jak zwykła metoda;
jak metoda „inline”;
wywoływany automatycznie w momencie tworzenia (deklaracji) konkretnego obiektu;
konstruktor często bywa przeciążany;
w przypadku braku konstruktora w definicji klasy dołączany jest konstruktor pusty (bez instrukcji)
Programowanie obiektowe
17
Konstruktor domyślny
funkcja składowa, którą można wywołać bez argumentów lub z wartościami domyślnymi;
jeżeli nie został zadeklarowany żaden konstruktor to kompilator dołącza pusty konstruktor domyślny:
Klasa :: Klasa() { };
jeżeli zadeklarujemy konstruktor przeciążony (z parametrami) to kompilator nie dołączy pustego konstruktora domyślnego;
kolejność wywołań konstruktorów:
klasy bazowe w kolejności deklaracji,
obiektowe składowe klasy w kolejności deklaracji,
ciało konstruktora;
Programowanie obiektowe
18
Lista inicjalizacyjna konstruktora
służy do inicjowania składników klasy, będących stałymi lub zmiennymi;
stanowi obejście ograniczenia, że w definicji klasy zmienne i stałe nie mogą być inicjalizowane (nie można im nadawać wartości początkowych);
poja
j wia
i s
ię
i t
y
t l
y k
l o p
rzy
y d
e
d fin
i i
n c
i ji
j konstr
t ukto
t ra
r ,
a
, a
n
ie
i p
rzy
y j
e
j go
deklaracji;
kolejność inicjalizacji:
składowe w kolejności wymienienia na liście,
ciało konstruktora
klasa::klasa(argumenty) : nazwa_pola(wartość początkowa)
[ , nazwa_pola(wartość początkowa)]
{
// ciało konstruktora
};
Programowanie obiektowe
19
Lista inicjalizacyjna konstruktora – przykład 1
class Punkt
{
double x, y;
public:
// …
Punkt(): x(0.0), y(0.0) { };
Punkt(double a, double b) : x(a), y(b) { };
};
Programowanie obiektowe
20
Lista inicjalizacyjna konstruktora – przykład 2
class abc
{
const double stala;
deklaracja konstruktora
float
a x
;
x
char c;
public:
abc(float pp, double dd, char znak);
};
...
abc::abc(float pp, double dd, char znak) : stala(dd), c(znak)
{
x=pp;
definicja konstruktora
}
Programowanie obiektowe
21
Lista inicjalizacyjna konstruktora – przykład 3
class Odcinek
{
Punkt p1;
Punkt p2;
Odci
c nek
e (
k double
e x
1
x ,
1 double
e y
1
y ,
1 double
e x
2
x ,
2 double
e y
2
y )
2 ;
};
...
Odcinek::Odcinek(double x1, double y1, double x2, double y2): p1(x1, y1)
{
p2 = Punkt(2.0, 2.0);
};
• obiekt p1 – inicjowanie listą inicjalizacyjną
• obiekt p2 – inicjowanie w ciele konstruktora
Programowanie obiektowe
22
ostatnia funkcja wykonywana przed usunięciem obiektu;
nazwa taka sama, jak nazwa klasy, ale poprzedzona tyldą „~”;
bez parametrów wejściowych;
bez możliwości przeciążania (jeden w klasie);
wywoływany automatycznie w momencie niszczenia obiektu (wychodzenia z bloku)
kolejność wywoływania:
ciało destruktora;
destruktory obiektów składowych (kolejność odwrotna do deklaracji w klasie);
destruktor klasy (klas) bazowych (kolejność odwrotna do deklaracji w klasie);
to, kiedy dokładnie likwidowane są obiekty zależy od konkretnego kompilatora
Programowanie obiektowe
23
Destruktor klasy „Klasa”:
~Klasa() {... };
lub
~Klasa();
…
Kl
K as
a a
s :
a :~Kl
K as
a a
s (
a ) {.
{ .. }
;
}
Przykład:
~Punkt()
{cout << "Destruktor punktu x= " <<x << ", y= " << y << endl;}
~Odcinek()
{ cout << "Destruktor odcinka <<endl; }
Programowanie obiektowe
24
Przykłady programowe
Program 3.1a
C:\
C:\
Program 3.1b
Programowanie obiektowe
25
Konstruktor klasy pochodnej
Lista inicjalizacyjna konstruktora
Na liście muszą znaleźć się konstruktory wszystkich klas bazowych:
• ich brak oznacza dla kompilatora konieczność wywołania konstru
r ktoró
r w
w domyś
y lnyc
y h z klas b
azowy
w c
y h;
• jeżeli w klasie bazowej brak jest domyślnego konstruktora a są inne konstruktory, to zostanie wygenerowany błąd;
Kolejność inicjalizacji:
• klasy bazowe (bezpośredni przodkowie w kolejności deklaracji),
• składowe w kolejności deklaracji,
• ciało konstruktora;
Programowanie obiektowe
26
Konstruktor klasy pochodnej
Lista inicjalizacyjna konstruktora
class KlasaA {
...
public:
Kl
K as
a a
s A
a
A (int t
)
{ ...};
};
class KlasaB : public KlasaA //deklaracja klasy pochodnej
{
public:
int x;
KlasaB (int par1, int par2) : KlasaA(par1), x(par2)
{ ...};
};
Programowanie obiektowe
27
Konstruktor klasy pochodnej - Przykład
class dorosly: public osoba
{
char * nr_dowodu;
pu
p b
u l
b ilc:
i
Program 3.2
void wczytaj ();
void wypisz ();
void ustaw(int wiek, char *p_imie, char *p_nazwisko, char *nr_dow); dorosly(int k_wiek, char *p_imie, char *p_nazwisko, char *nr_dow): osoba (k_wiek, p_imie, p_nazwisko),
nr_dowodu(kopiuj(nr_dow)) { };
Programowanie obiektowe
28
Konstruktor jest zwykle deklarowany jako publiczny, bo przecież
wprowadzane nim obiekty mogą być używane przez klasy zewnętrzne
Możemy jednak dla konstruktora przewidzieć ochronę za pomocą etykiet
private lub protected
Wówczas
z
as j
edn
d ak
n
ak takż
ak e
ż kon
k
s
on t
s ruow
u
ane
an ob
i
ob ekt
k y b
ę
b dą
d
ą dos
d t
os ępn
p e
n tylko
k w
o ob
r
ob ębi
b e
klasy z tym konstruktorem jako private albo jako protected tylko w zakresie klas dziedziczących.
Konstruktor może zamiast definiować obiekty podawać kopie obiektów zawartych w innej klasie. Wtedy jest to tak zwany konstruktor kopiujący.
Konstruktor może dokonywać konwersji typu obiektu z jednego w drugi.
Nazywamy go wtedy konstruktorem konwertującym.
Programowanie obiektowe
29
Konstruktor i destruktor
dla obiektów zdefiniowanych w blokach programowych:
konstruktor jest wywoływany, gdy sterowanie napotyka kod deklaracji zmiennej – obiektu;
destruktory są wywoływane po opuszczeniu bloku w kolejności odwrotnej do konstruktorów;
dla
l o
bie
i któ
t w g
lo
l baln
l yc
y h (
sta
t ty
t c
y znyc
y h):
)
konstruktory są uaktywniane przed wywołaniem funkcji main(), w kolejności definicji;
destruktory są uaktywniane po zakończeniu bloku main(), w kolejności odwrotnej do definicji;
dla obiektów dynamicznych:
po zastosowaniu operatora „new”: alokacja pamięci a potem wywołanie konstruktora;
po zastosowaniu „delete”: wywołanie destruktora i potem dealokacja pamięci;
Programowanie obiektowe
30
Przykłady programowe
C:\
Program 3.3
C:\
Program 3.4
Programowanie obiektowe
31
32