Wykład 8
Transkrypt
Wykład 8
Programowanie obiektowe w C++ Wykład 11 dr Lidia Stępień Akademia im. Jana Długosza w Częstochowie L. Stępień (AJD) Programowanie obiektowe w C++ 1 / 34 STL - rys historyczny utworzona została w 1994 r. Tworcami są Alex Stepanow oraz Meng Lee. Powstała w Hewlett-Laboratories. Do jej utworzenia posłużono się programowaniem uogólnionym (generycznym). L. Stępień (AJD) Programowanie obiektowe w C++ 2 / 34 Programowanie uogólnione, a obiektowe uogólnione obiektowe koncentruje się na algorytmach koncentruje się na danych celem jest tworzenie kodu niezależnego od typu danych (iteratory) szablony pozwalają na tworzenie funkcji lub klas dla ogólnego typu danych STL udostępnia ogólną reprezentację algorytmów szablony pozwalają tworzyć ogolną reprezentację algorytmów, ale nie bez zmian w ich podstawowych projektach L. Stępień (AJD) Programowanie obiektowe w C++ 3 / 34 STL, ang. Standard Template Library zawiera szablony m.in.: kontenerów, iteratorów, obiektów funkcyjnych oraz algorytmów. L. Stępień (AJD) Programowanie obiektowe w C++ 4 / 34 Kontener Jednostka, która umożliwia przechowywanie wielu wartości. Kontenery udostępniane przez STL są homogeniczne (jednorodne) czyli, że mogą zawierać wyłącznie wartości tego samego typu. Algorytmy Grupa instrukcji opisujących sposób wykonania konkretnego zadania, jak np. sortowanie tablicy czy wyszukiwanie na liście określonej wartości. Iterator Obiekt pozwalający przemieszczać się po elementach kontenera. Przypomina on wskaźnik używany podczas odwoływania się do elementów tablicy. Iteratory są uogólnieniem wskaźników. Obiekt funkcyjny (funktor) Obiekt zachowujący się jak funkcja. Funktory mogą być obiektami klas lub wskaźnikami do funkcji. L. Stępień (AJD) Programowanie obiektowe w C++ 5 / 34 Kontener Jednostka, która umożliwia przechowywanie wielu wartości. Kontenery udostępniane przez STL są homogeniczne (jednorodne) czyli, że mogą zawierać wyłącznie wartości tego samego typu. Algorytmy Grupa instrukcji opisujących sposób wykonania konkretnego zadania, jak np. sortowanie tablicy czy wyszukiwanie na liście określonej wartości. Iterator Obiekt pozwalający przemieszczać się po elementach kontenera. Przypomina on wskaźnik używany podczas odwoływania się do elementów tablicy. Iteratory są uogólnieniem wskaźników. Obiekt funkcyjny (funktor) Obiekt zachowujący się jak funkcja. Funktory mogą być obiektami klas lub wskaźnikami do funkcji. L. Stępień (AJD) Programowanie obiektowe w C++ 5 / 34 Kontener Jednostka, która umożliwia przechowywanie wielu wartości. Kontenery udostępniane przez STL są homogeniczne (jednorodne) czyli, że mogą zawierać wyłącznie wartości tego samego typu. Algorytmy Grupa instrukcji opisujących sposób wykonania konkretnego zadania, jak np. sortowanie tablicy czy wyszukiwanie na liście określonej wartości. Iterator Obiekt pozwalający przemieszczać się po elementach kontenera. Przypomina on wskaźnik używany podczas odwoływania się do elementów tablicy. Iteratory są uogólnieniem wskaźników. Obiekt funkcyjny (funktor) Obiekt zachowujący się jak funkcja. Funktory mogą być obiektami klas lub wskaźnikami do funkcji. L. Stępień (AJD) Programowanie obiektowe w C++ 5 / 34 Kontener Jednostka, która umożliwia przechowywanie wielu wartości. Kontenery udostępniane przez STL są homogeniczne (jednorodne) czyli, że mogą zawierać wyłącznie wartości tego samego typu. Algorytmy Grupa instrukcji opisujących sposób wykonania konkretnego zadania, jak np. sortowanie tablicy czy wyszukiwanie na liście określonej wartości. Iterator Obiekt pozwalający przemieszczać się po elementach kontenera. Przypomina on wskaźnik używany podczas odwoływania się do elementów tablicy. Iteratory są uogólnieniem wskaźników. Obiekt funkcyjny (funktor) Obiekt zachowujący się jak funkcja. Funktory mogą być obiektami klas lub wskaźnikami do funkcji. L. Stępień (AJD) Programowanie obiektowe w C++ 5 / 34 Przykład 1 #include<iostream> #include<vector> using namespace std; int main(){ vector<int> A(5); int n; cin >> n; vector<float> B(n); A[0] = 1; for(int i = 0; i < n; ++i) cin >> B[i]; } L. Stępień (AJD) Programowanie obiektowe w C++ 6 / 34 Do czego można wykorzystać vector? Kontenery biblioteki STL udostępniają pewne podstawowe metody, dzięki którym można odczytywać informacje o tych kontenerach oraz wykonywać operacje na ich elementach, np. size() - zwraca liczbę elementów kontenera, swap() - zamienia zawartość dwóch kontenerów, begin() - zwraca iterator wskazujący na pierwszy element w kontenerze, end() - zwraca iterator wskazujacy element leżący bezpośrednio za ostatnim elementem kontenera. L. Stępień (AJD) Programowanie obiektowe w C++ 7 / 34 Iterator Jest uogólnieniem wskaźnika. Może być wskaźnikiem, ale równie dobrze może być obiektem, dla którego zdefiniowano takie operacje, jak: wyłuskiwanie (operator*()) czy inkrementacja (operator++()). Umożliwiają bibliotece STL udostępnienie jednolitego interfejsu dla rożnych klas kontenerowych, nawet tych, które nie mogą korzystać ze zwykłych wskaźnikow. W każdej z klas kontenerowych zdefiniowany jest odpowiedni iterator. Nazwa jego typu określona jest przy pomocy lokalnej instrukcji typedef ta nazwa to iterator. L. Stępień (AJD) Programowanie obiektowe w C++ 8 / 34 Przykład 2 // Deklaracja iteratora vector<double>::iterator pd; // Dla obiektu vector<double> a; // i iteratora pd możemy wykonać operacje: pd = a.begin(); *pd = 1.23; pd++; ´ L. Stępień (AJD) Programowanie obiektowe w C++ 9 / 34 end() Zwraca iterator wskazujący element leżący bezpośrednio za ostatnim elementem kontenera. Element ten nazywamy elementem ograniczającym. (Podobnie jak ´\0´w łańcuchu.) Przykład: vector<double>::iterator pd; for(pd = a.begin(); pd != a.end(); pd++) cout << *pd << endl; L. Stępień (AJD) Programowanie obiektowe w C++ 10 / 34 push_back() - wstawianie na koniec wektora vector<double> a; double temp; while(cin >> temp && temp >=0) a.push_back(temp); cout<<’’Rozmiar wektora: ’’<<a.size()<<endl; L. Stępień (AJD) Programowanie obiektowe w C++ 11 / 34 erase() - usuwanie określonych fragmentów wektora Ma dwa argumenty będące iteratorami: pierwszy - wskazuje na początek zakresu; drugi - wskazuje element znajdujący się bezpośrednio za końcem zakresu. Przykład: a.erase(a.begin(), a.begin() + 2); Jaki przedział odpowiada powyższemu zakresowi? L. Stępień (AJD) Programowanie obiektowe w C++ 12 / 34 insert() - dopełnienie metody erase() Ma trzy argumenty: pierwszy - podaje pozycję, od której będą wstawiane nowe elementy; drugi i trzeci - definiują zakres, którego elementy zostaną wstawione do wektora. Przykład: vector<int> s; vector<int> n; s.insert( s.begin(), n.begin()+1, n.end() ); s.insert(s.end(), n.begin()+1, n.end() ); L. Stępień (AJD) Programowanie obiektowe w C++ 13 / 34 Funkcje nie powiązane z żadną klasą STL for _each() o trzech argumentach: dwa pierwsze to iteratory wyznaczające zakres elementów kontenera; trzeci jest wskaźnikiem do funkcji (obiekt funkcyjny). Funkcja for _each() wywołuje dla każdego elementu kontenera, mieszczącego się w wyznaczonym zakresie, funkcję wskazywaną przez trzeci z argumentów. Przykład: for_each(a.begin(), a.end(), F); // gdzie void F(); L. Stępień (AJD) Programowanie obiektowe w C++ 14 / 34 Funkcje nie powiązane z żadną klasą STL random_shuffle() o dwu argumentach będących iteratorami wyznaczającymi zakres oraz przestawiających w sposób losowy elementy znajdujące się w tym zakresie. Wymaga swobodnego dostępu do elementów, jak ma to miejsce w klasie vector . Przykład: random_shuffle( a.begin(), a.end() ); L. Stępień (AJD) Programowanie obiektowe w C++ 15 / 34 Funkcje nie powiązane z żadną klasą STL sort() sortuje elementy z zakresu wyznaczonego przez iteratory wykorzystując w tym celu przeciążony operator <. Przykład: vector<int> liczby; sort( liczby.begin(), liczby.end() ); UWAGA: Jeśli elementami wektora są obiekty zdefiniowane przez użytkownika, to należy dla nich zdefiniować funkcję operator <(). L. Stępień (AJD) Programowanie obiektowe w C++ 16 / 34 Przykład 3 template<typename T> T* szukaj_w_tab(T *tab, int r, T const &w) { for(int i = 0; i < r; ++i) if(tab[i] == w) return &tab[i]; // return tab+i; return nullptr; } L. Stępień (AJD) Programowanie obiektowe w C++ 17 / 34 Przykład 4 typedef struct { double w; W * nast; }W; W* szukaj_lista(W *pocz, double const& wart) { W *start; for(start = pocz; start != nullptr; start = start->nast) if(start->w == wart) return start; return NULL; } L. Stępień (AJD) Programowanie obiektowe w C++ 18 / 34 UWAGI Szablony pozwalają na uniezależnienie kodu od typu danych. Różnią się zastosowanymi algorytmami, choć zasada działania obydwu algorytmów jest podobna. Celem jest udostępnienie tylko jednej funkcji wyszukiwania, która byłaby niezależna zarówno od typu danych przechowywanych w kontenerach, jak i od struktury samego kontenera. L. Stępień (AJD) Programowanie obiektowe w C++ 19 / 34 Iteratory Dla iteratora powinna istnieć możliwość: udostępniania wskazywanej przez niego wartości (wyłuskiwanie); przypisania go do innego iteratora (p = q); porownywania go z innym iteratorem (p == q, p! = q); przemieszczania po wszystkich elementach kontenera (+ + p, p + +, − − p, p − −). L. Stępień (AJD) Programowanie obiektowe w C++ 20 / 34 Wskaźnik a iterator typedef double * iterator; iterator szukaj_tab(iterator tab, int r, double const &war) { iterator koniec = tab+r; for(; tab <= koniec; ++tab) if(*tab == war) return tab; return nullptr; } L. Stępień (AJD) Programowanie obiektowe w C++ 21 / 34 Modyfikacja typedef double * iterator; iterator szukaj_tab(iterator pocz, iterator kon, double const &war) { iterator pom; for(pom = pocz; pom != kon; ++pom) if(*pom == war) return pom; return nullptr; } L. Stępień (AJD) Programowanie obiektowe w C++ 22 / 34 Klasa iterator dla listy typedef struct { double w; W* nast; } W; class iterator{ W* pt; public: iterator():pt(0) { } iterator(W* pt) : pt(pt) { } double operator*() { return pt->w; } iterator& operator++(){ // dla ++pt pt = pt->nast; return *this; } iterator& operator++(int){ //dla pt++ iterator tmp = *this; pt = pt ->nast; return tmp; } // ... operator==(), operator!=(), itd. }; L. Stępień (AJD) Programowanie obiektowe w C++ 23 / 34 Zastosowanie klasy iterator iterator szukaj_lista(iterator poczatek, double const &war) { iterator pom; for(pom = poczatek; pom != 0; ++pom) if(*pom == war) return pom; return nullptr; } L. Stępień (AJD) Programowanie obiektowe w C++ 24 / 34 Jak utworzony został kod biblioteki STL? Dla każdej klasy kontenerowej (np. vector , list, map) zdefiniowano odpowiedni typ iteratora. (Dla pewnych klas jest to wsaźnik, dla innych obiekt, ale każdy z nich udostępnia operatory ∗, czy ++.) Każda z klas kontenerowych została wyposażona w element ograniczający. Algorytm ogolny - niezależny od typu danych i od typu kontenera. Definiujemy iteratory spełniające wymagania algorytmu dla każdego z kontenerów. Podstawowe właściwości iteratora oraz kontenera oddzielamy od wymagań algorytmu. L. Stępień (AJD) Programowanie obiektowe w C++ 25 / 34 Przykład 5 vector<double> :: iterator prA; vector<double> A; for( prA = A.begin( ); prA != A.end( ); prA++ ) cout << *prA << endl; list<double> B; list<double> :: iterator prB; for( prB = B.begin( ); prB != B.end( ); prB++) cout << *prB << endl; L. Stępień (AJD) Programowanie obiektowe w C++ 26 / 34 Rodzaje iteratorów iterator wejściowy (ang. input iterator) iterator wyjściowy (ang. output iterator) iterator postępujący (ang. forward iterator) iterator dwukierunkowy (ang. bidirectional iterator) iterator dostępu swobodnego (ang. random access iterator) L. Stępień (AJD) Programowanie obiektowe w C++ 27 / 34 Iterator wejściowy Jest iteratorem jednokierunkowym - można stosować operator ++, ale nie −−. Pozwala na dostęp do wszystkich elementów kontenera. Nie ma gwarancji, że przy każdym kolejnym przejściu kontenera jego elementy przetwarzane są w tej samej kolejności. Wykorzystywany jest przez program tylko do odczytywania danych z kontenera (przy pomocy operatora wyłuskania). Znajduje zastosowanie tylko w algorytmach jednoprzebiegowych, które nie zmieniają danych przechowywanych w kontenerach. L. Stępień (AJD) Programowanie obiektowe w C++ 28 / 34 Iterator wyjściowy Jest iteratorem jednokierunkowym - można stosować operator ++, ale nie −−. Pozwala na dostęp do wszystkich elementów kontenera. Nie ma gwarancji, że przy każdym kolejnym przejściu kontenera jego elementy przetwarzane są w tej samej kolejności. Wykorzystywany jest przez program tylko do modyfikowania (ale nie odczytywania) danych z kontenera (przy pomocy operatora wyłuskania). Znajduje zastosowanie tylko w algorytmach jednoprzebiegowych, ktore modyfikują dane przechowywane w kontenerach. L. Stępień (AJD) Programowanie obiektowe w C++ 29 / 34 Iterator postępujący Jest iteratorem jednokierunkowym - można stosować tylko operator ++. Pozwala na dostęp do wszystkich elementów kontenera. Przy każdym kolejnym przejściu kontenera jego elementy przetwarzane są w tej samej kolejności. Po użyciu operatora ++ można wyłuskiwać wcześniej zapamiętane elementy, mając pewność, że ich wartości nie ulegną zmianie. Wykorzystywany jest przez program zarówno do modyfikowania, jak i odczytywania danych z kontenera (przy pomocy operatora wyłuskania). Znajduje zastosowanie w algorytmach wieloprzebiegowych. L. Stępień (AJD) Programowanie obiektowe w C++ 30 / 34 Iterator dwukierunkowy Ma te same własności co iterator postępujący. Ponadto umożliwia korzystanie z operatora dekrementacji ( w formie przedrostkowej i przyrostkowej). L. Stępień (AJD) Programowanie obiektowe w C++ 31 / 34 Iterator dostępu swobodnego Posiada wszystkie cechy iteratora dwukierunkowego. Ponadto umożliwia wykonywanie operacji wymagających dostępu swobodnego oraz posługiwania się operatorami relacyjnymi. L. Stępień (AJD) Programowanie obiektowe w C++ 32 / 34 Niech: a, b będą wartościami iteratora, n będzie liczbą całkowitą i r będzie zmienną lub referencją reprezentującą iterator dostępu swobodnego. wyrażenie komentarz a + n, n + a wskazuje na n-ty element za tym, na który wskazuje a a-n wskazuje na n-ty element przed tym, na który wskazuje a r += n Równoważne r = r + n r -= n Równoważne r = r - n a[n] Równoważne *(a+n) b-a Wartość n taka, że b = a + n a<b Prawda, jeśli b - a > 0 a>b Prawda, jeśli b < a a >= b Prawda, jeśli !(a < b) a <= b Prawda, jeśli !(a > b) L. Stępień (AJD) Programowanie obiektowe w C++ 33 / 34 Hierarchia iteratorów Właściwość Wejściowy Wyjściowy Postępujący Dwukierunkowy Dostępu swobodnego Wyłuskiwanie i czytanie Tak Nie Tak Tak Tak Wyłuskiwanie i modyfikacja Nie Tak Tak Tak Tak Ustalony i powtarzalny porządek Nie Nie Tak Tak Tak ++i, i++ Tak Tak Tak Tak Tak –i, i– Nie Nie Nie Tak Tak i[n] Nie Nie Nie Nie Tak i+n Nie Nie Nie Nie Tak i-n Nie Nie Nie Nie Tak i += n Nie Nie Nie Nie Tak i -= n Nie Nie Nie Nie Tak L. Stępień (AJD) Programowanie obiektowe w C++ 34 / 34