1
Programowanie obiektowe
Wykład 4
Dziedziczenie
Konstruktory i destruktory
2
Programowanie obiektowe
Dziedziczenie
Dziedziczenie to technika pozwalaj
ą
ca na definiowanie nowych klas przy
wykorzystaniu klas wcze
ś
niej istniej
ą
cych
Wyra
ż
a zwi
ą
zki hierarchiczne mi
ę
dzy klasami;
Specjalizuje lub generalizuje klasy;
Przykład:
ka
ż
dy dorosły i ka
ż
de dziecko jest osob
ą
(generalizacja);
dorosły jest przypadkiem szczególnym osoby, podobnie jak dziecko
(specjalizacja);
osoba
dziecko
dorosły
klasa bazowa
klasy pochodne
3
Programowanie obiektowe
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);
Dziedziczenie
4
Programowanie obiektowe
Posta
ć
ogólna dziedziczenia:
class Klasa_pochodna: sekcja Klasa_bazowa_1 [, Klasa_bazowa_N]
{
// nowe składowe
// funkcje odziedziczone nadpisane (przedefiniowane)
};
tzw. dziedziczenie wielobazowe
Dziedziczenie
sekcja docelowa dla składowych
dziedziczonych
5
Programowanie obiektowe
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 (::)
6
Programowanie obiektowe
Przykład – klasa osoba
class osoba
{
int wiek;
char imi
ę
[20], nazwisko[30];
public:
void wczytaj();
void ustaw(int wiek, char *p_imi
ę
, char *p_nazwisko);
void wypisz();
};
7
Programowanie obiektowe
Zało
ż
enia rozszerzaj
ą
ce dla klasy „dorosly”:
numer dowodu:
char *nr_dowodu;
prywatny dla klasy „dorosly”;
metody wczytaj, wypisz, ustaw:
dost
ę
pne publicznie;
odziedziczone z klasy bazowej;
Przykład – klasa dorosly
8
Programowanie obiektowe
Klasa „dorosly”
class dorosly: public osoba
{
char * nr_dowodu;
public:
void wczytaj ();
void wypisz ();
void ustaw(int wiek, char *p_imie, char *p_nazwisko,
char *nr_dow);
};
klasa pochodna
klasa bazowa
sekcja docelowa dla składowych
dziedziczonych
nowa składowa
metody odziedziczone ale przedefiniowane
Dziedziczenie
9
Programowanie obiektowe
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
public
Klasa_bazowa;
// sekcja
// private
// sekcja
// protected
// sekcja
// public
Klasa_bazowa
// sekcja
// private
// sekcja
// protected
// sekcja
// public
Klasa_pochodna
Dziedziczenie
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
10
Programowanie obiektowe
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
protected
Klasa_bazowa;
// sekcja
// pivate
// sekcja
// protected
// sekcja
// public
Klasa_bazowa
// sekcja
// pivate
// sekcja
// protected
// sekcja
// public
Klasa_pochodna
Dziedziczenie
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
11
Programowanie obiektowe
sekcja docelowa dla składowych dziedziczonych:
class Klasa_pochodna :
private
Klasa_bazowa;
// sekcja
// private
// sekcja
// protected
// sekcja
// public
Klasa_bazowa
// sekcja
// private
// sekcja
// protected
// sekcja
// public
Klasa_pochodna
Dziedziczenie
dziedziczone ale niedostępne w klasie
pochodnej; dostępne poprzez
dziedziczone funkcje nieprywatne
12
Programowanie obiektowe
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 prywatne stosujemy wtedy, gdy chcemy aby nie było
publicznego dost
ę
pu do odziedziczonych składników klasy
bazowej;
Nie podlegaj
ą
dziedziczeniu:
konstruktory
destruktory
Dziedziczenie
trzeba je zdefiniować w klasie pochodnej
13
Programowanie obiektowe
Dziedziczenie jest technik
ą
definiowania nowych klas;
Dziedziczenie jest jedn
ą
z najwspanialszych cech j
ę
zyków
programowania obiektowego;
Umo
ż
liwia:
oszcz
ę
dno
ść
pracy,
tworzenie hierarchii klas (hierarchia wprowadza naturalne
relacje mi
ę
dzy klasami),
tworzenie klas ogólnych (klas przeznaczonych do
dziedziczenia np. ogólna klasa „kolejka”)
Dziedziczenie - podsumowanie
14
Programowanie obiektowe
Przykład hierarchii klas
Dziedziczenie
samochód
osobowy
ciężarowy
autobus
Fiat
VW
opel
„wywodzi się”
15
Programowanie obiektowe
Zgodno
ść
typów:
class KlasaA
{
…
}
class KlasaB: public KlasaA
{
....
};
KlasaA a;
KlasaB b;
a = b; // ?
b = a; // ?
dozwolone, ale kopiuje si
ę
tylko tyle, ile jest w KlasaA
niedozwolone
Dziedziczenie - ograniczenia
zmienne obiektowe (obiekty)
16
Programowanie obiektowe
Zgodno
ść
typów:
KlasaA *ap;
KlasaB *bp;
ap = bp;
// ?
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;
poprawne (wyst
ą
pi polimorfizm)
niedozwolone
dozwolone (styl j
ę
zyka C)
dozwolone (styl j
ę
zyka C++)
Dziedziczenie
wska
ź
niki na obiekty
17
Programowanie obiektowe
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 przydziela mu si
ę
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”;
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)
18
Programowanie obiektowe
Konstruktor domy
ś
lny
funkcja składowa , któr
ą
mo
ż
na wywoła
ć
bez argumentów lub z
domy
ś
lnymi warto
ś
ciami;
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 domy
ś
lnego bezparametrowego;
kolejno
ść
wywoła
ń
konstruktorów:
klasy bazowe w kolejno
ś
ci deklaracji,
obiektowe składowe klasy w kolejno
ś
ci deklaracji,
ciało konstruktora;
Konstruktory
19
Programowanie obiektowe
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
deklaracji;
klasa::klasa(argumenty) : nazwa_stałej(warto
ść
pocz
ą
tkowa)
[ , nazwa_stałej(warto
ść
pocz
ą
tkowa)]
{
// ciało konstruktora
};
Konstruktory
20
Programowanie obiektowe
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) { };
};
Konstruktory
21
Programowanie obiektowe
Lista inicjalizacyjna konstruktora – przykład 2
class abc
{
const double stala;
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;
}
deklaracja konstruktora
Konstruktory
definicja konstruktora
22
Programowanie obiektowe
Lista inicjalizacyjna konstruktora
umo
ż
liwia inicjalizowanie zmiennych – tak jak w kodzie
konstruktora;
ponadto umo
ż
liwia inicjalizowanie pól: referencji oraz stałych;
kolejno
ść
inicjalizacji:
składowe w kolejno
ś
ci deklaracji,
ciało konstruktora;
Konstruktory
23
Programowanie obiektowe
Lista inicjalizacyjna konstruktora – przykład 3
class Odcinek
{
Punkt p1;
Punkt p2;
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);
};
Konstruktory
• obiekt p1 – inicjowanie listą
• obiekt p2 – inicjowanie konstruktorem (zadziałają dwa konstruktory!)
24
Programowanie obiektowe
ostatnia funkcja wykonywana przed usuni
ę
ciem obiektu;
nazwa taka, 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
Destruktory
25
Programowanie obiektowe
Destruktor klasy „Klasa”:
~Klasa() { };
lub
~Klasa();
…
Klasa::~Klasa() { };
Przykład:
~Punkt()
{cout << "Destruktor punktu x= " <<x << ", y= " << y << "\n"; }
~Odcinek()
{ cout << "Destruktor odcinka \n"; }
Destruktory
26
Programowanie obiektowe
Przykłady programowe
Konstruktory
Program 4.1a
Program 4.1b
C:\
C:\
27
Programowanie obiektowe
Konstruktor klasy pochodnej
Lista inicjalizacyjna konstruktora
class KlasaA {
public:
KlasaA (int t)
{ ...};
};
class KlasaB : public KlasaA
//deklaracja klasy pochodnej
{
public:
int x;
KlasaB (int par1, int par2) : KlasaA(par1), x(par2)
{ ...
};
};
Konstruktory
28
Programowanie obiektowe
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;
• 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;
Konstruktory
29
Programowanie obiektowe
Konstruktor klasy pochodnej - Przykład
class dorosly: public osoba
{
char * nr_dowodu;
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 (wiek, p_imie, p_nazwisko),
nr_dowodu(copy_string(nr_dow)) { };
};
Konstruktory
Program 4.2
30
Programowanie obiektowe
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
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
.
Konstruktory
31
Programowanie obiektowe
Konstruktor i destruktor
dla obiektów zdefiniowanych w blokach programowych:
konstruktor jest wywoływany, gdy sterowanie napotyka kod definicji
zmiennej – obiektu;
destruktory wywoływane po opuszczeniu bloku w kolejno
ś
ci
odwrotnej do konstruktorów;
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;
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;
Destruktory
32
Programowanie obiektowe
Przykłady programowe
Konstruktory i destruktory
Program 4.3
Program 4.4
33
Programowanie obiektowe
Konstruktorem kopiującym w danej klasie jest konstruktor, który można
wywołać z jednym argumentem typu referencja obiektu danej klasy:
klasa::klasa(klasa &)
Konstruktor kopiujący wprowadza obiekty identyczne z już istniejącymi,
czyli ich kopie (konstruowanie obiektu na podstawie wzoru).
Konstruktor kopiujący może być wywołany niejawnie:
1.
W sytuacji gdy do funkcji jest przez wartość przesyłany obiekt klasy X.
Wówczas tworzona jest kopia tego obiektu.
2.
W sytuacji kiedy funkcja zwraca przez wartość obiekt klasy X.
Wtedy także tworzona jest kopia obiektu.
To, że konstruktor kopiujący podaje obiekt kopiowany przez referencję daje
mu możliwość zmiany zawartości obiektu klasy!!
Konstruktor kopiujący
34
Programowanie obiektowe
Przyjrzyjmy się wywołaniu konstruktora klasy o nazwie klasa, którego
argumentem jest referencja do obiektu danej klasy
klasa::klasa(klasa&)
Taki konstruktor nie konstruuje nowego obiektu tylko tworzy kopię innego,
już istniejącego obiektu danej klasy.
Pozostałe argumenty konstruktora są domyślne.
Przykłady konstruktorów kopiujących:
X::X(X&)
lub
X::X(X&, float=3.1415, int=0)
Konstruktor kopiujący
35
Programowanie obiektowe
Nie można pominąć referencji w konstruktorze kopiującym, bo gdyby
konstruktor X wywoływał obiekty swojej klasy X przez wartość, czyli
wytwarzałby swoją kopię, to powstaje nie zamknięta pętla tworzenia kopii.
Konstruktor kopiujący może uszkodzić oryginał!!
Zabezpieczamy się przed taką sytuacją następująco:
X::X(const X&obiekt)
Teraz konstruktor X wie, że obiekt klasy X musi być wywoływany jako
stały. Konstruktor kopiujący jest domyślnie typu const, czyli nie może
zmienić sam siebie.
Konstruktor kopiujący
36
Programowanie obiektowe
Przykład programowy
Program 4.5
Konstruktor kopiujący
37
Programowanie obiektowe