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

Post on 20-Jan-2016

52 views 0 download

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)

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

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.

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 ();};

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

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

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.

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.

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.

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

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.

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.

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.

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.

WIRTUALNY DESTRUKTOR

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

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

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.

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.

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;

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.