1 / 20

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.

megan
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. Spis treści • Metody wirtualne • Implementacja polimorfizmu • Wczesne i późne wiązanie metod wirtualnych • Klasy abstrakcyjne • Klasa pair<> • Klasa vector<>

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

  4. Składowe funkcje wirtualne • Przykład deklaracji klas z metodami wirtualnymi i zwykłymi: class bazowa { public: voidopis_zwykly (); virtualvoidopis_wirtualny (); }; class pochodna: public bazowa { public: voidopis_zwykly (); virtualvoidopis_wirtualny (); };

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  19. 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;

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

More Related