K URS JĘZYKA C++ – WYKŁAD 6 (7.04.2014) Polimorfizm.

1 K URS JĘZYKA C++ – WYKŁAD 6 (7.04.2014) Polimorfizm ...
Author: Kuba Zastawny
0 downloads 2 Views

1 K URS JĘZYKA C++ – WYKŁAD 6 (7.04.2014) Polimorfizm

2 S PIS TREŚCI Metody wirtualne Implementacja polimorfizmu Wczesne i późne wiązanie metod wirtualnych Klasy abstrakcyjne Klasa pair Klasa vector

3 S KŁ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.

4 S KŁ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 (); };

5 S KŁADOWE FUNKCJE WIRTUALNE Przykład definicji metod wirtualnych i zwykłych: void bazowa::opis_zwykly() { cout

6 S KŁ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()

7 S KŁ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.

8 P OLIMORFIZM 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.

9 I MPLEMENTACJA 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.

10 R EZULTAT 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 () {/*…*/}

11 I NNE 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.

12 F UNKCJA 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.

13 K LASY 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.

14 K LASY 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.

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

16 K ONSTRUKTOR 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).

17 K LASA PAIR W pliku nagłówkowym zdefiniowano szablon klasy pair, 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 pi = new pair (”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.

18 K LASA PAIR Typy występujące w parze mogą być wydedukowane, gdy para jest tworzona za pomocą funkcji szablonowej make_pair(). Przykład: pair 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.

19 K LASA VECTOR W pliku nagłówkowym zdefiniowano szablon klasy vector, 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 coll; for (int i=1; i

20 K LASA 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.