Wykład 4
Dziedziczenie
Konstruktory i destruktory
Programowanie obiektowe
1
Konstruktory i destruktory
Dziedziczenie
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;
Przykład:
osoba
klasa bazowa
Programowanie obiektowe
2
Przykład:
ka
ż
dy dorosły i ka
ż
de dziecko jest osob
ą
(generalizacja);
dorosły jest przypadkiem szczególnym osoby, podobnie jak dziecko
(specjalizacja);
dziecko
dorosły
klasy pochodne
Klasa pochodna:
dziedziczy wszystkie zmienne z sekcji „public” i „protected” klasy
bazowej;
dziedziczy wszystkie funkcje z sekcji „public” i „protected” klasy
bazowej;
Dziedziczenie
Programowanie obiektowe
3
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);
Posta
ć
ogólna dziedziczenia:
class Klasa_pochodna: sekcja Klasa_bazowa_1 [, Klasa_bazowa_N]
{
Dziedziczenie
sekcja docelowa dla składowych
dziedziczonych
Programowanie obiektowe
4
// nowe składowe
// funkcje odziedziczone nadpisane (przedefiniowane)
};
tzw. dziedziczenie wielobazowe
Dziedziczenie
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
jest mo
ż
liwe z u
ż
yciem operatora zakresu (::)
Programowanie obiektowe
5
jest mo
ż
liwe z u
ż
yciem operatora zakresu (::)
Przykład – klasa osoba
class osoba
{
int wiek;
char imi
ę
[20], nazwisko[30];
public:
void wczytaj();
Programowanie obiektowe
6
void wczytaj();
void ustaw(int wiek, char *p_imi
ę
, char *p_nazwisko);
void wypisz();
};
Zało
ż
enia rozszerzaj
ą
ce dla klasy „dorosly”:
numer dowodu:
char *nr_dowodu;
prywatny dla klasy „dorosly”;
Przykład – klasa dorosly
Programowanie obiektowe
7
prywatny dla klasy „dorosly”;
metody wczytaj, wypisz, ustaw:
dost
ę
pne publicznie;
odziedziczone z klasy bazowej;
Klasa „dorosly”
class dorosly: public osoba
{
klasa pochodna
klasa bazowa
sekcja docelowa dla składowych
dziedziczonych
Dziedziczenie
Programowanie obiektowe
8
char * nr_dowodu;
public:
void wczytaj ();
void wypisz ();
void ustaw(int wiek, char *p_imie, char *p_nazwisko,
char *nr_dow);
};
dziedziczonych
nowa składowa
metody odziedziczone ale przedefiniowane
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
public
Klasa_bazowa;
Klasa_bazowa
// sekcja
// public
Klasa_pochodna
// sekcja
// public
Dziedziczenie
Programowanie obiektowe
9
// public
// sekcja
// protected
// sekcja
// private
// public
// sekcja
// protected
// sekcja
// private
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
protected
Klasa_bazowa;
Klasa_bazowa
// sekcja
// public
Klasa_pochodna
// sekcja
// public
Dziedziczenie
Programowanie obiektowe
10
// public
// sekcja
// protected
// sekcja
// pivate
// public
// sekcja
// protected
// sekcja
// pivate
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
private
Klasa_bazowa;
Klasa_bazowa
// sekcja
// public
Klasa_pochodna
// sekcja
// public
Dziedziczenie
Programowanie obiektowe
11
// public
// sekcja
// protected
// sekcja
// private
// public
// sekcja
// protected
// sekcja
// private
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
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
ś
redni;
Dziedziczenie
Programowanie obiektowe
12
bezpo
ś
redni;
Dziedziczenie prywatne stosujemy wtedy, gdy chcemy aby nie było
publicznego dost
ę
pu do odziedziczonych składników klasy
bazowej;
Nie podlegaj
ą
dziedziczeniu:
konstruktory
destruktory
trzeba je zdefiniować w klasie pochodnej
Dziedziczenie jest technik
ą
definiowania nowych klas;
Dziedziczenie jest jedn
ą
z najwspanialszych cech j
ę
zyków
programowania obiektowego;
Umo
ż
liwia:
Dziedziczenie - podsumowanie
Programowanie obiektowe
13
Umo
ż
liwia:
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”)
Przykład hierarchii klas
Dziedziczenie
samochód
„wywodzi się”
Programowanie obiektowe
14
osobowy
ciężarowy
autobus
Fiat
VW
opel
Zgodno
ść
typów:
class KlasaA
{
…
}
class KlasaB: public KlasaA
{
Dziedziczenie - ograniczenia
Programowanie obiektowe
15
{
....
};
KlasaA a;
KlasaB b;
a = b; // ?
b = a; // ?
dozwolone, ale kopiuje si
ę
tylko tyle, ile jest w KlasaA
niedozwolone
zmienne obiektowe (obiekty)
Zgodno
ść
typów:
KlasaA *ap;
KlasaB *bp;
ap = bp;
// ?
poprawne (wyst
ą
pi polimorfizm)
Dziedziczenie
wska
ź
niki na obiekty
Programowanie obiektowe
16
bp = ap;
// ?
bp = (KlasaB*) ap;
// ?
bp = dynamic_cast<KlasaB*>(ap); // ?
Operator dynamic_cast zwraca 0 (dla wska
ź
ników) lub zgłasza
bad_cast (dla referencji), gdy rzutowanie si
ę
nie powiedzie;
niedozwolone
dozwolone (styl j
ę
zyka C)
dozwolone (styl j
ę
zyka C++)
Konstruktory
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:
wewn
ą
trz deklaracji klasy – domy
ś
lnie „inline”;
Programowanie obiektowe
17
wewn
ą
trz deklaracji klasy – domy
ś
lnie „inline”;
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)
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:
Konstruktory
Programowanie obiektowe
18
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;
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);
pojawia si
ę
tylko przy definicji konstruktora, a nie przy jego
Konstruktory
Programowanie obiektowe
19
pojawia si
ę
tylko przy definicji konstruktora, a nie przy jego
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
};
Lista inicjalizacyjna konstruktora – przykład 1
class Punkt
{
Konstruktory
Programowanie obiektowe
20
double x, y;
public:
// …
Punkt(): x(0.0), y(0.0) { };
Punkt(double a, double b) : x(a), y(b) { };
};
Lista inicjalizacyjna konstruktora – przykład 2
class abc
{
const double stala;
float x;
deklaracja konstruktora
Konstruktory
Programowanie obiektowe
21
float 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
Lista inicjalizacyjna konstruktora – przykład 3
class Odcinek
{
Punkt p1;
Punkt p2;
Odcinek(double x1, double y1, double x2, double y2);
Konstruktory
Programowanie obiektowe
22
Odcinek(double x1, double y1, double x2, double y2);
};
...
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
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
Destruktory
Programowanie obiektowe
23
(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
Destruktor klasy „Klasa”:
~Klasa() {... };
lub
~Klasa();
…
Klasa::~Klasa() {... };
Destruktory
Programowanie obiektowe
24
Klasa::~Klasa() {... };
Przykład:
~Punkt()
{cout << "Destruktor punktu x= " <<x << ", y= " << y << endl;}
~Odcinek()
{ cout << "Destruktor odcinka <<endl; }
Przykłady programowe
Konstruktory
Program 3.1a
C:\
Programowanie obiektowe
25
Program 3.1b
C:\
Konstruktor klasy pochodnej
Lista inicjalizacyjna konstruktora
Na li
ś
cie musz
ą
znale
źć
si
ę
konstruktory wszystkich klas
bazowych:
• ich brak oznacza dla kompilatora konieczno
ść
wywołania
konstruktorów domy
ś
lnych z klas bazowych;
Konstruktory
Programowanie obiektowe
26
konstruktorów domy
ś
lnych z klas bazowych;
• 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;
Konstruktor klasy pochodnej
Lista inicjalizacyjna konstruktora
class KlasaA {
...
public:
KlasaA (int t)
Konstruktory
Programowanie obiektowe
27
KlasaA (int t)
{ ...};
};
class KlasaB : public KlasaA
//deklaracja klasy pochodnej
{
public:
int x;
KlasaB (int par1, int par2) : KlasaA(par1), x(par2)
{ ...};
};
Konstruktor klasy pochodnej - Przykład
class dorosly: public osoba
{
char * nr_dowodu;
public:
Konstruktory
Programowanie obiektowe
28
public:
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)) { };
Program 3.2
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 jednak także konstruowane obiekty będą dostępne tylko w obrębie
Konstruktory
Programowanie obiektowe
29
Wówczas jednak także konstruowane obiekty będą dostępne tylko w obrębie
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
.
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 obiektów globalnych (statycznych):
Konstruktory i destruktory
Programowanie obiektowe
30
dla obiektów globalnych (statycznych):
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;
Przykłady programowe
Konstruktory i destruktory
Program 3.3
C:\
Programowanie obiektowe
31
Program 3.4
C:\
Programowanie obiektowe
32