Problème avec les 'keys' d'un map de la STL

Problème avec les 'keys' d'un map de la STL - C++ - Programmation

Marsh Posté le 17-03-2004 à 16:37:24    

J'aimerai utiliser un type polymorphique dont chaque sous-type possède son propre opérateur < (operator< ) comme 'key' d'un map.
 
Mais le problème c'est qu'on ne peut pas donner de type pointeur comme 'key' (map<KeyType*, ...> ) donc mon 'key' que je donnerai lors d'une recherche (m[key]) sera automatiquement casté vers son parent 'KeyType' et donc c'est l'opérateur < du parent qui sera appellé.
 
J'aimerai utiliser cela pour créer des index (map) sur une table contenant des enregistrements et le but est que l'index puisse s'appliquer à différents type (int, long, str, etc..).
 
voila mon code :  
Fichier 'main.cpp'

Code :
  1. /**
  2.   * Fichier principal de test des tables en mémoire
  3.   */
  4. //désactive le warning 4786 (bug de krosoft avec les 'map' pour changer un peu)
  5. #pragma warning(disable : 4786)
  6. #include <iostream>
  7. #include <vector>
  8. #include <map>
  9. #include <list>
  10. #include <string>
  11. using namespace std;
  12. #include "baseType.h"
  13. int main(int argc, char** argv)
  14. {
  15.    //exemple d'utilisation d'index
  16.    //les définitons de type  
  17.    typedef vector<BaseType*> Record;
  18.    typedef list<Record> Table;
  19.    typedef map<BaseType, Record> Index;
  20.    //la table
  21.    Table table;
  22.    //création de trois enregistrements
  23.    Record e1(2), e2(2), e3(2);
  24.    e1[0] = new Char('a');
  25.    e1[1] = new Int(1);
  26.    e2[0] = new Char('b');
  27.    e2[1] = new Int(2);
  28.    e3[0] = new Char('c');
  29.    e3[1] = new Int(3);
  30.    //on insère les trois enregistrements (lignes)
  31.    table.push_back(e1);
  32.    table.push_back(e2);
  33.    table.push_back(e3);
  34.    //création d'un index sur le premier champs
  35.    Index index;
  36.  
  37.    //on insère successivement les enregistrements dans l'index
  38.    for(Table::iterator i = table.begin(); i != table.end(); i++)
  39.    {
  40.       index[*((*i)[0])] = (*i);
  41.    }
  42.  
  43.    //affichage de la ligne dont le champs 0 est 'b'
  44.    Record r = index[Char('b')];
  45.    cout << r[0]->getChar() ;//<< "|" << r[1]->getInt() << endl;
  46.    return 0;
  47. }


 
 
Fichier 'baseType.h' (je n'ai écrit le code que pour les type int et char)

Code :
  1. /**
  2.   * Représente une valeur de base : char, int, long, double, str
  3.   */
  4. #include <string>
  5. #include <iostream>
  6. using namespace std;
  7. class BaseType
  8. {
  9. public:
  10.    /**
  11.      * les opérateurs d'affectation pour les différents types.
  12.      */
  13.    virtual BaseType& operator=(char){return *this;};
  14.    virtual BaseType& operator=(int){return *this;};
  15.    virtual BaseType& operator=(long){return *this;};
  16.    virtual BaseType& operator=(double){return *this;};
  17.    virtual BaseType& operator=(string){return *this;};
  18.    /**
  19.      * les accesseurs.
  20.      */
  21.    virtual char getChar() const{return 0;};
  22.    virtual int getInt() const{return 0;};
  23.    virtual long getLong() const{return 0;};
  24.    virtual double getDouble() const{return 0.0;};
  25.    virtual string getString() const{return "";};
  26.    /**
  27.      * les comparaisons
  28.      */
  29.    virtual bool operator<(const BaseType& c) const{ cout << "plus petit BaseType " << endl; return false; }
  30. };
  31. /**
  32.   * Représente un caractère.
  33.   */
  34. class Char : public BaseType
  35. {
  36. public:
  37.    Char(char c):v(c){};
  38.    BaseType& operator=(char);
  39.    char getChar() const;
  40.    bool operator<(const BaseType& c) const{ cout << "plus petit Char" << endl; return this->v < c.getChar(); }
  41. private:
  42.    char v;
  43. };
  44. /**
  45.   * Représente un entier.
  46.   */
  47. class Int : public BaseType
  48. {
  49. public:
  50.    Int(int c):v(c){};
  51.    BaseType& operator=(int);
  52.    int getInt() const;
  53.    bool operator<(const BaseType& c) const{ cout << "plus petit Int" << endl; return this->v < c.getInt(); }
  54. private:
  55.    int v;
  56. };


 
 
Fichier baseType.cpp

Code :
  1. #include "baseType.h"
  2. BaseType& Char::operator=(char v)
  3. {
  4.    this->v = v;
  5.    return *this;
  6. }
  7. char Char::getChar() const
  8. {
  9.    return this->v;
  10. }
  11. BaseType& Int::operator=(int v)
  12. {
  13.    this->v = v;
  14.    return *this;
  15. }
  16. int Int::getInt() const
  17. {
  18.    return this->v;
  19. }


 
Je précise que mon code est compilable mais affiche :

plus petit BaseType
plus petit BaseType
plus petit BaseType
plus petit BaseType
plus petit BaseType
plus petit BaseType


 
Mon but serait qu'il utilise les opérateurs < des classes enfants, si vous avez une solution n'hésitez pas (même si elle n'a plus rien a voir avec ce que j'ai fait) !


Message édité par Ummon le 17-03-2004 à 18:30:24
Reply

Marsh Posté le 17-03-2004 à 16:37:24   

Reply

Marsh Posté le 17-03-2004 à 17:01:07    

Ummon a écrit :


 
Mais le problème c'est qu'on ne peut pas donner de type pointeur comme 'key' (map<KeyType*, ...> )  

si
 
 
sinon je vois ton problème. on touche la une prochaine fonctionnalité du C++ (multimethode).
 
avant de répondre : que doit il se passer si on compare 2 objets de types différents ?

Reply

Marsh Posté le 17-03-2004 à 17:09:22    

En fait un objet index porte sur le même type (par exemple int) qui représente un champs de ma table mais une table peut contenir plusieurs index, par exemple un pour un champs int et un pour un champs char (comme dans mon code-exemple).
Je n'ai pas envie de faire un type index pour chaque type de base (int, char, etc.) car mon but final et de généraliser et de mettre les index dans un vecteur, si il y a plusieurs type d'index alors cela posera problème.


Message édité par Ummon le 17-03-2004 à 17:14:15
Reply

Marsh Posté le 17-03-2004 à 17:27:59    

comment j'aurais traiter le problème avec le C++ actuel.
j'y vais un pue bourrin en laissant l'exception passé, on pourrait très bien,  
1) tenter le cast
2) tenter une conversion (avec un constructeur / operator Type)
 

Code :
  1. #include <iostream>
  2. struct Base
  3. {
  4.   virtual ~Base()
  5.   { }
  6.   virtual bool less(const Base &other) const =0;
  7. };
  8. struct Foo
  9.   : public Base
  10. {
  11.   bool less(const Foo &other) const
  12.   {
  13.     std::cout << "bool Foo::less(const Foo &other) const\n";
  14.     return this < &other;
  15.   }
  16.   virtual bool less(const Base &other) const
  17.   {
  18.     std::cout << "bool Foo::less(const Base &other) const\n";
  19.     return less(dynamic_cast<const Foo &>(other));
  20.   }
  21. };
  22. struct Bar
  23.   : public Base
  24. {
  25.   bool less(const Bar &other) const
  26.   {
  27.     std::cout << "bool Bar::less(const Bar &other) const\n";
  28.     return this < &other;
  29.   }
  30.   virtual bool less(const Base &other) const
  31.   {
  32.     std::cout << "bool Bar::less(const Base &other) const\n";
  33.     return less(dynamic_cast<const Bar &>(other));
  34.   }
  35. };
  36. inline bool operator<(const Base &lhs, const Base &rhs)
  37. {
  38.   std::cout << "bool operator<(const Base &lhs, const Base &rhs)\n";
  39.   return lhs.less(rhs);
  40. }
  41. inline bool operator<(const Foo &lhs, const Foo &rhs)
  42. {
  43.   std::cout << "bool operator<(const Foo &lhs, const Foo &rhs)\n";
  44.   return lhs.less(rhs);
  45. }
  46. inline bool operator<(const Bar &lhs, const Bar &rhs)
  47. {
  48.   std::cout << "bool operator<(const Bar &lhs, const Bar &rhs)\n";
  49.   return lhs.less(rhs);
  50. }
  51. int main()
  52. {
  53.   Base *b1, *b2;
  54.   Foo f1, f2;
  55.   Bar g1, g2;
  56.   std::cout << "Foo < Foo\n";
  57.   f1 < f2;
  58.   std::cout << '\n';
  59.   std::cout << "Bar < Bar\n";
  60.   g1 < g2;
  61.   std::cout << '\n';
  62.   b1 = &f1;
  63.   b2 = &f2;
  64.   std::cout << "Base& < Base& -> Foo < Foo\n";
  65.   *b1 < *b2;
  66.   std::cout << '\n';
  67.   b1 = &g1;
  68.   b2 = &g2;
  69.   std::cout << "Base& < Base& -> Bar < Bar\n";
  70.   *b1 < *b2;
  71.   std::cout << '\n';
  72.  
  73.   b1 = &f1;
  74.   b2 = &g1;
  75.   try
  76.     {
  77.       std::cout << "Base& < Base& -> Foo < Bar\n";
  78.       *b1 < *b2;
  79.     }
  80.   catch(std::bad_cast &ex)
  81.     {
  82.       std::cout.flush();
  83.       std::cerr << "Failed " << ex.what() << '\n';
  84.     }
  85. }


 
sinon j'ai toujours pas tout compris, je vois pas trop le problème à utiliser des index de types différents.
pusique que tes index sont du meme types, pourquoi tu utilises pas les template alors ?

Reply

Marsh Posté le 17-03-2004 à 17:44:10    

Je voudrai eviter le cast dynamique.
Ce que j'appel des index différents ca serait :
 

Code :
  1. typedef map<Int, Record> IndexInt;
  2. typedef map<Char, Record> IndexChar;
  3. etc..


 
Mais maintenant si je veux mettre mes index dans un 'vector' bein c'est plus trop possible puisqu'ils sont de type différent.
j'aurais voulu faire ça par la suite :

Code :
  1. vector<Index> indexes;


Message édité par Ummon le 17-03-2004 à 17:46:19
Reply

Marsh Posté le 17-03-2004 à 18:09:02    

ben fais le !
 
il faut juste que planque un peu le truc : tes classes Index on besoin d'avoir une base commume.
 
donc tu fais une class (abstraite?), tes classes index en hérite, et pouf, vector<Index*> et c'est gagné

Reply

Marsh Posté le 17-03-2004 à 18:19:38    

ouais c'était un peu ma solution de secours, je voulais eviter d'écrire du code supplémentaire

Reply

Marsh Posté le 17-03-2004 à 18:25:57    

cai pas une solution de secours. tu veux du polymorphisme ? ben fais en

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed