Kurs języka C++ – wykład 6 (7.04.2014)

20
KURS JĘZYKA C++ – WYKŁAD 6 (7.04.2014) Polimorfizm

description

Kurs języka C++ – wykład 6 (7.04.2014). Polimorfizm. Spis treści. Metody wirtualne Implementacja polimorfizmu Wczesne i późne wiązanie metod wirtualnych Klasy abstrakcyjne Klasa pair Klasa vector. Składowe funkcje wirtualne. - PowerPoint PPT Presentation

Transcript of Kurs języka C++ – wykład 6 (7.04.2014)

Page 1: Kurs języka C++  – wykład 6 (7.04.2014)

KURS JĘZYKA C++ – WYKŁAD 6 (7.04.2014)

Polimorfizm

Page 2: Kurs języka C++  – wykład 6 (7.04.2014)

SPIS TREŚCI

Metody wirtualne Implementacja polimorfizmu Wczesne i późne wiązanie metod wirtualnych Klasy abstrakcyjne Klasa pair<> Klasa vector<>

Page 3: Kurs języka C++  – wykład 6 (7.04.2014)

SKŁADOWE FUNKCJE WIRTUALNE

Składowe funkcje wirtualne pozwalają na przedefiniowanie w każdej klasie pochodnej funkcji składowych zadeklarowanych w klasie bazowej.

Poprzez funkcje wirtualne w programie zapewnione jest wywołanie metody najlepiej odpowiadającej obiektowi.

Składowe funkcje wirtualne należy opatrzyć deklaratorem virtual (wewnątrz klasy).

W definicji metody wirtualnej poza klasą nie używa się deklaratora virtual.

Page 4: Kurs języka C++  – wykład 6 (7.04.2014)

SKŁADOWE FUNKCJE WIRTUALNE Przykład deklaracji klas z metodami wirtualnymi i zwykłymi:

class bazowa{public: void opis_zwykly (); virtual void opis_wirtualny ();};

class pochodna: public bazowa{public: void opis_zwykly (); virtual void opis_wirtualny ();};

Page 5: Kurs języka C++  – wykład 6 (7.04.2014)

SKŁADOWE FUNKCJE WIRTUALNE

Przykład definicji metod wirtualnych i zwykłych:

void bazowa::opis_zwykly(){ cout << "bazowa::opis_zwykly()" << endl; }void bazowa::opis_wirtualny(){ cout << "bazowa::opis_wirtualny()" << endl; }

void pochodna::opis_zwykly(){ cout << "pochodna::opis_zwykly()" << endl; }void pochodna::opis_wirtualny(){ cout << "pochodna::opis_wirtualny()" << endl; }

Page 6: Kurs języka C++  – wykład 6 (7.04.2014)

SKŁADOWE FUNKCJE WIRTUALNE

Przykład użycia metod wirtualnych i zwykłych:

bazowa *a = new bazowa();a->opis_zwykly();a->opis_wirtualny();// bazowa::opis_zwykly()// bazowa::opis_wirtualny()

bazowa *b = new pochodna();b->opis_zwykly();b->opis_wirtualny();// bazowa::opis_zwykly()// pochodna::opis_wirtualny()

Page 7: Kurs języka C++  – wykład 6 (7.04.2014)

SKŁADOWE FUNKCJE WIRTUALNE

Funkcja wirtualna musi być zdefiniowana dla klasy, w której po raz pierwszy została zadeklarowana.

Funkcji wirtualnej można używać nawet wtedy, gdy z jej klasy nie wyprowadzi się żadnej klasy pochodnej.

Klasa pochodna, która nie potrzebuje specjalnej wersji funkcji wirtualnej, nie musi jej dostarczać.

Funkcja w klasie pochodnej z tą samą nazwą i z tą samą listą argumentów co funkcja wirtualna w klasie podstawowej nadpisuje (ang. override) wersję funkcji wirtualnej z klasy bazowej.

Page 8: Kurs języka C++  – wykład 6 (7.04.2014)

POLIMORFIZM

Uzyskanie zachowania się funkcji adekwatnego do typu obiektu nazywa się polimorfizmem (ang. polymorphism).

Klasa z funkcjami wirtualnymi nazywa się klasą polimorficzną.

Aby zachowanie obiektu było polimorficzne należy się do niego odnosić za pomocą wskaźnika albo referencji.

Dzięki polimorfizmowi programy stają się rozszerzalne (ang. extensibility) – modyfikacja kodu polega na dodaniu nowej klasy bez potrzeby zmian w kodzie istniejącym.

Page 9: Kurs języka C++  – wykład 6 (7.04.2014)

IMPLEMENTACJA ZACHOWAŃ POLIMORFICZNYCH

Obiekty klas polimorficznych mają dodatkowe pole identyfikujące typ obiektu.

Decyzję o wyborze funkcji do wykonania podejmuje się w trakcie działania programu (jest to tak zwane późne wiązanie, w przeciwieństwie do zwykłych funkcji gdzie obowiązuje wczesne wiązanie).

Każda klasa polimorficzna posiada swoje miejsce w tablicy metod wirtualnych.

Polimorfizm jest więc kosztowny (miejsce i czas) – dlatego nie wszystkie metody są wirtualne.

Page 10: Kurs języka C++  – wykład 6 (7.04.2014)

REZULTAT FUNKCJI WIRTUALNEJ Przy nadpisywaniu funkcji wirtualnej trzeba zachować

odpowiedni typ rezultatu: albo rezultat musi być identyczny, albo rezultat musi być kowariantny (referencja lub wskaźnik

do obiektu tej samej klasy lub do klasy, dla której jest ona jednoznaczną i dostępną klasą podstawową).

Przykład:owoc * bazowa::fun () {/*…*/}pomelo * pochodna::fun () {/*…*/}

Page 11: Kurs języka C++  – wykład 6 (7.04.2014)

INNE CECHY FUNKCJI WIRTUALNYCH

Funkcja wirtualna w klasie nie może być statyczna. Dostęp do funkcji wirtualnej może być zmieniony w

klasach pochodnych (co zależy od sposobu dziedziczenia) – dostęp ten zależy więc tylko od typu wskaźnika albo referencji.

Funkcje wirtualne mogą być przyjacielami w innych klasach.

Page 12: Kurs języka C++  – wykład 6 (7.04.2014)

FUNKCJA WIRTUALNA WCZEŚNIE ZWIĄZANA

Funkcja wirtualna będzie wcześnie związana gdy będzie wywołana na rzecz konkretnego obiektu znanego z nazwy:klasa ob;// …ob.funwirt();

Funkcja wirtualna będzie wcześnie związana gdy użyjemy kwalifikatora zakresu:wsk->klasa::funwirt();ref.klasa::funwirt();

Funkcja wirtualna będzie wcześnie związana gdy wywołamy ją w konstruktorze.

Funkcja wirtualna może być wbudowana.

Page 13: Kurs języka C++  – wykład 6 (7.04.2014)

KLASY ABSTRAKCYJNE

Klasy abstrakcyjne służą do definiowania interfejsów (pojęć abstrakcyjnych).

Klasa abstrakcyjna zawiera co najmniej jedną abstrakcyjną metodą wirtualną (funkcja czysto wirtualna).

Deklaracja metody czysto wirtualnej wygląda następująco:virtual typ funkcja (lista-argumentów) = 0;

Nie trzeba (ale można) podawać definicji metody czysto wirtualnej. W klasach potomnych, które nie mają być klasami abstrakcyjnymi,

należy zdefiniować wszystkie odziedziczone metody abstrakcyjne.

Page 14: Kurs języka C++  – wykład 6 (7.04.2014)

KLASY ABSTRAKCYJNE

Nie wszystkie metody w klasie abstrakcyjnej muszą być abstrakcyjne. Żaden konstruktor ani destruktor nie może być abstrakcyjny. Nie można utworzyć obiektu klasy abstrakcyjnej:

nie wolno zdefiniować funkcji, która odbierałaby argument takiej klasy przez wartość;

nie wolno zdefiniować funkcji, która zwracałaby wynik takiej klasy przez wartość;

klasa abstrakcyjna nie może być typem w jawnej konwersji.

Page 15: Kurs języka C++  – wykład 6 (7.04.2014)

WIRTUALNY DESTRUKTOR

W klasach polimorficznych (zawierających metody wirtualne) destruktor definiujemy jako wirtualny.

Page 16: Kurs języka C++  – wykład 6 (7.04.2014)

KONSTRUKTOR NIE MOŻE BYĆ WIRTUALNY ALE…

Czasami istnieje potrzeba wyprodukowania nowego obiektu tej samej klasy – w takiej sytuacji można zdefiniować funkcję wirtualną, która będzie przygotowywać taki obiekt (zastąpi konstruktor domyślny albo kopiujący).

Page 17: Kurs języka C++  – wykład 6 (7.04.2014)

KLASA PAIR<>

W pliku nagłówkowym <utility> zdefiniowano szablon klasy pair<F,S>, który służy do przechowywania pary wartości.

Para std::pair<> to struktura z dwoma polami first i second dowolnych typów podawanych jako parametry wzorca.

Przykład:pair<string,double> pi = new pair<string,double>(”pi”,3.141593);

W szablonie klasy std::pair<> zdefiniowano oprócz konstruktora z dwiema wartościami inicjalizującymi pola first i second także konstruktor kopiujący i domyślny.

Page 18: Kurs języka C++  – wykład 6 (7.04.2014)

KLASA PAIR<>

Typy występujące w parze mogą być wydedukowane, gdy para jest tworzona za pomocą funkcji szablonowej make_pair().

Przykład:pair<string,double> e = make_pair(string(”e”),2.718282);

Dla szablonu klasy std::pair<> zdefiniowano nieskładowe operatory relacji porównujących == i < (porównywane są pierwsze pola, a gdy te są równe porównywane są drugie pola).

Funkcja składowa oraz zewnętrzna funkcja szablonowa swap<>() zamienia zawartości dwóch par.

Page 19: Kurs języka C++  – wykład 6 (7.04.2014)

KLASA VECTOR<> W pliku nagłówkowym <vector> zdefiniowano szablon klasy vector<T>, który służy do przechowywania dowolnej liczby wartości określonego typu.

Kolekcja std::vector<> przechowuje swoje elementy w tablicy dynamicznej – dodawanie (metoda push_back()) i usuwanie (metoda pop_back()) elementów na końcu tablicy działa bardzo szybko.

Przykład:vector<int> coll;for (int i=1; i<=10; ++i) coll.push_back(i*i);for (int i=0; i<coll.size(); ++i) cout << coll[i] << ’ ’;cout << endl;

Page 20: Kurs języka C++  – wykład 6 (7.04.2014)

KLASA VECTOR<> W kolekcji std::vector<> istnieją metody do wstawiania

elementu na początku wektora push_front() i usuwania elementu z początku pop_front().

Dostęp do elementów w wektorze jest realizowany za pomocą operatora indeksowania [] albo za pomocą metody at(); odczytanie wartości pierwszego elementu w wektorze można zrobić za pomocą metody front() a ostatniego za pomocą back().

Metoda empty() mówi czy wektor jest pusty a metoda size() zwraca liczbę wszystkich elementów w wektorze.

Metoda clear() usuwa wszystkie elementy z wektora.