Partage
  • Partager sur Facebook
  • Partager sur Twitter

Passer une fonction à une autre

dans le but d'executer cette fonction depuis une autre

Sujet résolu
Anonyme
    30 juillet 2007 à 15:11:39

    Bonjour.

    J'ai un soucis avec le passage de fonction en paramètre.

    J'ai essayé quelque chose mais j'obtient l'erreur :
    \C++\Exercices\MenuSDL\ActionMenuSDL.cpp:: In member function `void ActionMenuSDL::SDL_main(int, int)':
    \C++\Exercices\MenuSDL\ActionMenuSDL.cpp:45: error: `((ActionMenuSDL*)this)->ActionMenuSDL::c_fctToCall' cannot be used as a function
    :: === Build finished: 1 errors, 0 warnings ===


    Je vous montre mon code :
    #include <SDL.h>

    /// ActionMenuSDL::

    class ActionMenuSDL
    {
        public:
            ActionMenuSDL(SDL_Rect rect, SDL_Surface *surf, int *fctToCall);
            ActionMenuSDL(int x, int y, int w, int h,
                                                 SDL_Surface *surf, int *fctToCall);
            ~ActionMenuSDL();

        private:
            SDL_Rect c_rect;
            int *c_fctToCall;
            SDL_Surface *c_surf;

    }; // fin class ActionMenuSDL


    ActionMenuSDL::ActionMenuSDL(SDL_Rect rect, SDL_Surface *surf, int *fctToCall)
                             : c_rect(rect), c_fctToCall(fctToCall), c_surf(surf) {}

    ActionMenuSDL::ActionMenuSDL(int x, int y, int w, int h,
           SDL_Surface *surf, int *fctToCall) : c_fctToCall(fctToCall), c_surf(surf)
    {
        c_rect.x = x;
        c_rect.y = y;
        c_rect.w = w;
        c_rect.h = h;
    }

    ActionMenuSDL::~ActionMenuSDL(void)
    {
        SDL_FreeSurface(c_surf);
    }

    void ActionMenuSDL::main(int mouseX, int mouseY)
    {
        if (mouseX > c_rect.x && mouseX < (c_rect.x + c_rect.w) &&
                                mouseY > c_rect.y && mouseY < (c_rect.y + c_rect.h))
            *c_fctToCall(); // cannot be used as a function
    }
     


    Voilà.

    Je comprends pas trop pourquoi ça ne marche pas. Je prends l'adresse de la fonction et demande à l'exécuter.

    Je vous remercie d'avance pour votre aide.

    Hiura
    • Partager sur Facebook
    • Partager sur Twitter
      30 juillet 2007 à 15:45:23

      Salut,
      Ce que tu a mis là, est-ce que c'est la définition complète de ta classe ou c'est juste une partie? Car si c'est tout le code, je ne vois pas la définition de ta méthode c_fctToCall().
      Si tu penses à ceci:
      int *c_fctToCall;

      tu te trompes complètement,ce n'est pas une fonction.Revois les pointeur de fonction du langage C.
      ps: je ne vois pas non plus de méthode main(int mouseX,int mouseY).
      • Partager sur Facebook
      • Partager sur Twitter
        30 juillet 2007 à 16:09:15

        1. ta fonction membre main n'est pas déclarée... ( et je ne conseille pas d'utiliser le nom de fonction "main"... )

        2. ce n'est pas ainsi qu'on déclare une pointeur de fonction mais sous la forme :
        // pointeur sur fonction ayant un retour de type int et aucun paramètre d'appel
        int (*p_fonction)();
        // pointeur sur fonction avec type de retour void et ayant 2 paramètres de type int
        void (*p_fontion2)( int, int );


        ref : http://c.developpez.com/megacours/x2012.html
        • Partager sur Facebook
        • Partager sur Twitter
        Anonyme
          30 juillet 2007 à 19:41:01

          Bonjour!

          Citation : zabibof

          Salut,
          Ce que tu a mis là, est-ce que c'est la définition complète de ta classe ou c'est juste une partie? Car si c'est tout le code, je ne vois pas la définition de ta méthode c_fctToCall().
          Si tu penses à ceci:

          int *c_fctToCall;


          tu te trompes complètement,ce n'est pas une fonction.Revois les pointeur de fonction du langage C.
          ps: je ne vois pas non plus de méthode main(int mouseX,int mouseY).



          Donc : oui je me plante totalement avec ma façon de faire :-°
          et oui je ne sais pas faire des copié-collés >_< ma méthode main est bien déclarée comme il faut.

          Citation : MatteX

          1. ta fonction membre main n'est pas déclarée... ( et je ne conseille pas d'utiliser le nom de fonction "main"... )

          2. ce n'est pas ainsi qu'on déclare une pointeur de fonction mais sous la forme :

          // pointeur sur fonction ayant un retour de type int et aucun paramètre d'appel
          int (*p_fonction)();
          // pointeur sur fonction avec type de retour void et ayant 2 paramètres de type int
          void (*p_fontion2)( int, int );



          ref : http://c.developpez.com/megacours/x2012.html



          1 : ça dérange tant que ça qu'elle s'appelle main? Parce que je ne sais pas quoi mettre sinon qui soit cours simple et qui signifie que cette méthode fasse "tout". Avez-vous une idée?

          2 : merci pour le lien je vais le lire, mais c'est du C, est-ce totalement compatible avec le C++ (dans le sens : est-ce qu'en C++ il est préférable de faire autrement même si cette technique marche?).

          Merci

          Hiura
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            30 juillet 2007 à 20:10:23

            Ça fonctionne parfaitement en C++.

            J'ai eu besoin de faire une callback pour un petit truc en C++, voilà les sources :
            http://fichiers.asibasth.com/temp/ArtTools.rar

            Regarde les méthodes RegisterCallback et MainLoop, et l'utilisation dans le main, ça devrait t'être utile.
            • Partager sur Facebook
            • Partager sur Twitter
              30 juillet 2007 à 20:18:30

              Au pire tu peux toujours te créer carrément un type "fonction" :

              typedef int (*FUNC)();


              Ici tu définis un type pointeur sur fonction nommé FUNC qui prend des paramètres indéfinis...

              Et tu peux définir des variables comme ceci :

              FUNC execution;
              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                30 juillet 2007 à 20:45:12

                Bonjour.

                Donc j'ai lu une partie du tuto de développez et j'ai réussis à faire quelque chose qui marche.

                Pour ceux que ça intéresse :
                /// ActionMenuSDL::
                /** contenu du .h :
                class ActionMenuSDL
                {
                    public:
                        ActionMenuSDL(SDL_Rect rect, SDL_Surface *surf,
                                                                       void (*fctToCall)(void));
                        ActionMenuSDL(int x, int y, int w, int h,
                                                    SDL_Surface *surf, void (*fctToCall)(void));
                        ~ActionMenuSDL(void);

                        void main(int mouseX, int mouseY);

                    private:
                        SDL_Rect c_rect;
                        void (*c_fctToCall)(void);
                        SDL_Surface *c_surf;

                }; // fin class ActionMenuSDL
                **/


                #include <iostream>
                #include <SDL.h>
                #include "MenuSDL.h"
                using namespace std;

                ActionMenuSDL::ActionMenuSDL(SDL_Rect rect, SDL_Surface *surf,
                                                void (*fctToCall)(void)) : c_rect(rect),
                                                         c_fctToCall(fctToCall), c_surf(surf) {}

                ActionMenuSDL::ActionMenuSDL(int x, int y, int w, int h, SDL_Surface *surf,
                                 void (*fctToCall)(void)) : c_fctToCall(fctToCall), c_surf(surf)
                {
                    c_rect.x = x;
                    c_rect.y = y;
                    c_rect.w = w;
                    c_rect.h = h;
                }

                ActionMenuSDL::~ActionMenuSDL(void)
                {
                    SDL_FreeSurface(c_surf);
                }

                void ActionMenuSDL::main(int mouseX, int mouseY)
                {
                    if (mouseX > c_rect.x && mouseX < (c_rect.x + c_rect.w) &&
                                            mouseY > c_rect.y && mouseY < (c_rect.y + c_rect.h))
                        (*c_fctToCall)();
                }
                 


                Par contre je ne comprends pas comment faire avec ta technique, psychoh13. Peux-tu me donner un exemple (par ex. dans le même style que ce que j'ai fait). Merci :)

                Hiura

                ps : @Asibasth : je me sens un peux pommé dans ton truque. Je ne l'ai pas encore lu, mais je vais le faire :) Merci.
                • Partager sur Facebook
                • Partager sur Twitter
                  30 juillet 2007 à 22:35:27

                  1- A priori non, mais je ne le ferai pas.

                  2- oui, oui.
                  cf p.ex. boost::function, boost::bind
                  • 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.
                    31 juillet 2007 à 0:19:54

                    Alors euh... Pour mon exemple, personnellement je suis plutôt côté C, mais je vois pas pourquoi cette technique ne marcherait pas sous C++ :

                    Le typedef que je t'ai donné n'est pas trop trop conseillé, en ce sens qu'il ne définit aucun paramètre et donc que tu peux mettre autant de paramètres que tu veux ainsi tu peux ne pas savoir comment exécuter la fonction donnée = prise de risques.

                    Donc il vaut mieux, dans le typedef définir les types pour pouvoir limiter les erreurs.

                    Imaginons que les fonctions que ta méthode doit appeler soit des fonctions qui prennent deux entiers et qui en retourne un, tu définis ton type comme ça:

                    typedef int (*FUNC)(int, int);


                    Dans ta classe tu définis un attribut :

                    class Executor {
                        private :
                            FUNC target;
                        public :
                            Executor();
                            void setTarget(FUNC uneFonction);
                            void executeTarget();
                    };


                    Voilà comment tu vas utiliser ta petite classe :

                    Executor myExecutor;

                    FUNC uneFonction = maFonction; // maFonction étant définie autre part

                    myExecutor.setTarget(uneFonction);

                    myExecutor.execute();


                    NB : tu n'es pas obligé de passer par la deuxième ligne, tu peux directement mettre le nom de la fonction dans setTarget(), du moment que cette fonction prend en paramètre 2 int.

                    Pour l'implémentation de ta classe ça donne à peu prêt ceci :

                    Executor::Executor() {}
                    void Executor::setTarget(FUNC uneFonction)
                    {
                        target = uneFonction;
                    }

                    void Executor::executeTarget()
                    {
                        cout << "Une valeur = " << target(5, 10) << endl;
                    }


                    Tout simplement.

                    En fait, cette instruction :

                    typedef int (*FUNC)(int, int);


                    Permet d'économiser l'écriture de ce que les autres t'ont indiqué, au lieu d'écrire :

                    private:
                        int (*maFonction)(int v1, int v2);


                    tu vas écrire :

                    private:
                        FUNC maFonction;


                    Au lieu d'écrire :

                    public:
                        setTarget(int (*uneFonction)(int, int));


                    Tu vas écrire :

                    public:
                        setTarget(FUNC uneFonction);


                    Mais dans les deux cas d'écriture présenté au-dessus, pour exécuter ta cible, tu devras simplement faire ça :

                    maFonction(5, 10);


                    Je vais faire des tests plus approfondis pour voir tout ce qu'il est possible de faire avec des type pointeurs sur fonction en C++.
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      31 juillet 2007 à 0:46:55

                      Merci beaucoup pour ces infos, mais si j'utilise "typedef int (*FUNC)()", comment suis-je sensé faire passer les paramètres?

                      Merci !-)

                      Hiura
                      • Partager sur Facebook
                      • Partager sur Twitter
                        31 juillet 2007 à 1:32:50

                        En fait, le C++ se demandera si tu te fous pas un peu de sa gueule si tu mets () vide, mais, en revanche, voici le resultat d'un petit travail de tests :

                        Définissons notre type spécial de cette manière (définition se trouvant de Executor.h):

                        typedef int (*FUNC)(...);


                        Considérons la classe Executor, définie ainsi :

                        Executor.h :

                        typedef int (*FUNC)(...);

                        class Executor {
                        private:
                            FUNC theExecuted;
                        public:
                            Executor(FUNC toExecute = NULL);
                            void setExecuted(FUNC toExecute);
                            FUNC getExecuted(void);
                            void executeWithValue(int v1, int v2);
                            void executeOtherValues(int v1, float v2, char v3);
                        };


                        Définissons maintenant les méthodes :

                        Executor.cpp :

                        #include "Executor.h"

                        using namespace std;

                        Executor::Executor(FUNC toExecute) : theExecuted(toExecute)
                        { }

                        void Executor::setExecuted(FUNC toExecute)
                        {
                            theExecuted = toExecute;
                        }

                        FUNC Executor::getExecuted(void)
                        {
                            return theExecuted;
                        }

                        void Executor::executeWithValue(int v1, int v2)
                        {
                            if(theExecuted != NULL) // Si le pointeur est NULL, il y a un plantage, il faut donc vérifier que ce n'est pas le cas
                                cout << "Valeur = " << theExecuted(v1, v2) << endl;
                        }

                        void Executor::executeOtherValues(int v1, float v2, char v3)
                        {
                            if(theExecuted != NULL)
                                cout << "Resultat = " << theExecuted(v1, v2, v3) << endl;
                        }


                        Dans la première execute, nous exécutons donc une méthode contenant 2 arguments, dans l'autre une qui utilise 3 arguments.

                        Considérons pour finir le main suivant :

                        main.cpp :

                        #include <iostream>
                        #include "Executor.h"

                        using namespace std;

                        int uneFonction(int v1, int v2)
                        {
                            return v1 * v2;
                        }

                        int uneAutreFonction(int v1, float v2, char v3)
                        {
                            return v1 + v2 * v3;
                        }

                        int main (int argc, char * const argv[]) {
                           
                            Executor monExec;

                            // On définit la cible comme étant la méthode prenant 2 int
                            monExec.setExecuted((FUNC)uneFonction);
                            // On exécute le bon exécuteur
                            monExec.executeWithValue(5, 10);
                            // On exécute le mauvais exécuteur
                            monExec.executeOtherValues(5, 5.5, 'a');

                            // On définit la cible comme étant la méthode prenant 1 int, 1 float et 1 char
                            monExec.setExecuted((FUNC)uneAutreFonction);
                            // On exécute le bon exécuteur
                            monExec.executeOtherValues(5, 5.5, 'a');
                            // On exécute le mauvais exécuteur
                            monExec.executeWithValue(5, 10);
                           
                            return 0;
                        }


                        Nous obtenons donc le résultat suivant :

                        Valeur = 50
                        Resultat = 0
                        Resultat = 5
                        Valeur = 5


                        Nous pouvons déjà voir ici que lorsque une fonction est exécutée avec les bons paramètres, le résultat obtenu équivaut le résultat attendu. Et lorsque les paramètres sont mauvais, les valeurs sont en général à zéro (à vérifier selon le compilateur et la machine, je suis sous GCC distribution Apple/Darwin).

                        Donc si l'utilisateur sait ce qu'il fait il aura le résultat voulu.

                        Il faut noter que si l'on choisit de ne pas définir le type de retour d'une fonction FUNC, par exemple on peut écrire "void *" au lieu de "int", ce système marchera pour toutes les valeurs de type entier et pointeur, mais ne marchera pas pour les valeurs à virgule flottante, il faudra donc éventuellement créé des types spécifiques pour chaque valeur. Il est cependant possible à mon avis, d'utiliser un type Union contenant chaque type retournable, par exemple :

                        union Retournable {
                            char car;
                            int entier;
                            float flottant;
                            double doubleFlottant;
                        };


                        Et créer une structure permettant de connaître la valeur retourné ainsi que la fonction :

                        typedef Retournable (*FUNC)(...);

                        struct Caller {
                            FUNC calling;
                            char theReturn;
                        };


                        On donne le type en un caractère (par exemple i = int, d = double, f = float, c = char, etc.), on donne la fonction comme d'habitude, et l'appeleur vérifiera le type retourné via theReturn, et choisira le bon type à afficher par exemple :

                        executant(Caller function)
                        {
                            Retournable ret = function.calling(valeur);
                            switch(function.theReturn)
                            {
                                case 'i' :
                                    cout << "Un entier = " << ret.entier << endl;
                                    break;
                                case 'c' :
                                    cout << "Un char = " << ret.car << endl;
                                    break;
                                case 'd' :
                                    cout << "Un double = " << ret.doubleFlottant << endl;
                                    break;
                                case 'f' :
                                    cout << "Un float = " << ret.flottant << endl;
                                default :
                                    cerr << "Undefined type" << endl;
                                    break;
                            }
                        }


                        Voilà à peu près comment ça peut se passer.

                        DISCLAIMER : Ceci est un code non testé !
                        • Partager sur Facebook
                        • Partager sur Twitter
                        Anonyme
                          31 juillet 2007 à 9:00:10

                          :waw: Trop merci!!

                          C'est un vrai tuto ce que tu as fait là!! ;)

                          Merci à tous je peux mettre en résolu.

                          PS: dans ton switch tu as oublié les break; mais peux importe j'ai compris le système :) .
                          • Partager sur Facebook
                          • Partager sur Twitter
                            31 juillet 2007 à 10:58:31

                            break corrigés :D

                            De rien pour le tuto :D
                            • Partager sur Facebook
                            • Partager sur Twitter

                            Passer une fonction à une autre

                            × 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