Wykład 4

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

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

Dziedziczenie

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

Dziedziczenie

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

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 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

Przykład – klasa osoba

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

Przykład – klasa dorosly

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

Dziedziczenie

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

Dziedziczenie

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

Dziedziczenie

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

Dziedziczenie

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

Dziedziczenie

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 - podsumowanie

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

Dziedziczenie

Przykład hierarchii klas

samochód

„wywodzi się”

osobowy

cięŜarowy

autobus

Fiat

VW

opel

Programowanie obiektowe

14

Dziedziczenie - ograniczenia

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

Dziedziczenie

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

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:

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

Konstruktory

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

Konstruktory

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

Konstruktory

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

Konstruktory

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

Konstruktory

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

Destruktory

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

Destruktory

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

Konstruktory

Przykłady programowe

Program 3.1a

C:\

C:\

Program 3.1b

Programowanie obiektowe

25

Konstruktory

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

Konstruktory

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

Konstruktory

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

Konstruktory

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

Konstruktory i destruktory

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

Konstruktory i destruktory

Przykłady programowe

C:\

Program 3.3

C:\

Program 3.4

Programowanie obiektowe

31

Programowanie obiektowe

32