[general] Comment structurer un programme sans main

Comment structurer un programme sans main [general] - C++ - Programmation

Marsh Posté le 22-05-2008 à 16:01:17    

Ca vous est peut-être déjà arrivé, lorsqu'on utilise certaines librairies, on ne doit plus utiliser de "main", mais on a un objet qui se crée, appelons le Appli, et on doit partir de lui pour notre programme...

 

Comment vous faites pour vos variables et autres ?
Pour le moment, j'en mets quelques unes en global, et les autres en attribut de la classe Appli, mais c'est pas pratique du tout je trouve.

 

Des expériences? suggestions ?

 

[edit] : pour illustrer, voila mes classes
Voila mes classes :
App, Frame et Panel sont obligatoires (librairie wxwidgets)
On remarque que toutes les classes ont besoin des autres, ce qui force à faire des boucle entre elles (genre App* Panel::GetParent()), pas montré ici :

Code :
  1. class App // Classe principale, instanciée au lancement de l'application
  2. {
  3. public:
  4.  SDLFrame *frame;
  5.  bool OnInit();
  6.  <type> MesParams;  // mes paramètres
  7.  Jeu *J;            // ma classe,
  8.                     // elle a besoin de MesParams
  9.                     // et de Panel (frame->panel)
  10. };
  11. class Frame
  12. {
  13. private:
  14.  Panel *panel;
  15.  void onFileNew(wxCommandEvent &event);
  16. };
  17. class Panel
  18. {
  19. public:
  20.  void Paint();     // a besoin des attributs et
  21.                    // méthodes de J car appelle J->affiche()
  22.  void createScreen();
  23.  void OnMouse(wxMouseEvent& event);
  24.  Surface *screen;
  25. };


Message édité par DarWog le 26-05-2008 à 23:13:44
Reply

Marsh Posté le 22-05-2008 à 16:01:17   

Reply

Marsh Posté le 22-05-2008 à 16:39:31    

[:vinx2]

Reply

Marsh Posté le 22-05-2008 à 19:36:44    

LOL ok, je recommence^^
 
En gros, avec certaines libs, ya plus de main :
avec wxWidgets, on a un objet wxApp qui est instancié à l'exécution, et dont le constructeur (on y touche pas) appelle une méthode "OnInit()" et "OnRun", dans lesquelles en quelques sortes je copie mon main.  
 
Mais comme on est dans une méthode d'une classe, on crée pas des objets comme ca comme un bourrin, donc je les mets en attributs de la classe...

Reply

Marsh Posté le 22-05-2008 à 19:49:06    

Y a jamais de main() dans une lib (sauf durant le développement pour tests éventuellement).
 
Pour les variables, ben c'est en private dans la classe, avec éventuellement les getter/setter qui vont avec, si besoin.  
Je ne comprends pas ton souci en fait.

Reply

Marsh Posté le 23-05-2008 à 11:55:31    

Code :
  1. class Appli: wxApp
  2. {
  3. public:
  4. int param1;
  5. int paramN;
  6. Jeu* J;
  7. int OnRun();
  8. int OnInit();
  9. int OnExit();
  10. }
  11. Class Jeu
  12. {
  13. private:
  14. blablabla;
  15. public:
  16. void affiche();
  17. void move(blablabla);
  18. }


Donc je dois recenser toutes les variables possible et les mettre en attribut, et faire des méthodes get/set... arf
Pour le moment c'est un peu moins propre, je mettais tout en public car J.affiche() a besoin des attributs de Appli.J et n'y accède pas.
 
Sinon peut-être faire une classe contenant juste les param, en attribut de Appli, et passé aux méthodes... c'est ptetre le plus simple.


Message édité par DarWog le 23-05-2008 à 15:56:04
Reply

Marsh Posté le 23-05-2008 à 12:02:19    

Attends, j'écris un exemple pour être sûr d'avoir compris ton problème :

Code :
  1. class A {
  2. private :
  3.   <type> foo;
  4.   <type> bar;
  5. public:
  6.   foobar();
  7. };
  8.  
  9. class B {
  10. public:
  11.   A instance;
  12.   barfoo();
  13. };
 

Donc d'après toi, B.instance.foobar() n'accèderait pas aux variables foo et bar ?
Pourtant, si. La classe A est une entité à part entière, si tu instancies 10.000 classes A avec des valeurs toutes différentes pour foo et bar, chaque instance de A aura accès à ses propres valeurs de foo et bar...

 

Donc la fonction foobar() a bien accès aux variables foo et bar. En revanche, la fonction barfoo() de la classe B ne peut pas y avoir accès.

Message cité 1 fois
Message édité par Elmoricq le 23-05-2008 à 12:04:13
Reply

Marsh Posté le 23-05-2008 à 15:55:19    

Elmoricq a écrit :

[...] En revanche, la fonction barfoo() de la classe B ne peut pas y avoir accès.

C'est justement cette partie qui m'interesse si tu regardes mon message.
 
 
au final, je pense que le plus simple, ayant une classe A comme suit, et B ayant besoin de tous les bar et foo :

Code :
  1. class A{
  2. private:
  3.   <type> foo;
  4.   <type> bar;
  5.   B* b;
  6. public:
  7.   foobar();
  8. };


 soit de mettre les paramètres tous en public dans A, et de mettre un lien de B vers A :

Code :
  1. class B{
  2. private:
  3.   A* parent;
  4. public:
  5.   B(A* a){parent=a}
  6. };
  7. ...
  8. A::A{b=new B(this);}


Comme ca on a accès à tout par "parent->foo"
 
Soit de faire un truc annexe pour les variables :

Code :
  1. struct Param{
  2.   <type> foo;
  3.   <type> bar;
  4.   ...
  5. };
  6. class A{
  7. private:
  8.   Param* param;
  9.   B* b;
  10. public:
  11.   foobar();
  12. };
  13. class B{
  14. private:
  15.   Param* param;
  16. public:
  17.   B(Param* a){param=a}
  18. };
  19. ...
  20. A::A{b=new B(param);}


Ce qui allège les classes, mais si B a besoin des méthodes de A, il faut quand-même faire le lien vers le parent.
 
 
 

Reply

Marsh Posté le 23-05-2008 à 16:00:39    

Références circulaires, c'est mal.

 

C'est bien plus simple d'écrire :

Code :
  1. class A {
  2.    private :
  3.      <type> foo;
  4.      <type> bar;
  5.    public:
  6.      foobar();
  7.      getfoo();
  8.      getbar();
  9.    };
  10.    
  11.    class B {
  12.    public:
  13.      A instance;
  14.      barfoo();
  15.    };
 

Et si B a besoin de foo ou de bar, il appelle getfoo() et getbar().
Ainsi, la classe A conserve le contrôle sur ses membres. Je le mets en gras parce que c'est une notion très importante. De plus, ça améliore la maintenabilité et la lisibilité : tu distingues d'un seul coup d'oeil les membres totalement privés qui servent au fonctionnement interne de la classe, et ne sont donc pas destinés à un quelconque lecteur extérieur, de celles qui sont des informations importantes pour ceux qui instancient la classe.


Message édité par Elmoricq le 23-05-2008 à 16:00:48
Reply

Marsh Posté le 26-05-2008 à 09:45:13    

Oui, je comprends : pour que la "mère" accède proprement aux attributs de la classe qu'elle instancie...
Sauf que mon problème est que les classes doivent être imbriquées : exemple classe A mère qui contient des instances de F1 et F2 :

Code :
  1. Class A{
  2. private:
  3.   F1* instance;
  4.   F2* instance;
  5. public:
  6.   <type> fooA;
  7.   <type> barA;
  8.   foobarA(){utilise barF1,fooF1,foobarF1(),barF2,fooF2,foobarF2()};// ok par getbarF1...
  9. };
  10. class F1{
  11. public:
  12.   <type> fooF1;
  13.   <type> barF1;
  14.   foobarF1(){utilise fooA,barA,foobarA(),barF2,fooF2,foobarF2()};// besoin de A* parent
  15. };
  16. class F2{
  17. public:
  18.   <type> fooF2;
  19.   <type> barF2;
  20.   foobarF2(){utilise fooA,barA,foobarA(),barF1,fooF1,foobarF1()};// besoin de A* parent
  21. };


Et c'est là que ca devient le bordel :/
Et pour ce qui est de cette structure tordue, j'ai pas le choix, j'aimerais pouvoir éviter...


Message édité par DarWog le 26-05-2008 à 09:46:26
Reply

Marsh Posté le 26-05-2008 à 09:59:49    

Uh... F1 et F2 ont besoin de connaître A, qui lui-même instancie F1 et F2 ?
 
Jette ton diagramme de classe et refais-le, tu ne t'en sortiras pas. En tout cas pas proprement.

Reply

Marsh Posté le 26-05-2008 à 09:59:49   

Reply

Marsh Posté le 26-05-2008 à 10:07:58    

LOL, comme je te dis, j'ai pas vraiment le choix, c'est la librairie qui me force à ça, enfin c'est l'impression que j'ai, d'où mon post :
Comment structurer un programme avec les classes "forcées" de la librairie (sans main) vu que tous les objets sont attributs de la classe principale... et qu'ils souhaiteraient se parler entre eux
Ce soir je poste le détail des classes auxquelles je peux pas toucher + les miennes, voire si ya une solution moins pire qu'une autre^^


Message édité par DarWog le 26-05-2008 à 10:08:25
Reply

Marsh Posté le 26-05-2008 à 12:06:05    

 

[:roi]

Message cité 1 fois
Message édité par vapeur_cochonne le 26-05-2008 à 12:22:47

---------------
marilou repose sous la neige
Reply

Marsh Posté le 26-05-2008 à 12:20:57    


 
Vapeur qui fait genre d'avoir compris  :sarcastic:


---------------
When it comes to business/legal topics, just assume almost everyone commenting has no idea what they’re taking about and have no background in these subjects because that’s how it really is. Harkonnen 8-> Elmoricq 8====>
Reply

Marsh Posté le 26-05-2008 à 12:23:03    

Dion a écrit :


 
Vapeur qui fait genre d'avoir compris  :sarcastic:


j'ai édité pour éviter cette confusion :jap:


---------------
marilou repose sous la neige
Reply

Marsh Posté le 26-05-2008 à 19:39:19    

Voila les classes obligatoires : App, Frame, et Panel
App : c'est l'application, Frame la fenêtre (menus...), et Panel l'affichage
 
Le seul truc "à moi" est Jeu, qui a une méthode affiche() (avant affichait en cout<<, et maintenant affiche dans Panel->paint() )
 

Code :
  1. class App // Classe principale, instanciée au lancement de l'application
  2. {
  3. public:
  4.  SDLFrame *frame;
  5.  bool OnInit();
  6.  <type> MesParams;  // mes paramètres
  7.  Jeu *J;            // ma classe,  
  8.                     // elle a besoin de MesParams
  9.                     // et de Panel (frame->panel)
  10. };
  11. class Frame
  12. {
  13. private:
  14.  Panel *panel;
  15.  void onFileNew(wxCommandEvent &event);
  16. };
  17. class Panel
  18. {
  19. public:
  20.  void Paint();     // a besoin des attributs et  
  21.                    // méthodes de J car appelle J->affiche()
  22.  void createScreen();
  23.  void OnMouse(wxMouseEvent& event);
  24.  Surface *screen;
  25. };


J'ai mis mes trucs (jeu et param) dans App, j'aurais pu choisir de les mettre dans Panel, mais il doit être possible d'avoir plusieurs Panels pour un seul Jeu.
:)

Reply

Marsh Posté le 26-05-2008 à 20:40:24    

D'après ce que j'ai lu en cherchant rapido, vu que c'est tout géré par événement, tu va avoir quelque part (dans onRun?) une boucle qui boucle indéfiniment jusqu'a ce que tu ferme ton programme.
 
Un truc dans le style

Code :
  1. bool quit = false;
  2. Jeu *J = new Jeu(/*tu passes ce dont tu a besoin*/);
  3. while (false == quit)
  4. {
  5.    //Recup events
  6.    //Gestion events en utilisant J ou autre
  7. }
  8. delete J;


 
il me semble...


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

Marsh Posté le 26-05-2008 à 22:00:27    

Justement, c'est ca qui est pas cool avec wxWidgets, ya aucune buocle^^ (du moins pas visible)
En fait, on a une classe qui est instanciée (App), et après, les évènement gèrent en quelque sorte des interruptions : on associe un event à une méthode de la frame ou du panel :

 
Code :
  1. void Frame::onFileNew(wxCommandEvent &event);
  2.  void Frame::onFileExit(wxCommandEvent &event){ Close(); }
  3.  void Frame::OnKeyDown(wxKeyEvent &event);
  4.  void Panel::OnMouse(wxMouseEvent& event);


et quand il se passe rien, c'est la méthode OnIdle qui est appelée.

Code :
  1. void Panel::onIdle(wxIdleEvent &event);


Message édité par DarWog le 26-05-2008 à 22:01:01
Reply

Marsh Posté le 26-05-2008 à 22:39:01    

Bah tu surcharge onRun() pour y mettre ta gestion des events ou gère a la fois ceux de wxwidget et ceux de la SDL nan?

 

En tout cas je voit pas trop le trip de départ du topic avec tes noeuds de dépendances de classes...


Message édité par kyntriad le 26-05-2008 à 22:40:43

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

Marsh Posté le 26-05-2008 à 23:08:16    

les évènements sont apparement gérés tout seul comme j'ai dit (On Idle si rien, et d'autres méthodes de Frame si on couche la souris, clavier ou les menus), on peut pas faire de boucle à la main.
Et ce sont des evenements wx, SDL ne récupère rien, tout est géré en wx.
Pour mon trip de dépendance, dans mon post de 19h39, on voit que chaque classe a besoin des infos des autres, donc si App contient frame qui contient panel, app accède à tout, mais il faut faire une boucle pour que panel accède à App (et donc à Jeu). Enfin c'est le bordel, mais ca marche.

Reply

Marsh Posté le 26-05-2008 à 23:28:23    

en general, on met dans Idle les calculs necessaires à l'affichage d'une nouvelle frame, dans onKeyboard les controles du jeu, OnPaint l'affichage de la frame en cours ...
 
Pas besoin de boucle explicite.

Reply

Marsh Posté le 26-05-2008 à 23:31:15    

et donc a quoi te sert sdl si tout est géré en wx?

 

edit: ah ok (pas refresh avt le post de joel :p)


Message édité par kyntriad le 26-05-2008 à 23:32:42

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

Marsh Posté le 27-05-2008 à 09:01:21    

@kyntriad : wx pour les menus, sdl pour l'affichage.
@Joel : c'est ce que je fais avec Onkeyboard/OnMouse, mais pour l'affichage, je commence par avoir un programme qui tourne sans (en mode console) : Jeu contient le plateau et les pièces, donc j'ai des méthodes plateau->affiche() et pièces->affiche(), où j'ai remplacé les "cout" par des "SDL_Blit_surface".
Pour afficher, Paint() appelle donc le Jeu J, qui est dans App, d'où la boucle de Panel vers App :/

 

Et je veux pas mettre le Jeu dans Panel car un jeu peut avoir plusieurs fenêtres d'affichage.

 

Autre détail, la variable screen doit être accessible à tout ce qui affiche, donc Panel et Jeu.


Message édité par DarWog le 27-05-2008 à 09:02:42
Reply

Marsh Posté le 27-05-2008 à 09:42:50    

déjà Jeu ne devrait contenir que la logique du jeu et utilisé des événements pr dire à une autre classe Affichage que son état à changer. Dans Idle, juste Jeu est manipulée et lance des event sur Affichage. Dans Paint juste Affichage est appelée.

Reply

Marsh Posté le 27-05-2008 à 10:51:42    

Intéressant, j'avais jamais imaginé ça, j'ai toujours fait des méthodes affiche(), mais jamais séparé le tout...
donc en gros, je change mes ->affiche() en ->SetAffiche(ClassAffiche, paramaffich) et Créer une ClassAffiche qui sera appelée par OnPaint().
Reste à placer ClassAffiche :
 * si on la met dans App, il faudra la passer en paramètre à Panel.
 * sinon on la met dans Panel, et on passe autant de ClassAffiche à Jeu qu'il existe de Panel.

 

Merci pour cette idée, je vais voir ce que ca donne sur mon code...

 


Message édité par DarWog le 27-05-2008 à 13:18:12
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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