Templates, Containers et STL Structures de données de base tableau, liste chaînée file, pile, arbres, hashtable collection, ensemble 2 caractéristiques
Les SDDs classiques Ne pas recoder à chaque fois (projet archi : copier/coller de "file FIFO classique". c'était un module, en C++, une classe réutilisable) Indépendant du type/classe contenu
Interface de code/ de données comportements génériques (cf polymorphisme) décrits de manière algorithmique : dans une pile d'entiers, on empile, on dépile dans une pile d'objets de classe A, on empile, on dépile même algorithme qui effectue cela !
Interface de code/ de données deux niveaux d'interface, réalisables en C++ interface de codage : bâtir une SDD sur une SDD sous-jacente : tableau et pile, liste chaînée et file, liste chaînée et hashtable par l'héritage privé.
Interface de code/ de données créer une classe dont les méthodes sont indépendantes du type de contenu : un tableau de qqchose; une file de qqchose; une hashtable de clef qqchose et de valeur qqchose…
Interface de code/ de données les classes dites template (template=patron, modèle) ou méta-classe (classe de classe), au sens de la composition. ne donne pas lieu à du code compilé.
Instanciation de template 1ère étape : les fonctions templates exemple : la fonction max : indépendante du type de données à comparer à condition que ce type ou classe implémente : un opérateur de comparaison
Instanciation de template définition de fonction template : template T max(T a, T b) { T res; if (a>b)// opérateur de comparaison { res = a;// opérateur = } else { res = b; } return res; }
Instanciation de template appel à cette fonction template : le compilateur détermine le type et rédige la fonction (pas de polymorphisme) template_fonc.cpp
Instanciation de template instanciation implicite : informations du code suffisantes : bm = ::max(ba,bb); type instancié : bouh instanciation explicite bm = ::max (ba,bb);
Template & classes Définir une classe container (stockage) contient : composition (ou association) rôle de cette classe : décrire un comportement générique : comment stocker des objets
Hiérarchie de conteneurs niveau de stockage : physique (tableau, liste chaînée) logique (pile, file, hashtable) où classer les arbres ? en fonction de leur interface logique
Hiérarchie de conteneurs D'autres types de conteneur : les collections ? (set, bag,…) choix d'après … l'interface logique = les méthodes à fournir pour accéder aux données.
Hiérarchie de conteneurs On ne travaillera plus jamais avec les tableaux et les listes chaînées…en tant que SDD. coder une seule fois les classes tableau et listes pour tous les types contenus : ne change rien à [], ajout de cellule, insertion de cellule, etc…
arbres Hiérarchie de conteneurs tableauliste chaînée stockage physique stockage logique pilefilehashtable collections ??
Hiérarchie de conteneurs un peu de simplification ! un arbre est un stockage logique et physique une collection ? que souhaite-t-on faire avec les stockages logiques ?
Hiérarchie de conteneurs tableauliste chaînée pilefilehashtable collections ?? arbres
Hiérarchie de conteneurs fonctions de base : créer, détruire, copier ajouter un élément récupérer un élément (en le supprimant ou non) tester si le conteneur est vide / plein accéder itérativement aux éléments
Hiérarchie de conteneurs fonctions de base : créer, détruire, copier : constructeurs / destructeurs
Hiérarchie de conteneurs fonctions de base : ajouter un élément : push pour une pile enqueue pour une file put(key,value) pour une hashtable add(?) pour une collection
Hiérarchie de conteneurs fonctions de base : récupérer un élément (en le supprimant ou non) pop pour pile dequeue pour une fille get(key) pour une hashtable get(?) pour une collection
Hiérarchie de conteneurs fonctions de base : tester si le conteneur est vide / plein IsEmpty() pour tous les stockages IsFull() ??? ne devrait jamais arriver !
Hiérarchie de conteneurs fonctions autres : trier insérer selon un critère d'ordonnancement ; simple utilisation de l'opérateur =, et insérer n'intervient jamais dans les stockages logiques !
Hiérarchie de conteneurs Donc une collection est soit une pile, soit une file, soit une hashtable (à peu de choses près) car les fonctions présentées suffisent. Suffisant pour cette année, la classe collection sera développée en Java et C#
Hiérarchie de conteneurs tableauliste chaînée pilefilehashtable arbres
Hiérarchie de conteneurs Le tableau en tant que stockage logique : nous allons traiter en exemple complet la partie II du projet d'architecture : les caches cache et RAM sont des tableaux ! un tableau est une hashtable.
Hiérarchie de conteneurs la clef est l'indice entier et la fonction de hashage est : long hashcode(long index) { return index; }
Hiérarchie de conteneurs On peut donc en déduire qu'une classe hashtable est une classe tableau pour laquelle la surcharge de l'opérateur [] fait le calcul de la clef à partir de son paramètre ? attention à la prise de tête…. OUI !
Hiérarchie de conteneurs syntaxe de cet opérateur : operator[](type paramètre); le type indique ce qui peut être écrit entre les crochets. exemple : stringindex.cpp
Retour aux templates Écriture d'une classe template template class A {//que du bon code dedans}; est la déclaration de la classe A qui est une classe template par rapport à la classe donné en paramètre
Classe template exemples : template class conteneur {}; template class oups {}; class et typename sont équivalents.
Classe template utilisation du type paramétré : dans la classe, le type (ou classe) précisé entre <> est utilisable comme un type quelconque. classe template non compilable car type non connu !
Classe template template class oups { private : T *_val; public : oups() { _val = new T; } ~oups() { if(_val){delete _val;} } }; Rédigé dans un fichier non compilable :.h ou.tpp (attention aux extensions)
Classe template Séparation interface / code, dans le même fichier, rappeler la propriété template syntaxe parfois lourde ! la prudence est de mise exemple : templatex.cpp
Classe template Quand se fait la compilation de cette classe ? à l'instanciation du type paramétré : dans main() : cont ct; ici, la classe paramètre X est int : on peut compiler la classe !
Classe template A noter : n'est compilé que ce qui est appelé (valable pour les classes basiques). intéressant, mais combien de classes sont compilées dans cet exemple ? cont ct1; cont ct2; un exemplaire par instanciation !
Classe template lourd pour les classes qui sont gourmandes en fonctions ! à surveiller : la classe paramétrée doit fournir les méthodes utilisées par la classe instanciée. exemple : templatex.cpp
Héritage et template Souvenez-vous de tablopile (héritage privé). héritage public : héritage de données et d'interface héritage privé : héritage de stockage, de support
Héritage et template Idée : créer une classe conteneur tablo, qui est une classe template Instanciation : un tablo de qqchose or, une pile est un tablo (par héritage privé) mais peut-on créer une pile de qqchose qui soit un tableau de qqchose ?
Héritage et template Héritage compatible avec les templates (heureusement). exemple : tablo_template.dev
Template et héritage Pour être complet, une classe conteneur devrait permettre, de même qu'un tableau (tout bête) d'être : un conteneur de T donc un conteneur de toute sorte de T devrait supporter le polymorphisme
Template et héritage devrait supporter le polymorphisme… la réponse à cette question par l'exemple. tablo_template.dev c'était donc du suspens pédagogique… le principe d'instanciation est évidemment compatible avec le polymorphisme !
Standard Template Library (STL) Ensemble de classes conteneurs et les itérateurs associés Ensemble de conteneurs déjà programmés, un itérateur est un objet dont le rôle est de parcourir ce conteneur pour accéder aux objets qui y sont stockés.
Standard Template Library (STL) exemples de conteneurs : vector, set, queue, hashtable, tree, list comment choisir un conteneur : en fonction de l'efficacité pour les opérations à effectuer opposition vector / list
Standard Template Library (STL) exemple d'utilisation d'un itérateur : fonctions : begin(), end() du conteneur : initialisent l'itérateur opérateur ++ : avance l'itérateur dans le conteneur opérateur * : accès à l'élément désigné par l'itérateur. exemple : tablo_iterator.dev
Standard Template Library (STL) Pour le projet C++ : il vous appartient de vous documenter sur la STL et les itérateurs. (vous devrez écrire vous même une classe conteneur et un itérateur…).
Les fichiers en C++ Les classes ifstream et ofstream (f pour fichier) création de flots sur disque, pour les fichiers texte #include font partie du namespace std
Fichiers texte traité comme un flot d'E/S classique opérateurs > classes ofstream (output : écriture) ifstream (input : lecture)
Fonctions de base constructeurs : ofstream(char *); ifstream(char *); fermeture : fonction close();
Fonctions de base créer un fichier texte en écriture : ofstream outfile("name.txt"); outfile << data [<< data ][<< endl]; outfile.close();
Fonctions de base Lire les données d'un fichier texte : ifstream infile("name.txt"); if (infile) // test de succès d'ouverture { infile >> data [>> data]; infile.close(); } else { // un message ? }
Fonctions de base La fin de fichier se teste avec la fonction eof() mais compte une ligne ou une donnée en trop ! il faut d'abord compter le nombre de lignes du fichier puis le lire. utilité d'une première ligne de fichier indiquant le nombre de lignes à lire !
Fonctions de base Sinon : utiliser la fonction getline() : bool getline(fstream &, string); renvoie true si la lecture a pu être faite, false sinon. exemple : getline.dev
Fonctions de base attention à utiliser getline() et non pas >> pour lire des lignes entières. >> a des délimiteurs de lecture, dont le caractère ' ' …
Les fichiers binaires on précise le type de fichier à lire dans le constructeur avec un paramètre supplémentaire : std::ios_base::binary et utiliser les fonctions read() et write() à vous de vous documenter !
Un exemple (presque) complet…
Conclusion Le C++, c'est super !