C++: Templates

 

Considérant qu'un dictionaire est une table de hash dont la classe clé est string, voici la classe EtudiantDict qui permet de gérer un dictionaire de pointeurs sur des étudiants : le type de la clé est string, c'est le nom de l'etudiant.
 
Voici la classe EtudiantDict et un test d'utilisation :
 
#include "iostream"
#include "map"
#include "string"
 
using namespace std;
 
class Etudiant
{
public:
  Etudiant() {}
  Etudiant(string n, string p) : nom(n), prenom(p) {}
  string clePourHashage() const { return nom; }
  friend ostream & operator << (ostream & out, const Etudiant &);
protected:
  string nom;
  string prenom;
};
 
ostream & operator << (ostream & out, const Etudiant & e)
{
  return out << "Etudiant(" << e.nom << "," << e.prenom << ")";
}
 
class EtudiantDict {
public:
  EtudiantDict() {}
  bool ajouterEtudiant(Etudiant * et) {
    if (!trouverEtudiant(et->clePourHashage())) {
      dict_[et->clePourHashage()] = et;
      return true;
    }
    return false;
  }
  bool retirerEtudiant(string nom) {
    Etudiant * et = trouverEtudiant(nom);
    if (et) {
      dict_.erase(nom);
      return true;
    }
    return false;
  }
  Etudiant * trouverEtudiant(string nom) const {
    hash_map<string, Etudiant*>:: const_iterator itor = dict_.find(nom);
    return itor == dict_.end()? 0:(*itor).second;
  }
  Etudiant * operator[](string nom) { return trouverEtudiant(nom); }
  const hash_map<string, Etudiant*> & tableDeHash() const { return dict_; }
 
protected:
  map<string, Etudiant*> dict_;
};
 
main()
{
  EtudiantDict dict;
  char c = 0;
  while (c != 'q') {
    cout << "(a)jouter (s)upprimer a(f)ficher (l)ister (q)uitter\n";
    cin >> c;
    switch (c) {
    case 'a' : {
      string nom, prenom;
      cout << "nom et prenom : ";
      cin >> nom >> prenom;
      dict.ajouterEtudiant(new Etudiant(nom, prenom));
      break;
    }
    case 'l' : {
      // declaration et initialisation d'un iterateur
      hash_map<string, Etudiant*> copie(dict.tableDeHash());
      hash_map<string, Etudiant*>:: iterator itor = copie.begin(); 
      for (; itor != copie.end(); itor++) {
cout << *(*itor).second << endl;
      }
      break;
    }
    case 's' : 
    case 'f' : {
      cout << "nom: ";
      string nom;
      cin >> nom;
      if (dict.trouverEtudiant(nom)) { // si on trouve la cle nom dans le carnet
if (c == 'f') {
 cout << *(dict[nom]) << endl;
} else {
 dict.retirerEtudiant(nom);
}
      } else {
cout << "aucun Etudiant pour '" << nom << "'" << endl;
      }
      break;
    }
    default : if (c != 'q') cout << "choix invalide." << endl;
    }
  }
}
 
 
 

Plan de travail

Un premier template

On imagine bien que ce dictionaire n'est pas très satisfaisant : on ne peut l'utiliser que pour des étudiants. Or, on désire réutiliser cette mise en oeuvre pour, par exemple, stocker des livres. La clé serait le nom du livre.
  • Mettre en oeuvre les classes Livre et LivrDict avec un test en suivant le même modèle que pour Etudiant et EtudiantDict;
  • Mettre en oeuvre le template Dict et testez votre mise en oeuvre en remplacant LivrDict et EtudiantDict dans les programmes développés précédemment; Le template Dict est paramétré par le type B qui représente le type des objets ou valeurs stockées. 
 
template <class B>
class Dict {
// completer ici
};
 
 

Le template «hash_dict»

On demande de mettre en oeuvre le template de table de hash «hash_dict» avec les types de la clé et de l'objet stocké en parametre. Pour cela, on pourra s'appuyer sur le Map déjà développé en TP de Java.