Sunteți pe pagina 1din 11

Programare orientată pe obiecte Curs 6

PROGRAMARE ORIENTATĂ PE OBIECTE

Tratarea excepțiilor

O excepție este o eroare care poate să apară la rularea unui program.


Exemple:
• încercarea de deschidere a unui fișier ce nu există
• depășirea limitelor unui tablou
• încercarea de alocare a unui spațiu de memorie ce depășește dimensiunea heap-ului
• erori aritmetice
• etc.

Excepțiile pot fi gestionate în mod tradițional (ex.: apelarea metodelor exit() sau abort(), afișarea
unor mesaje de eroare), se pot returna coduri de eroare lasând sau nu programul într-o stare de eroare,
se poate utiliza variabila globală errno pentru a indica o eroare, se pot apela funcții error-hanhler
etc., însă aceste metode se caracterizează prin faptul că porţiunile de cod „normale“ se întrepătrund
cu cele de tratare a excepţiilor, iar claritatea programelor are de suferit din cauza ramificărilor
generate de numeroasele teste ale indicatorilor de eroare. Există și situații în care metodele clasice
nu pot fi eficiente (ex. erorile apărute în constructori, aceștia fiind definiți prin funcții care nu
returneaza nimic).

O soluție este oferită de următorul model:


• o funcţie care nu poate gestiona o problemă, aruncă o excepţie (throws) cu scopul ca
funcția care a apelat-o (direct ori indirect) să gestioneze problema.
• funcţia care „vrea” să gestioneze o anumită problema indică acest lucru captând excepţia
respectivă .

Acest model presupune folosirea try, throw şi catch, astfel având posibilitatea ca o eroare apărută
într-o funcţie să fie tratată în alta. Prima funcție doar generează sau aruncă excepţia (throw).
Aruncarea unei excepții nu garantează că excepţia va fi şi tratată în afara funcţiei. Pentru aceasta,
trebuie specificată o secvenţă de cod care detectează sau prinde excepţia şi o tratează. Programatorul
trebuie să includă într-un bloc try codul care ar putea genera o eroare generatoare a unei excepţii.
Blocul try este urmat de unul sau mai multe blocuri catch. Fiecare bloc catch specifică tipul
excepţiei pe care o poate detecta și va executa blocul corespunzator tipului excepției.

Excepţiile sunt interceptate şi prelucrate folosind construcţia try şi catch, care are sintaxa:

1
Programare orientată pe obiecte Curs 6

try{
//codul care ar putea genera erori
}
catch(Tip1 Var1){
//tratare exceptie
}
...
catch(Tipn VarN){
//tratare exceptie
}

Fiecare bloc catch are între paranteze rotunde tipul de excepţie care va fi interceptat şi prelucrat de
blocul de instrucţiuni.

Important: Blocurile try şi catch formează o singură construcţie (nu se poate folosi un bloc try fără
cel puţin un bloc catch şi nu se poate folosi un bloc catch fără un bloc try). Între cele două blocuri
nu pot exista alte secvenţe de instrucţiuni. Se pot înlănţui oricâte blocuri catch, câte unul pentru
fiecare tip de excepţie ce se doreşte a fi tratată.

Exemplu:
void main(void){
cout << "Start" << endl;
try {
cout << "Exemplu tratare exceptii." << endl;
throw 100;//lansam o exceptie
cout << "Cod care nu se va executa.";
}
catch(int i) {
cout << "Am captat exceptia care are codul: "<< i << endl;
}
cout << "Stop" << endl;
}

Dacă în blocul catch am fi avut

catch(double i) {
cout << "Am captat exceptia care are codul: "<< i << endl;
}

atunci excepția nu ar fi fost captat[ (am lansat o exceptie de tip int) și ar fi condus la o terminare
anormală a programului.

Exemplu:

Fie funcţia:
int factorial(int n){
if(n<0)//aruncam o exceptie
throw "Argumentul trebuie sa fie pozitiv";
if(n==0)return 1;
return n*factorial(n-1);
}
void main(){
cout<<"Start test exceptii"<<endl;
cout<<"n!="<<factorial(-5)<<endl;
cout<<"Sfarsit test exceptii"<<endl;
}
2
Programare orientată pe obiecte Curs 6

În acest caz ajungem la o terminare anormală a programului. Mesajul "Sfarsit test exceptii" nu
mai apare. Execuţia se întrerupe în momentul apariţiei excepţiei.

Dacă tratăm excepţia în funcţia main:

void main(){
cout<<"Start test exceptii"<<endl;
try{
cout<<"n!="<<factorial(-5)<<endl;
}
catch(char* p){
cout<<p<<endl;
}
catch(int){
cout<<"O alta exceptie";
}
cout<<"Sfarsit test exceptii"<<endl;
}

atunci rezultatul execuţiei va fi:


Start test exceptii
Argumentul trebuie sa fie pozitiv
Sfarsit test exceptii
Press any key to continue

Se observă apariţia mesajului “Sfarsit test exceptii”.

Exemplu:

void div(double a, double b)


{
try
{
if (!b) throw b;
cout << "a / b = "<<a/b<<endl;
}
catch (double b)
{
cout << "Nu se poate imparti la zero..."<<endl;
}
}
void main()
{
double i, j;
do
{
cout << "Introduceti numaratorul(0 pentru stop) :"<<endl;
cin>>i;

cout << "Introduceti numitorul: "<<endl;


cin>>j;
div(i, j);
} while (i != 0);
};

3
Programare orientată pe obiecte Curs 6

Important: Excepţiile pot fi utilizate în constructori.


Exemplu:

class Test{
char* pv;
public:
Test(char* p)
{
if (p == 0 || p == "")//Nu permitem ca pv sa fie null sau sirul vid.
throw invalid_argument("Argumentul este null sau blank");
else
pv = p;
}
};

Cel mai simplu mod de a defini o excepţie este acela de a defini o clasă special creată pentru acel
tip de eroare. O excepţie poate purta informaţii despre eroarea pe care o reprezintă. Pot fi aruncate
excepţii de orice tip cu condiţia să poate fi copiate.
Exemplu:

class NoCopy {
NoCopy(const NoCopy& x) = delete;//fara constructor de copiere
};

class Eroare{
// ...
};
void f(int n){
Eroare e;
switch (n){
case 0:
throw e; // OK
break;
case 1:
throw NoCopy{}; // eroare: nu se poate copia NoCopy
break;
case 2:
throw Eroare; // eroare: Eroare este un tip
break;
case 3:
throw Eroare{}; // valabil doar in C++11
break;
}
}

Exemplu:

class Vector{
static const int DMAX=100;// dimensiune maxima vector
float* v;
int d; // numar de elemente vector
public:
class Range{}; // clase exceptii
class Size {};
4
Programare orientată pe obiecte Curs 6

Vector(int n);
float& operator[](int i);
};

Vector::Vector(int n){
if(n < 0 || n >= DMAX)
throw Size();
d = n;
v = new float[n];
};

float& Vector::operator[](int i){


if(i >= 0 && i < d)
return v[i];
throw Range();
};

void main(){
try{
Vector v(200); // declanseaza exceptia Size
v[130] = 1.3; // declanseaza exceptia Range
}
catch(Vector::Size){
cout<<"Depasire dimensiune maxima admisa"<<endl;
}
catch(Vector::Range){
cout<<"Depasire limite tablou"<<endl;
}
}

Clasele de excepţii standard formează o ierarhie bazată pe clasa exception. Aceasta conţine o
funcţie virtuală what ce returnează un char*. Această ierarhie poate fi folosită pentru simplificarea
tratării erorilor.

Principalele clase sunt :

5
Programare orientată pe obiecte Curs 6

logic_error - pentru raportarea erorilor detectabile înainte de execuţia programului


runtime_error - pentru raportarea erorilor din timpul execuţiei programului.
domain_error - raportează violarea unei precondiţii
invalid_argument - argument invalid pentru o funcţie
length_error - un obiect cu o lungime mai mare decât valoarea maximă reprezentabilă
out_of_range - în afara domeniului
range_error - violarea unei postcondiţii
overflow_error - operaţie aritmetică eronată (depăşire)
bad_cast - operaţie dynamic_cast eronată
bad_alloc - eroare de alocare

Exemplu:

std::vector<int> vect(10);
try {
vect.resize(vect.max_size() + 1);
}

catch (const std::length_error& e) {


cout << "Length error: " << e.what() << '\n';
}

try {
vect.at(20) = 100;
}
catch (const std::out_of_range& e) {
cout << "Out of Range error: " << e.what() << '\n';
}

Important: Dacă dorim să captăm orice excepție putem folosi blocul catch(...).
Sintaxă
try{
//codul care ar putea genera erori
}
catch(Tip1 Var1){
//tratare exceptie
}
...
catch(Tipn VarN){
//tratare exceptie
}
catch(…){
// captraza orice exceptie
}

Nu este încurajată utilizarea blocului catch(...) deoarece se pierde orice informaţie despre
excepţia apărută. În cazul în care totuși este folosit atunci prelucrările din cadrul acestui bloc
trebuie să fie independente de tipul erorii.

Dacă se dorește re-aruncarea unei exceptii către contextul superior atunci se folosește clauza throw
fără niciun argument.

Excepiile pot fi relansate așa cum se poate urmări în exemplul de mai jos.
6
Programare orientată pe obiecte Curs 6

Exemplu:
void f(void)
{
try{
throw "Ok";
}
catch (char*){
cout << "Am captat char* in f()... " << endl;
throw;
}
}
void main(){
cout << "Start..." << endl;
try{
f();
}
catch (char*){
cout << "Am captat char * in main..." << endl;
}
cout << "Sfarsit...";
};

Relansarea unei excepții se poate folosi spre exemplu în catch(…) pentru eliberare de resurse apoi
throw.
try {
//instructiuni ce pot genera excepții
}
catch(…){
//eliberare resurse
throw;
}

Unele funcţii nu aruncă excepţii iar pentru a indica acest lucru se poate declara funcţia
respectivă ca funcţie noexcept.
Este util pentru un programator să știe că o funcție nu va arunca excepții deoarece nu trebuie
sa mai scrie blocul try/catch pentru apelul funcţiei respective şi de asemenea modulul de optimizare
al compilatorului nu mai are în vedere toată calea petru găsirea unui handler.

Exemplu:
double functieCareNuAruncaExceptii(double) noexcept{
//...
}

Pentru o funcție se putea implementa restricționarea exceptiilor (o listă cu tipuri de excepții


acceptate) însă dificultățile de implementare în practică au condus la renunțarea la această abordare
începând cu C++11.

Temă: Să se implementeze sub forma unui tablou alocat dinamic clasa Stiva, gestionând excepțiile
ce pot apărea.

7
Programare orientată pe obiecte Curs 6

Diagrame UML
UML( Unified Modeling Language) este un limbaj vizual de modelare utilizat pentru specificarea,
construirea şi documentarea sistemelor de aplicaţii orientate obiect şi nu numai.
O diagrama UML este o prezentare grafică a unui set de elemente, cel mai adesea exprimate ca un
graf de noduri (elementele) și arce (relațiile).

Tipuri de diagrame UML


• Diagrame ale Cazurilor de Utilizare (Use Case)
• Diagrame de clase
• Diagrame de obiecte
• Diagrame de secvenţă
• Diagrame de stare
• Diagrame de colaborare
• Diagrame de activitate

Diagramele de clase sunt folosite în modelarea orientată obiect pentru a descrie structura statică a
sistemului, modului în care este el structurat. Se oferă o notaţie grafică pentru reprezentarea claselor
(entităţi ce au caracteristici comune) și relațiilor (relațiile dintre două sau mai multe clase).

Reprezentarea unei clase

IdClasa

vizibilitate idAtribut
vizibilitate idAtribut: tip
vizibilitate idAtribut:
tip=valoare_implicita
vizibilitate idMetoda
vizibilitate
idMetoda(lista_param):tip_returnat

Specificarea Atributelor
Sintaxa:
vizibilitate idAtribut : tip = valoare_implicitia
unde:
• vizibilitate reprezintă protecția atributului și poate să aibă una din următoarele valori
+ - public
- - privat
# - protected (opțional)

• idAtribut este identificatorul atributului


• tip – este tipul acestuia
• valoare_implicita reprezintă valoarea inițială a atributului (opțională)

8
Programare orientată pe obiecte Curs 6

Specificarea Metodelor
Sintaxa:
vizibilitate idMetoda(idP1:tip1, ..., idPn:tipN) : tip_returnat
unde:
• vizibilitate reprezintă protecția atributului și poate să aibă una din următoarele valori
+ - public
- - privat
# - protected (opțional)
• idMetoda este identificatorul metodei
• idP1,..., idPn sunt parametrii metodei
• tip1, ..., tipN sunt tipurile parametrilor
• tip_returant reprezintă tipul valorii returnate de metodă

Elementele utilizate şi notaţiile lor sunt următoarele:

Element Descriere Notaţie


O clasă este reprezentată printr-un dreptunghi cu trei
compartimente: în cel de sus se trece numele clasei, în mijloc
Clasă
se trec atributele clasei iar jos se trec operaţiile specifice
clasei.
Moştenirea este o relaţie care indică faptul că o clasă
moşteneşte caracteristicile unei clase părinte. Sensul săgeţii
Moştenire
indică sensul în care se poate spune despre clasa copil că este
de tipul clasă părinte.

Asocierea este o relaţie generică între două clase. Aceste pot


Asociere defini regulile numerice de asociere (unu la unu, unu la mai
mulţi, mai mulţi la mai mulţi).

Atunci când o clasă depinde de o altă clasă, în sensul că


Dependenţă utilizează acea clasă ca şi atribut al său, se foloseşte relaţia de
dependenţă.

Agregarea indică o relaţie de tip întreg-parte (se poate spune


Agregare despre clasa părinte că are clase de tip copil). În această relaţie,
clasa copil poate exista şi fără clasa părinte.

Această relaţie derivă din agregare dar se utilizează atunci


Compoziţie când o clasă copil nu poate exista decât în cazul existenţei
clasei părinte.

9
Programare orientată pe obiecte Curs 6

Exemplu

Clasă

Moştenirea este o relaţie prin care se indică faptul că o clasă moşteneşte caracteristicile clasei
părinte. În plus, clasa copil poate avea propriile caracteristici.

Asocierea arată existenţa unei relaţii între clase. În exemplul de mai jos, între Persoană şi
Autovehicul există următoarea relaţie:
o Persoană poate avea zero, unul sau mai multe Autovehicule.

În exemplul de mai jos, relaţia dintre Articol şi Lista de preţuri este de tip mai mulţi la mai mulţi: un
Articol poate să apară pe mai multe Liste şi o Listă poate avea mai multe Articole. Pe Liste diferite
Articolele pot avea preţuri diferite.

10
Programare orientată pe obiecte Curs 6

Dependenţa indică faptul că o clasă depinde de altă clasă, în sensul în care o funcţie oarecare
depinde de un parametru al său.

Agregarea indică faptul că o clasă părinte are elemente de tipul clasei copil. În exemplul de mai jos
Ţara poate avea mai multe Judeţe dar, în acelaşi timp, un Judeţ poate exista chiar şi în cazul în care
clasa Ţara nu există.

Într-o relaţie de tip compoziţie clasa copil nu poate exista decât dacă există o instanţă a clasei părinte.
În exemplul de mai jos instanţa clasei Comisie există atâta timp cât există instanţa clasei Examen.

11

S-ar putea să vă placă și