La libreria standard C++ (nel seguito libstdc++), parte integrante della definizione del linguaggio, include ed estende la libreria standard C (libc). In particolare include la Standard Template Library (STL), nata come componente aggiuntivo, che utilizza estensivamente le tecniche della programmazione generica.
La libstdc++ è costituita da un vasto numero di classi e funzioni che trattano di:
Tutte le definizioni della libstdc++ sono contenute nel namespace std, motivo per cui la maggior parte dei programmi iniziano con la direttiva:
using namespace std;in caso contrario i simboli andranno qualificati con il prefisso std::.
Tramite la tecnica della programmazione generica è possibile definire ed implementare delle parti di codice indipendenti dai tipi di dati trattati, accedendo così ad un superiore livello di astrazione del codice con reali vantaggi sulla sua riutilizzabilità.
Facciamo notare che l'istanza del codice definito in modo generico avviene staticamente, cioè durante la compilazione, quindi:
Il codice di una funzione che restituisca il massimo tra due generici argomenti può ad esempio essere scritto:
template <typename T> T max(T x, T y) { return x > y ? x : y ; }dove la dichiarazione template comunica al compilatore che la successiva dichiarazione di funzione utilizza un generico tipo T che sara` noto solo al momento dell'effettivo utilizzo del codice. La parola chiave typename, introdotta ad hoc, può in questo uso essere sostituita dalla parola chiave class. Typename serve però anche a qualificare esplicitamente un tipo astratto, nel caso in cui il compilatore non possa dedurlo da sè:
typename T oggettoDiTipoT;
L'utilizzo di una funzione generica non comporta in generale alcuna differenza con una analoga funzione tipizzata, in quanto il tipo corretto può in gegerale essere dedotto dal compilatore dal tipo degli argomenti passati, e viene quindi istanziato automaticamente senza richiedere alcuna specifica aggiuntiva. Nel caso in cui non sia possibile dedurlo dal contesto (ovvero dai parametri) andrà invece specificato al momento della chiamata:
int ret=max<int>(5,7);
Una classe template viene definita in modo analogo ad una funzione:
template <class T1> class ListaGenerica { // .. // definizione di membri e proprietà // che utilizzano il tipo generico T1 // ad esempio: public: T1 getPar(); };Mentre nell'implementazione è necessario specificare per ogni metodo che si tratta di un template, ad esempio il l'implementazione della funzione getPar sarà:
template <class T1> T1 ListaGenerica<T1>::getPar(){ // .. corpo della funzione ..// }Al momento dell'istanza andrà quindi specificato il tipo da utilizzarsi in luogo del tipo generico:
ListaGenerica<float> listaFloat;e nel seguito l'oggetto istanziato sarà utilizzabile come sempre.
Con le classi generiche, ma non con le funzioni, è possibile definire il tipo di default, da utilizzarsi in caso di mancata specifica:
template <class T1=double>Nell'istanza che voglia utilizzare i tipi di default le parentesi angolari andranno quindi lasciate vuote:
ListaGenerica<> listaDouble;
I tipi generici utilizzati in un template possono naturalmente essere più di uno:
template <class T1, class T1, class T3=double, >Ed è anche possibile l'annidamento di tipi generici:
Array< Array<int> > arrayOfIntArray;Si noti che lo spazio fra le parentesi angolari è necessario a non interpretarle come un operatore di shift.
La STL implemente una serie di oggetti contenitori generici, il cui contenuto può essere di qualsiasi tipo:
Per poter accedere ai singoli elementi di un contenitore esiste l'oggetto iteratore , che astrae e generalizza il concetto di puntatore. Ad esempio:
// istanza di un iteratore a vettore di interi vector<int>::iterator it; // punta l'iteratore al primo elemento di un vettore di interi it = v_int.begin(); // passa al secondo elemento it++; // estrae l'elemento int num=*it; // estrae l'elemento di 3 posizioni successivo int n2 = it[3];
Tutti i contenitori ammettono i seguenti costruttori (c è un generico contenitore):
// costruttore di contenitore vuoto c::c(); // costruttore di copia c::c(const c& other); // riversamento da un contenitore di altro tipo c::c(Iter first, Iter last);ed i seguenti metodi:
// ridimensiona ad n elementi void c::resize(size_type n); // ritorna la dimensione attuale size_type c::size() ; // true se il contenitore è vuoto bool c::empty(); // ritorna la capacità massima size_type c::max_size();Tutti i contenitori sono dinamici, cioè allocano la memoria necessaria quando serve. L'oggetto vector permette, per ottimizzazione è la possibilità di riservare preventivamente una certa quantità di memoria tramite l'operazione:
void vector::reserve(size_type n);
La classe string, messa a disposizione dal C++ non è, come in C, un vettore di caratteri ma è un contenitore di caratteri, molto simile a vector<char>. La maggior parte degli algoritmi della STL sono applicabili anche alla classe string.
...TODO