jimko My computer NEVER cras | 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 :
- #include <stdlib.h>
- #include <stdio.h>
- // Template abstrait (pur): les classes filles doivent écrire les accesseurs get/set,
- // ce qui leur permet de typer et nommer les membres x et y selon leur gout:
- template <class Type> // tiens, une autre question: "typename" ou bien "class" ??!
- class PosTpl
- {
- public:
- int valid; // instance valide
- public:
- // Accesseurs virtuels purs à définir dans les classes filles
- virtual Type GetX() const = 0;
- virtual Type GetY() const = 0;
- virtual void SetX(Type v) = 0;
- virtual void SetY(Type v) = 0;
- public:
- // Constructeur standard
- PosTpl<Type>()
- {
- valid= false;
- }
- // Arithmétique dont les classes filles hériteront:
- // Cette méthode est OK
- void operator*=(float k)
- {
- SetX( Type(GetX() * k) );
- SetY( Type(GetY() * k) );
- }
- ///--->
- // Mais ce constructeur est malheureusement illégal:
- PosTpl<Type>(Type _x, Type _y)
- {
- SetX(_x); // <-- error: abstract virtual `void PosTpl<Type>::SetX(Type) [with Type = int]' called from constructor
- SetY(_y);
- valid= true;
- }
- // ...et mon gros problème c'est qu'il n'est donc pas possible d'écrire ce genre de méthodes,
- // qui devraient retourner une instance de classe. :(
- PosTpl<Type> RotLeft()
- {
- return PosTpl<Type>( -GetY(), GetX() );
- }
- ///---<
- };
- // exemples de classes filles:
- // Instanciation des templates abstraits pour les types que l'on va utiliser;
- // c'est logiquement requis par (certains!?) compilateurs:
- template class PosTpl<int>;
- template class PosTpl<float>;
- // 1) Classe dérivée: vecteur 2D entières avec acces public à x et y
- class PosVec : public PosTpl<int>
- {
- public:
- int x,y;
- public:
- // Ces constructeurs sont forcément ignorées par le template-class de base, c'aurait été trop beau
- // PosVec() { x= y= 0; valid=false; }
- // PosVec(int _x, int _y) { x=_x; y=_y; }
- protected:
- int GetX() const { return x; }
- int GetY() const { return y; }
- void SetX(int _x) { x=_x; }
- void SetY(int _y) { y=_y; }
- };
- // 2) Exemple de classe dérivée: coordonnées géographiques flottantes avec acces public à lon et lat
- class PosGeo : public PosTpl<float>
- {
- public:
- float x,y;
- public:
- PosGeo() { x= y= 0; valid=false; }
- PosGeo(int _x, int _y) { x=_x; y=_y; }
- protected:
- float GetX() const { return x; }
- float GetY() const { return y; }
- void SetX(int _x) { x=_x; }
- void SetY(int _y) { y=_y; }
- public:
- // Puis autres méthodes spécialisées à cette classe géo:
- // PosGeo DeplacementAuCap(int direction, int distance) { ... }
- // (etc)
- };
- int main(int,char**)
- {
- PosVec vec;
- vec.x= 12;
- vec.y= 10;
- printf("Vecteur: %d,%d\n", vec.x,vec.y);
- PosVec rot= vec.RotLeft();
- printf("Rot: %d,%d\n", rot.x,rot.y);
- return 0;
- }
|
|