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