dziedziczenie - cs.put.poznan.pl - dziedziczenie.pdf · tarka portier s relacja między typami...

51
Dziedziczenie

Upload: phungnhan

Post on 11-Aug-2019

223 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie

Page 2: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Sieci klas (dziedziczenia, typów)

Odwzorowanie modelu: abstrakcja generalizacji

Osoba

Związkowiec

Kierowca

Sekretarka

Portier

Prezes

Relacja między typami danych

Figura

jest (is a)

Kwadrat

obwód, pole, obróć, przesuń

obwód, pole, obróć, przesuń

Implementacja: dziedziczenie kodu i struktur danych

Osoba

dziedziczenie

Student

imię, nazwisko, wiek, płeć

uczelnia, rok_studiów, kierunek, nr_indeksu

Page 3: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Przykład sieci dziedziczenia

Osoba

nadklasa

specjalizacja

podklasa

Mężatka

generalizacja Relacja podtypu

AKO:a kind of (is a)

łańcuch

dziedziczenia

Panna

podklasa

nadklasa

Relacja podtypu

AKO

Kobieta

Nomenklatura

Klasa bazowa (Nadklasa): klasa, po której się dziedzi-czy

Klasa pochodna (Podklasa): klasa dziedzicząca

Generalizacja: abstrakcja polegająca na usunięciu bądź uogólnieniu pewnych cech z opisu klasy

Specjalizacja: dodanie lub uszczegółowienie pewnych cech klasy

Relacja podtypu – a kind of: określa zależność funk-cjonalną między klasą dziedziczoną i dziedziczącą; kla-sa dziedzicząca zawiera w sobie funkcjonalność klasy dziedziczonej. Relacja ta jest przechodnia.

Page 4: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Implementacja dziedziczenia

Osoba Nazwisko Płeć Adres Przeprowadź się

Kowalski Nazwisko: Kowalski

Płeć: Mężczyzna

Adres: Poznań, ul. Piwna 7

Pracownik Etat Awansuj Płaca Daj podwyżkę Zakład pracy Zmień pracę

Prezes Gabinet Sekretarka Zmień sekretarkę Samochód służbowy Zmień samochód

Morzy Nazwisko: Morzy

Płeć: Mężczyzna

Adres: Poznań, ul. Krucza 2

Etat: Portier

Płaca: 1200 zł

Zakład pracy: Hurtownia A&A

Tarzan Nazwisko: Tarzan

Płeć: Mężczyzna

Adres: Poznań, ul. Browarna 13

Etat: Prezes

Płaca: 12 000 zł

Zakład pracy: Hurtownia A&A

Gabinet: 100 m2

Sekretarka: 180 cm

Samochód służbowy: Volvo S80

Page 5: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wsparcie dla jednoczesnej otwartości i stabilności

modułów programowych

Wymaganie otwartości modułów jest konsekwencją po-trzeby rozwoju i utrzymania systemów informatycznych.

Wymaganie stabilności modułów jest wynikiem potrzeby osiągnięcia stabilizacji eksploatowanych systemów in-formatycznych.

Równoczesne spełnienie tych dwóch wymagań jest bar-dzo kłopotliwe.

Moduły programowe powinny być jednocześnie otwarte i stabilne.

Moduły programowe powinny być otwarte na dalszy rozwój: dodanie nowej funkcjonalności lub zmianę im-plementacji.

Eksploatowane moduły powinny być stabilne. Modyfi-kowanie poprawnie działającego modułu może spo-wodować jego błędne działanie.

Page 6: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Konsekwencje braku stabilności modułu

Współdzielenie kodu przez modyfikację

Dany jest system informatyczny SI1 obejmujący moduły programowe A, B, C i D.

B A C D

Chcemy wykorzystać moduł A do budowy nowego sys-temu SI2 składającego się z modułów X, Y, Z i zaadop-towanego modułu A. Chcąc utrzymywać tylko jedną wersję modułu A, rozszerzamy funkcjonalność modułu A, tak by spełniał on jednocześnie wymagania systemów SI1 i SI2.

B’ A’

Z

C’ D’

Y

X

SI1

SI2 propagacja modyfikacji

Moduł A stracił stabilność. Jego modyfikacja do postaci A’ może spowodować niepoprawne działanie systemu SI1 i wymusić modyfikacje modułów B, C i D.

Page 7: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Rozwiązania tradycyjne Utrzymywanie wielu wersji modułów

Współdzielenie kodu przez tworzenie wersji

Dla zapewnienia stabilności modułu A, budowy systemu SI2 zostanie wykorzystana nowa wersja modułu A.

SI2

utrzymywanie ścieżki powiązania

B A C D

A’

Z Y

X SI1

Równoległe utrzymywanie wielu wersji modułów jest kłopotliwe. Pewne zmiany muszą być aplikowane nieza-leżnie na kilku wersjach modułów, co wiąże się z więk-szą pracochłonnością i jest potencjalną przyczyną błę-dów niespójności.

Page 8: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Zastosowanie dziedziczenia

Współdzielenie kodu przez dziedziczenie

Dziedziczenie jako mechanizm współdzielenia imple-mentacji modułów programowych wspiera równocześnie otwartość i stabilność oprogramowania.

B A C D

A’

Z Y

X SI1

SI1

Współdzielenie implementacji

Wspólny kod modułów programowych powiązanych związkiem dziedziczenia jest łatwiejszy i mniej praco-chłonny w utrzymaniu.

Dziedziczenie klas jest silnym mechanizmem umożliwiającym konstruowanie kodu wielokrot-nego użytku

Page 9: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Własności relacji dziedziczenia

Czym klasa pochodna może się różnic od klasy bazowej?

1. Dodawanie nowych cech: metod i zmiennych 2. Redefinicja cech (przesłanianie – ang. overriding)

Redeklaracja kowariantna metod

Redeklaracja kowariantna zmiennych 3. Implementacja cech abstrakcyjnych

CZWOROKĄT

FIGURA

WIELOKĄT

PROSTOKĄT

obwód*

obrót(int)*

obwód++

wierzchołki

obwód+

obrót(int)+

TRÓJKĄT

obwód++

wysokość

cecha – definicja nowej cechy cecha* – definicja cechy abstrakcyjnej cecha+ – implementacja cechy abstrakcyjnej cecha++ – redefinicja cechy

obwód++

Page 10: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Składnia dziedziczenia w języku C++

class Osoba {

protected:

char nazwisko [Max];

char płeć;

unsigned wiek;

public:

Osoba (char*, char, unsigned);

Void ZmieńNazwisko(char*);

void DaneOsobowe( );

};

class Pracownik : public Osoba {

protected:

char Etat [Max]; //nowa cecha

unsigned płaca; //nowa cecha

public:

Pracownik (char*, char, unsigned, char*);

void Awansuj(char*); //nowa cecha

void DajPodwyżkę(unsigned); //nowa cecha

void DaneOsobowe( ); //redefinicja cechy

};

...

Osoba Morzy("Morzy",'M',45);

Morzy.DaneOsobowe();

Pracownik Buła("Buła",'M',38,"portier");

Buła.Awansuj("prezes");

Buła.ZmieńNazwisko("Tarzan");

Buła.DaneOsobowe();

W języku C++ nie są dziedziczone:

konstruktory i destruktory klasy

przeciążony operator=()

„przyjaciele” klasy

klasa bazowa

Page 11: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Kowariantna redeklaracja cech klasy (Eiffel)

Kowariantna redeklaracja cech klasy: specjalizacja typu atrybutu klasy - zgodna z relacją pod-

typu; specjalizacja typów parametrów wejściowych lub warto-

ści zwrotnej metod class OSOBA

małżonek OSOBA

małżeństwo (m: OSOBA) is

do

małżonek := m

end

… -- inne cechy

end -- class OSOBA

class KOBIETA inherit OSOBA

redefine małżonek, małżeństwo

-- kowariantna redeklaracja atrybutu

małżonek MĘŻCZYZNA -- kowariantna redeklaracja metody

małżeństwo (m: MĘŻCZYZNA) is

do

małżonek := m

end

… -- inne cechy

end -- class KOBIETA

Page 12: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Składanie metod

Użyteczny jest mechanizm, w którym definicja metody redefiniowanej może korzystać z kodu metody przesła-nianej.

class PRACOWNIK { // C++

public:

float Wylicz_płacę( );

...

class KIEROWNIK: public PRACOWNIK {

public:

float Wylicz_płacę( );

...

float KIEROWNIK::Wylicz_płacę( ) {

return 2,5*(PRACOWNIK::Wylicz_płacę());

}

class PRACOWNIK { // JAVA

public float Wylicz_płacę( );

...

class KIEROWNIK extends PRACOWNIK {

public float Wylicz_płacę( ){

return 2,5*(super.Wylicz_płacę());

}

Page 13: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie, a hermetyczność

Dostępność odziedziczonych elementów publicznych w obiektach podklasy.

1. Zachowanie relacji podtypu

Wszystkie publiczne elementy nadklasy muszą pozo-stać publiczne w jej podklasach.

Klasa B dziedziczy po klasie A

Funkcjonalność(A) Funkcjonalność(B)

2. Niezależność dziedziczenia i hermetyczności (postu-lowana)

Istnieją przypadki, w których interfejs publicznych me-tod podklasy nie obejmuje wszystkich publicznych metod nadklasy.

class Wielokąt {

public:

void DodajWierzchołek(Punkt);

float Pole( );

};

class Prostokąt: public Wielokąt {

...

};

...

Wielokąt *wp = new Prostokąt(p1, p2);

wp -> DodajWierzchołek(p3); //???

Page 14: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Niezależność dziedziczenia od hermetyczności

Innym przykładem zastosowanie niezależności dziedzi-czenia od hermetyczności jest wykorzystanie podklas jako zawężających widoków nadklasy.

Konto

Konto_ klient

public: otwórz zmień PIN wpłata wypłata blokada saldo zamknij

Konto_ księgowość

Konto_ zarząd

public: otwórz blokada saldo zamknij

public: zmień PIN wpłata wypłata saldo

public:

saldo

Całkowita niezależność interfejsów podklas z nadklasą oznacza pomylenie dziedziczenia klas z kompozycją klas.

Page 15: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Niezależność dziedziczenia od hermetyczności – składnia C++

Zależność relacji podtypu od hermetyczności

class Wielokąt {

public:

void DodajWierzchołek(Punkt);

float Pole( );

};

class Prostokąt: public Wielokąt {

private:

Wielokąt::DodajWierzchołek;

};

...

Wielokąt *wp = new Prostokąt(p1, p2); //błąd

class Konto {

public:

void Otwórz();

void Wpłata(float );

void Wypłata(float );

float Saldo();

void Blokada();

};

class KontoKlient: private Konto {

public:

Konto::Wpłata;

Konto:Wypłata;

Konto::Saldo;

};

Page 16: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie „przyjaciół” klasy

udostępnienie

cechy a

A

B1

B

propagacja

cechy a

A1

dziedziczenie

przyjaciół

? ?

class B; class A {

private:

int a;

friend class B;

};

class A1: public A { };

class B {

public:

void b1(A);

void b2(A1);

};

class B1: public B {

public:

void d(A);

};

void B::b1(A x){

x.a=0; } //OK, klasa B jest przyjacielem klasy A void B::b2(A1 x){

x.a=0; } //błąd, klasa B nie jest przyjacielem klasy A1 void B1::d (A x){

x.a=1 } //błąd, klasa B1 nie dziedziczy dostępu do A::a

Relacja przyjaźni nie jest dziedziczona po

żadnej ze stron

Page 17: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie klas w języku Java

W języku Java dziedziczone są wszystkie zmienne i me-tody nadklasy za wyjątkiem konstruktorów. Nie ma try-bów dziedziczenia prywatnego i chronionego. Dzięki te-mu relacja pod-typu jest zawsze zachowana w łańcuchu dziedziczenia.

class Point {

int x, y;

Point(int x, int y) {

this.x = x;

this.y = y; }

...

}

class ColoredPoint extends Point {

static final int WHITE=0, BLACK=1;

int color;

ColoredPoint(int x, int y) {

this(x, y, WHITE);

}

ColoredPoint(int x, int y, int color) {

//wywołanie konstruktora nadklasy – składanie metod

super(x, y); // Point(x,y) this.color = color;

}

...

}

Wywołanie konstruktora klasy bazowej musi mieć miej-sce w pierwszej linii kodu konstruktora klasy pochodnej.

Page 18: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Klasy abstrakcyjne

Klasy abstrakcyjne są to klasy, które nie mają kompletnej implementacji. W związku z tym, klasy te nie mogą mieć wystąpień. Mogą one służyć je-dynie jak pośredni etap dla dziedziczących po nich klas zawierających implementację cech abstrak-cyjnych.

Zdefiniowanie danej klasy jako abstrakcyjnej uniemożliwia tworzenie wystąpień tej klasy.

Własna implementacja klasy abstrakcyjnej wiąże się z występowaniem błędów w czasie wykonywa-nia programów:

class figura {

public:

virtual void obróć (int)

{ error (" klasa abstrakcyjna" );

virtual void rysuj ( )

{ error (" klasa abstrakcyjna" );

};

figura f; // nieprzydatny obiekt

f.obróć(45); // błąd

Page 19: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Klasy abstrakcyjne w C++

Składnia języka C++ umożliwia definiowanie klas abstrakcyjnych. Kompilator języka uniemożliwia tworzenie zmiennych (typów funkcji i metod oraz parametrów wejściowych funkcji i metod), których typem jest klasa abstrakcyjna.

class figura {

public:

virtual void obróć (int) = 0;

virtual void rysuj ( ) = 0;

// klasa nie może zawierać definicji metod obróć i rysuj };

figura f; //błąd składniowy

//wystąpienie klasy abstrakcyjnej

figura f1( ); // błąd składniowy - jw.

void f2(figura); // błąd składniowy - jw. figura *fp; // OK

figura &fr; // OK

Klasy pochodne klasy abstrakcyjnej powinny zawierać implementację abstrakcyjnych cech klasy.

class prostokąt : public figura {

public:

virtual void obróć (int);

// przesłania figura::obróc

virtual void rysuj ( );

// przesłania figura::rysuj

}

Page 20: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Interfejsy

Język Java oprócz klas abstrakcyjnych, obejmuje dodatkowo pojęcie interfejsu, który może być trak-towany jako szczególna klasa abstrakcyjna, która w ogóle nie posiada implementacji.

interface Colorable {

void setColor(int color);

}

Definicja interfejsu nie może zawierać:

elementów prywatnych

definicji zmiennych obiektów

metod typu final

Interfejsy powinny implementowane przez klasy. Pojedyncza klasa może implementować wiele in-terfejsów. Interfejs może reprezentować po-jedynczy aspekt klasy. class Colored implements Colorable {

int setColor(int color) {...};

}

Interfejsy mogą być powiązane siecią dziedzicze-nia o topologii zbioru acyklicznych grafów.

Page 21: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Topologia sieci dziedziczenia

Dziedziczenie jednokrotne (SmallTalk 80, C#, klasy w języku Java) - każda klasa ma co najwy-żej jedną nadklasę. Sieć klas ma kształt hierar-chii.

Dziedziczenie wielokrotne (C++, Eiffel, interfejsy w języku Java) - klasy mogą dziedziczyć po wie-lu nadklasach. Sieć klas ma kształt grafu acy-klicznego skierowanego.

Sieć klas może być rozłączna (C++) lub być nie-podzielna i mieć wyróżniony wierzchołek, który jest korzeniem sieci (SmallTalk 80, Java, C#).

Page 22: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Globalna struktura dziedziczenia w języku Eiffel

Rozszerzenie sieci klas o dwie uniwersalne klasy syste-mowe: ANY i NONE.

ANY

NONE

Klasy zdefiniowane przez użytkowników

Każda klasa dziedziczy po klasie ANY – możliwość zdefiniowania wspólnych cech wszystkich klas

Wszystkie klasy są generalizacją klasy NONE – klasa wartości nieokreślonych lub pustych (void, nill, null).

Page 23: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie interfejsów, a dziedziczenie klas w języku Java

Topologie związków dziedziczenia między klasami i interfejsami w języku Java są odmienne.

Klasy mogą dziedziczyć bezpośrednio po tylko jednej nadklasie. Topologia sieci związków dziedziczenia klas ma kształt drzewa o jednym wyróżnionym korzeniu reprezentującym klasę Object.

Interfejsy mogą dziedziczyć bezpośrednio po wielu innych interfejsach. Topologia sieci związków dziedziczenia interfejsów ma kształt zbioru grafów acyklicznych skierowanych.

Związki implementacji między interfejsami i klasami maja topologię grafów acyklicznych skierowanych. Pojedyncza klasa może imple-mentować wiele interfejsów.

Sieci dziedziczenia klas i interfejsów oraz imple-mentacji tworzą jedną sieć podtypów.

Page 24: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie wielokrotne (C++)

W języku C++ klasy mogą bezpośrednio dziedzi-czyć po wielu nadklasach. Brak mechanizmu wie-lokrotnego dziedziczenia wymaga wielokrotnej im-plementacji i utrzymania tych samych cech róż-nych klas.

Student

StudentPracujący

Pracownik

class Pracownik {

...

float płaca;

char *etat;

... };

class Student {

...

char *uczelnia;

int rokStudiów;

float średniaOcen;

... };

class StudentPracujący : public Pracownik,

public Student { ... };

Page 25: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie wielokrotne (C++)

Klasa dziedzicząca może dziedziczyć po różnych klasach cechy o takich samych nagłówkach. Meto-dy lub zmienne o takich samych deklaracjach ale pochodzące z różnych klas są rozróżniane po miejscu ich zdefiniowania.

Student

StudentPracujący

Pracownik

class Pracownik {

public:

void dane_kontaktowe(); };

...

class Student {

void dane_kontaktowe(); }; ...

class StudentPracujący : public Pracownik,

public Student { }; ...

StudentPracujący sp;

sp.Student::dane_kontaktowe();

sp.Pracownik::dane_kontaktowe();

Page 26: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wielokrotne dziedziczenie z tego samego źródła

class Osoba {

protected:

char *nazwisko;

...

public:

void Nazwisko(char*);

void wiek(int);

...

};

class Pracownik : public Osoba{ ... };

class Student : public Osoba { ... };

class StudentPracujący : public Pracownik,

public Student { ... };

StudentPracujący sp(...);

sp.Nazwisko("Tarzan"); // niejednoznaczne wywołanie

sp.Student::Nazwisko("Tarzan"); // OK

sp.Pracownik::Nazwisko("Kowalski"); // OK

-- student sp ma dwa niezależne nazwiska

Student

StudentPracujący

Pracownik

Osoba

Pracownik::Nazwisko Student::Nazwisko

Page 27: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Specyfika C++ dziedziczenie wirtualne

a) dziedziczenie zwykłe b) dziedziczenie wirtualne

skonsolidowany obszar pamięci

wskaźniki na poszczególne składowe obiektu

class Osoba {...};

class Pracownik : public virtual Osoba {...};

class Student : public virtual Osoba {...};

class StudPrac:public Student,public Pracownik {...};

StudentPracujący sp(...);

sp.Nazwisko("Tarzan"); // jednoznaczne wywołanie

// student sp ma jedno nazwisko

Pracownik:wiek

Pracownik:nazwisko

Pracownik:imię

Student:wiek

Student:nazwisko

Student:imię

Student:rok

Student:uczelnia

Pracownik:firma

Pracownik:wiek

nazwisko

imię

wiek

vbase

etat

płaca

uczelnia

rokStudiów

vbase

vbazse

Page 28: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Polimorfizm

Polimorfizm umożliwia podstawienie pod daną zmienną różnych typów obiektów. Typ podstawianego obiektu

musi występować w relacji jest z typem zmiennej.

Podstawiany obiekt nie jest poddawany konwersji!!! Za-chowuje on pełną funkcjonalność zgodą z jego własnym typem.

Taki rodzaj podstawienia jest nazywany podstawieniem polimorficznym; a zmienne są nazywane zmiennymi polimorficznymi. Zmiennymi polimorficznymi mogą być parametry wejściowe metod.

class Wielokąt {...);

class Prostokąt extends Wielokąt {...);

class Trójkąt extends Wielokąt {...);

Wielokąt w; // zmienna polimorficzna

Prostokąt pr = new Prostokąt(p1, p2);

Trójkąt tr = new Trójkąt (p3, p4, p5);

// podstawienia polimorficzne

w = pr; // podstaw prostokąt pod wielokąt

w = tr; // podstaw trójkąt pod wielokąt

Typowym zastosowaniem polimorfizmu są polimorficz-ne struktury danych

// polimorficzna struktura danych

Wielokąt [] tw;

// podstawienia polimorficzne

tw[0] = pr;

tw[1] = tr;

Page 29: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Podstawienie polimorficzne w C++

W języku programowania C++ poprawne są następujące typy podstawień polimorficznych:

Podstawienie pod wskaźnik klasy X adresu obiek-tu, który jest wystąpieniem publicznej podklasy kla-sy X.

Wielokąt *wp;

// klasa Trójkąt jest podklasą klasy Wielokąt

Trójkąt t(p1, p2, p3);

wp = &t;

Podstawienie pod zmienną referencyjną klasy X referencji na obiekt, który jest wystąpieniem pu-blicznej podklasy klasy X.

Trójkąt t(p1, p2, p3);

Wielokąt &wp = t;

Niemożliwe jest bezpośrednie podstawienie pod zmienną klasy X obiektu, który jest wystąpieniem podklasy klasy X.

Wielokąt w(p4, p2, p5, p6);

Trójkąt t(p1, p2, p3);

w = t; // utworzenie kopii wyniku rzutowania obiektu

Page 30: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wiązanie dynamiczne

Wiązanie – operacja przypisywania nazwom progra-mu źródłowego - wartości

WyliczObwód(prostokąt1) 6aaf:99bd

prostokąt1 9bb4:1240

prostokąt.WyliczObwód() 6900:1234

Wiązanie statyczne (wczesne) – wiązanie w czasie kompilacji

Trójkąt t = new Trójkąt(p1, p2, p3);

/* statyczne przypisanie komunikatowi obwód kodu me-

tody obwód z klasy Trójkąt wynikającej z typu zmiennej */

float = t.obwód();

Wiązanie dynamiczne (późne – ang. late binding) –wiązanie nazw komunikatów dla zmiennych polimor-ficznych w czasie działania programu. Polega na dynamicznym wyborze metody właściwej dla obiektu przypisanego zmiennej polimorficznej.

Figura f;

// podstawienie polimorficzne

f = New Trójkąt(p1, p2, p3);

/* dynamiczne przypisanie komunikatowi obwód kodu

metody obwód z klasy Trójkąt mimo, że z typu zmien-

nej f wynikałaby metoda klasy figura */

float = f.obwód();

Page 31: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wiązanie statyczne

Wiązanie statyczne nie gwarantuje proporcjonal-ności modyfikacji

class figura {...};

class Kwadrat {...};

class Trójkąt {...};

class Koło {...};

figura *lista_figur;

...

while (lista_figur.next != pusta) {

//przesuń kolejną figurę if lista_figur->typ = kwadrat

lista_figur-> przesuńKwadrat(x,y);}

if lista_figur->typ = koło

lista_figur-> przesuńKoło(x,y);}

...

while (lista_figur.next != pusta) {

//obróć kolejną figurę if lista_figur ->typ = kwadrat

lista_figur -> obróćKwadrat(x,y);}

Modyfikacja modułu A przez dodanie nowej klasy figur:

class Romb {...};

- propaguje się do wszystkich modułów przetwarzają-cych figury.

moduł A

moduł B

moduł C

class Romb {…};

Page 32: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wiązanie dynamiczne

Wiązanie dynamiczne ułatwia utrzymanie progra-mów ograniczając zasięg modyfikacji

class figura {...};

class Kwadrat {...};

class Trójkąt {...};

class Koło {...};

figura *lista_figur;

...

while (lista_figur.next != pusta) {

//przesuń kolejną figurę lista_figur -> przesuń(x,y);}

...

while (lista_figur.next != pusta) {

//obróć kolejną figurę lista_figur -> obróć(x,y);}

Modyfikacja modułu A przez dodanie nowej klasy figur:

class Romb {...};

nie wymaga modyfikacji kodu modułów B i C. Komunika-ty przesuń i obrót zostań dynamicznie przypisane do ko-du metod klasy Romb.

moduł A

moduł B

moduł C

class Romb {…};

Page 33: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wiązanie statyczne zmiennych polimorficznych (C++)

Domyślnym sposobem wiązania zmiennych polimorficz-nych w C++ jest wiązanie statyczne. Takie podejście jest niebezpieczne !!! Może ono powodować niewła-ściwe działanie programów. Wiązanie statyczne można stosować w celu zwiększenia efektywności działania programów jedynie w sytuacjach, gdy daje taki sam wynik jak wiązanie dynamiczne (rezygnacja z polimor-fizmu).

class Pracownik {

protected:

char Nazwisko [MaxN];

float stawka;

float płaca;

public:

void wylicz_płacę( );

};

class Kierownik : public Pracownik {

protected:

float dodatek_funkcyjny;

public:

void wylicz_płacę( );

};

// związanie statyczne Pracownik *pp= new Kierownik();

/* błędne wyliczenie płacy dla kierownika: Pracownik::wylicz_płacę() */

pp-> wylicz_płacę ( );

Page 34: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Implementacja wczesnego wiązania w C++

class Osoba {

char Imię [MaxI];

char Nazwisko [MaxN];

unsigned wiek;

public:

void print( );

};

class Student : public Osoba {

char Uczelnia [MaxU];

unsigned rokStudiów;

public:

void print( );

};

Osoba *op;

Student *sp = new Student();

sp -> print( ); // Student::print()

op = sp; //op i sp wskazują na ten sam obiekt

op -> print( ); // Osoba::print()

/* zmienna op umożliwia dostęp jedynie do osobowych

cech studenta */

Uaktywnienie metody print() zdefiniowanej w klasie Student

Uaktywnienie w obiekcie klasy Student przesłoniętej metody print() zdefiniowanej w klasie Osoba !!!

Page 35: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Wiązanie dynamiczne w C++

Dynamiczne wiązanie w C++ nie jest wiązaniem do-myślnym. Jest realizowane za pomocą mechanizmu funkcji wirtualnych.

class Pracownik {

protected:

char Nazwisko [MaxN];

float stawka;

float płaca;

public:

virtual void wylicz_płacę( );

};

class Kierownik : public Pracownik {

protected:

float dodatek_funkcyjny;

public:

void wylicz_płacę( );

};

// wiązanie dynamiczne

Pracownik *pp= new Kierownik();

// poprawne wyliczenie płacy dla kierownika

pp-> wylicz_płacę ( );

// Kierownik::wylicz_płacę()

Page 36: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Późne wiązanie w łańcuchu dziedziczenie

class PRACOWNIK {

public:

virtual float Wylicz_płacę( );

protected:

virtual float Wyznacz_podstawę( );

virtual float Wylicz_premię( );

...

}

float PRACOWNIK:: Wylicz_płacę( ) {

float s = this-> Wyznacz_podstawę( );

s += this-> Wylicz_premię( );

...

}

class KIEROWNIK: public PRACOWNIK {

protected:

float Wyznacz_podstawę ( ); //redefinicja

float Wylicz_premię ( ); //redefinicja

}

...

Kierownik Tarzan("Tarzan", 3500, 10);

float pensja = Tarzan.Wylicz_płacę( );

Tarzan Wylicz_płacę()

Wylicz_premię()

Pracownik

Kierownik

Wyznacz_podstawę()

"this" jako zmienna polimorficzna

Page 37: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Implementacja dynamicznego wiązania w C++

class Osoba {

char imię [MaxI];

char nazwisko [MaxN];

unsigned wiek;

public:

virtual void print( );

};

class Student : public Osoba {

char uczelnia [MaxU];

int rok;

public:

void print( );

};

Osoba *op;

Student *sp = new Student("Tarzan","PP");

op = sp;

op->print(); //Student::print()

Powyższe wywołanie będzie realizowane jako:

((op->vftbl[0]))(op)

tabela z adresami

kodu wirtualnych metod

vftbl

imię

nazwisko

wiek

uczelnia

rok

&Student::print() op

funkcjonalność

klasy Osoba

Page 38: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Implementacja wielokrotnego dziedziczenia w C++

class Student {

int indeks;

public:

virtual int indeks( );

...

};

class Pracownik {

char* etat;

public:

virtual char* etat( );

...

};

class StudentPrac : public Student, public Pracownik {

};

StudentPrac *spp;

*spp = new StudentPrac("Tarzan","prezes");

adres metody

&Student::indeks() spp

funkcjonalność

klasy Student

0

przesunięcie ciała obiektu

Student vftbl

indeks

uczelnia

rokStudiów

etat

płaca

Pracownik vftbl

funkcjonalność

klasy Pracownik

spp + delta PS

&Pracownik::etat() +delta PS

&Pracownik::płaca() +delta PS

W klasie StudentPrac kod metod odziedziczonych z klasy Pracownik ma nieak-tualne informacje o lokaliza-cji zmiennych etat i płaca.

Page 39: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Podstawienia polimorficzne wystąpień klas dziedziczących

w sposób wirtualny

class Osoba {...};

class Pracownik : public virtual Osoba {...};

class Student : public virtual Osoba {...};

Student *sp = new Student();

Osoba *op = sp;

Dwa wskaźniki na ten sam obiekt maja różne war-tości: op != sp.

nazwisko

imię

wiek

vbase

etat

płaca

uczelnia

rokStudiów

vbase

vbazse

sp

op

Page 40: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dynamiczna identyfikacja typu

Podstawienia polimorficzne ograniczają funkcjonalność obiektu do interfejsu typu zmiennej polimorficznej. W in-terfejsie zmiennej polimorficznej nie występują komuni-katy metod specyficznych dla podklas jej typu. W pew-nych sytuacjach może być potrzebny dostęp do cech obiektów niedostępnych poprzez interfejs zmiennej po-limorficznej.

Void DanePersonalne(Osoba* pos) {

cout << pos->podajPesel();

// jeżeli to student dodaj informacje o studencie // jak dynamicznie ustalić typ ? cout << pos->podajŚrednią(); //błąd

// jeżeli to pracownik dodaj informacje o pracowniku // jak dynamicznie ustalić typ ? cout << pos->podajEtat(); //błąd

}

Zmienna pos jest typu Osoba, w jej interfejsie nie ma

metod specyficznych dla pracowników i studentów.

W powyższym programie niezbędne jest ustalenie w trakcie działania programu klasy obiektu podstawionego pod zmienną polimorficzną.

Page 41: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Języki obiektowe ze zintegrowaną siecią klas

Klasy Systemowe (Metaclass, Class, Object, itp.) posia-dają funkcjonalność umożliwiającą dynamiczną identyfi-kację własności obiektów i klas: nazwy i typy atrybutów, nazwy i nagłówki metod, nazwę klasy obiektu, nazwę nadklasy obiektu, klasę jako obiekt, itp.

Przykłady w języku Java

Systemowa funkcjonalność obiektów i klas zdefiniowana w klasie Class:

boolean isInstance(Object obj)

String getName()

Method getMethod(String name, Class[] parameterTypes)

public Field[ ] getFields()

boolean isInstance(Object ClassObject)

Class getSuperclass()

Systemowa funkcjonalność obiektów i klas zdefiniowana w klasie Object:

Class getClass() // wynikiem jest obiekt “Class”

String toString() // serializacja obiektu

Page 42: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Mechanizm refleksji w języku Java

Mechanizm refleksji umożliwia tworzenia, w wyjątkowych i wymagających takich rozwiązań wypadkach, bardziej ela-stycznego kodu programów.

// dany jest duży i zmienny zbiór klas: Student, Pracownik, itd // rozwiązanie bez mechanizmu refleksji

if (s.equals("Student")) {

Student st = new Student(x,y,z);

st.zróbCoś();}

else if (s.equals("Pracownik")) {

Pracownik pr = new Pracownik(x,y,z);

Pr.zróbCoś();}

... // tyle rozwidleń ile różnych klas

// bardziej elastyczne rozwiązanie z mechanizmem refleksji

Class kl = s.getClass(); // kl jest obiektem - klasą Object o = kl.newInstance();

// korzystamy z obiektu kl jako fabryki obiektów Method mt = kl.getMethod("zróbCoś", null);

// mt jest obiektem – metodą mt.invoke(o, null); //wywołanie metody ...

Dynamiczna identyfikacja typu w wypadku podstawień polimorficznych

Osoba os; //zmienna polimorficzna ...

if os.isInstance(Student) { // os jest studentem? Student s = (Student)os;

s.średnia(); } //operacja właściwa dla studentów

Page 43: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dynamiczna identyfikacja typu w języku C++

Bibioteka: RTTI (Run Time Type Information)

#include <typeinfo>

void DanePersonalne(Osoba* pos) {

// część kodu odwołująca się do funkcjonalności osób

cout<<pos->Pesel();

// część kodu odwołująca się o funkcjonalności specyficznej

if (typeid(*pos)==typeid(Student))

// jeżeli to student podaj informacje o studencie

Student* pst=dynamic_cast<Student*>(pos);

cout << pst->ŚredniaOcen();

if (typeid(*pos)==typeid(Pracownik))

// jeżeli to pracownik dodaj informacje o pracowniku

Pracownik* ppr=dynamic_cast<Pracownik*>(pos);

cout << ppr->Etat();

}

Operator rzutowania dynamic_cast dokonuje konwer-

sji polimorficznego wskaźnika pos na wskaźnik na pod-

typ. Następuje zmiana typu wskaźnika wskazującego na ten sam obiekt.

Mimo, że zmienne pos i pst wskazują na ten sam obiekt,

to typ tych zmiennych jest różny.

Page 44: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dziedziczenie, a operacje tworzenia i usuwania obiektów Tworzenie wystąpień klas pochodnych C++

W języku C++ konstruktory obiektów nie mogą być prze-słaniane. W związku z tym obiekty, które są wystąpie-niami klas pochodnych muszą być inicjowane przez se-kwencję wywołań konstruktorów klas wzdłuż łańcucha dziedziczenia począwszy od korzenia grafu dziedzicze-nia. Potrzebny jest do tego mechanizm przekazywania parametrów aktualnych do tych konstruktorów.

class Osoba {

private:

char *nazwiskoOsoby;

public:

Osoba(char *nazwisko);

...};

Osoba::Osoba(char *nazwisko) {

strcpy(nazwiskoOsoby, nazwisko);

}

class Student : public Osoba {

private:

char *NazwaUczelni;

public:

Student(char *uczelnia, char *nazwisko);

...};

Student::Student(char *uczelnia, char *nazwisko):

Osoba(nazwisko) {

strcpy(NazwaUczelni, uczelnia);

} wywołanie konstruktora klasy bazowej

Page 45: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Dynamiczne wiązanie destruktorów

Destruktory wystąpień klas pochodnych są wywoływane w odwrotnej kolejności niż konstruktory, to jest począw-szy od destruktora klasy obiektu, poprzez destruktory klas bazowych, do destruktora klasy, która jest korze-niem grafu klas.

Żeby wywołać destruktor klasy obiektu podstawionego pod zmienną polimorficzną musi być on (destruktor) wią-zany dynamicznie.

class Osoba {

public:

virtual ~Osoba(); // destruktor dynamiczny ...};

class Student : public Osoba {

private:

ListaPubów *Pub;

public:

~Student();

...};

Student::~Student(){

delete [] ListaPubów;

}

Osoba *op = new Student("Tarzan", "PP");

...

delete op; //wywołanie destruktora ~Student

Page 46: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Ograniczenia polimorfizmu

Zmieniony zakres dostępności odziedzi-czonych cech klasy

class Wielokąt {

public:

void DodajWierzchołek(Punkt);

float Pole( );

};

class Prostokąt: public Wielokąt {

private:

Wielokąt::DodajWierzchołek;

};

… Wielokąt *wp

Prostokąt p = new Prostokąt(p1, p2);

wp = p; // błąd kompilacji

// podstawienie polimorficzne jest zabronione

Dodatkowe reguły statycznego typowania danych

(R1) Zabronione są polimorficzne wywołania metod o zmienionym zakresie dostępności odziedzi-czonych cech klasy

(R2) Zabronione są polimorficzne wywołania metod redeklarowanych kowariantnie

Page 47: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Ograniczenia polimorfizmu

Specjalizacja argumentów

Redeklaracja kowariantna cech wzdłuż łańcucha dziedziczenia

class STUDENT feature

współlokator: STUDENT

przydziel (inny: STUDENT) is

do współlokator := inny end

end -- class STUDENT

class DZIEWCZYNA inherit STUDENT

redefine współlokator, przydziel end

współlokator: DZIEWCZYNA

przydziel (inny: DZIEWCZYNA) is

do współlokator := inny end

end -- class DZIEWCZYNA

s: STUDENT; d: DZIEWCZYNA; c: CHŁOPAK

!! c.make(…); !!d.make(…)

-- tworzenie obiektów DZIEWCZYNA i CHŁOPAK

s : = d; -- błąd kompilacji

-- podstawienie polimorficzne jest niedozwolone -- żeby uniknąć błędu typu parametru wejściowego

s.przydziel(c); -- chłopak w pokoju dziewczyn

Page 48: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Metodyka stosowania dziedziczenia

“Mieć, czy być”

Model obiektowy oferuje dwa różne rodzaje powiązań międzymodułowych:

związek zawierania - ma (ang. has),

związek dziedziczenia - jest (ang. is a).

jest

B

A’

Ama

W pewnych szczególnych sytuacjach rozróżnienie to nie jest oczywiste

class INFORMATYK_1 inherit INŻYNIER feature …

end -- class INFORMATYK

class INFORMATYK_2 feature inżynier_we_mnie: INŻYNIER …

end -- class INFORMATYK

Page 49: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Kryterium wyboru

jest

INŻYNIER

maINFORMATYK

POETA

POWOŁANIE

HYDRAULIK

jest

INŻYNIER

INFORMATYKARCHITEKT

ELEKTRYK

Reguła zmienności

Nie używaj dziedziczenia do opisu relacji jest, jeżeli

relacja ta jest zmienna w czasie.

Reguła polimorfizmu

Użyj dziedziczenia do opisu relacji jest, jeżeli wystą-

pienia klasy mają być używane w sposób polimorficzny.

Page 50: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

Klasyfikacja zastosowań dziedziczenia

(Klasa B dziedziczy po klasie A)

1. Dziedziczenie opisujące związki występujące w modelu

1.1 Relacja podzbioru – zbiór wystąpień klasy B nale-ży do zbioru wystąpień klasy A i inne podzbiory kla-sy A są rozłączne z B: prostokąty -> wielokąty; ssa-ki -> kręgowce; pracownik -> osoba.

1.2 Perspektywa – wystąpienia klasy B ujawniają jedy-nie pewne aspekty wystąpień klasy A: pracow-nik_płace -> pracownik.

1.3 Ograniczenia - wystąpienia klasy B są wystąpie-niami klasy A, które spełniają pewne dodatkowe ograniczenia (dodatkowe niezmienniki nie występu-jące w klasie A): kwadraty -> prostokąty, okręgi -> elipsy.

1.4 Rozszerzenie – klasa B wprowadza nowe cechy, nie występujące w A, przy czym klasa A nie jest klasą abstrakcyjną: cząstka(masa, prędkość) -> punkt.

2. Dziedziczenie opisujące implementację

2.1 Konkretyzacja – klasa A opisuje ogólny typ da-nych, klasa B zawiera jego reprezentację: stos_jako_lista -> stos_abstrakcyjny.

2.2 Współdzielenie – abstrakcyjna klasa A zawiera pewne ogólne cechy wykorzystane w klasie B: licz-by -> wielkości_porównywalne (operacje >, >=, <, itd.).

Page 51: Dziedziczenie - cs.put.poznan.pl - Dziedziczenie.pdf · tarka Portier s Relacja między typami danych ra jest ( is a) t ,, ń,, ń Implementacja: dziedziczenie kodu i struktur danych

2.3 Implementacja – klasa A oferuje klasie B zbiór cech niezbędnych do jej implementacji.

2.4 Usługi - klasa A przekazuje klasie B zbiór użytecz-nych usług: klasa_użytkownika -> wyjątki.

3. Wariacje klas

3.1 Wariacje funkcjonalne – klasa B jest modyfikacją klasy A polegającą na redefinicji wybranych funkcji. Ogólna semantyka klasy A pozostaje niezmieniona.

3.2 Wariacje strukturalne - klasa B jest modyfikacją klasy A polegającą na redefinicji struktury klasy. Ogólna semantyka klasy A pozostaje niezmieniona.

3.3 Dematerializacja – klasa B przesłania efektywne (zaimplementowane) cechy klasy A przez cechy abstrakcyjne.