Colle C++ : pb de template abstrait

Colle C++ : pb de template abstrait - C++ - Programmation

Marsh Posté le 18-08-2007 à 16:27:50    

J'ai un probleme interessant de template abstrait en C++.
 
Contexte: je veux faire des classes de "points 2D entiers", "points 2D geodésiques", "coordonnées polaires", etc.
 
Non seulement je veux manipuler des données de type différents (flottants, entiers, etc, d'ou nécessité d'un template), mais pour des raisons de lisibilité et de sécurité je veux nommer les membres x et y spécifiquement (ici respectivement: i & j,  lon & lat,  size & angle).
Je veux aussi pouvoir ajouter des méthodes spécifiques à ces types de coordonnées.
Enfin, hors de question dans mon cas de devoir passer par des get/set verbeux pour l'acces aux membres, je veux un accès public direct aux membres x,y et lon,lat des classes filles.
 
En gros: je veux obliger l'utilisation de "x" pour la classe "point 2D" et obliger à utiliser "lon" pour la classe "points 2D géodésique".
Comme je ne pense pas qu'il soit possible de "masquer" ou privatiser certaines variables d'un union dans des classes dérivées, ca ne doit pas etre possible avec un template qui aurait des "unions" en float sur les différents nommages x et y (il permettrait d'utiliser salement "lon" à la place de "x" et vice versa).
 
Donc la solution à laquelle je pense c'est un template abstrait avec des accesseurs get/set virtuels purs protected sur les deux membres codant les coordonnées, qui sont alors définis dans des classes dérivées et qui permettent alors un acces rapide public et un nommage spécifique.
 
Maintenant le problème est lié aux méthodes du template qui *retournent* des instances du meme type que le template: elles font malheureusement appel à une classe virtuelle pure, aie: pas le droit! Comment faire alors?
 
Voila un bout de code qui montre le problème et permet d'essayer différentes solutions:  
En attendant j'ai abdiqué et je le fais à l'ancienne, le bon vieux et moche template en pur C à base de #define paramétrés!  ;)
 

Code :
  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. // Template abstrait (pur): les classes filles doivent écrire les accesseurs get/set,
  4. // ce qui leur permet de typer et nommer les membres x et y selon leur gout:
  5. template <class Type> // tiens, une autre question:  "typename" ou bien "class" ??!
  6. class PosTpl
  7. {
  8. public:
  9. int valid; // instance valide
  10. public:
  11. // Accesseurs virtuels purs à définir dans les classes filles
  12. virtual Type GetX() const = 0;
  13. virtual Type GetY() const = 0;
  14. virtual void SetX(Type v) = 0;
  15. virtual void SetY(Type v) = 0;
  16. public:
  17. // Constructeur standard
  18. PosTpl<Type>()
  19. {
  20.  valid= false;
  21. }
  22. // Arithmétique dont les classes filles hériteront:
  23. // Cette méthode est OK
  24. void operator*=(float k)
  25. {
  26.  SetX( Type(GetX() * k) );
  27.  SetY( Type(GetY() * k) );
  28. }
  29. ///--->
  30. // Mais ce constructeur est malheureusement illégal:
  31. PosTpl<Type>(Type _x, Type _y)
  32. {
  33.  SetX(_x); // <-- error: abstract virtual `void PosTpl<Type>::SetX(Type) [with Type = int]' called from constructor
  34.  SetY(_y);
  35.  valid= true;
  36. }
  37. // ...et mon gros problème c'est qu'il n'est donc pas possible d'écrire ce genre de méthodes,
  38. // qui devraient retourner une instance de classe.  :(
  39. PosTpl<Type> RotLeft()
  40. {
  41.  return PosTpl<Type>( -GetY(), GetX() );
  42. }
  43. ///---<
  44. };
  45. // exemples de classes filles:
  46. // Instanciation des templates abstraits pour les types que l'on va utiliser;
  47. // c'est logiquement requis par (certains!?) compilateurs:
  48. template class PosTpl<int>;
  49. template class PosTpl<float>;
  50. // 1) Classe dérivée: vecteur 2D entières avec acces public à x et y
  51. class PosVec : public PosTpl<int>
  52. {
  53. public:
  54. int x,y;
  55. public:
  56. // Ces constructeurs sont forcément ignorées par le template-class de base, c'aurait été trop beau
  57. //  PosVec()    { x= y= 0; valid=false; }
  58. //  PosVec(int _x, int _y) { x=_x; y=_y; }
  59. protected:
  60. int GetX() const { return x; }
  61. int GetY() const { return y; }
  62. void SetX(int _x) { x=_x; }
  63. void SetY(int _y) { y=_y; }
  64. };
  65. // 2) Exemple de classe dérivée: coordonnées géographiques flottantes avec acces public à lon et lat
  66. class PosGeo : public PosTpl<float>
  67. {
  68. public:
  69. float x,y;
  70. public:
  71. PosGeo()    { x= y= 0; valid=false; }
  72. PosGeo(int _x, int _y) { x=_x; y=_y; }
  73. protected:
  74. float GetX() const { return x; }
  75. float GetY() const { return y; }
  76. void SetX(int _x) { x=_x; }
  77. void SetY(int _y) { y=_y; }
  78. public:
  79. // Puis autres méthodes spécialisées à cette classe géo:
  80. //   PosGeo DeplacementAuCap(int direction, int distance) { ... }
  81. //  (etc)
  82. };
  83. int main(int,char**)
  84. {
  85. PosVec vec;
  86. vec.x= 12;
  87. vec.y= 10;
  88. printf("Vecteur: %d,%d\n", vec.x,vec.y);
  89. PosVec rot= vec.RotLeft();
  90. printf("Rot: %d,%d\n", rot.x,rot.y);
  91. return 0;
  92. }

Reply

Marsh Posté le 18-08-2007 à 16:27:50   

Reply

Marsh Posté le 18-08-2007 à 20:17:00    

bah le pb d'appel de virtuelle abstraite me parait independant du pb de template.
 
Ensuite, comme le disait la Mére Michel :
Melanger template et polymorphisme c'est pas bine bon.
 
Donc, le mieux c'ets de passer par une solution à base de template policy (comme expliqué dans le Alexandrescu 'Modern C+ Design')
 
en gros ca transforme ta hierarchie :
 
Point<T>, Point2D<T>, Point3D<T>, PointGeo<T>  
 
en
Point<T,_2D>
Point<T,_3D>
Point<T,Geo>
 
ou _2D,_3D, Geo sont des classes comportant des memebres de classes (prefixés par static donc) qui contiennent le code qui change entre les implantations.
 
 

Reply

Marsh Posté le 18-08-2007 à 21:02:09    

Ah oui, ça me plait davantage!
Mais là, je paye ma formation entièrement autodidacte pour le ++ du C, un peu trop vite faite à l'arrache. Ca sent donc le bouquin que je vais acheter rapidement si je ne trouve pas un exemple la de suite :)
A commencer par le fait que je n'ai encore jamais utilisé deux arguments dans un template ;)
 
Merci en tout cas pour ces infos!

Reply

Marsh Posté le 18-08-2007 à 22:27:52    

En vrac et pour commencer doucement sur les template avancée :
 
http://osl.iu.edu/~tveldhui/papers/techniques/

Reply

Marsh Posté le 18-08-2007 à 22:32:28    

Tu peux aussi chercher "traits".

Reply

Marsh Posté le 18-08-2007 à 23:03:49    

les traits c'est si peu comparé aux template policy :)

Reply

Marsh Posté le 18-08-2007 à 23:26:33    

Waa c'est de la bonne URL, ça, bourrée d'info!
Arretez je vais me mettre à la bourre!  :-)
 
et dire que je commençais à lorgner sur le D par curiosité...

Reply

Marsh Posté le 19-08-2007 à 18:39:10    

Joel F a écrit :

les traits c'est si peu comparé aux template policy :)


 
J'ai du mal à te comprendre.  Pour moi ce sont des choses qui se situent à des niveaux différents.
 
Les policies, qu'elles soient templates ou pas, c'est un design pattern.
 
Les traits, c'est au départ essentiellement une technique en C++ consistant à rassembler dans
un seul paramètre template une série d'entre eux.   On arrive donc à des structs n'ayant que des
membres statiques.  Quand ces paramètres concernent un type, on la paramètrise généralement
par ce type.
 
Certaines conceptions à base de politiques peuvent être implémentées avec des traits en C++.  Ca
me semble être le cas pour ce problème.

Reply

Marsh Posté le 19-08-2007 à 19:06:20    

je me suis mal exprimé. Dans ma tête, je voyais juste les traits tel que fournit par la STL. Mea culpa donc. :jap:

Reply

Sujets relatifs:

Leave a Replay

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