Zaawansowane programowanie w C++ (PCP) Wykład 6 - szablony. dr inż. Robert Nowak - p. 1/15
Kolekcje i algorytmy» Deklaracja szablonu y Pojęcia niezależne od typu: kolekcje (np. listy) algorytmy (np. znajdowania największego elementu) Mechanizmy eliminujace redundancję kodu. ręczna modyfikacja kodu wspólna a bazowa wykorzystanie szablonów - p. 2/15
Ręczna modyfikacja kodu» Deklaracja szablonu y typedef int Element;//element przykładowego kontenera class WektorInt { public: explicit WektorInt(int size = 10); //konstruktor kopiujący, operator przypisania, destruktor const Element& get(int idx) const;//zwraca element o danym Element& get(int idx);//zwraca element o danym indeksie //... private: Element* tab_;//tablica przechowująca elementy wektora int size_;//liczba elementów int capacity_;//wielkość tablicy }; konieczność ręcznej zmiany kodu (błędy!) utrudnione wprowadzanie modyfikacji (wiele kopii kodu) - p. 3/15
Klasa bazowa» Deklaracja szablonu y #include Object.h class WektorObj { public: explicit WektorInt(int size = 10); //konstruktor kopiujący, operator przypisania, destruktor const Object& get(int idx) const;//zwraca element o danym Object& get(int idx);//zwraca element o danym indeksie //... private: Object** tab_;//tablica przechowująca elementy wektora //... }; Wady: narzuty pamięciowe i czasowe problem typów wbudowanych - p. 4/15
Zastosowanie szablonów» Deklaracja szablonu y tempate<class T> class Wektor { public: explicit Wektor(int size = 10); //konstruktor kopiujący, operator przypisania, destruktor const T& get(int idx) const;//zwraca element o danym indek T& get(int idx);//zwraca element o danym indeksie void add(const T& val);//dodaje element na koniec kolekcji /* Dalsza część interfejsu y */ private: T* tab_;//tablica przechowująca elementy wektora int size_;//liczba elementów int capacity_;//wielkość tablicy }; Wektor<int> v;//kolekcja liczb całkowitych v.add(3); v.add(4);//operacje na kolekcji Wektor<Data> vd;//kolekcja obiektów y Data Wektor<Figura*> vf;//kolekcja wskaźników do y - p. 5/15
Deklaracja szablonu y» Deklaracja szablonu y Deklaracja szablonu: deklaracja-wzorca: template < lista-parametrów-wzorca > deklaracja lista-parametrów-wzorca: parametr-wzorca [,lista-parametrów-wzorca] parametr-wzorca: class identyfikator [= id-typu ] typename identyfikator [= id-typu ] Przykłady: template<class T> class Array { /* oparty o jeden typ */ }; template<typename T, typename U> class Graf{ /* zależny od dwu typów */ }; template<typename T, typename U = int> class BinTree{ /* Domyślny parametr szablonu */ }; - p. 6/15
generowanie typu» Deklaracja szablonu y nazwa-szablonu < typ [,typ] > Przykłady: Array<int> a; std::vector<double> vd; Graf<std::string, std::string> gr; vector<vector<int> > vv; Niejednoznaczności: zbyt bliskie położenie kończacych >, np. vector<vector<int>> v; znak >> jest operatorem przesunięcia prawidłowe vector<vector<int> > v; (dodatkowa spacja) - p. 7/15
Szablony - właściwości» Deklaracja szablonu y Szablony sa mechanizmem czasu kompilacji pozwalaja współdzielić kod źródłowy brak narzutów czasowych w czasie wykonania Organizacja plików źródłowych definicja (a nie tylko deklaracja) szablonu musi być widoczna w miejscu użycia organizacja plików źródłowych Kod nie jest kompilowany, jeżeli nie został użyty - p. 8/15
Przykład: std::pair» Deklaracja szablonu y Definicja znajduje się w <utility> template<class _T1, class _T2> struct pair { typedef _T1 first_type; typedef _T2 second_type; _T1 first;//pierwsza składowa _T2 second;//druga składowa }; pair() : first(), second() { } pair(const _T1& a, const _T2& b) : first( a), second( b) { } Przykłady użycia: std::pair<std::string,bool> a( Ala,true); a.first = Ola ; a.second = false; - p. 9/15
Szablony funkcji» Deklaracja szablonu y Wzorce funkcji: pozwalaja implementować algorytmy niezależne od typu template<typename T> void std::swap(t& a, T& b) { T tmp = a; a = b; b = tmp; } template<typename T> void printall(const vector<t>& v, std::ostream& os) { for(size_t i = 0; i!= v.size(); ++i) os << v[i] << ","; os << endl; } - p. 10/15
Argumenty wzorca funkcji» Deklaracja szablonu y Istnieje możliwość wyznaczania argumentów wzorca z argumentów podanych w wywołaniu template<typename T> void printall(const vector<t>& v, std::ostream& os) { /*... * vector<int> w; //dodanie elementów do wektora printall(w,cout);//printall<int>(w,cout) template<typename T> T* przydziel() { /* Tworzy obiekt i zwraca wskaźnik */ } int* pi = przydziel<int>();//niemożliwa automatyczna specjaliz - p. 11/15
Problem typu» Deklaracja szablonu y Typowy problem - jawne wskazanie, że identyfikator jest typem class Foo { public: typedef int Element; /* dalsza część implementacji y Foo */ }; template<typename T> void f(const T& t) { //Poniżej błędnie zakłada, że T::Element to nazwa składowej T::Element e = 0; //... //Poniżej jawnie wskazano, że T::Element to nazwa typu typename T::Element e = 0; //... }; - p. 12/15
Szablony kontra hierarchia» Deklaracja szablonu y Używaj szablonów gdy: ważne sa typy wbudowane nie można utworzyć wspólnej y podstawowej bardzo ważna jest efektywność akceptowalna jest powtórna kompilacja przy dodawaniu nowego typu W przeciwnym wypadku używaj hierarchii. - p. 13/15
Zasady tworzenia szablonów» Deklaracja szablonu y 1. zaimplementować typ konkretny 2. przetestować go 3. przekształcić go w szablon 4. wygenerować i przetestować kilka różnych typów - p. 14/15
Podział kodu wzorca na pliki» Deklaracja szablonu y Plik kontener.h - definicja y #ifndef KONTENER #define KONTENER template<typename T> class Kontener { /* Definicja y i metod inline */ }; #include kontener_impl.h #endif Plik kontener_impl.h - implementacja metod wzorca //Nie ma zabezpieczeń przed wielokrotnym dołączaniem template<typename T> T& Kontener<T>::get(int index) { /* Definicja metody */ } Plik kontener.cpp - kod niezależny od typu T - p. 15/15