Templates & STL Ou comment ne pas réinventer la roue à chaque fois
Templates Template : patron ou modèle Programmation générique : Implanter des algorithmes ou des conteneurs sans se soucier du type (classe) sous-jacent
Templates Exemple : comparer des objets pour avoir une comparaison de type min / max Toujours la même méthode : opérateurs de comparaison, =, ==, != Possible pour toute classe ou type proposant ces opérateurs
Exemple :classe Date Surcharge d'opérateurs ! class Date { long jj,mm,aa; public : date(long=1,long=1,long=2000); ~date(); bool operator<(const date &); // méthode membre bool operator>(const date &); // méthode membre // autres surcharges }; On peut écrire : Date d1, d2(3,7,2009); cout << (d1 < d2);
Exemple :classe Date bool Date::operator<(const date &uneDate) { bool res = false; if (this->aa < uneDate.aa) { res=true; } else if (aa == uneDate.aa) { … } return res; }
Fonction template Écrire une fonction "paramétrée" par un type template T mint(T a, T b) { if (a < b) { return a; } else { return b; }
Fonction template T inconnu (c'est le but): pas de compilation, doit être instancié par un type se place dans un fichier.h Ou séparation prototype / définition // templatemin.h template mint (T a, T b); // templatemin.cpp #include "templatemin.h" template T mint(T a, T b) { return ((a<b)?a:b); }
Fonction template : appel Instancier le type de manière implicite ou explicite // main.cpp #include "templatemin.h" int main(int argc, char *argv[]) { int a,b,c; a = 4; b = 7; c = mint(a,b); // le compilateur infère le type } c = mint (a,b);
Fonction template : appel Valable avec les classes qui surchargent < // main.cpp #include "templatemin.h" #include "Date.h" int main(int argc, char *argv[]) { Date d1(3,7,1995),d2,datemin; datemin = mint(d1,d2); // le compilateur infère le type } datemin = mint (d1,d2);
Autres aspects Peut être surchargé : template T mint(T a, T b); template T mint(T a, T b, T c); Plusieurs classes "paramètres" template { for(…) { tab[i] = tab[i] + val; } Nécessite simplement qu'on puisse "additionner" un T et un U : opérateur surchargé dans la classe T ou méthode friend
Classes template Patron de classe Utilisée pour les conteneurs entre autres Conteneur : classe stockant des éléments d'une autre classe Un tableau de… Une pile de … Une file de … Une liste chaînée de …
Conteneurs Présentent un comportement indépendant du type stocké Exemple : pile : empiler(); dépiler(); estPileVide(); Ces méthodes forment l'interface du conteneur => fichier.h
Conteneurs Dans le fichier.cpp : implémentation du comportement avec des templates Exemple : une pile représentée par un tableau (sans héritage) Classe template : une pile de qqchose…
Exemple : pile // dans pile.h template class Pile { T *elements; long maxElem; long nbElem; public : Pile(long tai):maxElem(tai),nbElem(0) { if(tai>0) { elements = new T[tai] } else { maxElem=0; elements = NULL; } }; Constructeur bien utile pour une initialisation correcte du pointeur elements.
Exemple : pile template class Pile { T *elements; long maxElem; long nbElem; public : ~Pile() { if (elements != NULL) { delete[] elements; } bool estPileVide(void) { return (nbElem == 0); } };
Exemple : pile template class Pile { T *elements; long maxElem; long nbElem; public : void empiler(T value) { if (nbElem < maxElem) { elements[nbElem++] = value; } T depiler(void) { if (!estPileVide()) { return (elements[--nbElem]); } else { ??? } } };
Utilisation de la pile // dans main.cpp #include "pile.h" int main(int argc, char *argv[]) { Pile pipile; pipile.empiler(3.12); cout << "on depile :" << pipile.depiler(); cout << "la pile est vide ? :" << pipile.estPileVide(); Pile pileDate; pileDate.empiler(Date(1,4,2003)); pileDate.empiler("12/10/1964"); cout << pileDate.depiler() << endl; return 0; } C'est ici que la classe template Pile est instanciée : compilée T est remplacé par double C'est ici que la classe template Pile est instanciée : compilée T est remplacé par double la classe template Pile est instanciée une deuxième fois : compilée T est remplacé par Date la classe template Pile est instanciée une deuxième fois : compilée T est remplacé par Date
Templates avec 2 paramètres template class Pile { T elements[size]; long nbElem; … }; typedef Pile pile10long; typedef Pile pile50string; //Dans main.cpp pile10long pipile; pipile.empiler(42);
STL : Standard Template Library Bibliothèque de Templates fourni en standard avec les environnements C++ Des conteneurs et des itérateurs listes, vecteurs, tables de hashage, … Réutiliser du code éprouvé et bien écrit Se concentrer sur la valeur ajoutée de l'application
STL : conteneurs vector : tableau redimensionnable list : liste doublement chaînée set : ensemble sans doublons multiset : ensemble triés map : tableau associatif (clé, valeur) avec un ordre hash_map : tableau associatif (clé, valeur) avec accès rapide mais sans ordre
STL : algorithmes Exemple avec le template vector #include vector vec(4); // tableau à 4 éléments vec[0] = 1; // l'opérateur [] est surchargé vec[1] = 3; vec[2] = vec[1]+1; vec[3] = vec[2]-vec[0]; Algorithmes de manipulation : reverse(vec.begin(), vec.end()); long tai = 17; vec.resize(tai); Chaque conteneur dispose de ses méthodes : aide au choix du type de conteneur. Les opérateurs classiques sont surchargés, on se concentre sur l'utilisation du conteneur et non sur son organisation
STL : itérateurs Implémentation d'un conteneur inconnue Seul son interface est intéressante (méthodes + propriétés connues) Généralisation des pointeurs pour parcourir un conteneur (une collection) Des méthodes fournissent le début et la fin du conteneur, un itérateur se "déplace" entre ces limites et joue le rôle d'un pointeur sur les éléments. Plus besoin de connaître l'organisation mémoire !
Itérateurs avec une list #include list _l; _l.push_front("hello"); _l.push_back("everybody"); _l.push_front("I say"); list ::iterator _it; for (_it=_l.begin(); _it != _l.end(); _it++) { cout << *_it << endl; } Initialisation du conteneur Déclaration de l'itérateur adapté Parcours du conteneur L'itérateur est un objet : la classe list ::iterator surcharge l'opérateur ++ pour "avancer" dans le conteneur en fonction de son organisation en mémoire
Template : généralisation Méthode de recherche de valeur dans un conteneur quelconque qui propose un itérateur. template Iter find(Iter first, Iter last, const T& value) { while (first != last) && (*first != value) { first++; } return first; } // utilisation vector vec(12); // on l'initialise vector ::iterator it = find(vec.begin(),vec.end,Date(3,3,2003)); … list l;// on l'initialise list ::iterator found = find(l.begin(),l.end(),6); cout << *found << endl; Méthode template de recherche
STL: classe map Recherche "map STL" : Iterators of a map container point to elements of this value_type. Thus, for an iterator called it that points to an element of a map, its key and mapped value can be accessed respectively with: 1 map ::iterator it; 2 (*it).first; // the key value (of type Key) 3 (*it).second; // the mapped value (of type T) 4 (*it); // the "element value" (of type pair ) Naturally, any other direct access operator, such as -> or [] can be used, for example: 1 it->first; // same as (*it).first (the key value) 2 it->second; // same as (*it).second (the mapped value)
STL: classe map Recherche "map STL" : Iterators: begin Return iterator to beginning (public member function) begin endendReturn iterator to end (public member function) rbeginrbegin Return reverse iterator to reverse beginning (public member function) rendrend Return reverse iterator to reverse end (public member function) Capacity: empty Test whether container is empty (public member function) empty sizesize Return container size (public member function) max_sizemax_size Return maximum size (public member function) Element access: operator[] Access element (public member function) operator[] Modifiers: insert Insert element (public member function) insert eraseerase Erase elements (public member function) swapswap Swap content (public member function) ClearClearClear content (public member function) Informations disponibles sur