Documente Academic
Documente Profesional
Documente Cultură
- Template-uri de clase
Template-urile (abloanele) de clase se mai numesc i tipuri parametrizate i se
folosesc pentru crearea claselor generice. Pentru adaptarea unei astfel de clase,
este nevoie de unul sau mai muli parametri de tip care transform clasa dintr-una
generic n una particular.
Pentru a nelege ce este un template de clas vom folosi noiunea de stiv
(stack). Aceasta este o structur de date care permite stocarea unor valori, ordinea
de citire a acestora fiind invers ordinii n care au fost nscrise n colecie. Regula
last-in-first-out specific stivelor este valabil indiferent de tipul elementelor care sunt
ncrcate. Cnd se pune problema instanierii unei stive, trebuie specificat tipul de
dat al elementelor. Template-urile de clase ofer posibilitatea implementrii unei
stive generice care poate fi particularizat pentru un tip specific de dat.
Template-urile de clase ncurajeaz reutilizarea codului prin posiblitatea de a
crea dintr-o clas generic a unei versiuni specifice unui tip de dat. Atunci cnd
programatorul dorete s foloseasc o variant adaptat unui tip de dat pentru
ablonul su, are la dispoziie o modalitate simpl de scriere pe baza creia
compilatorul scrie codul surs cerut. Astfel, clasa template Stack ar putea deveni o
baz pentru crearea unor clase adaptate: stiv de valori double, stiv de valori int,
stiv de valori char, stiv de valori Employee.
Exemplu
tstack1.h
#ifndef TSTACK1_H
#define TSTACK1_H
template <class T>
class Stack
{
public:
Stack(int = 10); //stiva are dimensiunea implicita 10
~Stack() { delete[] stackPtr; } //destructor
bool push(const T&); //insereaza un element in stiva
bool pop(T&);
//extrage un element din stiva
private:
int size;
//numarul de elemente din stiva
int top;
//localizarea elementului din varful stivei
cea a funciilor template. Funcia testStack din exemplul urmtor este similar
funciei main din exemplul anterior pentru c introduce o serie de valori n Stack<T>
prin funcia push i extrage aceste valori prin funcia pop. Funcia testStack
folosete parametrul formal T de tip pentru a reprezenta tipul de dat al valorilor
stocate n Stack<T>.
Exemplu
test2_tstack1.h
#include<iostream>
using std::cout;
using std::cin;
using std::endl;
#include "tstack1.h"
template<class T>
void testStack(
Stack<T> &theStack,
T value,
T increment,
const char* stackName)
{
cout << "\nInserarea elementelor in " << stackName << '\n';
while(theStack.push(value))
{
cout << value << ' ';
value += increment;
}
cout <<
<<
<<
<<
while(theStack.pop(value))
cout << value << ' ';
cout << "\nStiva este goala. Nu se mai pot extrage elemente\n";
}
int main()
{
Stack<double> doubleStack(5);
Stack<int> intStack;
testStack(doubleStack, 1.1, 1.1, "doubleStack");
testStack(intStack, 1, 1, "intStack");
return 0;
}
tstack1.h
5
#ifndef TSTACK1_H
#define TSTACK1_H
template <class T>
class Stack
{
public:
Stack(int = 10); //stiva are dimensiunea implicita 10
~Stack() { delete[] stackPtr; } //destructor
bool push(const T&); //insereaza un element in stiva
bool pop(T&);
//extrage un element din stiva
private:
int size;
//numarul de elemente din stiva
int top;
//localizarea elementului din varful stivei
T* stackPtr; //pointer la stiva
bool isEmpty() const {return top == -1;}
//functii
bool isFull() const {return top == size-1;} //utilitare
};
template<class T>
Stack<T>::Stack(int s)
{
size = s > 0 ? s : 10;
top = -1; //initial stiva este goala
stackPtr = new T[size]; //alocarea spatiului pentru elemente
}
//Introduce un element in stiva
//Intoarce 1 daca s-a putut face inserarea si 0 in caz contrar
template<class T>
bool Stack<T>::push(const T& pushValue)
{
if(!isFull())
{
stackPtr[++top] = pushValue; //plaseaza elementul in stiva
return true; //inserare realizata cu succes
}
return false; //inserarea nu s-a putut realiza
}
//Extrage un element din stiva
template<class T>
bool Stack<T>::pop(T& popValue)
{
if(!isEmpty())
{
popValue = stackPtr[top--]; //sterge elementul din stiva
return true; //extragere realizata cu succes
}
return false; //extragerea nu s-a putut realiza
}
#endif
Rulnd acest program obinem urmtorul rezultat:
Inserarea elementelor in doubleStack
1.1 2.2 3.3 4.4 5.5
Stiva este plina. Nu se mai poate insera elementul 6.6
Extragerea elementelor din doubleStack
5.5 4.4 3.3 2.2 1.1
Stiva este goala. Nu se mai pot extrage elemente
Inserarea elementelor in intStack
1 2 3 4 5 6 7 8 9 10
Stiva este plina. Nu se mai poate insera elementul 11
Extragerea elementelor din intStack
10 9 8 7 6 5 4 3 2 1
Stiva este goala. Nu se mai pot extrage elemente
n funcia main se instaniaz dou obiecte de tip Stack<double> numit
doubleStack i Stack<int> numit intStack. Aceste obiecte sunt folosite in cele
dou apeluri ale funciei testStack:
testStack(doubleStack, 1.1, 1.1, "doubleStack");
testStack(intStack, 1, 1, "intStack");
Remarcm faptul c programul din primul exemplu i cel de mai sus conduc la
rezultate identice.
if(ptr[i]
{
cout <<
<<
break;
}
else
cout <<
<<
== 0)
"Alocarea memoriei nu a fost posibila pentru ptr["
i << "]\n";
}
return 0;
}
Rulnd acest program putem obine, n funcie de calculator i de compilatorul
instalat, urmtorul rezultat:
S-au alocat 50000000 locatii double in ptr[0]
S-au alocat 50000000 locatii double in ptr[1]
S-au alocat 50000000 locatii double in ptr[2]
Alocarea memoriei nu a fost posibila pentru ptr[3]
Bucla for ar trebui s repete de 50 de ori operaia de alocare dinamic a 50000000
de locaii de memorie de tip double. Dac la un moment dat memoria devine
insuficient, operatorul new nu mai poate realiza corect alocarea memoriei i
returneaz valoarea 0. n acest caz se tiprete mesajul de pe ramura then:
Alocarea memoriei nu a fost posibila i bucla se ncheie.
Exemplul urmtor demonstreaz modul n care se poate trata excepia
bad_alloc la imposibilitatea alocrii memoriei prin operatorul new.
Exemplu
test_bad_alloc.h
#include <iostream>
using std::cout;
using std::endl;
#include <new>
using std::bad_alloc;
int main()
{
double *ptr[50];
try
{
for(int i = 0; i < 50; i++)
{
ptr[i] = new double[50000000];
cout << "S-au alocat 50000000 locatii double in ptr["
<< i << "]\n";
}
}
catch(bad_alloc e)
{
cout << "A aparut urmatoarea exceptie:
<< e.what() << endl;
}
"
return 0;
}
Rulnd acest program putem obine, n funcie de calculator i de compilatorul
instalat, urmtorul rezultat:
S-au alocat 50000000 locatii double in ptr[0]
S-au alocat 50000000 locatii double in ptr[1]
S-au alocat 50000000 locatii double in ptr[2]
A aparut urmatoarea exceptie: Allocation Failure
Atunci cnd alocarea dinamic nu mai este posibil, n blocul catch se tiprete
mesajul A aparut urmatoarea exceptie urmat de descrierea excepiei aa
cum este ea generat de compilator. Acest mesaj poate s difere de la un compilator
la altul.
Este posibil modificarea metodei standard prin care compilatorul trateaz
eroarea de nealocare a memoriei. Funcia set_new_handler definit de C++
standard n header-ul <new> primete ca argument implicit un pointer la o funcie
fr niciun argument i care returneaz void. Programatorul poate nregistra
aceast funcie ca fiind cea care se apeleaz la apariia erorii la alocarea memoriei
printr-un apel al lui set_new_handler. Odat nregistrat noua funcie, operatorul
new nu va mai genera excepia bad_alloc, ci va executa corpul noii funcii.
Exemplu
test_set_new_handler.h
#include <iostream>
using std::cout;
using std::cerr;
#include <new>
#include <cstdlib>
using std::set_new_handler;
void customNewHandler()
{
cerr << "A fost apelata functia customNewHandler";
abort();
}
int main()
{
double *ptr[50];
//Inregistrarea functiei customNewHandler care se apeleaza
10
11
12