Cap. 7. Template-uri
Template-ul implementeaza asa-zisul concept de "tip
parametrizat" ("parametrized type"). Un template reprezinta o familie
de tipuri sau functii, cu alte cuvinte, un sablon sau model. Acest concept a
fost introdus in primul rand pentru a creste gradul de reutilizabilitate a
codului. De exemplu, pentru a implementa o lista de numere intregi este necesara
in mod normal realizarea unei clase speciale (sa spunem ListOfIntegers),
iar pentru o lista de siruri alta clasa (sa spunem ListOfStrings).
Conceptul de template permite realizarea unei clase generale (sa spunem
List), care sa accepte orice tip de element, inclusiv tipuri necunoscute
la momentul implementarii acesteia. Tipul template-ului este stabilit in
momentul instantierii sale. Template-urile sunt foarte utile pentru realizarea
de biblioteci care trebuie sa ofere metode generice de prelucrare a datelor.
Sintaxa generala de declarare a unui template este urmatoarea:
template < ListaDeParametri > Declaratie
unde Declaratie reprezinta declararea sau definirea unei clase sau
functii, definirea unui membru static al unei clase template, definirea unei
clase sau functii membre al unei clase template, sau definirea unui membru
template al unei clase.
Clasele parametrizate (sau clasele template) se declara astfel:
template <class NumeParametru>
class NumeClasa {
// ...
// definirea clasei
}
Particularizarea (= stabilirea tipului) clasei template se face prin
intermediul unei constructii de genul:
NumeClasa <NumeParametru>
unde NumeParametru reprezinta tipul obiectului.
Functiile template se declara astfel:
template <class NumeParametru>
// ...
// declaratia functiei
Sa consideram in continuare ca exemplu implementarea unei stive generice
folosind template-uri.
#include <iostream.h>
template <class T> class StackItem {
public:
StackItem *Next;
T *Data;
StackItem(T __Data, StackItem <T> *__Next)
{
Data = new T(__Data);
Next = __Next;
}
};
template <class T> class Stack {
public:
T pop()
{
T result = *(Data->Data);
StackItem <T> *temp = Data;
Data = Data->Next;
delete temp;
return result;
}
T top()
{
}
void push(T __Data)
{
Data = new StackItem <T>(__Data, Data);
}
int isEmpty()
{
}
Stack()
{
}
private:
};
main()
{
Stack <int> anIntegerStack;
anIntegerStack.push(5);
anIntegerStack.push(7);
if(anIntegerStack.isEmpty())
- cout << "Stiva goala" << endl;
else
- cout << anIntegerStack.pop() << endl;
cout << anIntegerStack.top() << endl;
}
In exemplul urmator a fost implementata o lista generica (List).
Ca elemente a listei s-au folosit obiecte de tip Point (clasa definita in
Cap. 4). Pentru parcurgerea usoara a listei a fost
implementata o clasa de tip "iterator", care poate fi considerata ca
fiind un "cursor" care strabate lista. Functia List.begin() returneaza
un iterator pozitionat pe primul element al listei, List.end() pe
ultimul element al listei. Saltul la urmatorul element al listei se face cu
ajutorul operatorului ++ din clasa Iterator.
#include <iostream.h>
class Point
{
friend ostream& operator << (ostream& output, Point p);
protected:
public:
Point()
{
}
Point(unsigned X, unsigned Y)
{
}
~Point() {}
unsigned GetX()
{
}
unsigned GetY()
{
}
void SetX(unsigned X)
{
}
void SetY(unsigned Y)
{
}
};
ostream& operator << (ostream& output, Point p)
{
output << "(" << p.x << ", " << p.y << ")";
return output;
}
template <class T> class Item {
public:
Item *Next;
T *Data;
Item(T __Data, Item <T> *__Next)
{
Data = new T(__Data);
Next = __Next;
}
};
template <class T> class List {
public:
T pop_front()
{
T result = *(Data->Data);
Item <T> *temp = Data;
Data = Data->Next;
delete temp;
return result;
}
T front()
{
}
void push_front(T __Data)
{
Data = new Item <T>(__Data, Data);
}
int empty()
{
}
List()
{
}
class Iterator {
friend class List <T>;
protected:
Item <T> *Current;
Iterator(Item <T> *x)
{
}
public:
Iterator() {}
int operator == (Iterator& x)
{
return Current == x.Current;
}
int operator != (Iterator& x)
{
return Current != x.Current;
}
T operator *()
{
}
Iterator& operator ++(int)
{
Current = Current->Next;
return *this;
}
};
Iterator begin()
{
}
Iterator end()
{
Item <T> *temp;
for(temp = Data; temp; temp = temp->Next);
return Iterator(temp);
}
private:
};
main()
{
List <Point> anPointList;
List <Point>::Iterator index, end;
anPointList.push_front(Point(1, 1));
anPointList.push_front(Point(3, 14));
index = anPointList.begin();
end = anPointList.end();
if(anPointList.empty())
cout << "Lista vida" << endl;
else
for(; index != end; index++)
cout << endl;
}
Clasele template pot avea trei tipuri de prieteni (friends):
o clasa sau functie care nu este de tip template;
o clasa sau functie template;
o clasa sau functie template avand tipul specificat.
Daca este necesara particularizarea unei functii template sau a unei
functii membre a unei clase template pentru un anumit tip, functia respectiva
poate fi supraincarcata pentru tipul dorit.
Trebuie remarcat de asemenea ca in cazul in care o clasa template contine
membri statici, fiecare instanta a template-ului in cauza va contine propriile
date statice.
In capitolul ce urmeaza vor fi prezentate diverse particularitati legate
de programarea in C++ pe sisteme UNIX.
Realizat de Dragos Acostachioaie, ©1998
http://www.biosfarm.ro/~dragos