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