Classi contenitore
Supponiamo di voler realizzare una lista generica facilmente riutilizzabile.
Sulla base di quanto visto fino ad ora l'unica soluzione possibile sarebbe quella
di realizzare una lista che contenga puntatori ad una generica classe TInfo
che rappresenta l'interfaccia di un generico oggetto memorizzabile nella lista:
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;
};
TList::TCell::TCell(TInfo* Object, TCell* Next)
: StoredObject(Object), NextCell(Next) {}
TList::TCell::~TCell() {
delete StoredObject;
}
TInfo* TList::TCell::GetObject() {
return StoredObject;
}
TList::TCell* TList::TCell::GetNextCell() {
return NextCell;
}
TList::TList() : FirstCell(0) {}
TList::~TList() {
TCell* Iterator = FirstCell;
while (Iterator) {
TCell* Tmp = Iterator;
Iterator = Iterator -> GetNextCell();
delete Tmp;
}
}
void TList::Store(TInfo* Object) {
FirstCell = new TCell(Object, FirstCell);
}
L'esempio mostra una parziale implementazione di una tale lista (che assume
la proprieta` degli oggetti contenuti), nella realta` TInfo e/o
TList molto probabilmente sarebbero diverse al fine di fornire
un meccanismo per eseguire delle ricerche all'interno della lista e varie altre
funzionalita`. Tuttavia il codice riportato e` sufficiente ai nostri scopi.
Una implementazione di questo tipo funziona, ma soffre di (almeno) un grave
difetto: la lista puo` memorizzare tutta una gerarchia di oggetti, e questo
e` utile e comodo in molti casi, tuttavia in molte situazioni siamo interessate
a liste di oggetti omogenei e una soluzione di questo tipo non permette di verificare
a compile time che gli oggetti memorizzati corrispondano tutti ad uno specifico
tipo. Potremmo cercare (e trovare) delle soluzioni che ci permettano una verifica
a run time, ma non a compile time. Supponete di aver bisogno di una lista per
memorizzare figure geometriche e una'altra per memorizzare stringhe, nulla vi
impedisce di memorizzare una stringa nella lista delle figure geometriche (poiche`
le liste memorizzano puntatori alla classe base comune TInfo ).
Sostanzialmente una lista di questo tipo annulla i vantaggi di un type checking
statico.
Alcune osservazioni...
In effetti non e` necessario che il compilatore fornisca il codice macchina
relativo alla lista ancora prima che un oggetto lista sia istanziato, e` sufficiente
che tale codice sia generabile nel momento in cui e` noto l'effettivo tipo degli
oggetti da memorizzare. Supponiamo di avere una libreria di contenitori generici
(liste, stack...), a noi non interessa il modo in cui tale codice sia disponibile,
ci basta poter dire al compilatore "istanzia una lista di stringhe", il compilatore
dovrebbe semplicemente prendere la definizione di lista data sopra e sostituire
al tipo TInfo il tipo TString e quindi generare
il codice macchina relativo ai metodi di TList . Naturalmente perche`
cio` sia possibile il tipo TString dovrebbe essere conforme alle
specifiche date da TInfo , ma questo il compilatore potrebbe agevolmente
verificarlo. Alla fine tutte le liste necessarie sarebbero disponibili e il
compilatore sarebbe in grado di eseguire staticamente tutti i controlli di tipo.
Tutto questo in C++ e` possibile tramite il meccanismo dei template.
|