Sunteți pe pagina 1din 7

12. Template-uri de funcii.

Tratarea excepiilor
Template-urile (abloanele) reprezint una dintre cele mai puternice
caracteristici ale limbajului C++. Acestea permit definirea, printr-un singur segment
de cod, a unei ntregi game de funcii suprancrcate template de funcie sau a unei
ntregi serii de clase template de clas. n acest capitol vom discuta cazul funciilor.
Putem scrie generic, de exemplu, un singur template de funcie pentru ordonarea
unui ir de elemente, iar funcia poate fi apelat pentru valori de diverse tipuri: int,
double etc.
Tratarea excepiilor este o metod care permite programatorilor s scrie
programe mai robuste, mai clare i cu un grad mai mare toleran la erori.
Programele pot fi concepute astfel nct s detecteze i s trateze erorile (excepiile)
care pot aprea n timpul rulrii, evitnd astfel ntreruperile neplanificate ale
aplicaiilor.

12.1

Template-uri de funcii

Funciile suprancrcate realizeaz, de obicei, operaii similare pentru diferite


tipuri de date. Dac operaiile sunt identice pentru toate tipurile de date, acestea pot
fi realizate mai compact folosind template-uri de funcii. Programatorul trebuie s
scrie doar o singur definiie de template de funcie. Bazndu-se pe tipurile
argumentelor date explicit sau rezultate din apeluri ale acestor funcii, compilatorul
genereaz funcii separate n codul obiect pentru a manipula corespunztor fiecare
tip de apel. n limbajul C, acest lucru poate fi realizat folosind macrouri create prin
directiva de preprocesare #define. Este, ns, o metod care poate produce efecte
nedorite i care nu permite compilatorului s fac verificri de tip.
Toate definiiile de template-urile de funcii ncep prin cuvntul cheie template
urmat de lista parametrilor formali de tip ai template-ului de funcie plasat ntre < >.
Fiecare parametru formal de tip trebuie s fie precedat de cuvntul cheie class sau
de typename.
Parametrii formali de tip din definiia unui template de funcie sunt utilizai pentru
a specifica tipurile argumentelor funciei, tipul valorii returnate de funcie i pentru a
declara variabile n funcie. Definiia funciei este, astfel, cea a unei funcii obinuite.
Cuvintele cheie class sau typename folosite pentru a specifica parametrii de tip ai
template-ului au semnificaia de orice tip de dat predefinit sau definit prin program.
Programul de mai jos definete funcia PrintArray care tiprete
componentele unor tablouri.
#include <iostream>

Programarea calculatoarelor i limbaje de programare I

<iostream>
using std::cout;
using std::endl;
template< class T >
void PrintArray(const T *array, const int count)
{
for(int i = 0; i < count; i++)
cout << array[i] << " ";
cout << endl;
}
int main()
{
const int aCount = 5, bCount = 7, cCount = 6;
int a[aCount] = {1, 2, 3, 4, 5};
double b[bCount] = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7};
char c[cCount] = "HELLO";
cout << "Tabloul a contine: " << endl;
PrintArray(a, aCount);
cout << "Tabloul b contine: " << endl;
PrintArray(b, bCount);
cout << "Tabloul c contine: " << endl;
PrintArray(c, cCount);
return 0;
}
Acest program afieaz:
Tabloul a contine:
1 2 3 4 5
Tabloul b contine:
1.1 2.2 3.3 4.4 5.5 6.6 7.7
Tabloul c contine:
H E L L O
Funcia template PrintArray declar un singur parametru formal de tip cu
numele T. Identificatorul T poate fi nlocuit cu orice alt identificator valid. Prin T se
definete generic tipul tabloului ale crui componente urmeaz s fie tiprite. Atunci
cnd compilatorul detecteaz n program un apel al funciei PrintArray, tipul
argumentului generic este nlocuit cu tipul parametrului actual i se creeaz o funcie
pentru tiprirea tabloului cu acest tip. Noua funcie este apoi compilat.
n exemplul de mai sus, sunt instaniate trei funcii PrintArray, cu argumente
de tip int, double i char.
Exemplu
Instanierea pentru tipul de dat int este:
void PrintArray(const int *array, const int count)
{
for(int i = 0; i < count; i++)

Programarea calculatoarelor i limbaje de programare I

cout << array[i] << " ";


cout << endl;
}
Fiecare parametru formal de tip din definiia unui template de funcie apare, n
mod normal, cel puin o dat n lista de parametri ai funciei cel puin o dat. Numele
unui parametru formal de tip poate fi folosit o singur dat n lista de parametri ai
header-ului unui template.
n programul de mai sus, funcia PrintArray este apelat de trei ori cu
argumentele a de tip int*, b de tip double* i c de tip char* pentru primul
parametru. Apelul
PrintArray(a, aCount);
face ca apariiile lui T n funcia PrintArray s fie transformate n int i
compilatorul instaniaz funcia PrintArray pentru T de tip int. n mod
asemntor se ntmpl i pentru apelurile
PrintArray(b, bCount);
PrintArray(c, cCount);
n acest program, mecanismul template-urilor face ca programatorul s nu mai
fie nevoit s scrie trei funcii suprancrcate cu prototipurile
void PrintArray(const int *, const int);
void PrintArray(const double *, const int);
void PrintArray(const char *, const int);

12.2

Tratarea excepiilor

Exist mai multe tehnici prin care pot fi tratate erorile care apar n timpul rulrii
unui program. Cea mai folosit este aceea de a introduce n program secvene de
cod adaptate prevenirii unor posibile situaii nedorite. Erorile sunt tratate n locul n
care apar n program. Avantajul acestei abordri este c persoana care citete codul
poate vedea modalitatea de prelucrare a erorii n vecintatea codului i poate
determina dac metoda de tratare a excepiei este implementat corect.
Dezavantajul este c prin aceast schem codul este oarecum poluat cu secvene
de procesare a erorilor i devine mult mai greu de citit de un programator care este
concentrat pe aplicaia nsi. Aceast metod face codul mult mai greu de neles i
de meninut.
Tratarea excepiilor n C++ permite programatorilor s nlture partea de tratare
a excepiilor din secvena principal de program. Stilul C++ de tratare a excepiilor
permite interceptarea tuturor excepiilor sau a tuturor excepiilor de un anumit tip.
Aceasta face programul mult mai robust, reducnd probabilitatea de ntrerupere
neplanificat a programului.
Tratarea excepiilor se folosete n situaia n care programul poate s i
continue rularea dup ce depete eroarea care provoac excepia.

Tratarea excepiilor folosind try, throw i catch


Tratarea excepiilor n C++ este o metod care se aplic atunci cnd funcia
care detecteaz o eroare nu o i trateaz. Ea doar genereaz sau arunc excepia
(throw). Nu se garanteaz c excepia va fi i tratat n afara funciei. Pentru
aceasta, trebuie specificat o secven de cod care detecteaz sau prinde excepia
i o trateaz.
Programatorul trebuie s includ ntr-un bloc try codul care ar putea genera o
eroare generatoare a unei excepii. Blocul try este urmat de unul sau mai multe

Programarea calculatoarelor i limbaje de programare I

blocuri catch. Fiecare bloc catch specific tipul excepiei pe care o poate detecta
i trata. Dac excepia se potrivete cu tipul parametrului unuia dintre blocurile
catch, se execut codul acelui catch. Dac nu este identificat niciun bloc catch
care s trateze eroarea, se apeleaz funcia predefinit terminate care la rndul ei
apeleaz n mod implicit funcia predefinit abort pentru ntreruperea programului.
Dac ntr-un bloc try nu se genereaz nicio excepie, programul ruleaz
ignornd blocurile catch asociate lui.
Exemplu
#include <iostream>
#include <stdexcept>
using std::cin;
using std::cout;
using std::endl;
using std::runtime_error;
double Fractie(int numarator, int numitor)
{
if(numitor == 0)
throw runtime_error("Numitorul este 0");
return static_cast<double>(numarator)/numitor;
}
int main()
{
int numar1, numar2;
double rezultat;
cout << "Introduceti doi intregi (EOF pentru a termina): ";
while(cin >> numar1 >> numar2)
{
try
{
rezultat = Fractie(numar1, numar2);
cout << "Valoarea fractiei este: " << rezultat << endl;
}
catch(runtime_error e)
{
cout << "A aparut urmatoarea exceptie: "
<< e.what() << endl;
}
cout << "Introduceti doi intregi (EOF pentru a termina): ";
}
cout << endl;
return 0;
}
Un exemplu de rulare a acestui program este urmtorul:
Introduceti doi intregi (EOF pentru a termina): 3 4
Valoarea fractiei este: 0.75
Introduceti doi intregi (EOF pentru a termina): 5 0

Programarea calculatoarelor i limbaje de programare I

A aparut urmatoarea exceptie: Numitorul este 0


Introduceti doi intregi (EOF pentru a termina): CTRL-D
Programul de mai sus calculeaz rezultatul mpririi a dou numere ntregi.
Dac numitorul este 0, este declanat o excepie i se semnaleaz eroarea.
Programul conine un bloc try care cuprinde codul care ar putea genera o
excepie. Operaia de mprire a celor dou numere este implementat prin funcia
Fractie care genereaz o excepie prin instruciunea throw atunci cnd numitorul
este 0.
Clasa runtime_error face parte din biblioteca standard i este declarat n
fiierul header stdexcept. Este derivat din clasa de baz exception care face
parte tot din biblioteca standard, fiind declarat n fiierul header exception i care
este folosit pentru a declana excepii n C++. Declanarea excepiilor cu ajutorul lui
runtime_error permite adugarea unui mesaj care poate fi citit prin metoda
what(). Limbajul C++ ofer o ntreag gam de clase derivate din exception,
destinate diverselor tipuri de excepii care se pot declana ntr-un program. La rndul
su, programatorul poate s i defineasc propriile sale clase pentru declanarea
excepiilor, derivndu-le, spre exemplu, din exception sau din clasele derivate din
ea.
n exemplul de mai sus, blocul try este urmat imediat de un catch care
conine codul de tratare a excepiei de tip runtime_error. Atunci cnd ntr-un bloc
try este generat o excepie, ea va fi tratat de blocul catch care este destinat
acelui tip particular de excepie. Aadar, blocul catch din exemplu va trata doar
excepiile de tip runtime_error.
Dac n timpul execuiei codul din blocul try nu genereaz nicio excepie, toate
blocurile catch asociate acestui try vor fi ignorate, iar execuia cotinu cu prima
instruciune care urmeaz dup acestea.

Generarea unei excepii throw


Cuvntul cheie throw se folosete pentru a indica faptul c a aprut o
excepie. Un throw specific, n mod obinuit, un operand. Operandul lui throw
poate fi de orice tip. Dac este un obiect, l vom numi obiect excepie. Putem folosi,
ns, i obiecte care nu sunt destinate tratrii excepiilor, i chiar i expresii de orice
tip.
Imediat ce a fost declanat o excepie, aceasta va fi detectat de cel mai
apropiat secven de cod destinat tratrii excepiei respective. Secvenele de
tratare a excepiilor generate ntr-un bloc try sunt listate imediat dup blocul try.
Ca regul general pe care este bine s o urmm atunci cnd scriem
programe, excepiile trebuie declanate doar n interiorul blocurilor try. O excepie
care apare n afara unui try poate conduce la terminarea programului.

Tratarea unei excepii catch


Tratarea excepiilor se face prin blocuri catch. Fiecare astfel de bloc const din
cuvntul cheie catch urmat, ntre paranteze rotunde, de tipul excepiei i, opional,
de un nume de parametru. ntre acolade se gsete codul care trateaz excepia.
Atunci cnd este detectat o excepie, se execut codul dintre acolade.
Blocul catch definete un domeniu de accesibilitate propriu. Dac parametrul
are nume, atunci el poate fi invocat n blocul catch. Dac nu are nume, el este
5

Programarea calculatoarelor i limbaje de programare I

specificat numai n scopul potrivirii dintre blocul catch i tipul excepiei creia i este
destinat.
O excepie care nu este detectat apeleaz n mod implicit funcia
terminate() din biblioteca standard care, la rndul ei, termin programul prin
apelul funciei abort(). Programatorul poate schimba comportamentul funciei
terminate() facnd ca aceasta s apeleze o alt funcie. Numele noii funcii va fi
trimis ca parametru funciei set_terminate.
Un catch care este urmat ntre parantezele rotunde de trei puncte trateaz
toate excepiile.
Exemplu
catch(...)
Aceast opiune este plasat, de obicei, ca o ultim variant ntr-o serie de
blocuri catch. Un bloc try urmat de mai multe blocuri catch are un comportament
similar instruciunii switch care folosete o ramur case n funcie de valoarea
expresiei testate.

Generarea unei noi excepii n catch


Uneori, tratarea unei excepii nu poate fi fcut n blocul catch care a detectat-o
i atunci se poate decide ca excepia s fie transmis mai departe, lasnd tratarea ei
pe seama altei secvene de cod (rethrowing an exception). Instruciunea
throw;
lanseaz din nou excepia.
Exemplu
#include <iostream>
using std::cout;
using std::endl;
#include <exception>
using std::exception;
void ThrowException()
{
//Lanseaza o exceptie si o prinde imediat
try
{
cout << "Functia ThrowException" << endl;
throw exception(); //Genereaza exceptia
}
catch(exception e)
{
cout << "Exceptia tratata in ThrowException" << endl;
throw;
}
cout << "Acest text nu este tiparit";
}
int main()
{
try
{
6

Programarea calculatoarelor i limbaje de programare I

ThrowException();
cout << "Acest text nu este tiparit";
}
catch(exception e)
{
cout << "Exceptia tratata in main" << endl;
}
cout << "Programul continua dupa catch in main" << endl;
return 0;
}
Acest program afieaz:
Functia ThrowException
Exceptia tratata in ThrowException
Exceptia tratata in main
Programul continua dupa catch in main
Funcia ThrowException este apelat n blocul try din main. n blocul try
din funcia ThrowException este generat o excepie de tip exception care este
detectat imediat de blocul catch asociat acestui try. Aici, excepia este relansat,
fiind tratat n blocul catch din main.

Specificarea excepiilor
Lista excepiilor care pot fi generate de o funcie se poate specifica astfel:
int g(double h) throw(a, b, c)
{
//corpul functiei
}
Prin aceast list se restrnge gama excepiilor care pot fi declanate de funcia
g la tipurile a, b, c. Dac funcia genereaz o alt excepie dect cele listate, se
apeleaz automat funcia unexpected din biblioteca standard care, la rndul ei
apeleaz funcia terminate. Comportmenul funciei unexpected poate fi modificat
asemntor modului n care se intervine asupra funciei terminate, dar apelnd, de
data aceasta, funcia set_unexpected.
O funcie pentru care nu exist o astfel de list poate genera orice excepie.

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