Partage
  • Partager sur Facebook
  • Partager sur Twitter

Tableau de pointeurs de fonctions en fonctions

    12 avril 2018 à 22:44:45

    Bonjour,

    Je souhaite connaître s'il est possible de transmettre un tableau de pointeur de fonction en fonction. En effet, je crée dans mon "main" mon tableau de pointeur d'une ClasseMere que je remplis avec des ClasseFille via du polymorphisme.

    Je transmets mon tableau de pointeur à une fonction via ses arguments et je souhaite le propager à une deuxième fonction, mais pas en passant par le pointeur donné en argument. Je souhaite transmettre le pointeur à un autre pointeur pour envoyer celui-ci à une deuxième méthode.

    Et en faisant cela j'aimerais garder les actions comme ci c'était le tableau de pointeur initial.

    #include <iostream>
    #include "ClasseFille.h"
    #include "ClasseMere.h"
    using namespace std;
    
    void test(ClasseMere *pTabEnvoyeTest[]);
    void test1(ClasseMere *pTabEnvoyeTest1[]);
    
    void test(ClasseMere *pTabEnvoyeTest[])
    {
        ClasseMere *pointeur[2];
        pointeur = pTabEnvoyeTest;
        pointeur[0]->calcul();
        test1(pointeur);
    }
    
    void test1(ClasseMere *pTabEnvoyeTest1[])
    {
        ClasseMere *pointeur[2];
        pointeur = pTabEnvoyeTest1;
        pointeur[0]->calcul();
    }
    
    int main()
    {
        cout << "Hello World!" << endl;
    
        ClasseMere *tabFille[2] = {new ClasseFille(1), new ClasseFille(2)};
    
        test(tabFille);
    
        delete tabFille[0];
        tabFille[0] = 0;
    
        delete tabFille[1];
        tabFille[1] = 0;
    
        return 0;
    }
    

    Malheureusement cela ne compile pas... J'ai les messages d'erreur suivant :

    main.cpp:12: erreur : incompatible types in assignment of 'ClasseMere**' to 'ClasseMere* [2]' pointeur = pTabEnvoyeTest;

    main.cpp:20: erreur : incompatible types in assignment of 'ClasseMere**' to 'ClasseMere* [2]' pointeur = pTabEnvoyeTest1;

    Du coup j'ai essayé plusieurs combinaisons sans succès. Auriez vous une idée pour que je puisse directement manipuler les données du tableau de pointeur initial directement comme je l'ai mis dans mon code dans la fonction test1 avec pointeur[0]->calcul(); ?

    Merci d'avance du coup de pouce =)

    -
    Edité par CharlyLeroy 12 avril 2018 à 22:46:46

    • Partager sur Facebook
    • Partager sur Twitter
      13 avril 2018 à 2:01:53

      Bonsoir à vous, si je viens à vous c'est parce que j'ai beau cherché mais sans solution je veux faire jouer du son sur ma console mais je n'y arrive pas 
      comme vous pouvez le constater je code en C++
      voilà le code que j'ai sous la main en ce moment
      #include<Windows.h>
      #include<mmsystem.h>
      #include<stdio.h>
      #include<stdlib.h>
      #include<iostream>
      //#pragma comment( lib, "winmm.lib" ) 
      using namespace std;
      int main() {
      while (true) {
      PlaySound(TEXT("C:\\song\\DV009.WAV"), NULL, SND_ASYNC | SND_FILENAME);
      }
      • Partager sur Facebook
      • Partager sur Twitter
        13 avril 2018 à 7:18:03

        @Yaiko, tout est expliqué ici

        @PO Très bonne question d'ads00, en plus du fait u'il ne compile pas, c'est super moche et ça ne ferait de toute façon probablement pas ce que tu veux. Regarde ce petit programme:

        #include<vector>
        #include<memory>
        #include<iostream>
        #include<functional>
        
        
        // Un alias pour simplifier l'écriture
        template<class T>
        using Collection = std::vector<std::unique_ptr<T>>;
        
        // La fonction magique...
        template<class T, class F, class ... Args>
        void apply(Collection<T> & collection, F f, Args && ... args)
        {
            for (auto & p : collection) {
                f(*p, std::forward<Args>(args)...);
            }
        }
        
        // Une petite hiérarchie de classes pour illustrer
        class Base
        {
        public:
        
            Base() = default;
            virtual ~Base() = default;
            Base(Base const &) = delete;
            Base & operator = (Base const &) = delete;
        
            virtual void foo(int) = 0;
        };
        
        
        class Derived1 : public Base
        {
            int m_;
        
        public:
        
            Derived1(int k):m_{k}{}
            virtual ~Derived1() = default;
            void foo(int v) override {
                std::cout << "call Derived1::foo for instance "
                    << m_ << " with arg " << v << '\n';
            }
        };
        
        
        class Derived2 : public Base
        {
            int m_;
        
        public:
        
            Derived2(int k) :m_{ k } {}
            virtual ~Derived2() = default;
            void foo(int v) override {
                std::cout << "call Derived2::foo for instance "
                    << m_ << " with arg " << v << '\n';
            }
        };
        
        // Un nouvel alias pour simplifier encore plus l'écriture
        using TestColl = Collection<Base>;
        
        // une fontion pour tester ma fonction magique
        void callFoo(Base & b, int i) { b.foo(i); }
        
        int main()
        {
            // je crée mon tableau
            TestColl test{ };
        
            // je le remplis
            test.push_back(std::make_unique<Derived1>(1));
            test.push_back(std::make_unique<Derived2>(2));
        
            // appel de ma fonction magique en utilisant callFoo
            apply(test, &callFoo, 12);
            std::cout << '\n';
        
            /* Encore plus fort, je demande que la fonction magique appelle directement 
               la fonction membre foo */
            apply(test, std::mem_fn(&Base::foo), 25);
            return 0;
        }
        

        Ma "fonction magique" n'est pas vraiment une fonction, c'est un modèle que le compilateur va pouvoir utiliser pour générer à la compilation, les fonctions dont il aura besoin pour compiler mon programme. Ce modèle explique au compilateur comment générer une fonction qui exécute une fonction sur chaque élément de la collection en utilisant les paramètres args. Comme c'est un modèle, je veux qu'il puisse être utilisé pour un nombre arbitraire de paramètres, de n'importe quel type.

        -
        Edité par int21h 13 avril 2018 à 8:04:36

        • Partager sur Facebook
        • Partager sur Twitter
        Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
          13 avril 2018 à 17:09:06

          Bonjour,

          Les erreurs de compilation sont dues au fait qu'on ne peut pas appliquer l'opérateur d'affectation à un tableau.
          Sur la ligne pointeur = pTabEnvoyeTest;, pointeur est ici un tableau de 2 pointeurs, alors que pTabEnvoyeTest est lui un pointeur sur des pointeurs!

          Une correction simple consiste à se passer du tableau, le paramètre est utilisable directement

          void test( ClasseMere *pTabEnvoyeTest[] )
          {
              pTabEnvoyeTest[0]->calcul(); // Le pointeur reçu est utilisable comme un tableau
              test1( pTabEnvoyeTest );
          }

          Je pense que ton code te semble plus 'simple' que les solutions qui t'ont été fournies. Pourtant ton code qui utilise des 'vieux' objets issus du langage C très difficiles à utiliser en C++ (les tableaux 'bruts' sont des variables qui sont trompeuses, on n'utilise plus new et delete depuis des années, utilisation de pointeurs quand on peut s'en passer, using namespace std; est aussi un piège.) est complexe.
          Les codes fournis sont eux difficiles à lire pour un débutant, mais sont pourtant plus sûrs.

          • Partager sur Facebook
          • Partager sur Twitter

          En recherche d'emploi.

            13 avril 2018 à 21:40:27

            *+

            .

            Les codes fournis sont difficiles? je n'en suis pas si sûr, bon pour celui là, j'avoue, je me suis lâché, et je me suis fait plaisir, après tout, ce n'est pas tous les jours que j'ai l'occasion de jouer un peu avec des variadic template, et les occasions de pouvoir montrer ces choses là ne sont pas si nombreuses.  Je ne suis pas prof, je n'ai pas de contrainte de progression de mes lecteurs. Ma seule contrainte est selon moi, éthique: je me dois de ne montrer que du code qui soit le plus propre et le plus sûr possible. 

            -
            Edité par int21h 14 avril 2018 à 3:10:07

            • Partager sur Facebook
            • Partager sur Twitter
            Mettre à jour le MinGW Gcc sur Code::Blocks. Du code qui n'existe pas ne contient pas de bug
            Anonyme
              14 avril 2018 à 8:20:04

              @int21h

              Je suis loin d'être un spécialiste du C++, mais quelque chose m'interpelle dans ton code, on m'a toujours dit que unique_ptr n'est pas copiable (dis moi si je me trompe) et si dans le cas où je ne me trompe pas, push_back crée une copie sur l'objet. N'est-il pas plus adapté, d'utiliser une méthode plus spécifique des vector évitant cela comme emplace_back ?

              • Partager sur Facebook
              • Partager sur Twitter
                14 avril 2018 à 10:09:12

                oldProgrammer a écrit: on m'a toujours dit que unique_ptr n'est pas copiable (dis moi si je me trompe) et si dans le cas où je ne me trompe pas, push_back crée une copie sur l'objet. N'est-il pas plus adapté, d'utiliser une méthode plus spécifique des vector évitant cela comme emplace_back ?


                Si j'ai bien compris, le besoin est simplement de constituer un "tableau" (au sens large : array, vector, whatever) d'objets de différents types, de le passer à une fonction test qui fait un traitement sur un des éléments, et repasse le tableau à une autre fonction test1 qui est censé traiter aussi un élément.

                Le titre montre que L'OP s'est enfumé tout seul avec des histoires de pointeurs de fonctions, dont on ne voit pas la couleur.  On en retient qu'il est en train de s'embrouiller entre les notions de tableau, de pointeurs et de fonctions : en fait il passe un tableau de pointeurs comme paramètre à une fonction, c'est tout.  Donc  si on veut lui être utile, on va garder l'explication à ce niveau, pour commencer.

                Le bug, c'est essentiellement qu'on ne peut pas affecter un tableau (natif, le truc qui se déclare  MonType t[12]) dans un autre. C'est pour ça que ça tousse sur l'instruction

                   pointeur = pTabEnvoyeTest;

                et sa copine

                La réparation la plus directe est de remplacer le tableau par un std::array, ou un std::vector

                Au passage, on change les noms, parce qu'ils sont merdiques au possible.  Si c'est un tableau, on donne un nom qui dit ce qu'il représente, ou alors si ça n'a pas de signification, ou de rôle bien défini, on l'appelle tableau.

                #include <iostream>
                #include <vector>
                
                using namespace std;
                
                class ClasseMere {
                protected:
                  int m_n;
                public:
                  ClasseMere(int n) : m_n{n} {}
                  virtual void calcul() const { std::cout << "M" << m_n << std::endl; }
                  virtual ~ClasseMere() = default;
                };
                
                class ClasseFille : public ClasseMere {
                public:
                  ClasseFille(int n) : ClasseMere{n} {}
                  virtual void calcul() const override { std::cout << "F" << m_n << std::endl; }
                };
                
                // -------------------------------------------------------
                 
                 void test (const std::vector<ClasseMere *> & tableau);
                 void test1(const std::vector<ClasseMere *> & tableau);
                 
                void test (const std::vector<ClasseMere *> & tableau)
                {
                    auto copie = tableau;;                 // appel copy constructor
                    copie[0]->calcul();
                    test1(copie);
                }
                 
                void test1 (const std::vector<ClasseMere *> & tableau)
                {
                    auto copie =  tableau;             // appel constr de copie.
                    copie[1]->calcul();
                }
                 
                int main()
                {
                    std::vector<ClasseMere *> tableau {new ClasseFille(1), new ClasseFille(2)};
                 
                    test(tableau);
                 
                    delete tableau[0];
                    tableau[0] = nullptr;
                 
                    delete tableau[1];
                    tableau[1] = nullptr;
                 
                    return 0;
                }
                

                Ensuite il se pose la question des pointeurs intelligents.  Pour utiliser les pointeurs intelligents, il faut être intelligent aussi, parce qu'il faut choisir le type de pointeur intelligent en fonction du besoin.

                Ici c'est un exemple bidon, donc on n'a pas de notion de besoin.  Pourquoi est-ce qu'on crée une copie des tableaux, pourquoi dans test on ne le passe pas directement à test1 ?

                void test (const std::vector<ClasseMere *> & tableau)
                {
                    tableau[0]->calcul();
                    test1(tableau);
                }

                Ca serait beaucoup plus simple.  Parce que si on fait une copie du tableau, on doit se demander ce qu'on veut en faire

                • est-ce une copie superficielle ? un second tableau contenant les mêmes pointeurs vers les mêmes objets ? Dans ce cas ça exclut les unique_ptr, parce que c'est une notion de co-propriété.
                • est-ce un tableau contenant des copies des objets contenus dans le premier ? Là il va falloir prévoir un "clonage" des éléments.
                • est-ce qu'on veut transferer la propriété des élements d'un tableau à l'autre ?

                Si on n'a pas une réponse claire à cette question, c'est qu'on ne sait pas ce qu'on veut faire, et il est imprudent de recommander un type de pointeur intelligent en particulier.

                -
                Edité par michelbillaud 14 avril 2018 à 10:16:02

                • Partager sur Facebook
                • Partager sur Twitter
                  15 avril 2018 à 23:55:16

                  oldProgrammer a écrit: > on m'a toujours dit que unique_ptr n'est pas copiable (dis moi si je me trompe) et si dans le cas où je ne me trompe pas, push_back crée une copie sur l'objet.

                  Unique_ptr n'est effectivement pas copiable, mais cela n'empêche pas d'utiliser push_back qui possède une version prenant une rvalue et qui appel le constructeur de déplacement.

                  > N'est-il pas plus adapté, d'utiliser une méthode plus spécifique des vector évitant cela comme emplace_back ?

                  Emplace_back permet au vecteur de construire lui-même l'unique_ptr en lui donnant les paramètres du constructeur. Le problème, c'est que le constructeur d’unique_ptr prend un pointeur et l'extérieur devra faire le new. Sauf que si le vecteur n'arrive pas à construire l’unique_ptr et lance une exception, il y aura une fuite mémoire. Du coup, il vaut mieux utiliser make_unique et au final il n'y a pas de différence entre push_back et emplace_back ici (les 2 vont utiliser le constructeur de déplacement).

                  En règle général je préfère quand même emplace_back.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    16 avril 2018 à 10:38:42

                    La on est visiblement dans le cas où on veut représenter une collection d'objets de différents types, par polymorphisme, et donc se traduit par un vecteur/array/tableau de pointeurs, intelligents ou pas.

                    Admettons que que soit un vector d' unique_ptr, parce qu'on voudrait un tableau qui soit l'unique propriétaire des instances. Est-ce que un emplace_back (qui sert à créer une instance) n'est pas un canon pour tuer une mouche, et pointé dans la mauvaise direction ?

                    Il me semble qu'il s'agit plutôt d'utiliser make_unique (C++14) pour obtenir un unique_ptr vers une nouvelle instance.

                        std::vector<std::unique_ptr<A> > v;
                    
                        v.push_back( std::make_unique<A>(100));  // C++14
                        v.push_back( std::make_unique<B>(200));
                    
                        for (auto &ptr : v) {
                          ptr -> print();
                        }
                    


                    testé avec

                    class A {
                    protected:
                      int m_n;
                    public:
                      A(int n)
                         : m_n{n}
                      {}
                      virtual ~A() = default;
                      virtual void print() const {
                        std::cout << "A(" << m_n << ")" << std::endl;
                      }
                    };
                    
                    class B : public A {
                    public:
                      B(int n) : A{n} {}
                      void print() const override {
                            std::cout << "B(" << m_n << ")" << std::endl;
                      }
                    };
                    

                    résultat

                    A(100)
                    B(200)
                    




                    -
                    Edité par michelbillaud 16 avril 2018 à 10:39:56

                    • Partager sur Facebook
                    • Partager sur Twitter
                      20 avril 2018 à 14:13:59

                      Merci pour vos réponses qui sont nombreuses !

                      Je vous avoue que je ne suis pas un monstre en c++ et que les unique_ptr je ne maitrise pas du tout. Je n'ai pas encore travaillé ce point.

                      Cependant la solution à mon problème me semble apporté par @michelbillaud le 14/04/2018.

                      Je souhaitais faire passer de fonction en fonction mon tableau qui contenait des ClasseFille aux comportements différents car le but était, sous un développement Qt, d'utiliser des Signaux et Slot pour passer mon tableau de type ClasseMere en paramètre à de nouveaux objets créés à l'appel de SLOT pour qu'ils puissent utiliser les ClasseFille.

                      Une fois mon tableau ClasseMere passé en argument, je ne voulais pas le dupliquer en créant une autre variable ClasseMere, mais utiliser un pointeur du même type pour faire juste une copie par référence.

                      Cependant je ne connais pas encore les type "auto" comme type de variable, donc je ne sais pas trop le comportement que ça implique dans les fonctions test et test1 données en exemple.

                      Mais de ce que tu as donné en solution j'ai l'impression que je suis contraint de faire du constructeur de copie pour passer mon tableau de fonction en fonction.

                      Or je pense que ce dont j'ai besoin, c'est ce que tu as mentionné : un second tableau contenant les mêmes pointeurs vers les mêmes objets

                      Dans le meilleur des cas ça serait de passer en référence le tableau qui contient les pointeurs vers les objets. en conservant le comportement des fonctions test et test1 qui est :

                      void test (const std::vector<ClasseMere *> & tableau)
                      {
                          auto copie = tableau;;                 // pointeur sur le tableau de pointeur "tableau" et non plus appel copy constructor
                          copie[0]->calcul();
                          test1(copie);
                      }
                        
                      void test1 (const std::vector<ClasseMere *> & tableau)
                      {
                          auto copie =  tableau;             // pointeur sur le tableau de pointeur "tableau" et non plus appel copy constructor
                          copie[1]->calcul();
                      }



                      -
                      Edité par CharlyLeroy 20 avril 2018 à 14:18:28

                      • Partager sur Facebook
                      • Partager sur Twitter
                        20 avril 2018 à 14:31:50

                        CharlyLeroy a écrit:


                        Une fois mon tableau ClasseMere passé en argument, je ne voulais pas le dupliquer en créant une autre variable ClasseMere, mais utiliser un pointeur du même type pour faire juste une copie par référence.

                        Cependant je ne connais pas encore les type "auto" comme type de variable, donc je ne sais pas trop le comportement que ça implique dans les fonctions test et test1 données en exemple.

                        Mais de ce que tu as donné en solution j'ai l'impression que je suis contraint de faire du constructeur de copie pour passer mon tableau de fonction en fonction.

                        Or je pense que ce dont j'ai besoin, c'est ce que tu as mentionné : un second tableau contenant les mêmes pointeurs vers les mêmes objets

                        Dans le meilleur des cas ça serait de passer en référence le tableau qui contient les pointeurs vers les objets. en conservant le comportement des fonctions test et test1 qui est :

                        Faut savoir ce que tu veux :

                        • soit tu passes le même tableau
                        • soit tu passes une copie qui a le même contenu. Et dans ce cas la copie, il faut la faire.

                        Le type auto n'a rien de bien excitant : "auto copie = tableau", ça veut dire que copie est déclarée avec le même type que tableau. C'est une façon plus simple d'écrire "std::vector<ClasseMere *> copie = tableau;".  C'est plutot reposant, surtout si on change d'idée sur le type du tableau reçu en paramètre.

                        PS: ce qu'on donne c'est des indications techniques, pas des solutions à un problème. Tu n'as pas exposé de problème : on ne voit pas l'intérêt de transmettre un tableau, dans ton exemple où il suffirait de transmettre tabFille[0].

                        • Partager sur Facebook
                        • Partager sur Twitter

                        Tableau de pointeurs de fonctions en fonctions

                        × 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