Methode template intelligente

Methode template intelligente - C++ - Programmation

Marsh Posté le 07-01-2008 à 21:34:50    

Bonjour,
 
Avant toutes choses, autant préciser que je n'y connais pas grand chose en prog et que ce que j souhaite est surement tordu ou irréalisable mais bon, j'y crois :)
 
Alors voila je souhaiterais avoir une méthode template dans une classe qui me renvoie une valeur d'un certain type, ce type étant définie par un attribut interne de la classe (un entier qui prend plusieurs valeurs ...)
Un peu de code sera sûrement plus parlant (j'espère :roll:)
 

Code :
  1. // en réalité ces définitions sont ailleurs, je les rajoute ici pour compréhension
  2. #define VTK_DOUBLE 1
  3. #define VTK_FLOAT 2
  4. #define VTK_INT 3
  5. class MaClasseA
  6. {
  7.     MaClasseA(void );
  8.     template <typename T> T GetData(const int index);
  9.     void *ptr;
  10.     int type;
  11. }
  12. void MaClasseA::MaClasseA(void)
  13. {
  14. // ImageData est une instance de la classe vtkImageData de la librairie VTK et cette méthode renvoie un pointeur de type void * qui pointe vers un grand tableau 1D.  
  15. // Le souci est que je ne peux pas savoir à l'avance de quel type seront les données, cela dépend des images.  
  16. // Les données sont chargées ailleurs et j'ai simplifié le code pour compréhension, en tout cas j'ai accès à l'instance ImageData depuis le constructeur de cette classe.
  17.     ptr=ImageData->GetDataPointer();
  18.    
  19.     // renvoi VTK_DOUBLE ou VTK_FLOAT ou autres
  20.     type=ImageData->GetScalarType();
  21. }
  22. template <typename T> T MaClasseA::GetData(const int index)
  23. {
  24.    switch (type)
  25.    {
  26.         case VTK_DOUBLE :
  27.             return static_cast<double *>(ptr)[index];
  28.             break;
  29.         case VTK_FLOAT :
  30.             return static_cast<float *>(ptr)[index];
  31.             break;
  32.         default :
  33.             break;
  34.     }
  35. }
  36. class MaClasseB : public MaClasseA
  37. {
  38.     MaClasseB();
  39.     void MaMethodeAuPif(void);
  40. }
  41. void MaClasseB::MaClasseB(void){;}
  42. void MaClasseB::MaMethodeAuPif(void)
  43. {
  44.     cout<<"Valeur du voxel 150 "<<GetData(50)<<endl;
  45. }


Tout le problème se situe sur cette dernière méthode qui ne fonctionne pas dans l'état (dommage !). Et je ne veux pas avoir à faire ce qui suit sans quoi l'intérêt de la méthode template est plus que limité !
 

Code :
  1. void MaClasseB::MaMethodeAuPif(void)
  2. {
  3.     switch (InstanceClasseA->GetType())
  4.    {
  5.         case VTK_DOUBLE :
  6.             cout<<"Valeur du voxel 150 "<<GetData<double>(50)<<endl;
  7.             break;
  8.         case VTK_FLOAT :
  9.             cout<<"Valeur du voxel 150 "<<GetData<float>(50)<<endl;
  10.             break;
  11.         default :
  12.             break;
  13.     }
  14. }


Est ce qu'il existe un moyen de récupérer ma valeur avec une seule fonction, sans passer par le switch case ? Ca serait pas mal car je vais avoir énormément de méthodes du type [B]MaMethodeAuPif [/B]dans différentes classes qui héritent de MaClasseA, et je voudrais éviter le switch avec les 15 types à chaque fois ...
 
Voila merci d'avance et redites si c'est incompréhensible ou autres
Bonne soirée et merci pour votre forum riche en information
Simon


Message édité par Takahani le 07-01-2008 à 21:36:43
Reply

Marsh Posté le 07-01-2008 à 21:34:50   

Reply

Marsh Posté le 07-01-2008 à 21:41:34    

bah, un template c'ets purement statique, donc défini à la compilation. La ca ne te sera d'aucune utilité.

 

Le simple fait que tu fasse un switch sur un indicateur de type montre qu'il y a un defaut. Il fuat ici utiliser le polymorphisme

 

Sinon un bête :

 
Code :
  1. template <typename T> T MaClasseA::GetData(const int index)
  2. {
  3.    return static_cast<T*>(ptr)[index];
  4. }
 

solutionne le pb sans pouvoir faire de check.
De toute façon stocker un void* et transtyper derriere c'est moche.
Assure toi que contruire un MaClasse<T> renvoit un T* et basta

 

Edit : Ah , VTK c'est has been niveau lib.


Message édité par Joel F le 07-01-2008 à 21:52:18
Reply

Marsh Posté le 09-01-2008 à 16:11:37    

Bonjour, merci pour la réponse. Effectivement le polymorphisme sera surement plus adapté, mais je ne m'en sort toujours pas ... Des que je charge une image, je voudrais instancier une classe fille, qui hérite d'une classe mere, et ainsi faire fonctionner le polymorphisme. Seulement comment peut-on déclarer des méthodes dans les classes filles, qui n'ont pas le même constructeur que les classes mères ? J'entend pas la des méthodes surchargées qui ne renvoient pas le même type que la méthode virtuelle de la classe mère ?
 
Voici des bouts de code que je souhaiterais utiliser, mais je bloque :
 

Code :
  1. class AccessData{
  2. protected:
  3.     void* pData;
  4. public:
  5.     AccessData(void* data) {pData=data; }
  6.     virtual void GetData(int x, ...);
  7. };
  8. class Access_Char : public AccessData {
  9. public:
  10.     Access_Char(void* data):AccessData(data){;}
  11.     virtual char GetData(int x){return static_cast<char*>(pData)[x];}
  12. };
  13. class Access_Unsigned_Char : public AccessData {
  14. public:
  15.     Access_Unsigned_Char(void* data):AccessData(data){;}
  16.     virtual uchar GetData(int x){return static_cast<uchar*>(pData)[x];}
  17. };


Puis dans une autre classe, j'aurai un pointeur vers AccessData
 

Code :
  1. AccessData *pData;


Et au moment du chargement des l'images, je pourrai alors faire un :
 

Code :
  1. int nDataInType=ImageDataInput->GetScalarType();
  2.     switch (nDataInType)
  3.     {
  4.         case VTK_CHAR :
  5.             pDataIn=new Access_Char(pDataInput);
  6.             break;
  7.         case VTK_UNSIGNED_CHAR :
  8.             pDataIn=new Access_Unsigned_Char(pDataInput);
  9.             break;
  10.            
  11.         case VTK_SHORT :
  12.             pDataIn=new Access_Short(pDataInput);
  13.             break;   
  14.     }


Et ainsi pouvoir de n'importe où appeler ma valeur au pixel x avec la méthode GetData(x);
 
Malheureusement cela ne fonctionne pas, je reçois une erreur au compilateur du type :
erreur: valeur void n'a pas été ignorée comme elle aurait dû l'être
 
Forcément il s'attend à un retour de type void. Comment faire ? Il faut mélanger des templates avec cette architecture  :??:  ?
 
Merci si kkun sait faire ça  :jap:

Reply

Marsh Posté le 09-01-2008 à 16:31:59    

rencadre toi sur le Design pattern Factory et Abstract Factory ;)

Reply

Marsh Posté le 09-01-2008 à 16:37:03    

Oui c'est sur mon programme n'ets pas super bien pensé mais bon, je suis pas programmeur, ce qui m'intéresse c'est la facilité d'utilisation du code :)
 
Et comme je suis très dépendant de VTK -pas si mal au passage ;), pour l'imagerie médicale, je ne connais pas mieux !-
Et bien je dois faire avec leur fichu pointeur de donnée en void*  
Je vais creuser encore un peu !
merci de l'aide en tout cas !

Reply

Marsh Posté le 09-01-2008 à 16:51:02    

Takahani a écrit :

Oui c'est sur mon programme n'ets pas super bien pensé mais bon, je suis pas programmeur, ce qui m'intéresse c'est la facilité d'utilisation du code :)


 
Les DP n'ont aucun rapprot avec quoique se soit. C'ets juste de sméthodes éprouvées. La typiquement tu as besoin d'une factory
http://fr.wikipedia.org/wiki/Fabri [...] ception%29

Reply

Marsh Posté le 09-01-2008 à 17:04:26    

Merci, je ne connaissais pas du tout ce procédé !
Effectivement pour la construction ça va me simplifier la tache, par contre derriere il me faut toujours une méthode virtuelle qui renvoie un type générique pour la classe mère (AccessData) et des méthodes virtuelles filles qui elles renvoient respectivement des valeurs de types différents. Pour la méthode GetData() je ne vois pas bien encore comment faire  (suis vraiment un boulet, dsl ...)
Mais bon au moins j'apprends un peu ;)

Reply

Marsh Posté le 09-01-2008 à 17:07:35    

regarde l'exemple sur wiki, c'est un truc qui s'appelle ImageReader ;)

Reply

Marsh Posté le 09-01-2008 à 17:28:20    

Ok j'ai donc fabriqué une classe :
 

Code :
  1. class FabriqueAccess{
  2. public:
  3.     AccessData* GetAccess(int type, void *data)
  4.     {
  5.         switch (type)
  6.         {
  7.             case VTK_DOUBLE :
  8.                 return new Access_Double(data);
  9.                 break;
  10.             case VTK_FLOAT :
  11.                 return new Access_Float(data);
  12.                 break;
  13.         }
  14.     }
  15. };


Avec les autres classes :

Code :
  1. class AccessData{
  2. protected:
  3.     void* pData;
  4. public:
  5.     AccessData(void* data) {pData=data; }
  6.     virtual void GetData(int x);
  7. };
  8. class Access_Float : public AccessData {
  9. public:
  10.     Access_Float(void* data):AccessData(data){;}
  11.     virtual float GetData(int x){return static_cast<float*>(pData)[x];}
  12. };
  13. class Access_Double : public AccessData {
  14. public:
  15.     Access_Double(void* data):AccessData(data){;}
  16.     virtual double GetData(int x){return static_cast<double*>(pData)[x];}
  17. };


Et comme ça pour instancier la classe je n'ai besoin que des lignes :

Code :
  1. FabriqueAccess *fa=new FabriqueAccess();
  2. pDataIn=fa->GetAccess(nDataInType, pDataInput);


Ca ça fonctionne nickel merci du tuyau c'est effectivement plus propre avec la factory  :jap:  
 
 
Par contre mon gcc ne veut pas compiler car la méthode GetData de la classe mere AccessData renvoit un void et que les autres méthode filles Access_Double et tout renvoi kkchose de différents. Il me donne une erreur du type :
 

Code :
  1. erreur: conflicting return type specified for «virtual double Access_Double::GetData(int)"
  2. erreur: overriding «virtual void AccessData::GetData(int)&


Désolé d'éprouver ta patience, si tu en as marre c'est pas grave, je comprendrai  :whistle:

Reply

Marsh Posté le 09-01-2008 à 17:31:31    

fait une méthode abstraite
 

Code :
  1. class AccessData{
  2. protected:
  3.     void* pData;
  4. public:
  5.     AccessData(void* data) {pData=data; }
  6.     virtual int GetData(int x) = 0;
  7. };

Reply

Marsh Posté le 09-01-2008 à 17:31:31   

Reply

Marsh Posté le 09-01-2008 à 18:06:44    

Il n'en veux pas de la méthode abstraite, il n'est tjrs pas d'accord d'avoir un type de retour différent entre la méthode abstraite et les méthodes filles. Ce n'est pas grave, je vais revoir la conception de mon programme.
Merci de ta patience !

Reply

Marsh Posté le 09-01-2008 à 18:07:53    

ça peut pas marcher ces virtual avec des types de retours différents

Reply

Marsh Posté le 09-01-2008 à 18:09:19    

Tout le pb est là finalement :D

Reply

Marsh Posté le 09-01-2008 à 18:19:09    

pourquoi personne veut du variant ?

Reply

Marsh Posté le 09-01-2008 à 18:25:33    

Variant vient avec la plateforme de dev microsoft, non ?
Le programme doit être cross-plateforme

Reply

Marsh Posté le 09-01-2008 à 18:42:12    

variant ca vien de BOOST :o
www.boost.org

Reply

Marsh Posté le 09-01-2008 à 18:44:29    

Ok, pkoi pas alors, mais il faut inclure tout boost dans le projet alors ...
C'est pas trop relou à compiler sou wind**be ?
 
Je vais me renseigner. Tjrs un grand merci !
 

Reply

Marsh Posté le 09-01-2008 à 19:19:41    

c'ets uen bibliothèque de .h ... ca se compile guère. En outre, y a deja le binaire win32 de fournie

Reply

Marsh Posté le 10-09-2008 à 01:14:18    

Tiens à propos de ce problème de variant, vous auriez pas par hasard une idée de solution vaguement élégante sans utiliser boost par hasard ?

 


Message édité par kyntriad le 10-09-2008 à 01:15:35

---------------
You can't start a fire with moonlight
Reply

Marsh Posté le 10-09-2008 à 08:33:41    

bah non vu que boost implante la version élégante :E
si c'est des prb de lourdeur d'include, regarde du coté de boost bcp pour extraire la partie strictement nécessaire.

 

Mais bon, commencez à vous habituez à ça, boost c'est l'antichambre de std ;)


Message édité par Joel F le 10-09-2008 à 08:34:32
Reply

Marsh Posté le 10-09-2008 à 10:49:02    

Joel F a écrit :

bah non vu que boost implante la version élégante :E
si c'est des prb de lourdeur d'include, regarde du coté de boost bcp pour extraire la partie strictement nécessaire.

 

Mais bon, commencez à vous habituez à ça, boost c'est l'antichambre de std ;)

 

Ben à vrai dire j'aimerai beaucoup pouvoir bosser avec sur ce coup-là mais en l'occurrence ça risque d'être foutrement compliqué de faire accepter aux chef d'inclure boost au projet.


Message édité par kyntriad le 10-09-2008 à 10:49:12

---------------
You can't start a fire with moonlight
Reply

Marsh Posté le 10-09-2008 à 10:52:40    

v_v foutu daycidorz >_>
ils utilisent pas la STL aussi :o

Reply

Marsh Posté le 10-09-2008 à 11:26:10    

Joel F a écrit :

v_v foutu daycidorz >_>
ils utilisent pas la STL aussi :o

 

Bon j'ai lancé la machine administrative pour savoir si je peux ou pas :o

 


Message édité par kyntriad le 10-09-2008 à 11:26:44

---------------
You can't start a fire with moonlight
Reply

Marsh Posté le 10-09-2008 à 11:33:59    

bon courage :D

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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