1 / 12

Licznik

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;}

lassie
Download Presentation

Licznik

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 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> { • public: • Integer_Count() { reset_value = 0; reset(); } • Integer_Count (int new_value) • { reset_value = 0; value = new_value; } • ~Integer_Count() { } • void increment(); • void decrement(); • char* asBase(int number_base); • };

  2. Szablony (wzorce) • Przykład 1: Szablon klasy - • klasa implementująca wektory dowolnego typu. • template <class T > • class vector { • protected: • T * v; • int size; • public: • vector (int); // konstruktor • T& operator [ ] (int); • T& elem (int i) { return v [ i ]; } • .... • }; • vector <int> v1 (200); • vector <complex > v2 (10); • vector <String> vs(100); • vector <Ksztalt*> figury(20); • Przykład 2: Szablon funkcji - uniwersalna funkcja sortująca. • template <class T > void sort (vector <T> & v); • To jest nieskończenie wiele funkcji. • Przy wywołaniu funkcji wyznacza się funkcję stosując przeciążanie. • vector <complex> cv (100); • vector <String > cs (300); • sort (cv); // wywołuje funkcję sort (vector <complex>) • sort (cs); // wywołuje funkcję sort (vector <String>)

  3. Przykład - wektory • template <class T > • class vector { • protected: • T *v; // właściwy wektor - tablica • int sz; // rozmiar • public: • vector (int); // konstruktor z rozmiarem • vector (vector<T>&); // konstruktor kopiujący • virtual ~vector() { delete v; }; // destructor • int size ( ) { return sz; } • void set_size ( int ); // ustawia rozmiar • T& operator [ ] (int); // dostęp do elementów z kontrolą • T& elem (int i ) // dostęp do elementów bez kontroli • { return v [ i ]; } • friend vector<T> operator+ (vector<T> & a, vector<T> & b); • // tworzy wektor będący sumą wektorów • vector<T> & operator= (vector<T> & ); // przypisanie • } • template <class T> • vector <T>:: vector ( int s) • { • if (s < 0 ) error (“zly rozmiar”); • sz = s; • v = new T [ s ]; • } • template <class T> • vector <T>:: vector (vector <T>& w) • { • sz = w .size(); • v = new T [sz ]; • for (i = 0; i < sz; i++) v [ i ] = w. elem (i); • }

  4. template <class T> • vector <T> :: vector <T>& operator= (vector <T>& w) • { • if (sz != w.size ()) error (“ niezgodne rozmiary wektorów “); • for (int i = 0; i < s; i++) this -> elem ( i ) = w . elem ( i ); • } • template <class T> • vector <T> :: T& operator [] (int i) • { • if (i < 0 || i >= sz) error (“przekroczenie zakresu tablicy”); • return v [ i ]; • } • template <class T> • vector <T> operator+ (vector<T>& a, vector<T>& b) • { • int s = a.size (); • if (s != b.size()) error ( “ zły rozmiar welktora”); • vector<T> suma(s); // nowy wektor • for (int i = 0; i < s; i++) • suma.elem(i) = a.elem(i) + b.elem(i); • return suma; • }

  5. ios istream ostream iostream Wielodziedziczenie(dziedziczenie wielobazowe) Chcemy mieć graf (acykliczny) dziedziczenia, a nie drzewo. • 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.

  6. a z B b a z C c d a b c d 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; }; 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; }; 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 { ... }

  7. 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

  8. Obsługa wyjątków • Co to jest wyjatek? • 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ć

  9. 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ą

  10. 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 • }

  11. 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 • public: • 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); • }

  12. 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)

More Related