Programowanie obiektowe
Transkrypt
Programowanie obiektowe
Programowanie obiektowe Wykład 5. C++: szablony Szablony ◮ Szablony to technika realizacji polimorfizmu na innym poziomie niż za pomocą funkcji wirtualnych i dziedziczenia. ◮ Mechanizm ten można rozumieć jako ’inteligentniejsze’ makrodefinicje. ◮ Szablony nie są w bezpośredni sposób związane z programowaniem obiektowym. Szablony funkcji przykład problemu: definiujemy funkcję porównującą... ...liczby całkowite: int compare(int a, int b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } Szablony funkcji przykład problemu: definiujemy funkcję porównującą... ...liczby całkowite: int compare(int a, int b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ...liczby rzeczywiste: int compare(float a, float b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } Szablony funkcji przykład problemu: definiujemy funkcję porównującą... ...liczby całkowite: int compare(int a, int b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ...liczby rzeczywiste: int compare(float a, float b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ... i tak samo dla każdego innego typu Szablony funkcji przykład problemu: definiujemy funkcję porównującą... ...liczby całkowite: int compare(int a, int b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ...liczby rzeczywiste: int compare(float a, float b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ... i tak samo dla każdego innego typu ... pod warunkiem, że ma zdefiniowany operator < Szablony funkcji przykład problemu: definiujemy funkcję porównującą... ...liczby całkowite: int compare(int a, int b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ...liczby rzeczywiste: int compare(float a, float b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } ...pudełka class Pudelko { public: float dl,sz,wy; Pudelko(float d, float s, float w) : dl(d), sz(s), wy(w) {} int operator<(Pudelko& p) { return dl*sz*wy < p.dl*p.sz*p.wy; } }; int compare(Pudelko a, Pudelko b) { if(a<b) return 1; else if(b<a) return -1; else return 0; } Szablony funkcji podstawowe informacje ◮ szablon funkcji jest sparametryzowaną definicją funkcji ◮ szablon funkcji definiuje się w zakresie globalnym ◮ parametrem szablonu funkcji jest typ (klasa), bądź lista typów ◮ wszystkie parametry szablonu muszą wystąpić w opisie argumentów funkcji szablonowej (kompilator odnajduje szablon na podstawie wywołania funkcji) Składnia: template< opis˙parametrów > definicja funkcji Szablony funkcji przykład class Pudelko { public: float dl,sz,wy; Pudelko(float d, float s, float w) : dl(d), sz(s), wy(w) {} int operator<(Pudelko& p) { return dl*sz*wy < p.dl*p.sz*p.wy; } }; template <class T> int compare(T a, T b) { if(a<b) return -1; else if(b<a) return 1; else return 0; } int main() { cout << compare(1,2) << endl //-1 << compare(1.5,2.5) << endl //-1 << compare(’a’,’b’) << endl //-1 << compare(Pudelko(1.0,2.0,2.0),Pudelko(2.0,1.5,4.2)) << endl;//-1 } Szablony funkcji parametry ◮ parametrem szablonu funkcji jest typ (klasa), bądź lista typów ◮ wszystkie parametry szablonu muszą wystąpić w opisie argumentów funkcji szablonowej (kompilator odnajduje szablon na podstawie wywołania funkcji) ◮ oprócz obowiązkowego użycia parametrów szablonu w opisie argumentów funkcji szablonowej, można ich używać w dowolnym miejscu w definicji tej funkcji (jako nazwy typu). template<class S, class T> T* jakasfunkcja(S a, T b) { T *l = new(T); int r=sizeof(S); ... return l; } Szablony funkcji ◮ jedynym ograniczeniem, jakie w definicji szablonu można nałożyć na typy argumetów funkcji szablonowej jest by niektóre z nich były takie same, np. szablon template <class K, class L, class M> void f(K a, L b, K c, M d) ... pasuje do wywołania f(3,’e’,5,"Ala") ale do wywołania f(3,’e’,’a’,"Ala") nie. Szablony funkcji jak to działa ◮ natrafiając na wywołanie funkcji, kompilator sprawdza, czy istnieje funkcja o podanej nazwie, liczbie i typie argumentów ◮ jeśli nie, sprawdza, czy istnieje szablon pozwalający taką funkcję wygenerować, jeśli tak – generuje odpowiednią funkcję ◮ jeśli nie, sprawdza czy isnieje funkcja którą można dopasować dokonując konwersji typów argumentów, jeśli tak, dokonuje wiązania z zastosowaniem konwersji typów Szablony funkcji sytuacje wyjątkowe ◮ ◮ ◮ często zdarza się, że funkcje wygenerowane z szablonu będą działać poprawnie (lub w ogóle będą poprawne) w większości przypadków, ale nie we wszystkich szablon z poprzedniego przykładu nie będzie działał poprawnie dla typu char* nie nadaje się on w ogóle np. dla typu class Data { public: int dzien, miesiac, rok; } za względu na brak operatora < cout << compare(1,2) << endl // -1 << compare(1.5,2.5) << endl // -1 << compare(’a’,’b’) << endl // -1 << compare(Pudelko(1.0,2.0,2.0),Pudelko(2.0,1.5,4.2)) << endl // -1 << compare("Ala","Ola") << endl // 1 (!) << compare((string)"Ala",(string)"Ola") << endl; // -1 Szablony funkcji funkcje specjalizowane ◮ wyjątki od sposobu generownia funkcji zdefiniowanego przez szablon można zdefiniować pisząc funkcję specjalizowaną ◮ funkcja specjalizowana to funkcja, której nazwa i typy parametrów pasują do szablonu, tyle że jest jest to normalna funkcja Szablony funkcji funkcje specjalizowane template <class T> int compare(T a, T b) { if(a<b) return -1; else if(b<a) return 1; else return 0; } int compare(const char* a, const char* b) { return strcmp(a,b); } int main() { cout << compare(1,2) << endl // -1 << compare(1.5,2.5) << endl // -1 << compare(’a’,’b’) << endl // -1 << compare(Pudelko(1.0,2.0,2.0),Pudelko(2.0,1.5,4.2)) << endl // -1 << compare("Ala","Ola") << endl // -1 << compare((string)"Ala",(string)"Ola") << endl; // -1 } Szablony klas podstawowe informacje ◮ szablon klasy jest sparametryzowaną definicją klasy ◮ szablon klasy definiuje się w zakresie globalnym Składnia: template< opis˙parametrów > class nazwaklasy { ... }; Szablony klas przykład (bardzo typowy) Szablon klasy Stos, którego parametrem jest typ elementów przechowywanych na stosie. template <class T> class Stos { public: Stos() : n(0) } Stos& push(T e) { T pop() { int empty() { operator int() { private: T dane[100]; int n; }; dane[n++]=e; return *this; } // dodanie elementu return dane[--n]; } // pobranie elementu return n==0; } // test czy pusty return n; } // dodatkowy bajer Szablony klas klasa szablonowa ◮ po zdefniowaniu szablonu klas template< opis˙parametrów > class nazwaklasy { ... }; nazwą klasy szablonowej jest nazwaklasy<parametry> ◮ posługujemy się nią jak zwykłymi nazwami klas/typów ◮ w momencie napotkania takiej nazwy, kompilator generuję definicję klasy szablonowej dla podanych parametrów (jeśli wcześniej już tego nie zrobił) Szablony klas użycie klasy szblonowej int main() { Stos<char> stosznakow; // Stos<int> stosliczb; // stosznakow.push(’A’).push(’l’).push(’a’); stosliczb.push(1).push(2).push(3); Stos<char> drugistosznakow=stosznakow; // while(stosznakow) // { cout << stosznakow.pop(); } cout << endl; while(stosliczb) { cout << stosliczb.pop(); } cout << endl; } generowana jest klasa Stos<char> generowana jest klasa Stos<int> klasa Stos<char> już jest bajer Szablony klas parametry ◮ Szablon klasy może mieć wiele parametrów (separatorem jest przecinek) ◮ Parametrem szablonu klasy może być: ◮ ◮ ◮ typ (class nazwa) wartość całkowita stała (int nazwa) template < class Typ, int rozmiar > także stałe wyrażenie będące adresem obiektu globalnego lub funkcji globalnej (rzadsze zastosowanie) Szablony klas definicje metod klasy szablonowej poza ciałem klasy ◮ definicje metod klasy szablonowej umieszczone poza ciałem klasy są w istocie szablonami definicji metod ◮ mają postać taką jak szablony funkcji, z tą oczywiście różnicą, że ich nazwę poprzedza się nazwą klasy szablonowej ◮ podobnie też jak w przypadku szablonów funkcji, można definiować metody specjalizowane Szablony klas definicje metod klasy szablonowej poza ciałem klasy template <class T> class Stos { public: Stos(); Stos& push(T e); T pop(); itd private: T dane[100]; int n; }; template<class T> Stos<T>::Stos() : n(0) {} template<class T> Stos<T>& Stos<T>::push(T e) { dane[n++]=e; return *this; } template<class T> T Stos<T>::pop() itd. { return dane[--n]; } Szablony klas definicje metod klasy szablonowej poza ciałem klasy (lupa) ◮ są to szablony metod template<class T> Stos<T>::Stos() : n(0) {} template<class T> Stos<T>& Stos<T>::push(T e) { dane[n++]=e; return *this; } template<class T> T Stos<T>::pop() itd. return dane[--n]; Szablony klas definicje metod klasy szablonowej poza ciałem klasy (lupa) ◮ nieodłączną częścią nazwy klasy szablonowej jest parametr(y) template<class T> Stos<T>::Stos() : n(0) {} template<class T> Stos<T>& Stos<T>::push(T e) { dane[n++]=e; return *this; } template<class T> T Stos<T>::pop() itd. return dane[--n]; Szablony klas definicje metod klasy szablonowej poza ciałem klasy (lupa) ◮ nazwa konstruktora (destruktora) nie jest nazwą klasy — bez parametu template<class T> Stos<T>::Stos() : n(0) {} template<class T> Stos<T>& Stos<T>::push(T e) { dane[n++]=e; return *this; } template<class T> T Stos<T>::pop() itd. return dane[--n]; Szablony klas parametry nie będące typami – przykład W szablonie stosów dodajemy parametr określający rozmiar. template <class T, int max> class Stos { public: Stos() : n(0) {} Stos& push(T e) { dane[n++]=e; return *this; } T pop() { return dane[--n]; } int empty() { return n==0; } operator int() { return n; } private: T dane[max]; int n; }; int main() { Stos<char,20> stos; stos.push(’A’).push(’l’).push(’a’); while(stos) { cout << stos.pop(); } cout << endl; } Szablony klas klasa szablonowa jako klasa bazowa ◮ ◮ Klasa szablonowa może być klasą bazową innej klasy. Klasa szablonowa może być klasą bazową w szablonie klasy. template<class T> class K { ... }; class L : K<int> { ... } template<class S> class M : K<int> { ... } Szablony klas klasa szablonowa jako klasa bazowa ◮ ◮ Klasa szablonowa może być klasą bazową innej klasy. Klasa szablonowa może być klasą bazową w szablonie klasy. template<class T> class K { ... }; class L : K<int> { ... } template<class S> class M : K<int> { ... } Szablony klas szablon klasy jako klasa bazowa ◮ ◮ szablonu klasy można użyć jako klasy bazowej w innym szablonie klasy parametry szablonu klasy bazowej muszą być parametrami szablonu klasy pochodnej albo muszą mieć ustaloną wartość template<class T, int max> class Stos { ... }; template<class S, int max> class lepszystos : K<S,max> { ... } template<class S> class stosstulementowy : K<S,100> { ... } Szablony klas szablon klasy jako klasa bazowa ◮ ◮ szablonu klasy można użyć jako klasy bazowej w innym szablonie klasy parametry szablonu klasy bazowej muszą być parametrami szablonu klasy pochodnej albo muszą mieć ustaloną wartość template<class T, int max> class Stos { ... }; template<class S, int max> class lepszystos : K<S,max> { ... } template<class S> class stosstulementowy : K<S,100> { ... } Szablony klas składowe statyczne klas szablonowych Każda instancja klasy szablonowej ma swój komplet składowych statycznych.