Classi template
La definizione di codice generico e in particolare di una classe template (le
classi generiche vengono dette template class) non e` molto complicata,
la prima cosa che bisogna fare e` dichiarare al compilatore la nostra intenzione
di scrivere un template utilizzando appunto la keyword template :
template < class T >
Questa semplice dichiarazione (che non deve essere seguita da ";") dice
al compilatore che la successiva dichiarazione utilizzera` un generico tipo T
che sara` noto solo quando tale codice verra` effettivamente utilizzato, il compilatore
deve quindi memorizzare quanto segue un po' cose se fosse il codice di una funzione
inline per poi istanziarlo nel momento in cui T sara`
noto.
Vediamo come avremmo fatto per il caso della lista vista sopra:
template < class TInfo >
class TList {
public:
TList();
~TList();
void Store(TInfo& Object);
/* ... */
private:
class TCell {
public:
TCell(TInfo& Object, TCell* Next);
~TCell();
TInfo& GetObject();
TCell* GetNextCell();
private:
TInfo& StoredObject;
TCell* NextCell;
};
TCell* FirstCell;
};
Al momento l'esempio e` limitato alle sole dichiarazioni, vedremo in seguito
come definire i metodi del template .
Intanto, si noti che e` sparita la dichiarazione della classe TInfo ,
la keyword template dice al compilatore che TInfo
rappresenta un nome di tipo qualsiasi (anche un tipo primitivo come int
o long double ). Le dichiarazioni quindi non fanno piu` riferimento
ad un tipo esistente, la` dove e` stato utilizzato il nome fittizio TInfo .
Inoltre il contenitore non memorizza piu` tipi puntatore, ma riferimenti alle
istanze di tipo.
Supponendo di aver fornito anche le definizioni dei metodi, vediamo come istanziare
la generica lista:
TList < double > ListOfReal;
double* AnInt = new double(5.2);
ListOfReal.Store(*AnInt);
TList < Student > MyClass;
Student* Pippo = new Student(/* ... */);
ListOfReal.Store(*Pippo); // Errore!
MyClass.Store(*Pippo); // Ok!
La prima riga istanzia la classe template TList sul tipo
double in modo da ottenere una lista di double ; si
noti il modo in cui e` stata istanziato il template ovvero tramite
la notazione
NomeTemplate < Tipo >
(si noti che Tipo va specificato tra parentesi angolate).
Il tipo di ListOfReal e` dunque TList < double > .
Successivamente viene mostrato l'inserzione di un double e il tentativo
di inserimento di un valore di tipo non opportuno, l'errore sara` ovviamente segnalato
in fase di compilazione.
La definizione dei metodi di TList avviene nel seguente modo:
template < class TInfo >
TList < TInfo >::
TCell::TCell(TInfo& Object, TCell* Next)
: StoredObject(Object), NextCell(Next) {}
template < class TInfo >
TList < TInfo >::TCell::~TCell() {
delete &StoredObject;
}
template < class TInfo >
TInfo& TList < TInfo >::TCell::GetObject() {
return StoredObject;
}
template < class TInfo >
TList < TInfo >::TCell*
TList < TInfo >::TCell::GetNextCell() {
return NextCell;
}
template < class TInfo >
TList < TInfo >::TList() : FirstCell(0) {}
template < class TInfo >
TList < TInfo >::~TList() {
TCell* Iterator = FirstCell;
while (Iterator) {
TCell* Tmp = Iterator;
Iterator = Iterator -> GetNextCell();
delete Tmp;
}
}
template < class TInfo >
void TList < TInfo >::Store(TInfo& Object) {
FirstCell = new TCell(Object, FirstCell);
}
Cioe` bisogna indicare per ogni membro che si tratta di codice relativo ad un
template e contemporaneamente occorre istanziare la classe template utilizzando
il parametro del template .
Un template puo` avere un qualsiasi numero di parametri non c'e` un limite
prestabilito; supponete ad esempio di voler realizzare un array associativo,
l'approccio da seguire richiederebbe un template con due parametri e
una soluzione potrebbe essere la seguente:
template < class Key, class Value >
class AssocArray {
public:
/* ... */
private:
static const int Size;
Key KeyArray[Size];
Value ValueArray[Size];
};
template < class Key, class Value >
const int AssociativeArray < Key, Value >::Size = 100;
Questa soluzione non pretende di essere ottimale, in particolare soffre di un
limite: la dimensione dell'array e` prefissata. Fortunatamente un template
puo` ricevere come parametri anche valori di un certo tipo:
template < class Key, class Value, int size >
class AssocArray {
public:
/* ... */
private:
static const int Size;
Key KeyArray[Size];
Value ValueArray[Size];
};
template < class Key, class Value, int size >
const int AssocArray < Key, Value, size >::Size = size;
|