Notes concernant la demo 7 ========================== Creation d'un patron de classe generique List qui gere les operations definies par le patron suivant: Il ne vous est pas demande de suivre cette declaration a la lettre, vous pouvez en particulier ajouter ou retirer des membres. Seules les fonctionnalites offertes dans la declaration doivent etre respectees. template class List{ private: int nb; // nb d'elets dans la liste Node * first; // pointeur sur le premier elt de la liste Node * last; // pointeur sur le dernier elt de la liste friend ostream& operator<< (ostream& os, const List& l); // note le T dans (ostream... n'est pas necessaire public: List(); // constructeur par defaut : liste vide List(const List & other); // constructeur de recopie ~List(); // destructeur List & operator = (const List & rhs); // operateur d'affectation T & operator [] (const int i); // operateur d'indexation T * Head() const {return (first)? &(first->elt):NULL;} // retourne l'elt first T * End() const {return (last)? &(last->elt):NULL;} // retourne l'elt last void insert_head(T e); // insertion en tete de liste void insert_end(T e); // insertion en fin de liste void remove_head(); // supprimer le premier elt void remove_end(); // supprimer le dernier elt List & tail(); // retourne une liste privee du premier elt void removeAll(); // empty the list void remove(T val); // enlever un element dont la valeur est specifiee en argument bool search(T val); // chercher un maillon dont la valeur est specifiee bool isEmpty() const {return !nb;} // liste vide ? int size() const {return nb;} // nb d'elements dans la liste }; Cette declaration s'appuie sur le patron de class Node dont une declaration possible est: template class Node{ friend class List; // List peut acceder aux champs prives de Node friend ostream& operator<< (ostream& os,const List& l); // idem pour la surdefinition de << private: Node(T e,Node *pnext=0); // constructeur T elt; // la donnee de ce maillon Node * next; // le champ suivant }; A titre indicatif voici un programme qui devrait fonctionner avec ce que vous venez d'ecrire. int main(void) { List x,w; x.insert_head(4.4); x.insert_head(3.3); x.insert_head(2.2); x.insert_head(1.1); List y(x); // constructeur de recopie (car creation) List z=x; // constructeur de recopie (car creation) w=x; // operateur d'affectation cout<< "List(x) = "<< x << endl; // pourquoi utiliser removeAll alors qu'on peut faire plus complique ? while(!x.isEmpty()){ cout<< "Removal of " << *(x.Head())<< " in list x" << endl; x.remove_head(); } cout<< "List(x) = "<< x << endl; // note bien que les elts de x n'exitent plus, ceux des listes obtenues par recopie // exitent encore (voir le code de l'operateur de recopie) .. mais voir plus bas... // pour un cas pathologique... cout<< "List(y) ="<< y << endl; cout<< "List(z) ="<< z << endl; cout<< "List(w) ="<< w << endl; // illustration de tail cout << "le cas de tail\n"; List v; v=y.tail(); cout<< "List(v) (tail of y) = "<< v << endl; cout<< "List(y) = "<< y << endl; // notre patron de classe peut aussi bien gerer des listes d'entiers List i; i.insert_head(3); i.insert_head(2); i.insert_head(1); cout<< "List(i) = " << i << endl; // ou encore des listes de string List ph; ph.insert_end("C++"); ph.insert_end("quel"); ph.insert_end("beau"); ph.insert_end("langage"); cout << "List(ph) = " << ph << endl; ph.remove("beau"); cout << "List(ph) = " << ph << endl; ph.insert_head("Assurement"); ph.insert_end("complique"); cout << "List(ph) = " << ph << endl; // et si on testait la supression cout << "Search(C++,ph) = " << ph.search("C++") << endl; cout << "Search(belle,ph) = " << ph.search("belle") << endl; ph.remove_head(); ph.remove_end(); cout << "List(ph) = " << ph << endl; ph.remove_head(); ph.remove_end(); cout << "List(ph) = " << ph << endl; ph.remove("quel"); cout << "List(ph) = " << ph << endl; cout << "Search(tout,ph) = " << ph.search("tout") << endl; cout << "Search(belle,ph) = " << ph.search("belle") << endl; // et qu'advient-il si j'ai une liste de char * ?? List liste; liste.insert_head("voulu !"); liste.insert_head("comme"); liste.insert_head("toujours"); liste.insert_head("pas"); liste.insert_head("fonctionne"); liste.insert_head("ne"); liste.insert_head("tout"); cout << "liste[0]=" << liste[0] << endl; cout << "liste[1]=" << liste[1] << endl; liste[2] = "marche"; // un peu dangereux non ? cout << "List(liste) = " << liste << endl; List copie = liste; cout << "List(copie) = " << copie << endl; liste.removeAll(); cout << "List(liste) = " << liste << endl; cout << "List(copie) = " << copie << endl; return 0; }