• Nie Znaleziono Wyników

Wstęp do programowania obiektowego

N/A
N/A
Protected

Academic year: 2021

Share "Wstęp do programowania obiektowego"

Copied!
21
0
0

Pełen tekst

(1)

Wstęp do programowania obiektowego

Wyjątki

(2)

WYJĄTKI

(3)

Jeżeli w jakimś miejscu programu zajdzie nieoczekiwana sytuacja,

programista piszący ten kod powinien zasygnalizować o tym.

Dawniej polegało to na zwróceniu

specyficznej wartości, co nie było zbyt szczęśliwym rozwiązaniem, bo sygnał musiał być takiego samego typu jak wartość zwracana przez funkcję.

Obecnie w wielu językach mamy

specjalne mechanizmy do obsługi takich sytuacji.

(4)

W przypadku obsługi sytuacji wyjątkowej mówi się o obiekcie sytuacji wyjątkowej, co często

zastępowane jest słowem "wyjątek".

Wyjątki się zgłasza lub „rzuca”, w C++

służy do tego instrukcja throw.

Wyjątek zgłasza się po stwierdzeniu błędu, którego rozwiązanie nie jest możliwe na obecnym poziomie (w definicji obecnej funkcji/metody), ale może być możliwe gdzieś „wyżej”.

4

(5)

Tam gdzie spodziewamy się wyjątku umieszczamy blok try, w którym

umieszczamy "podejrzane" instrukcje.

Za tym blokiem muszą (tzn. musi być przynajmniej jedna) pojawić się bloki catch.

(6)

Przykład

try // w instrukcjach poniżej może coś się nie udać {

fun();

fun2(); //podejrzane funkcje, operacje, itp.

}

catch(char obj) {

//tu coś robimy, staramy się kryzys rozwiązać innym sposobem, np. anulujemy operację, żądamy dodatkowych danych od użytkownika, wypisujemy błąd itp.

}

(7)

Co dzieje się po zgłoszeniu wyjątku?

Przeszukiwany jest stos wywołań funkcji w poszukiwaniu takiej, która zawiera obsługę wyjątku danego typu (czyli odpowiednią instrukcję catch).

Jeżeli odpowiednia obsługa wyjątku zostanie znaleziona, wyjątek jest obsługiwany.

Jeżeli w trakcie poszukiwań nie został znaleziony pasujący blok obsługi wyjątku, wracamy do punktu wejściowego programu, czyli funkcji main.

Jeżeli i w main nie ma obsługi zgłoszonego wyjątku, program jest przerywany w trybie awaryjnym.

Sterowanie nigdy nie wróci do opuszczonych wcześniej funkcji!

(8)

Po obsłudze wyjątku, program może się znajdować w znacząco innym

stanie niż przed, co może utrudniać debugowanie.

Niektóre sytuacje są na tyle krytyczne dla wykonania programu, że nie ma sensu ich obsługiwać wyjątkami.

(9)

W instrukcji catch umieszczamy typ jakim będzie wyjątek. Rzucić możemy wyjątek typu int, char, ale również klasy definiowane przez użytkownika

Nazwa tego obiektu nie jest konieczna, ale jeżeli

chcemy mieć dostęp do obiektu to musimy ten obiekt jakoś nazwać (funkcjonuje to jako zmienna lokalna).

Bloków catch może być więcej, najczęściej tyle ile możliwych typów do złapania.

Co ważne jeżeli rzucimy wyjątek konkretnego typu to

"wpadnie" on do pierwszego odpowiadającego bloku catch nawet jeżeli inne nadają się lepiej. Dotyczy to zwłaszcza klas dziedziczonych.

catch(…) wychwytuje wszystkie typy wyjątków

(10)

#include<iostream>

using namespace std;

double Dziel(double a, double b) //funkcja zwraca iloraz a / b {

if (b == 0) //przez zero się nie dzieli

throw "dzielenie przez zero!"; //rzucamy wyjątek return a / b;

}

int main() {

try {

Dziel(10, 0);

}

catch(const char* w) {

cout<<"Wyjatek: "<<w;

}

cin.get();

return 0;

}

(11)

Dobrym zwyczajem (obowiązkowym w wielu współczesnych językach obiektowych, np.

Java) jest pisanie obok deklaracji funkcji jakie wyjątki może ona rzucać:

void fun(int aa) throw(char)

zapis ten w C++ oznacza że funkcja fun może wyrzucić tylko wyjątek typu char.

Zapis throw() oznacza, że funkcja nie może w ogóle wyrzucać wyjątków, a brak zapisu

oznacza, że może wyrzucić dowolny wyjątek.

(12)

Wiele języków posiada rozbudowaną

obsługę wyjątków, włącznie z utworzoną hierarchią klas wyjątkowych.

Standardowa biblioteka C++ oferuje klasę exception, zdefiniowaną w pliku

nagłówkowym <exception>, która

udostępnia dodatkową metodę wirtualną o nazwie what(char *), którą

nadpisujemy we własnej klasie wyjątku, dziedziczącego z exception, by

zwracała jego opis.

(13)

Blok catch przyjmuje obiekt typu exception przez referencję.

Wychwytuje więc też obiekty z klasy dziedziczącej (myexception).

(14)

Klasy wyjątków zdefiniowane w

bibliotece standardowej C++

(15)

Niektóre wyjątki z biblioteki standardowej C++

bad_alloc - niemożliwa alokacja pamięci

bad_cast - niemożliwa konwersja dynamiczna

bad_exception - nieobsłużony wyjątek (niepasujący do żadnego catch)

bad_typeid - wyrzucane przez typeid

ios_base::failure - wyrzucane przez funkcje z bilbioteki iostream

runtime_error – błędy wykrywane tylko podczas wykonania programu

(16)

Przechwytywanie wyjątku klasy bad_alloc

try {

int * myarray= new int[1000000000];

}

catch (bad_alloc&) {

cout << "Error allocating memory." << endl;

}

(17)

Przechwytywanie bad_alloc jako exception (klasy nadrzędnej)

#include <iostream>

#include <exception>

using namespace std;

int main () { try

{

int* myarray= new int[1000000000];

}

catch (exception& e) {

cout << "Standard exception: " << e.what() << endl;

}

return 0;

}

(18)

#include <iostream>

#include <exception>

using namespace std;

class myexception: public exception

{ virtual const char* what() const throw() { return "My exception happened";

} };

int main () { try

{ myexception myex; // tworzenie obiektu wyjątku throw myex; // zgłoszenie wyjątku

} catch (exception& e)

{ cout << e.what() << endl;

} return 0;

} 18

Tworzenie własnej klasy wyjątku

(19)

#include<iostream>

#include<string>

#include<cmath>

using namespace std;

double dziel(double, double) throw(string);

int main() {

try {

cout<<dziel(10, 2) << endl; // wykona się cout<<dziel(10, 0) << endl; // zgłosi wyjątek cout<<dziel(10, 5) << endl; // nie wykona się }

catch(string w) {

cout<<"Wyjatek: "<<w;

}

cin.get();

return 0;

}

double dziel(double a, double b) throw(string) if (b == 0) {

{string wyjatek = "dzielenie przez zero!";

(20)
(21)

Łańcuch dynamiczny wywołań

funkcji i wyjątki

Cytaty

Powiązane dokumenty

 Standardowo wywoływany jest konstruktor bezparametrowy (lub domyślny) klasy nadrzędnej..  Aby do konstrukcji podobiektu klasy bazowej

patrzymy w prawo: jeśli jest tam nawias otwierający okrągły '(', to będzie to funkcja (odczytujemy liczbę i typ parametrów); jeśli będzie tam nawias otwierający kwadratowy '[',

• Parametrami szablonów mogą być również szablony klas, jako tak zwane szablony parametrów szablonów.. Stack&lt;int, std::vector&gt;

 OutputIterator set_union (InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, InputIterator2 last2, OutputIterator result);.  OutputIterator

Model dziedziny (uzupełniony): klasy, atrybuty klas oraz

 Jednostka programu, która zadeklarowała instancję klasy (obiekt), ma dostęp do publicznych bytów tej klasy, ale tylko poprzez tę instancję.  Każda instancja klasy ma

 Symbole pojawiające się wyłącznie po prawej stronie to symbole terminalne.  Generalnie symbole terminalne to symbole z alfabetu definiowanego języka,

lista składowych klasy ® [specyfikator dostępu :] lista składowych klasy private: sekcja prywatna (domyślna dla class) - składowe klasy są widoczne tylko w obrębie