Szablony (wzorce) Przykład 1: Szablon klasy -

Slides:



Advertisements
Podobne prezentacje
Tablice 1. Deklaracja tablicy
Advertisements

C++ wykład 9 ( ) Szablony.
C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 4 ( ) Przeciążanie operatorów.
Język C/C++ Funkcje.
C++ wykład 7 ( ) Wyjątki.
Programowanie obiektowe
Deklaracje i definicje klas w C++ Składowe, pola, metody Konstruktory
Klasa listy jednokierunkowej Przekazywanie parametrów do funkcji
Dzisiejszy wykład Wyjątki.
Programowanie obiektowe
Programowanie obiektowe PO PO - LAB 4 Wojciech Pieprzyca.
Standardowa biblioteka języka C++
Programowanie obiektowe
Wzorce.
Prowadzący: mgr inż. Elżbieta Majka
Dziedziczenie. Po co nam dziedziczenie? class osoba { char * imie, char * imie, * nazwisko; * nazwisko;public: void wypisz_imie(); void wypisz_imie();
Bezpieczeństwo wyjątków w C++: OpenGL
Wielodziedziczenie od środka Konrad Lipiński
OOPC++ - wstêp, klasy1 Klasy Do struktury można dołączyć operacje działające na jej polach. struct date { int day, month, year; void set (int d, int m,
Licznik template<class Count_Type> class Count { public:
ODE Zapytania. Pętla for (1) Do obiektów będących instancjami klas możemy uzyskać dostęp za pomocą pętli for Zakres tej pętli to wszystkie obiekty klasy.
Obiektowe metody projektowania systemów Command Pattern.
Struktury.
C++ wykład 2 ( ) Klasy i obiekty.
C++ wykład 7 ( ) Wyjątki. Ogólne spojrzenie na wyjątki Wyjątki zaprojektowano do wspierania obsługi błędów. System wyjątków dotyczy zdarzeń synchronicznych.
Zasady zaliczenia Warunki uzyskania zaliczenia:
Podstawy programowania II
Programowanie obiektowe III rok EiT
Programowanie urządzeń mobilnych – wykład IV
Java 3 MPDI Programowanie obiektowe W7. import java.io.*; public class X { // kontrukcja throws – określenie jakie wyjątki może dana metoda // sygnalizować
Podstawy programowania II
T: Różnice pomiędzy programowaniem strukturalnym a obiektowym
Programowanie obiektowe w C++
Programowanie obiektowe III rok EiT
Programowanie obiektowe III rok EiT
Dziedziczenie Maciek Mięczakowski
Inicjalizacja i sprzątanie
Seminarium problemowe
Programowanie obiektowe Wykład 3 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/21 Dariusz Wardowski.
Programowanie obiektowe Wykład 6 dr Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ 1/14 Dariusz Wardowski.
Programowanie obiektowe 2013/2014
Programowanie w języku C++
K URS JĘZYKA C++ – WYKŁAD 7 ( ) Wyjątki.
Treści multimedialne - kodowanie, przetwarzanie, prezentacja Odtwarzanie treści multimedialnych Andrzej Majkowski informatyka +
K URS JĘZYKA C++ – WYKŁAD 10 ( ) Szablony.
Programowanie strukturalne i obiektowe C++
Kurs języka C++ – wykład 4 ( )
K URS JĘZYKA C++ – WYKŁAD 2 ( ) Klasy i obiekty.
Wyjątki. Po co nam wyjątki? Często pisząc jakiś kod staramy się go uczynić uniwersalnym, jesteśmy w stanie wykryć sytuacje niepoprawne, ale nasz kod może.
Paweł Starzyk Obiektowe metody projektowania systemów
Dziedziczenie wielobazowe. dana klasa może mieć kilka bezpośrednich klas bazowych: dana klasa może mieć kilka bezpośrednich klas bazowych: kolorpołożenie.
Dziedziczenie Wykład 7 Dziedziczenie sekwencyjne
Wykład 4 Klasa Vec, której konstruktory alokują pamięć dla obiektów 1.Przykład definicji klasy Vec 2.Definicje konstruktorów i destruktora 3.Definicja.
PO13-1 / 19 Wykład 13 Wyjątki i ich zgłaszanie Wyłapywanie wyjątków Obsługa wyjątków Wykorzystanie polimorfizmu Filtrowanie wyjątków Błędy w konstruktorach.
Wykład 5 Klasa Vec i jej operatory 1.Kategorie operatorów 2.Operatory ogólne - przykłady 3.Operatory specjalne [ ], ( ) oraz –> 4.Operatory new i delete.
Wykład 8 Polimorfizm 1.Funkcje polimorficzne 2.Czyste funkcje wirtualne i klasy abstrakcyjne PO8-1 / 38.
Partnerstwo dla Przyszłości 1 Lekcja 28 Dziedziczenie i rodzaje dziedziczenia.
Podstawy informatyki Operatory rzutowania Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały.
Podstawy informatyki Mechanizm obsługi sytuacji wyjątkowych Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu.
K URS JĘZYKA C++ – WYKŁAD 3 ( ) Przenoszenie Składowe statyczne Funkcje wbudowane Argumenty domyślne.
C++ mgr inż. Tomasz Turba Politechnika Opolska 2016.
Programowanie Obiektowe – Wykład 6
Kurs języka C++ – wykład 3 ( )
(według:
Delegaty Delegat to obiekt „wiedzący”, jak wywołać metodę.
Programowanie Obiektowe – Wykład 2
Kurs języka C++ – wykład 4 ( )
PGO Dziedziczenie Michail Mokkas.
Zapis prezentacji:

Szablony (wzorce) Przykład 1: Szablon klasy - klasa implementująca wektory (prawie) dowolnego typu. template <class T > class Wektor { protected: T * v; // właściwy wektor - tablica int sz; // rozmiar public: Wektor (int); // konstruktor z rozmiarem T& operator [ ] (int); // dostęp do elementów z kontrolą T& elem (int i) const { return v [ i ]; } // Uwaga na const! .... }; // pełna implementacja dalej Wektor <int> v1 (20), v2(20); Wektor <complex<float> > v3 (10); Wektor <string> vs(10); Wektor <Ksztalt*> figury(20); // Wektor wskaźników - to może nie działać Wektor <int> v4 = v1+v2; // Jest zdefiniowane dodawanie Przykład 2: Szablon funkcji - uniwersalna funkcja sortująca. template <class T > void sort (Wektor <T> & v); To jest rodzina nieskończenie wielu funkcji. Funkcję przy wywołaniu wyznacza się stosując przeciążanie. Wektor <complex<double> > cv (10); Wektor <string > cs (30); sort (cv); // wywołuje funkcję sort (Wektor<complex<double> >) sort (cs); // wywołuje funkcję sort (Wektor<string>)

Licznik template<class Count_Type> class Count { public: // Konstruktory/Destruktory Count() { } virtual ~Count() { } // Funkcje implementujące akcje obiektów virtual void increment() = 0; virtual void decrement() = 0; void reset() {value = reset_value;} // Funkcje dające dostęp do prywatnych atrybutów obiektów Count_Type get_value() { return value; } void set_value(Count_Type new_value) { value = new_value; } Count_Type get_reset_value() { return reset_value; } void set_reset_value(Count_Type new_value) { reset_value = new_value; } protected: Count_Type value; Count_Type reset_value; }; class Integer_Count : public Count<int> { Integer_Count() { reset_value = 0; reset(); } Integer_Count (int new_value) { reset_value = 0; value = new_value; } ~Integer_Count() { } void increment(){value++;} void decrement(){value--;} char* asBase(int number_base);

Przykład - wektory template <class T > class Wektor { protected: T *v; // właściwy wektor - tablica int sz; // rozmiar public: Wektor(int); // konstruktor z rozmiarem Wektor(const Wektor&); // konstruktor kopiujący virtual ~Wektor() { delete[] v; }; // destruktor int size() const { return sz; } void set_size ( int ); // ustawia rozmiar (nie ma tu impl.) T& operator[] (int); // dostęp do elementów z kontrolą T& elem(int i) const // dostęp do elementów bez kontroli { return v[ i ]; } // dla kompilatora ta metoda jest const (sic!) Wektor operator+(const Wektor&); // tworzy wektor będący sumą wektorów Wektor& operator=(const Wektor& ); // przypisanie }; template <class T> Wektor <T>:: Wektor(int s) { if (s < 0 ) blad ("Zły rozmiar"); sz = s; v = new T[ s ]; // Wymaga konstruktora bezargumentowego w T } Wektor <T>:: Wektor (const Wektor <T>& w) sz = w .size(); v = new T [sz ]; for (int i = 0; i < sz; i++) v [ i ] = w. elem (i);

template <class T> Wektor <T>& Wektor<T>::operator=(const Wektor <T>& w) { if (sz != w.size()) blad("Niezgodne rozmiary wektorów"); for (int i = 0; i < s; i++) elem( i ) = w.elem( i ); } T& Wektor<T>::operator[](int i) if (i < 0 || i >= sz) blad("Przekroczenie zakresu tablicy"); return v[ i ]; Wektor<T> Wektor<T>::operator+ (const Wektor<T>& a) int s = size(); if (s != a.size()) blad("Zły rozmiar wektora"); Wektor<T> suma(s); // nowy wektor suma.elem(i) = elem(i) + a.elem(i); return suma; Uwagi: - zamiast funkcji blad lepiej użyć obsługi wyjątków, - const w elem jest poprawne zwn C++, choć niekoniecznie zwn na nasze oczekiwania, [] też można było zadekalrować jako const, - zwykle dla wskaźników wolelibyśmy mieć inną realizację, można to dookreślić: class Wektor<T*> {....};

Dziedziczenie wielokrotne (dziedziczenie wielobazowe) Chcemy mieć graf (acykliczny) dziedziczenia, a nie drzewo. istream iostream ostream ios class A { ...}; class B : { ... }; class C : public A, public B { ... }; // klasa C dziedziczy po A i po B Najważniejsze Problemy: W jaki sposób wyszukiwać funkcje wirtualne? Rozwiązanie w C++: Jakakolwiek niejednoznacznośc jest błędem. Może być tylko jedna możliwa funkcja do wyboru.

Użycie zmiennej a jest niejednoznaczne. Powtarzanie się klas. class A { int a; }; class B : public A { int b; }; class C: public A { int c; }; class D : public B, public C { int d; }; a z B b a z C c d warstwa B wartstwa C Użycie zmiennej a jest niejednoznaczne. Trzeba kwalifikować zmienną a nazwą klasy (np. B :: a ). Pytanie: czy chcemy, żeby były dwa “egzemplarze” warstwy klasy A, czy jeden? Na ogół chcemy jeden. class A { int a; }; class B : virtual public A { int b; }; class C: virtual public A { int c; }; class D : public B, public C { int d; }; a b c d warstwa A warstwa B wartstwa C warstwa D class ios { .... }; class isrtream : virtual public ios { ... } class ostream : virtual public ios { ... } class iostream : public iostream, public ostream { ... }

Programowanie Obiektowe Program = zbiór obiektów współpracujących poprzez komunikaty (funkcje) Używamy abstrakcyjnych typów danych Projektując program projektujemy klasy i akcje obiektów jakie mają być klasy jakie mają być hierarchie klas co obiekt ma robić (jakie funkcje mają mieć klasy) Nie interesuje nas podział na funkcje (jak w programowaniu strukturalnym). Funkcje są wyznaczone w naturalny sposób przez akcje obiektów Atrybuty obiektów są chronione (niedostępne z zewnątrz) Projektujemy klasy tak, aby mogły być wielokrotnie użyte (czyli dosyć ogólne). Specjalizujemy klasy poprzez dziedziczenie Używamy funkcji wirtualnych - wtedy każdy obiekt wykonuje akcje sobie właściwe

Obsługa wyjątków Co to jest wyjatek? Po co obsługuje się wyjątki? To jest wyjątkowa sytuacja w czasie wykonywania operacji ( funkcji), której nie potrafimy obsłużyć na danym poziomie abstrakcji, czyli w tej funkcji. Operacja, która wykryła wyjątkową sytuację, zwykle nie rozumie dobrze jej znaczenia. Sensowne jest więc przekazanie informacji do “wyższej instancji”, czyli do funkcji, która tę operacją (funkcję) wywołała. Nazywa się to zgłoszeniem wyjątku. Funkcja, która wykonuje operację zgłaszającą wyjątek może go obsłużyć (wyłapać), zignorować (czyli zostawić do obsłużenia przez “jeszcze wyższą instancję”) lub propagować (przekazać jeszcze wyżej). Wyjątki nie obsłużone są obsługiwane przez system (jako błędy) i na ogół powodują zakończenie programu. Po co obsługuje się wyjątki? Zasada programu (systemu) bezpiecznego i odpornego na błędy: Program nigdy nie ma prawa “paść” w sposób niekontrolowany. Program zawsze musi wypisać komunikat zrozumiały dla użytkownika. Przykłady wyjątków: 1. próba pobrania czegoś z pustego stosu funkcja używająca stosu sama powinna zdecydować, co to znaczy 2. przepełnienie stosu (np. implementowanego w tablicy) może funkcja działająca na stosie potrafi temu zaradzić? 3. brak pliku otwieranego do czytania może zwykle taki plik jest, ale jak nie ma, to trzeba go założyć

C++ Co dają mechanizmy obsługi wyjątków? Moduł implementujący abstrakcyjną strukturę danych (np. stos) nie powinien zawierać obsługi błędów, bo dla użytkownika tej struktury to mogą być błędy innego rodzaju. Przykład: Funkcja zamieniająca wyrażenie na ONP. Przy poprawnym wyrażeniu stos nigdy nie będzie pusty, więc nie warto obciążać funkcji sprawdzaniem tego. Próbę zdjęcia czegoś z pustego stosu warto obsłużyć jako wyjątek - niepoprawne wyrażenie. Co dają mechanizmy obsługi wyjątków? szansę zareagowania na każdą sytuację we właściwy sposób wydzielenie części obsługującej wyjątki z właściwego programu C++ Klasa wyjątków - opisuje wyjątki jakiegoś rodzaju. throw wyjatek - zgłasza wyjątek try { ..... f ( ... ) } catch (< klasa wyjątku1 > ) {... // kod obsługi wyjątku1 zgłoszonego w trakcie // wykonywania funkcji f catch ( < klasa wyjątku2 > ) { // kod obsługi wyjatku 2 ....... // dalszy ciąg programu - wyjątki nas nie interesują

template <class T> class Stos { private: T * top; int max_size; T * s; public: Stos (int n = 10 ) { s = top = new T [size = n]; } class Empty { } ; // wyjatek - pusty stos class Overflow { }; // wyjątek - przepełnienie stosu int empty { return top == s ;} void push (T & elem ) { if (top > s + max_size - 1) throw Overflow ( ); s [ top++ ] = elem; } T & pop ( ) { if (top == s) throw Empty ( ); return s [ -- top ]; } }; class Koniec { }; // wyjątek powodujący zakończenie programu void ONP ( ... ) { Stos < char > S (100); try { .... S.push (x); ... x = S.pop ( ); } catch (Stos <char>:: Overflow) { cout << “Za długie wyrażenie \n“; throw Koniec ();} catch (Stos <char>:: Empty) { // pominięcie wyrażenia do końca cout << “Niepoprawne wyrażenie \n”; } void main () .... try { ... ONP ( ... ) ...} catch (Koniec) { } // akcje końcowe - zamykanie plików itp

Wyjątek to jest obiekt - może mieć atrybuty void G () { try { // .... F (... ); // .. } catch (Wyjatek ) { // ... obsługa możliwa do wykonania na poziomie funkcji G throw ; // propagacja tego samego wyjątku wyżej // ... void H ( ) { try { // .... G ( ); // .... catch (Wyjątek ) { // ... obsługa na poziomie funkcji H } Wyjątek to jest obiekt - może mieć atrybuty class Wektor { public: class Zakres { // wyjatek - przekroczenie zakresu int indeks; // indeks przekraczający zakres Zakres ( int i) { indeks = i; } }; int & Wektor :: operator [ ] (int i) { if (0 <= i && i < rozm ) return p[i]; throw Zakres (i);

void f (Wektor & w) { // ... try { zrób_coś (w); ... } catch (Wektor :: Zakres z ) { cerr << “zły indeks “ << z.indeks << ‘\n’; } Wektor :: Zakres z deklaracja wyjątku Określa, jaki rodzaj (typ) wyjatku jest to wyłapywany. Właściwym wyjątkiem jest z. Wyjątek zgłoszony, ale nie obsłużony powoduje wywołanie funkcji terminate () kończącej program. Można określić, jakie wyjątki może zgłaszać dana funkcja: void f ( ...) throw (x2, x3, x4) { ... } Funkcja f może zgłaszać tylko wyjatki x2, x3, x4. Próba zgłoszenia czegoś innego powoduje wywołanie funkcji unexpected () kończącej program (przez wywołanie funkcji terminate() ). Jeśli nie ma tego w deklaracji funkcji, to może ona zgłosić każdy wyjątek. void f ( ) throw (); // nie zgłasza żadnych wyjątków Tego typu deklaracje są ważne dla funkcji zewnętrznych (bibliotecznych)