Elementi di programmazione ad oggetti a. a. 2009/2010 Corso di Laurea Magistrale in Ingegneria Elettronica Docente: Mauro Mazzieri, Dipartimento di Ingegneria Informatica, Gestionale e dellAutomazione
Lezione 7 Template
Programmazione generica La programmazione generica utilizza i tipi come parametri Consentono di definire famiglie di funzioni o di classi, che differiscono sulla base di tipi su cui operano Il compilatore genera una specializzazione per ogni combinazione di tipi usata La programmazione generica consente di generare automaticamente del codice a partire da definizioni generali
Template di funzione Le funzioni sovraccaricate realizzano funzionalità analoghe su dati diversi I template servono ad effettuare le stesse funzioni su dati diversi Forniscono un meccanismo con cui è possibile preservare la semantica delle funzioni e delle chiamate di funzioni Consentono di generare automaticamente istanze dello stesso algoritmo che operano su dati diversi Una funzione viene solitamente definita come template quando la sua implementazione rimane invariata per un insieme di tipi di dato diversi gestiti
Definizione di template template segue la definizione della funzione Es. template T minore(T a, T b) { return a < b ? a : b; } int main() { cout << minore(10, 20); cout << minore(2.45, 1.14); }
Definizione di template La parola chiave template è sempre posta allinizio di una dichiarazione ed una definizione di template È seguita da una lista di parametri racchiusi tra e separata da virgole La lista di parametri non può essere vuota Un parametro può essere costituito Da un tipo Da un valore costante
Template di classe I membri di una classe generica sono dichiarati e definiti esattamente come per le classi non generiche Se un membro è definito esternamente, deve essere esplicitamente dichiarato come template Sono molto usati per definire una serie di manipolazioni (contenitore, algoritmi) su dati specificati dal parametro di tipo
Template di classe Un template di classe è un classe con uno o più parametri di tipo Luso tipico è per i contenitori Li si vuole rendere indipendenti dal tipo di oggetto effettivamente contenuto template class Sequenza { C* s; int size; int n; public: Sequenza(); Sequenza(const C*); Sequenza(const Sequenza&); ~Sequenza(void); C operator[](int) { return s[i]; } }; Non è possibile sovraccaricare il nome di una classe template
Template di classe Un template di classe può avere i membri static Ogni specializzazione ha i propri membri Un membro condiviso va messo in una classe base non template I template di funzione possono essere funzioni membro Un template di classe può avere come membri dei template di funzione
Template con costanti Un parametro di template può essere costituito da una costante Costanti di tipo intero possono essere utilizzate per fornire dimensioni o limiti template class Buffer { C v[maxsize]; int size; // … } Si può usare un parametro di template per definire i successivi parametri template bool sottoSoglia(C v[dim]) { for (int i = 0; i < dim; i++) if (v[i] < val) return true; return false; }
Esempio: template con costante template T minore(T (&v)[size]) { T result = v[0]; for (int i = 1; i < size; i++) if (v[i] < result) result = v[i]; return result; } int main() { int a[] = {1, 2, 3, 4}; double b[] = {0.3, 0.8, 7, 12, 0.1}; cout << minore(a) << endl; cout << minore(b) << endl; return 0; }
Deduzione degli argomenti di un template Quando viene chiamato un template di funzione, i tipi ed i valori degli argomenti sono determinati sulla base dei tipi e valori della argomenti Specializzazione del template I tipi degli argomenti non devono corrispondere esattamente, ma le uniche conversioni possibili sono Da Lvalue a Rvalue, da array a puntatore, da funzione a puntatore Conversioni di qualificazione const Da classe a classe base Non è possibile sovraccaricare il nome di una classe template
Tipi dei parametri Un template dipende solo dalle proprietà dei tipi di parametri Non richiede che i tipi utilizzati come argomenti siano esplicitamente correlati In particolare, non richiede che appartengano ad una specifica gerarchia di ereditarietà
Specializzazione Consente di definire implementazioni alternative per un template template class Sequenza { //… } // specializzazione template<> class Sequenza { //… } Nelle specializzazione sono tolti dalle <> i parametri per cui si fa la specializzazione Possibile specializzazione parziale
Specializzazione e implementazione comune Una specializzazione può servire a creare unimplementazione comune per una famiglia di parametri di tipo // template di contenitore generico template class Vector { //… } // specializzazione di contenitore di puntatori a void template<> class Vector { //… } // specializzazione per tutti i puntatori template class Vector : private Vector { //… }
Sovraccarico dei template di funzione Le specializzazioni generate a partire da un template vengono chiamate utilizzando la risoluzione dei sovraccarichi Il template di funzione può essere sovraccaricato Da altri template che differiscono per numero di parametri Da funzioni senza template Risoluzione del sovraccarico: 1. Tentativo di risoluzione con funzione senza template 2. Se fallisce, il compilatore cerca un template di funzione e se lo trova genera e utilizza la specializzazione 3. Se non trova ancora alcuna corrispondenza o se ci sono corrispondenze multiple, errore
Ereditarietà e template È possibile derivare una classe template da una classe tradizionale Si fa per esempio per fornire una implementazione comune Si può derivare una classe template da unaltra classe template Es. derivare da Vector una CheckedVector che effettua controlli sugli indici I template di classe forniscono uninterfaccia comune ad una famiglia Sono una forma di polimorfismo Polimorfismo dinamico: funzioni virtuali Polimorfismo statico o parametrico: template
Nota finale È generalmente opportuno effettuare il debug di un funzione o classe su di un tipo concreto, prima di renderla generica