.1 Szablony... 1.2 Szablony funkcji... 2.3 Szablony klas....4 Szablony jako wstęp do biblioteki STL....1 Szablony Szablony definiują sparametryzowane rodziny klas, funkcji. Szablony deklarujemy i definiujemy za pomocą słowa kluczowego template. Składnia polecenia template: template < parametry_szablonu > definicja_szablonu Zastosowania szablonów: definicja funkcji, które mogą operować na dowolnych typach danych, tzn. argumenty funkcji i zwracany typ moŝe być dowolnego typu, definicja klas, struktur, tablic mogących przechowywać róŝne typy danych. Przykład 1. Składnia szablonu klasy z jednym parametrem. template<class T> class NazwaKlasy ; Przykład 2. Składnia szablonu funkcji. template<parametry szablonu> zwracanytyp nazwafunkcji(lista argumentów) template<class T> T nazwafunkcji(t t) return t; Słowo kluczowe class, oznacza typ parametru szablonu. Typ class moŝna zamienić dowolnym typem danych lub słowem kluczowym typename. 1
.2 Szablony funkcji Szablon funkcji definiuje sparametryzowaną rodzinę funkcji. Przykład 1. Składnia szablonu funkcji. template<parametry szablonu> zwracanytyp nazwafunkcji(lista argumentów) Przykład 2. Funkcja MAX(int, int) zwraca liczbę większą, typu int. Szablon funkcji maxx(const T&, const T&)zwraca liczbę większą dowolnego typu (w-01-template-funmax.cpp). template <class NazwaTypu> NazwaTypu maxx(nazwatypu x, NazwaTypu y) return (x > y)? y : x; ; inline int MAX(int a, int b) return a > b? a : b; template<class T> inline const T& maxx(const T& a, const T& b) return a > b? a : b; void main () double a, b, c; int x =, y =, z; a = 8.33; b = 7.99; c = maxx(a,b); cout << c << endl; z = maxx(x,y); cout << z << endl; z = MAX(x,y); cout << z << endl; 2
Przykład 3. Definicja szablonu funkcji. Do szablonu funkcji moŝna przekazywać wartości o róŝnych typach (w-02-template-argfunkcji.cpp) using namespace std ; template < class tt > tt Funkcja( const tt& ); int Funkcja( const int& ri ) cout << "Funkcja( const int&) " << endl; return ri; double Funkcja( const double & rd ) cout << "Funkcja( const float&)" << endl; return rd; const int ci = 99; const double cd = 3.14; const char cch= 'A'; Funkcja(ci); Funkcja(cd); Funkcja(cCh); template < class tt > tt Funkcja( const tt& rt ) cout << "Funkcja( const tt&)" << endl; return rt; 3
Przykład 4. Definicja szablonu funkcji. Do szablonu funkcji moŝna przekazywać referencje lub wskaźniki róŝnych typów (w-03-template-argfunkcji.cpp) template<typename T> T ftr(const T &x) cout << "\n ftr(const T &) = "; return x; template<typename T> T ftp(const T *pz) cout << "\n ftp(const T *) = "; return *pz; static char f(const char &rc) cout << "\n f(const char &) = "; return rc; static char f(const char *pch) cout << "\n f(const char *) = "; return *pch; char c = 'A'; char *pc = &c; cout << ftr(c); cout << ftp(pc); cout << f(c); cout << f(pc); cout << "\n"; double d = 3.14; double *pd = &d; cout << ftr(d); cout << ftp(pd); cout << "\n"; 4
.3 Szablony klas Szablony klasy definiuje sparametryzowaną rodzinę klas. Przykład 1. Składnia szablonu klasy. template<class T> class NazwaKlasy ; Przykład 2. Definicja szablonu klasy. Konstruktor, destruktor klasy zdefiniowany jest poza klasą (w-04-template-klasa.cpp). template <class t> class A A(); ~A(); ; template <class t> A<t>::A() cout << "A()" << endl; template <class t> A<t>::~A()cout << "~A()" << endl; A<int> ai ; A<double> ad ; Przykład 3. Definicja szablonu klasy. Typ atrybutu klasy zaleŝy deklaracji obiektu (w-0-template-atrybuttypuintdouble.cpp). template <class T> class A A() cout << "A()" << endl; ; ~A() cout << "~A()" << endl; ; T x; ; A<int> ai; //tworzenie obiektu typu A<int> ai.x = 99; // ai.x = 3.14; // błąd, conversion from 'double' to 'int' A<double> ad; //tworzenie obiektu typu A<double> ad.x = 3.14; // ad.x = "3,14"; // błąd, cannot convert from 'const char []' to 'double'
Przykład 4. Szablon struktury, sparametryzowany zbiór struktur (w-06-template-getset.cpp). template<class T> struct W private: T* in; void set(t* x) in = x; T get() cout << "get(), in= "; return *in; ; W<double> w; double d = 3.14; w.set(&d); cout << w.get() << endl; Przykład. Definicja szablonu tablicy. Przeładowanie operatora [ ] (w-07-template-tablica.cpp). template<class T> class Array static const int size = 0; T A[size]; // przeładowanie operatora [ ] T& operator[](int index) return A[index]; ; int main() Array<int> ia; // definicja tablicy typu int Array<double> da; // definicja tablicy typu double // inicjowanie tablic typu int, double for(int i = 0; i < ; i++) ia[i] = i * i; da[i] = double(i) * 1.414; // przekierowanie na standardowe wyjście wartości elementów tablic for(int j = 0; j < ; j++) cout << j << ": " << ia[j] << ", " << da[j] << endl; 6
Przykład 6. Definicja szablonu klasy. Metoda operuje na atrybucie klasy ( w-08-template-dane.cpp) template <class T> class A A() A(T n); ~A() void pokaz_dane(); protected: T dane; ; template <class T> A<T>::A(T x) : dane(x) template <class T> void A<T>::pokaz_dane() cout << "dane= " << dane << endl; A<int> a(2); a.pokaz_dane(); A<char> b('q'); b.pokaz_dane(); A<double> d(1.2); d.pokaz_dane(); 7
Przykład 7. Definicja szablonu klasy z dwoma parametrami. Metoda operuje na atrybutach klasy (w-09-template-dane.cpp). template <class T1, class T2> class A A() cout << "A()" << endl; A(T1, T2); ~A()cout << "~A()" << endl; void pokaz_dane(); private: T1 dane1; T2 dane2; ; template <class T1, class T2> A<T1, T2> :: A(T1 x, T2 y) : dane1(x), dane2(y) cout << "A(T1,T2)" << endl; template <class T1, class T2> void A<T1, T2>::pokaz_dane() cout << "dane1= " << dane1 << endl; cout << "dane2= " << dane2 << endl; A<int, double> a(,3.); a.pokaz_dane(); 8
Przykład 8. Definicja szablonu klasy. Przeładowanie operatora << klasy ostream (w-09-template-str_out.cpp) class Dane char dane[128]; int i; double d; ; ostream& operator << (ostream& str_out, Dane & q) str_out << "q.dane= " << q.dane << endl; str_out << "q.i = " << q.i << endl; str_out << "q.d = " << q.d << endl; return str_out; ; template <class T> class A A(T); void pokaz_d(); private: T d; ; template <class T> A<T>::A(T x): d(x) template <class T> void A<T>::pokaz_d() cout << d << endl; // przeładowany operator << Dane dane="tekst", 00, 21.33; A<Dane> x(dane); x.pokaz_d(); 9
.4 Szablony jako wstęp do biblioteki STL Standard Template Library (biblioteka STL, Standardowa Biblioteka Wzorców) zawiera zdefiniowane struktury danych i algorytmy pozwalające wykonywać operacje na tych strukturach. Biblioteka STL oparta jest na szablonach. Komponenty biblioteki STL: kontenery (containers), stosowane do zarządzania zbiorami obiektów. Kontenery mogą być implementowane jako, tablice (arrays), linkowane listy (linked lists), kolejki, mapy. iteratory (iterators), stosowane do przeszukiwania kontenerów (zbiorów obiektów), przechodzenia między obiektami. algorytmy, określają operacje wykonywane na zawartości kontenerów lub na obiektach. Typy kontenerów: sequence containers (sekwencyjne kontenery), uporządkowane zbiory, w których kaŝdy element zajmuje określone połoŝenie. PołoŜenie elementu w kontenerze zaleŝy od czasu i miejsca wstawienia elementu do kontenera, nie zaleŝy do wartości elementu. associative containers (łączone kontenery), zbiór uporządkowanych elementów, w którym połoŝenie zaleŝy od wartości elementu i algorytmu sortującego. Przykładami zdefiniowanych w STL sekwencyjnych kontenerów są: wektory (vectors), kolejki o dwóch końcach, tzn. obiekty moŝna wstawiać na początku lub na końcu kolejki (deques), listy (lists), tablica stringów. Przykładami zdefiniowanych w STL łączonych kontenerów są: zbiory (sets), multisets, automatyczne sortowanie według określonego algorytmu, mapy (maps), multimaps, elementami są pary (klucz, wartość). Automatyczne sortowanie według określonego algorytmu dla klucza. Predefiniowane w STL specjalne kontenery (container adapters) stos (stack). uporządkowany zbiór elementów, zarządzany według zasady LIFO (last-in-first-out). kolejki (queues), uporządkowany zbiór elementów, zarządzany według zasady FIFO (first-in-first-out). kolejki z priorytetem (priority queues), uporządkowany zbiór elementów, w którym elementy mogą mieć określony priorytet w algorytmie sortowania. Literatura: N. Josuttis, C++ Biblioteka standardowa. Podręcznik programisty, Helion, 03. SGI, Standard Template Library Programmer's Guide, http://www.sgi.com/tech/stl/ A. Stepanov, Notes on Programming, http://www.stepanovpapers.com/notes.pdf D. Musser, G. Derge, A. Saini, C++ Programming with the Standard Template Library, Addison-Wesley, 1998.
Przykład 1. UŜycie list (w--template-lista1.cpp). Metody klasy list uŝyte w programie: size() zwraca liczbę elementów listy. begin()-zwraca iterator wskazujący na pierwszy element listy. end()-zwraca iterator wskazujący na ostatni element listy. pop_front() usuawa element z początku listy. push_front() dodaje element na początek listy. #include <list> typedef list<int> typedef list<int>::iterator IntList; IntListIterator; template<class T, class A> void showlist(const list<t, A>& alist) cout << "size() = " << alist.size() << endl; for (list<t, A>::const_iterator i = alist.begin(); i!=alist.end(); ++i ) cout << *i << endl; IntList listaa(); int j = 0; // wynik // działania // programu size() = 0 1 size() = 4 1 size() = 0 1 for (IntListIterator ia = listaa.begin(); ia!= listaa.end(); ++ia ) *ia = * j++; showlist(listaa); // usun pierwszy element listaa.pop_front(); showlist(listaa); // dodaj nowy element na poczatek listy listaa.push_front(0); showlist(listaa); 11
Przykład 2. UŜycie list (w-11-template-lista2.cpp). #include <list> typedef list<int> typedef list<int>::iterator IntList; IntListIterator; template<class T, class A> void showlist(const list<t, A>& alist) cout << "size() = " << alist.size() << endl; for (list<t,a>::const_iterator i = alist.begin(); i!= alist.end(); ++i) cout << *i << endl; IntList listaa(); int j = 0; for (IntListIterator ia = listaa.begin(); ia!= listaa.end(); ++ia) *ia = * j++; showlist(listaa); IntList j = ; listab(6); for (IntListIterator ib = listab.begin(); ib!= listab.end(); ++ib) *ib = 2 * j--; showlist(listab); IntList listac = listaa; IntList listad = listab; // sklej bez sortowania listaa.merge(listab); showlist(listaa); showlist(listab); // Odwróć kolejnosc elementow w listaa listaa.reverse(); showlist(listaa); // sortuj i sklej listac.sort(); listad.sort(); listac.merge(listad); showlist(listac); showlist(listad); // wynik // działania // programu size() = 0 1 size() = 6 18 16 14 12 size() = 11 0 1 18 16 14 12 size() = 0 size() = 11 12 14 16 18 1 0 size() = 11 0 12 14 1 16 18 size() = 0 12
Przykład 3. UŜycie stosu (w-12-template-stos.cpp). Metody klasy stack uŝyte w programie: size() zwraca liczbę elementów stosu. push()- dodaje element do stosu. top() zwraca referencje (adres)do elementu znajdującego się na szczycie stosu. #include <stack> template<class T, class C> void ShowStack(stack<T, C>& astack) cout << "astack.size()= " << astack.size() << endl; if (!astack.empty()) cout << "astack.top() = " << astack.top() << endl; int main() // utwórz stos liczb calkowitych stack<int> sint; ShowStack(sInt); // wrzuć elementy na stos for (unsigned int i = 0; i < ; ++i) sint.push(i * 2); ShowStack(sInt); sint.top() = 0; ShowStack(sInt); // pobierz wszystkie elementy ze stosu while (!sint.empty()) cout << sint.top() << endl; sint.pop(); return 0; 13
Przykład 4. UŜycie zbiorów (w-13-template-set.cpp). Metody klasy set uŝyte w programie: size() zwraca liczbę elementów w zbiorze. begin()-zwraca iterator wskazujący na pierwszy element w zbiorze. end()-zwraca iterator wskazujący na ostatni element w zbiorze. insert() wstawia element, zakres elementów do zbioru. #include <set> #include <string> template <class Kontener> void pokazzbior( const Kontener & k ) Kontener :: const_iterator itr; for( itr = k.begin( ); itr!= k.end( ); itr++ ) cout << *itr << '\n'; set<string> s; // uporządkowanie alfabetyczne //set<string, greater<string> > s; // uporządkowanie odwrócone s.insert( "czerowny" ); s.insert( "zielony" ); s.insert( "niebieski" ); pokazzbior( s ); 14