Pointeurs sur fonction membre, héritage, toussa

Pointeurs sur fonction membre, héritage, toussa - C++ - Programmation

Marsh Posté le 23-03-2006 à 18:43:54    

Note : le problème n'est pas un problème pour déclarer ou appeller une fonction membre à travers un pointeur.
Note² : j'ai lu la premiere page des sujets C++ donnés par la recherche : "pointeur fonction membre". J'ai lu aussi quelques truc sur codeproject (dans ce genre la).  
 
 
Imaginons une classe de base (

class Base ;

) et une classe dérivée (

class Fille ;

).
Dans une des méthodes de la classe Base, on trouve un :

void (Base::* fonctionAAppeller)() f = kekchoseQuiMeDonneUneFonctionAAppeller() ;


 
La feinte, c'est que ce

kekchoseQuiMeDonneUneFonctionAAppeller()

est virtuel, et renvoie en réalité un

void (Fille::*)()

.
 
La question : Puis-je travailler en considérant des pointeurs sur fonction membre d'une classe dérivée comme pointeurs sur fonction membre de la classe parente ? (le but serait d'éviter d'avoir à écrire 500

virtual void Base::fonction_xxx() {}

, avec xxx de 000 à 499 :o !
Note : Base peut hériter multiplement de plein de trucs, mais Fille n'hérite que de Base.
 
J'ai bien une petite idée de la réponse, vu que pour que ca marche il a fallu que je caste mon pointeur comme un gros barbare, mais on sait jamais, quelqu'un a peut être déja fait ce genre de trucs...

Reply

Marsh Posté le 23-03-2006 à 18:43:54   

Reply

Marsh Posté le 23-03-2006 à 18:59:34    

heu j ai pas tout pige, mais si tu as:
 
virtual Mere::fct();
virtual Fille1::fct();
virtual Fille2::fct();
virtual Fille3::fct();
...
 
alors les pointeurs vers toutes ces fonctions sont de aussi type virtual Mere::fct();

Reply

Marsh Posté le 23-03-2006 à 19:19:09    

Ouaip mais la ca serait plutot un truc du genre :
 

Code :
  1. class Base {
  2. public :
  3.   virtual void appellerFonctionX(int x)
  4.   {
  5.     void(Base::*fonction)() = 0 ;
  6.     fonction = table[x] ;
  7.     if ( fonction == 0 ) throw exception("pas content" ) ;
  8.     (*this.*fonction)() ;
  9.   }
  10. private :
  11.   map<int, void(Base::*)()> table ;
  12. protected :
  13.   void enregistrer(int i, void(Base::*f)())
  14.   {
  15.     table[i] = f ;
  16.   }
  17. } ;
  18. class Fille : public Base {
  19. public :
  20.   void f1() ;
  21.   void f2() ;
  22.   void f3() ;
  23.   //......
  24.   Fille()
  25.   {
  26.      enregistrer(1, (void(Base::*)())f1 ) ;
  27.      enregistrer(2, (void(Base::*)())f2 ) ;
  28.      enregistrer(3, (void(Base::*)())f3 ) ;
  29.      //......
  30.   }
  31. } ;


 
J'aurais plutot tendance à dire que je vais etre obligé de déclarer plein de virtual void fx() ; dans ma classe de base, mais bon...
 
edité : j'me rappellais plus comment c'était fait, j'ai remis la map à la place du switch...


Message édité par Mackila le 23-03-2006 à 19:24:11
Reply

Marsh Posté le 23-03-2006 à 19:51:56    

> J'aurais plutot tendance à dire que je vais etre obligé de déclarer plein de virtual void fx() ; dans ma classe de base, mais bon...
- exact
 
Je ne pige pas ce que tu veut faire, ça me parait pas très organisé.
 
-? Est tu sûr d avoir besoin de N classes filles contenant M fonctions virtuelles?
 
Une autre organisation:
N classes filles, chacune mères de M classes petite-fille.
 
Encore une autre organisation:
N*M classes filles
 
Tu peut mixer ces solutions avec des templates...

Reply

Marsh Posté le 23-03-2006 à 22:11:09    

En gros je cherche à me faire un outil pour écrire facilement des séquences, pour gérer un processus industriel.
Je dois donc pouvoir lancer des traitements, attendre, vérifier des comptes-rendus, tout en vérifiant en permanence un ensemble de conditions de fonctionnement.
 
Ma classe Base s'appelle en fait BaseSequence, et Fille est en réalité SequenceTruc.
 
Mon moteur de séquence fait partie de BaseSequence, et ressemble à ca :
 

Code :
  1. class BaseSequence {
  2. //....
  3. private :
  4.   map<int, void(BaseSequence::*)()> tableEtapes ;
  5. public :
  6.   bool run() ;
  7. protected :
  8.   virtual void PreSequence() ;
  9.   virtual void PostSequence() ;
  10. //....
  11. } ; // class BaseSequence
  12. void PreEtape()
  13. {
  14. }
  15. void PostEtape()
  16. {
  17. }
  18. bool BaseSequence::run()
  19. {
  20.   do
  21.   {
  22.     Sleep(10) ;
  23.     PreEtape() ;
  24.     void(Base::*traitementEtape)() = 0 ;
  25.     traitementEtape = tableEtapes[numeroEtape] ;
  26.     if ( traitementEtape == 0 ) throw exception("Etape inexistante" ) ;
  27.     (*this.*traitementEtape)() ;   
  28.     PostEtape() ;
  29.   }
  30.   while ( ! estTerminee() ) ;
  31.   return true ; // Séquence terminée avec succès
  32. }


 
Je peux ainsi mettre dans PreEtape() et PostEtape() mon code de vérification, qui peut lancer ce qu'il veut comme exception si une des conditions nécessaire au fonctionnement n'est pas bonne.
 
Dans ma classe SequenceTruc, je me déclare des fonctions d'étape, que j'associe à un numéro d'étape en les insérant dans ma map tableEtapes.
 
Mon problème étant : est ce que je peux raisonnablement stocker des void(SequenceTruc::*)() dans une map qui attend des void(BaseSequence::*)(), sachant que SequenceTruc hérite et n'hérite que de BaseSequence.
 
Sinon je vois pas comment faire à part me déclarer un nombre suffisant de fonctions "étapes" virtuelles dans ma classe BaseSequence, mais ca fait bourrin je trouve :/...
 
edit : au passage, ca marche comme ca, mais vu que pour insérer mes pointeurs void(SequenceTruc::*)() dans ma map, j'ai casté comme un gros bourrin, j'me dis qu'il y a un truc foireux dans le bazar... Et j'ai pas envie de laisser un truc foireux dans ce code...
 
edit² : tiens, j'me demande si yaurait pas un holdup à faire à coup de templates... Faudra que je voie ca, demain...


Message édité par Mackila le 23-03-2006 à 22:17:52
Reply

Marsh Posté le 23-03-2006 à 22:31:12    

> void(Base::*traitementEtape)();
- fait un typedef, sinon c est pas pratique.
 
> est ce que je peux raisonnablement stocker des void(SequenceTruc::*)() dans une map qui attend des void(BaseSequence::*)()
- oui à condition de spécifier que c est une fonction virtuelle, je peut pas te donner la syntaxe, mais tu doit avoir ``virtual`` quelque part.
 
> Sinon je vois pas comment faire à part me déclarer un nombre suffisant de fonctions "étapes" virtuelles dans ma classe BaseSequence, mais ca fait bourrin je trouve :/...
- je n ai pas l impression que tu ait besoin d autre chose que:

Code :
  1. // une étape générique
  2. classe Etape
  3. {
  4.   virtual void PreEtape() throw Error =0;
  5.   virtual void PostEtape() throw Error =0;
  6.   virtual void Etape() throw Error =0;
  7. }
  8. // un type d étape particulier
  9. class EtapeCeci: public Etape
  10. {
  11.   EtapeCeci(...) { ... }
  12.   void PreEtape() { ... }
  13.   void PostEtape() { ... }
  14.   void Etape() { ... }
  15. }
  16. // un autre type d étape particulier
  17. class EtapeCela: public Etape
  18. {
  19.   EtapeCela(...) { ... }
  20.   void PreEtape() { ... }
  21.   void PostEtape() { ... }
  22.   void Etape() { ... }
  23. }
  24. // une séquence composée d étapes
  25. class Sequence
  26. {
  27.   Etape* etapes[];
  28.   void ajouter(Etape*) { ... }
  29.   void supprimer(Etape*) { ... }
  30.   void go() throw Error
  31.   {
  32.     etapes[i]->preEtape();
  33.     etapes[i]->Etape();
  34.     etapes[i]->postEtape();
  35.   }
  36. }


 
Cherche sur le web: functionoids
Une bonne doc:
http://snet.wit.ie/GreenSpirit/c++ [...] #faq-33.10

Reply

Marsh Posté le 23-03-2006 à 22:33:26    

errata:

Code :
  1. class Sequence
  2.     {
  3.      Etape* etapes[];
  4.      void ajouter(Etape*) { ... }
  5.      void supprimer(Etape*) { ... }
  6.      void go() throw Error
  7.      {
  8.        for(i=0;....i++)
  9.        {
  10.          etapes[i]->preEtape();
  11.          etapes[i]->Etape();
  12.          etapes[i]->postEtape();
  13.        }
  14.      }
  15.     }

Reply

Marsh Posté le 23-03-2006 à 22:53:10    

L'idée d'indiquer que mon pointeur de fonction pointe sur quelque chose de virtual me plait bien, ca me permettrait de valider le fonctionnement de mon bazar comme je l'ai testé aujourd'hui.
 
Merci pour le lien, j'ai parcouru, je lirai ca calmement demain.
 
Enfin au pire des cas, je peux écrire une méthode run() par séquence, ca me tuera pas (mais bon c'est domage, le but aurait été de n'avoir de défini dans la classe SequenceTruc que ce qui a rapport directement avec le process de la dite séquence. Histoire d'éviter d'oublier un truc le jour lointain ou je voudrai rajouter une séquence...)

Reply

Marsh Posté le 23-03-2006 à 23:35:38    

Le coup du pointeur sur fonction viruelle, ça me parait louche.
A mon avis tu doit pouvoir faire autrement.
 
> Enfin au pire des cas, je peux écrire une méthode run() par séquence
- Alors ça je ne comprends pas... justement le but de faire des étapes virtuelles est d avoir qu un seul run().
 
Avoir des Etapes fonctionoides te permettraient d ajouter des conditions, et des sauts.
 
Par exemple une étape condition:

Code :
  1. class EtapeVerifierPorte: public Etape
  2. {
  3.   Etape* sioui;
  4.   Etape* sinon;
  5.   bool resultat;
  6.   EtapeVerifierPorte(Etape* e_sioui, Etape* e_sinon): sioui(e_sioui), sinon(e_sinon) {}
  7.   // vérifie la validité de l étape
  8.   void PreEtape()
  9.   { if (!sioui) throw Error; if (!sinon) throw Error; }
  10.   // l étape
  11.   void Etape()
  12.   {
  13.     resultat=verifierFermeturePorte();
  14.   }
  15.   // retourne la prochaine étape
  16.   Etape* PostEtape()
  17.   { return resultat?sioui:sinon;  }
  18. }


 
Ensuite tu peut écrire une séquence qui utilise cette etape:

Code :
  1. Etape* e_fermer=new EtapeFermerPorte()
  2. Etape* e_chauffer=new EtapeChauffer()
  3. Etape* e_arret=new EtapeArretUrgence()
  4. Etape* e_verifierporte=new EtapeVerifierPorte(e_chauffer, e_arret);
  5. Sequence* s;
  6. s.ajouterEnPremier(e_fermer);
  7. s.ajouter(e_verifierporte);
  8. s.ajouter(e_arret);
  9. s.ajouter(e_chauffer);
  10. s.run();


Reply

Marsh Posté le 24-03-2006 à 09:44:02    

En fait j'suis en train de lire ceci, et j'suis en train d'essayer de comprendre tout le bazar pour voir si ce que je fais ne serait pas autorisé, en fait  :??:
 

Code :
  1. struct A { };
  2. struct B : A { virtual void f(); };
  3. struct C : A { virtual void g(); };
  4. void h() {
  5. // base class pointer to derived object
  6. A *objptr = new C;
  7. // base class member pointer to derived member
  8. void (A::*memptr)() = (void (A::*)()) &C::g;
  9. // ... handled as a pair ...
  10. // ... eventually dereferenced as a pair ...
  11. (objptr->*memptr)();
  12. }


 
 
edit : et ca. Ouaip enfin ce que j'ai tenté a l'air foireux. Tout le monde n'a pas l'air d'accord la dessus...


Message édité par Mackila le 24-03-2006 à 09:58:28
Reply

Marsh Posté le 24-03-2006 à 09:44:02   

Reply

Marsh Posté le 24-03-2006 à 11:52:51    

ben, moi j ai rien contre les pointeurs sur fonctions virtuelles, mais franchement, c est vraiment bizarre que tu en arrive à ça: les fonctions virtuelle sont faites justement pour éviter d avoir des pointeurs sur fonctions pas pratiques à utiliser.
 
Tu devrai vraiment lire la doc que je t ai filé, elle explique bien. Je suis quasiment sûr que tu y trouvera ce que tu cherche.
 
Sinon, j ai pas très bien compris la structure de ton programme, mais est ce que avoir des étapes polymorphes ne suffirait pas?

Reply

Marsh Posté le 24-03-2006 à 11:56:01    

struct A { virtual void etape(); };
struct B : A { void etape(); };
struct C : A { void etape(); };
A* b=new B();
A* c=new C();
b->etape(); // appelle B::etape();
c->etape(); // appelle C::etape();

Reply

Marsh Posté le 24-03-2006 à 15:20:27    

Parcequ'à chaque cycle, je veux pouvoir décider de l'étape qui sera executée au cycle d'après.
Et j'ai fait ca avec des pointeurs de fonction. Et pour pas me prendre la tête avec les pointeurs de fonction, bah je les ai planqués derrière une map<int, pointeurDeFonction> et je travaille avec l'int.
 
Effectivement, si mon downcast de pointeur de fonction s'avérait être véreux à mort, alors il me "suffirait" de définir dans ma classe BaseSequence une tripotées de fonctions virtuelles :
 

Code :
  1. class BaseSequence {
  2. // [...]
  3. protected :
  4. virtual void etape_initiale() ;
  5. virtual void etape_1() ;
  6. virtual void etape_2() ;
  7. virtual void etape_3() ;
  8. virtual void etape_4() ;
  9. // [...]
  10. virtual void etape_247() ;
  11. virtual void etape_248() ;
  12. // [...]
  13. private :
  14. void etapeInvalide() ;
  15. // [...]
  16. } ; // class BaseSequence
  17. void BaseSequence::etapeInvalide()
  18. {
  19. cerr << "etapeInvalide #" << etapeCourante << endl ;
  20. termineSequence() ;
  21. }
  22. void BaseSequence::etape_initiale() { etapeInvalide() ; }
  23. void BaseSequence::etape_1() { etapeInvalide() ; }
  24. void BaseSequence::etape_2() { etapeInvalide() ; }
  25. void BaseSequence::etape_3() { etapeInvalide() ; }
  26. // [...]
  27. void BaseSequence::etape_247() { etapeInvalide() ; }
  28. // [...]


 
C'est vrai qu'avec cette solution, j'évite d'avoir à remplir mon tableau de pointeurs dans l'initialisation des séquences.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Voila à quoi ressemble le code, et ce que j'ai trouvé jusqu'à maintenant :
 
 
 
SequenceInitialisation.cpp
 

Code :
  1. // [...]
  2. bool SequenceInitialisation::PreEtape()
  3. {
  4. verificationPressions() ;
  5. if ( interfaceUtilisateur.ArretUrgence() ) throw exception("Arrêt d'urgence demandé !" ) ;
  6. if ( interfaceUtilisateur.annuler() ) return false ;
  7. return true ;
  8. }
  9. void SequenceInitialisation::InitEtapes()
  10. {
  11. cout << "SequenceInitialisation::InitEtapes()" << endl ;
  12. AjouteEtape(DEBUT_SEQUENCE, static_cast<fonctionEtape>(etape_initiale) ) ;
  13. AjouteEtape(1             , static_cast<fonctionEtape>(etape_1       ) ) ;
  14. // [...]
  15. }
  16. void SequenceInitialisation::etape_initiale()
  17. {
  18. cout << "Demarrage de la séquence d'initialisation" << endl ;
  19. etapeSuivante() ;
  20. }
  21. void SequenceInitialisation::etape_1()
  22. {
  23. // [...]
  24. }
  25. // [...]


 
 
SequenceInitialisation.h
 

Code :
  1. // [...]
  2. class SequenceInitialisation : public BaseSequence {
  3. // [...]
  4. } ; // class SequenceInitialisation
  5. // [...]


 
 
BaseSequence.cpp
 

Code :
  1. // [...]
  2. void BaseSequence::etapeSuivante()
  3. {
  4. etapeCourante += 1 ;
  5. // [...]
  6. }
  7. void BaseSequence::AjouteEtape(int numeroDEtape, void (BaseSequence::* fonctionDeLEtape)())
  8. {
  9. tableEtapes[numeroDEtape] = fonctionDeLEtape ;
  10. }
  11. bool BaseSequence::demarre()
  12. {
  13. // [...]
  14. void (BaseSequence::* etape)() = 0 ;
  15. etape = tableEtapes[etapeCourante] ;
  16. if ( etape != 0 )
  17. {
  18.  (*this.*etape)() ;
  19. }
  20. // [...]
  21. }
  22. // [...]


 
 
BaseSequence.h
 

Code :
  1. // [...]
  2. class BaseSequence : // [...]
  3. {
  4. // [...]
  5. protected :
  6. void etapeSuivante() ;
  7. void AjouteEtape(int numeroDEtape, void (BaseSequence::* fonctionDeLEtape)()) ;
  8. private :
  9. int etapeCourante ;
  10. map<int, void (BaseSequence::*)() > tableEtapes ;
  11. public :
  12. bool demarre() ;
  13. // [...]
  14. } ; // class BaseSequence
  15. // [...]


 
 
 
Ceci compile sans problème (Visual C++ 7.0.9500), et fonctionne aussi. Pour tester cette histoire de cast de pointeur de fonction membre, je me suis déclaré une classe bidon (en lui mettant des méthodes virtuelles), et j'ai modifié l'héritage de SequenceInitialisation en :
 

Code :
  1. class SequenceInitialisation : public bidon, public BaseSequence {
  2. // [...]
  3. } ; // class SequenceInitialisation


 
J'obtiens alors à la compilation un warning de niveau 1 (C4407) : Cast entre différentes représentations du pointeur membre, le compilateur peut générer du code incorrect.
L'aide pour ce warning me propose alors d'inverser l'ordre de l'héritage :
 

Code :
  1. // cast entre différentes représentations du pointeur en membre, le compilateur peut générer du code incorrect
  2. // Un cast de type incorrect a été détecté.
  3. // L'exemple suivant génère l'avertissement C4407 :
  4. // C4407.cpp
  5. struct C1
  6. {
  7. };
  8. struct C2
  9. {
  10. };
  11. struct C3 : C1, C2
  12. {
  13. };
  14. typedef void(C3::*PMF_C3)();
  15. typedef void(C2::*PMF_C2)();
  16. PMF_C2 f1(PMF_C3 pmf)
  17. {
  18.    return (PMF_C2)pmf;   // C4407, change type of cast,
  19.    // or reverse base class inheritance of C3 (i.e. : C2, C1)
  20. }
  21. int main()
  22. {
  23. }


 
Et effectivement, si j'écris ca ca fonctionne :
 

Code :
  1. class SequenceInitialisation : public BaseSequence, public bidon {
  2. // [...]
  3. } ; // class SequenceInitialisation


 
 
Ce que j'en retire, c'est que le cas a été prévu dans le compilo de visual studio (si quelqu'un pouvait tester avec le 2005...), mais je ne sais toujours pas si c'est quelque chose d'autorisé par le standard.
 
 
 
Après on peut faire un sondage : vous préférez la version pointeurs de fonctions, ou la version masse fonctions virtuelles (si je finis par choisir cette dernière, va falloir que je me ponde une macro ou kekchose pour me générer les X fonctions de base  [:petrus75] )
 
 

Reply

Marsh Posté le 24-03-2006 à 16:32:47    

> Parcequ'à chaque cycle, je veux pouvoir décider de l'étape qui sera executée au cycle d'après.
 
- Dans ce cas tu peut faire retourner à Etape::postEtape() une pointeur vers l étape suivante.
 
> Et pour pas me prendre la tête avec les pointeurs de fonction, bah je les ai planqués derrière une map<int, pointeurDeFonction>
 
- Au lieu de stocker des pointeurs sur fonction, tu peut directement stocker des étapes.
 
Relis le code que j ai posté plus haut, il fait la même chose, mais il est plus simple à lire: ne necessite pas plein de fonctions virtuelles, ne necessite pas de pointeur sur fonction, permet une meilleure organisation de ton programme.
 
Il me semble que tu n a pas saisi comment fonctionnent les classes abstraites et les fonctions virtuelles. Je ne saurais que te consiller _vivement_ de lire une doc sur le sujet. Un petit coup de google et tu trouvera plein de tutoriaux.

Reply

Marsh Posté le 24-03-2006 à 17:42:55    

Si je décide de remplacer mes étapes "fonctions" par des étapes "class etape", ca va me donner un truc du genre :
 

Code :
  1. //---------------------------------------------------------------------------
  2. class BaseEtape {
  3. // ...
  4. protected :
  5.     Sequence* sequence ;
  6. public :
  7.     void setSequence(Sequence*) ;
  8.     virtual void traite() = 0 ;
  9. // ...
  10. } ; // class BaseEtape
  11. class Sequence {
  12. // ...
  13. public :
  14.     Sequence(BaseEtape* etapeInitiale) ;
  15. protected :
  16.     BaseEtape* etapeCourante ;
  17. // ...
  18. } ; // class Sequence
  19. bool Sequence::demarre()
  20. {
  21.     do
  22.     {
  23.         if ( ! PreEtape() ) return false ;
  24.         if ( etapeCourante != 0 )
  25.         {
  26.             etapeCourante->traite() ;
  27.         }
  28.         else
  29.         {
  30.             throw exception("Etape invalide !" ) ;
  31.         }
  32.         if ( ! PostEtape() ) return false ;
  33.     }
  34.     while( ! estTerminee() ) ;
  35.     return true ;
  36. }
  37. //---------------------------------------------------------------------------
  38. class Etape1_seqExemple : public BaseEtape {
  39. // ....
  40. public :
  41.     void traite() ;
  42. } ; // class Etape1_seqExemple
  43. class Etape2_seqExemple : public BaseEtape {
  44. // ....
  45. public :
  46.     void traite() ;
  47. } ; // class Etape2_seqExemple
  48. // ....
  49. void Etape1_seqExemple::traite()
  50. {
  51.     // Ecrire ici ce qu'il y a faire dans l'étape 1.
  52.     // Quand on veut passer à une autre étape, il faut modifier le pointeur dans
  53.     // la sequence...
  54.     sequence->etapeSuivante( ??????? ) ; // <= faut connaitre la séquence suivante,
  55. //la :o, en plus de connaitre la sequence... Alors oui j'ai vu ton exemple dans lequel le
  56. //constructeur de telle étape prend comme paramètre des pointeurs sur les étapes
  57. //suivantes possibles, mais bon ca va devenir l'horreur ce truc, surtout si je
  58. //commence à avoir des boucles dans mes séquences !
  59. }
  60. void Etape2_seqExemple::traite()
  61. {
  62.     // ....
  63.     if ( /*....*/ )
  64.     {
  65.         sequence->etapeSuivante( ????? ) ;
  66.     }
  67. }
  68. // ....
  69. //---------------------------------------------------------------------------


 
J'suis désolé mais la je voie pas ou c'est plus simple...
Ce qui serait cool c'est que les mecs qui passeront derrière moi n'aient pas besoin d'être experts en C++ pour modifier le comportement d'une séquence... (avec ton histoire, j'imagine même pas la tête du pavé que je vais trouver lors de l'instanciation de la séquence, pour laquelle va falloir instancier toutes les étapes et leur renseigner tous les pointeurs vers les étapes suivantes...)
 
Le "modèle" que j'ai en tête, c'est le truc con :
 

Code :
  1. class BaseSequence {
  2.     // ....
  3. private :
  4.     int etapeCourante ;
  5. public :
  6.     virtual void traiteSequence() =0 ;
  7.     void demarre() ;
  8.     // ....
  9. } ; // class BaseSequence
  10. class SequenceSwitch : public BaseSequence {
  11. public :
  12.     void traiteSequence() ;
  13. } ; // class SequenceSwitch
  14. void SequenceSwitch::traiteSequence()
  15. {
  16.     switch( etapeCourante )
  17.     {
  18.     case 0 :
  19.         // traitement de démarrage de la séquence
  20.         break ;
  21.     case 1 :
  22.         // traitement étape 1
  23.         break ;
  24.     case 2 :
  25.         // traitement étape 2
  26.         break ;
  27.     // .....
  28.     }
  29. }
  30. void BaseSequence::demarre()
  31. {
  32.     do
  33.     {
  34.         PreEtape() ;
  35.         traiteSequence() ;
  36.         PostEtape() ;
  37.     }
  38.     while( ! estTerminee() ) ;
  39. }


 
 
 
.....
 
 
 
Boarf. En écrivant ca, j'suis en train de me demander si j'aurais pas mieux fait de faire directement mon switch comme un bourrin sans chercher compliqué. La avec mon idée de départ, j'ai remplacé un switch par une map avec des pointeurs de fonction  [:pingouino] .
 
Merde je suis trop con des fois [:pingouino] . J'ai du fumer un truc pas clair depuis hier...
 
Ca sert des fois, de tout écrire sur le forum, on se rend compte qu'en fait on cherche à faire un truc hyper tordu  [:pingouino]


Message édité par Mackila le 24-03-2006 à 17:44:11
Reply

Marsh Posté le 24-03-2006 à 17:52:50    

Pour l'instanciation passe par une Factory .
 
LE couple factory+functor est LA maniere de régler ces problemes. Au pire tu generes un ficheir txt genre xml qui contient la luiste des instanciations, tu le lit et le passe à la factory qui te renvoie l'objet sequence tout pret.
 
le switch ... autant faire du C

Reply

Marsh Posté le 24-03-2006 à 18:17:21    

Joelf> Un feed-back de Loki ?

Reply

Marsh Posté le 24-03-2006 à 18:44:11    

> (avec ton histoire, j'imagine même pas la tête du pavé que je vais trouver lors de l'instanciation de la séquence, pour laquelle va falloir instancier toutes les étapes et leur renseigner tous les pointeurs vers les étapes suivantes...)  
 
Bof, reprends l exemple que je t ai donné des la classe VerificationPorte: tu passe au constructeur de la classe Etape un pointeur vers l étape suivante. Tu peut même en avoir plusieurs:

Code :
  1. new EtapeFermerPorte(
  2.   new EtapeVerifierPorte(
  3.     new EtapeChaufferFour(
  4.       new EtapeOuvrirPorte(0),
  5.     new EtapeArretUrgence(0)
  6.     )
  7.   )
  8. )


 
Correspond à la séquence:
- FermerPorte
- VerifierPorte, si problème ArretUrgence
- sinon ChaufferFour
- puis OuvrirPorte
 
Tu peut changer les étapes suivantes au cours de la séquence, tu peut ajouter des conditions ou des variables globales dans les constructeurs...
 
Tu peut simuler des conditions, des boucles, des sauts...
 
Et en prime tu peut avoir une belle IHM sur tout ça pour gérer indépendamment les étapes et les séquences, faire des sous-séquences, définir des conditions ou variables globales, contrôler l execution de la séquence pas à pas, enregistrer/charger des séquences prédéfinies...
 
Sans IHM, à mon avis tu te prends la tête, autant coder directement en C ou même en BASIC. C est simple le BASIC.
 
Avec le switch, tu va beaucoup plus galérer, comme avec tes pointeurs de fonction. Enfin, je te laisse le découvrir.

Reply

Marsh Posté le 24-03-2006 à 19:14:49    

++fab a écrit :

Joelf> Un feed-back de Loki ?


 
loki  [:spyer] c'est gros, gras, enorme.
Depuis que j'utilise des factory, des typelistes ou des SmallObjects, mon poil est plus brillant et mon code
a les yeux qui pétillent  :sol:  
 
Blague à part : l'utiliser c'est l'adopter. En outre, c'est une vrai source d'inspiration. Grace aux typelist et multi-stratégies, pas mal de ems interfaces et de mes codes ont gagné en lisibilité//flexibilité


Message édité par Joel F le 24-03-2006 à 19:20:27
Reply

Marsh Posté le 25-03-2006 à 12:55:20    

nargy a écrit :

[...]
 
Et en prime tu peut avoir une belle IHM sur tout ça pour gérer indépendamment les étapes et les séquences, faire des sous-séquences, définir des conditions ou variables globales, contrôler l execution de la séquence pas à pas, enregistrer/charger des séquences prédéfinies...
 
[...]
 
Avec le switch, tu va beaucoup plus galérer, comme avec tes pointeurs de fonction. Enfin, je te laisse le découvrir.


 
Ouaip ca serait top, je me coderais bien un système complet d'écriture d'automatismes à la norme IEC 61131-3, avec l'IDE, les modules d'entrées sorties toussa.
 
Sauf que le projet est à terminer pour hier.
 
Je pense rester sur le switch (vais virer les pointeurs de fonction), avec une enum pour les numéros d'étape (histoire que l'IHM qui observe la séquence ne pete pas les plombs si j'insere une étape en plein milieu du bazar).
 
Avec le switch, je ne pense pas galérer, vu qu'il n'est pas prévu qu'il puisse y avoir deux étapes actives dans la même séquence. Au pire si ya besoin de ce genre de chose, alors j'utiliserai deux séquences.
 
 

Citation :

[...] Loki [...]


 
Ca m'a l'air sympa, ca. Je mets ca dans ma liste des trucs-à-regarder-quand-j'aurais-du-temps...

Reply

Sujets relatifs:

Leave a Replay

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