Partage
  • Partager sur Facebook
  • Partager sur Twitter

Fonction en paramètre

Envois de Macros notamment

Sujet résolu
    23 août 2007 à 15:46:04

    Salut à tous !

    Alors voila je suis en train de coder un projet en C++/SDL(et ses extensions)/FMOD, qui est en fait un jeu de shoot 2D.

    J'ai fini le menu principal du jeu mais je suis assez heuu maniac (?). Je trouve que le code source du Menu est loins d'être souple, et je voudrais le rendre plus souple.

    Je m'explique : dans le main, j'instancie la class Menu en envoyant au constructeur un booléen. Cette opération prépare un menu, qui ne contient rien pour l'instant. Puis j'appelle la méthode Menu::Newcomposed(nameOfComposed, 10). Le premier paramètre est un pointeur constant sur un char, le deuxième est l'ordonnée souhaitée pour l'onglet à créer. J'appelle donc 5 fois cette méthode (Jouer, Comment Jouer, Options, A propos... et Quitter). Jusque là pas de problème.

    Puis j'appelle Menu::Actualiz(), qui gère la gestion des évènements, la gestion d'un curseur, les cliques souris etc ...

    Seulement le voila le problème : les cliques souris ! Quand je clique sur le composant[0], je dois donner le code à effectuer, je le place donc dans la partie appropriée du code de Menu::Actualiz().

    PROBLEME : Si je veux instancier plusieurs menus, si je clique sur le composant[0] de chaque menu, j'obtiendrai EXACTEMENT le même résultat. J'ai donc rendu la méthode Menu::Actualiz() virtuelle. Je vous laisse imaginer le bordel :
    1. class Menu
    2. {
    3.     public :
    4.         Menu();
    5.         Menu(bool head);
    6.         virtual ~Menu();
    7.         unsigned short int Translatedssl(SDL_Surface *screen);
    8.         void Launch(SDL_Surface *screen);
    9.         void Newcomposed(const char *cName = "NULL", unsigned short int y = 0);  
    10.         virtual void Display(SDL_Surface *screen); // Display the menu on screen
    11.         virtual void Actualiz(SDL_Surface *screen); // Actualise screen
    12.         void Changecursor(SDL_Surface *screen, const char *mode);
    13.         bool Cursor(SDL_Surface *screen, SDL_Event *event);
    14.     protected :
    15.         unsigned short int nmbComposed;
    16.         // Surfaces
    17.         SDL_Surface *hide;
    18.         SDL_Surface *ssl;
    19.         SDL_Surface *cursor01;
    20.         SDL_Surface *cursor02;
    21.         // Graphic composed
    22.         Linked composed;
    23.         // Positions
    24.         SDL_Rect null;
    25.         SDL_Rect posSsl;
    26.         SDL_Rect posCursor;
    27.         // Event
    28.         SDL_Event event;
    29.         // FSOUND
    30.         FSOUND_SAMPLE *hit;
    31.         FSOUND_SAMPLE *missed;
    32.         // Boolean
    33.         bool _h;
    34.         bool finish;
    35.         bool cursSpecial;
    36. };
    37. class Menup : public Menu
    38. {
    39.     public :
    40.         Menup(){};
    41.         ~Menup(){};
    42.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    43. };
    44. class Menupv : public Menu
    45. {
    46.     public :
    47.         Menupv(){};
    48.         ~Menupv(){}
    49.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    50.     private :
    51.         Fileconf conf; // Configuration text class
    52. };
    53. class Menupd : public Menu
    54. {
    55.     public :
    56.         Menupd(){};
    57.         ~Menupd(){};
    58.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    59.     private :
    60.         Fileconf conf; // Configuration text class
    61. };
    62. class Menugt : public Menu
    63. {
    64.     public :
    65.         Menugt(){};
    66.         ~Menugt(){};
    67.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    68. };
    69. class Menugf : public Menu
    70. {
    71.     public :
    72.         Menugf(){};
    73.         ~Menugf(){};
    74.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    75. };
    76. class Page : public Menu
    77. {
    78.     public :
    79.         Page(const char *document);
    80.         ~Page();
    81.         void Actualiz(SDL_Surface *screen); // Remplaced methode
    82.         void Display(SDL_Surface *screen); // Remplaced methode
    83.     private :
    84.         SDL_Surface *infos;
    85.         SDL_Rect posInfos;
    86. };


    Vous comprenez le problème maintenant ....

    Voila donc ma question : je voudrais que la constructeur de Menu soit capable 'accepter en argument des macros pour que j'évite tout cet héritage qui, selon moi, n'est pas très très souple, vous ne trouvez pas ?

    Merci d'avance
    • Partager sur Facebook
    • Partager sur Twitter
      23 août 2007 à 16:05:13

      boost::function ou boost::signal t'aidera.
      • Partager sur Facebook
      • Partager sur Twitter
        23 août 2007 à 16:12:20

        Est-ce vraiment nécessaire de sortir boost pour çà ?
        1. typedef void (*menu_callback_t)(Menu& m);
        2. class Menu
        3. {
        4.   [...]
        5.   void Newcomposed(const char *cName = "NULL",menu_callback_t cb=NULL, unsigned short int y = 0);
        6. };
        7. void play_callback(Menu& m)
        8. {
        9.   // traitement
        10. }
        11. void func()
        12. {
        13.   Menu m;
        14.   ...
        15.   m.Newcomposed("Jouer",&play_callback);
        16. }
        • Partager sur Facebook
        • Partager sur Twitter
          23 août 2007 à 16:14:32

          Merci beaucoup pour vos réponses mais est-ce que quelqu'un peut m'expliquer comment ça fonctionne ? Que veut dire typedef void (*menu_callback_t)(Menu& m);

          Déjà je ne comprends pas le typedef (structure ?). Ensuite, qu'est-ce que ceci (*menu_callback_t)(Menu& m); ?

          Et je ne comprends pas l'initialisation du pointeur de fonction void (*menu_callback_t)(Menu& m);, si s'en est un...

          Voila merci beaucoup en tout cas
          • Partager sur Facebook
          • Partager sur Twitter
            23 août 2007 à 16:39:07

            pamaury -> Ah oui, j'ai pas tout lu, j'ai pas vu que la macro s'appliquait seulement sur les Menu...

            La c'est vrai que les pointeurs de fonctions peuvent suffire, ça dépend de ce qu'on fait avec ces fonctions.

            Le problème c'est qu'on ne peut pas passer de foncteurs par rapport à boost::function qui lui est générique (il sera d'ailleurs dans le prochain standard C++).

            Si on veut pouvoir paramétrer les fonctions pour qu'elles fassent autre chose qu'actualiser le menu d'une manière différente, c'est plus intéressant d'avoir boost::function, sinon, pointeurs de fonctions suffisent.

            -Skypers- -> menu_callback_t c'est un autre nom pour désigner le type d'un pointeur de fonction qui prend en argument une référence vers un menu, et qui renvoie void.
            • Partager sur Facebook
            • Partager sur Twitter
              23 août 2007 à 17:30:13

              Merci beaucoup pour vos réponses mais est-ce que quelqu'un peut m'expliquer comment ça fonctionne ? Que veut dire typedef void (*menu_callback_t)(Menu& m);

              Déjà je ne comprends pas le typedef (structure ?). Ensuite, qu'est-ce que ceci (*menu_callback_t)(Menu& m); ?

              Et je ne comprends pas l'initialisation du pointeur de fonction void (*menu_callback_t)(Menu& m);, si s'en est un...

              Voila merci beaucoup en tout cas

              EDIT : Je pense avoir compris : void (*menu_callback_t)(Menu& m); signifie que l'on utilisera un pointeur pointant sur une fonction quelquonque tant que celle-ci prend en argument une référence sur un Menu et qu'elle retourne void, c'est bien ça ?

              Et le typedef sert à quoi dans tout ça ?

              J'ai fait ce gestionnaire, mais ça plante :

              1. #include <iostream>
              2. using std::cout;
              3. using std::endl;
              4. typedef void (*func)(int number);
              5. void Double(int number);
              6. void call(func function_to_call);
              7. int main(int argc, char *argv[])
              8. {
              9.     cout << "Gestion de l'envoi d'une fonction simple en parametre d'une autre fonction...\n" << endl;
              10.     cout << "Test par envoi de fonction portant un int en argument : " << endl;
              11.     call(&Double(2));
              12.     system("pause");
              13.     return 0;
              14. }
              15. void Double(int number)
              16. {
              17.     cout << "Dans Double()" << endl;
              18. }
              19. void call(func function_to_call)
              20. {
              21.     function_to_call;
              22. }


              Erreur compilo : '&' requires l_value....
              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                23 août 2007 à 23:23:53

                bon je suis pas pro du tout alors je ne vais pas répondre... Je peux néanmoins te donner un lien sur les pointeurs de fonction...

                Hiura
                • Partager sur Facebook
                • Partager sur Twitter
                  24 août 2007 à 1:38:31

                  C'est ça qu'il faut écrire : call(&Double);

                  Car call attend en paramètre une fonction, et c'est "Double" la fonction vers laquelle qu'on veut lui donner.

                  Maintenant, call dispose d'une fonction et pour l'utiliser, il faut forcément lui donner un int, car call ne sait manipuler que des fonctions qui ne renvoient rien et qui ont besoin d'un int pour fonctionner.

                  On peut écrire call comme ça :
                  1. void call(func function_to_call)
                  2. {
                  3.     function_to_call(2);
                  4. }


                  ou mieux :

                  1. void call(func function_to_call, int i)
                  2. {
                  3.     function_to_call(i);
                  4. }


                  Sinon, le typedef ne sert qu'à simplifier l'écriture d'un type pointeur de fonction.
                  • Partager sur Facebook
                  • Partager sur Twitter
                    24 août 2007 à 10:47:19

                    Ok merci j'étais tombé sur un lien hier et j'ai appris tout ça, mais merci beaucoup en tout cas ! Mon menu est bien mieux ainsi (enfin je trouve :p )

                    Merci encore à vous ! Sinon, quelle est cette alternative boost ?
                    • Partager sur Facebook
                    • Partager sur Twitter
                      26 août 2007 à 2:37:29

                      Ben, imagine que tu veuilles définir des fonctions qui prennent des arguments de type T1, ..., TN qui renvoient le type Ret, alors le type à écrire avec boost::function c'est :

                      typedef boost::function<Ret (T1, T2, ..., TN)> FonctionType;

                      Ca accepte aussi bien les foncteurs (un objet d'une classe où l'opérateur () a été surchargé) que les pointeurs sur fonction.

                      C'est surtout utile quand tu veux appeler des fonctions membre.

                      Imagine que tu as dans un jeu, des objets qui ont tous une fonction membre update qui doivent tous être appelés sous des conditions particulières.
                      Le problème, c'est que ces objets n'ont pas tous le même type, ne font pas partie de la même hiérarchie polymorphe. Alors, plutôt que de stocker tous les différents types possibles, ce qui devient infernal à maintenir si le nombre de types des objets tend à croitre, une solution élégante est de stocker seulement des fonctions qui feront abstraction du type de chaque objet.

                      Tu dois savoir qu'une fonction membre a toujours un paramètre en plus, pour le pointeur this. Pour arriver à ce que l'on veut, il faudrait fixer le pointeur this de chaque pointeur de fonction membre, pour transformer le pointeur de fonction membre en une fonction qui n'a plus besoin qu'on lui associe un objet, car la fonction la connait déjà.

                      A partir d'une fonction, on retourne une autre fonction, la même mais avec des paramètres fixés. C'est l'application partielle de fonction ou curryfication, qu'on fait facilement dans les langages fonctionnels, qui permet de réaliser plein de choses de façon élégante.

                      En C++, on utilisera Boost.Bind, qui permet de faire ça :

                      Imagine que tu as une fonction comme ça :

                      1. int f(int x, int y, int z)
                      2. {
                      3.     // bla bla
                      4. }


                      C'est la fonction (x,y,z) -> f(x,y,z).

                      Alors cette expression

                      1. boost::bind(&f, 0, _1, _2);


                      veut dire :

                      crée moi la fonction qui à (y,z) associe la valeur f(0,y,z). Le _1 et le _2 correspondent respectivement au 1er et 2e paramètre de la fonction créée.

                      Autrement dit, elle crée dynamiquement la fonction suivante, sans qu'on ait besoin de l'écrire à la main :

                      1. int fonction(int y, int z)
                      2. {
                      3.     return f(0, y, z);
                      4. }


                      C'est pratique, ça nous évite souvent de devoir écrire des choses dégueulasses pour arriver au même résultat (en C++, pour créer dynamiquement des fonctions, il faudrait passer par l'écriture de classes locales, à chaque fois qu'on aurait besoin de faire ce genre d'opérations -> très fastidieux).
                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 août 2007 à 3:29:52

                        Merci beaucoup, mais sa semble être un peu compliqué, j'ai implémenté les pointeurs de fonction, ça marche bien, tu penses que c'est une erreur de les utiliser, que c'est "dégueulasse" ? :-°
                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 août 2007 à 8:46:52

                          Non c'est pas sale d'utiliser des pointeurs de fonctions.

                          Il vaut mieux juste indiquer clairement dans le nom de la variable que c'est un pointeur sur fonction.

                          Et utiliser un typedef pour renommer tout ça plus clairement peut aussi être bien.
                          • Partager sur Facebook
                          • Partager sur Twitter
                          Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
                            28 août 2007 à 12:01:35

                            C'est ce que j'ai fait ^^

                            Merci à tous en tout cas !

                            Et c'est pointeur de fonction peuvent-ils accepter des macros ?
                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 août 2007 à 13:10:18

                              Non.
                              Peut-être les fonctions inlines (qui seraientt alors dé-inlinées), mais je n'en suis plus sûr.

                              De toutes façons, des fonctions implémentées comme des macros, c'est mal. En C, ils n'ont pas le choix. En C++, on l'a.
                              • Partager sur Facebook
                              • Partager sur Twitter
                              C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.

                              Fonction en paramètre

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown