Partage
  • Partager sur Facebook
  • Partager sur Twitter

Accéder à un objet dans une classe

    18 mars 2019 à 20:20:08

    Bonjour,

    Je débute en c++ et je ne comprends pas une chose.

    Voici mon problème:

    j'essaie de rajouter des classes dans la bibliotheque servo sur Arduino pour piloter un projet: un quadrupède.

    J'ai 2 classes: une qui correspond au quadrupède (Spider) et l'autre à une des 4 pattes (Membre).

    class Membre
    {
    	private:
    		Servo hanche;
    		Servo cuisse;
    		Servo mollet;
    		
    		
    	public:
    	
    		Membre();
    		void attach(int pinHanche, int pinCuisse, int pinMollet);
    
    }; 
    
    
    class Spider 
    {
    	public:
    		Spider();
    		 Membre PatteAvG; 
    		void attach(int pinHanche, int pinCuisse, int pinMollet);
    				
    		
    	private:	
    
    	
    };



    2 fonctions permettant d'affecter des pins à un membre.

    void Spider::attach(int pinHanche, int pinCuisse, int pinMollet)
    {
    	this->attach(pinHanche, pinCuisse, pinMollet);
    
    }
    
    
    void Membre::attach(int pinHanche, int pinCuisse, int pinMollet)
    {
    	hanche.attach(pinHanche);
    	cuisse.attach(pinCuisse);
    	mollet.attach(pinMollet);
    	
    }

    Et le main:
    void main()
    {
        Spider araignee;
    
        araignee.PatteAvG.attach(5, 6, 7);
    
    }
    

    Tout fonctionne mais mon objet PatteAvG est public. Il faut que les attributs soit private et donc je ne peux plus y accéder dans le main. Je ne comprends pas comment contourner le problème.



    -
    Edité par cced 18 mars 2019 à 20:47:29

    • Partager sur Facebook
    • Partager sur Twitter
      18 mars 2019 à 22:47:36

      Lorsque tu instantie une classe, l'objet obtenu doit être utilisable immédiatement, sans avoir besoin de faire de manips supplémentaire.
      En d'autre termes, la seule fonction en charge d'initialiser l'objet est le constructeur et personne d'autre.

      Pour ton problème, fournit un ou des constructeurs avec paramètres, et le tour sera joué.

      • Partager sur Facebook
      • Partager sur Twitter
        19 mars 2019 à 13:59:43

        Bonjour Deedolith,

        Merci pour ton aide.

        En suivant ton conseil voila où j'en suis. J'ai passé mon objet patteAvG en private. Ensuite j'ai réalisé les 2 constructeurs avec une liste d'initialisation.

        Spider::Spider(Servo hanche, Servo cuisse, Servo mollet) : PatteAvG(hanche, cuisse, mollet)
        {	
        }
        
        Membre::Membre(Servo sHanche, Servo sCuisse, Servo sMollet) : hanche(sHanche), cuisse(sCuisse), mollet(sMollet)
        {
        }
        
        

        Maintenant que j'ai fait ça, je ne vois pas comment je fais dans le main pour affecter les pins avec ma fonction attach().

        • Partager sur Facebook
        • Partager sur Twitter
          19 mars 2019 à 14:08:15

          Deedolith a écrit:


          En d'autre termes, la seule fonction en charge d'initialiser l'objet est le constructeur et personne d'autre.


          Comme Deedolith te l'a fait savoir, la seule fonction en charge d'initialiser l'objet est le constructeur. "Attach" est une méthode qui initialise l'objet, elle doit donc être appelée dans le constructeur de l'objet.
          • Partager sur Facebook
          • Partager sur Twitter
          Didy7 -
            19 mars 2019 à 14:28:03

            Bonjour,

            comme il a été dit avant, ta fonction attach joue le rôle d'accesseur et effectivement, ça doit se passer dans le constructeur.

            Tu peux aussi essayer de  faire un héritage (privé ou public, à voir) de ta nouvelle classe comme héritant de servo, afin de redéfinir ta fonction attach. Ce serait intéressant de voir si ça marche

            -
            Edité par YES, man 19 mars 2019 à 14:30:09

            • Partager sur Facebook
            • Partager sur Twitter
              19 mars 2019 à 15:32:46

              Bonjour Didy7 et YES, man,

              Merci aussi pour votre aide.

              Je rame complétement.

              C'est dans mon constructeur spider que je dois appeler la fonction attach() de ma classe spider? Si c'est le cas, comment je fais pour obtenir les int correspondant au 3 pins déclarées dans le main. Aurais-je mal définie mon constructeur car lui attend des Servo?

              YES, man,

              Tu veux dire faire hériter ma classe Membre de la classe servo? Et ensuite modifier ma fonction attach() qui se trouve dans ma classe Membre. J'ai une fonction attach() dans chaque classe!

              • Partager sur Facebook
              • Partager sur Twitter
                19 mars 2019 à 15:33:08

                @cced, ta Spider doit avoir 8 membres, passe les en paramètre du constructeur de Spider.

                Heu "quadrupède" une Spider ??? Ça fait part du taxon des arachnides, donc 4 paires de pattes, pas 2.

                Si fournir les membres lors de la construction d'une Spider n'a pas d'intérêt, parce que c'est toujours les mêmes, quelques soit l'instance de Spider, pas besoin de les passer en paramètre du constructeur, mais juste appeler le constructeur de Membre pour chacun des champs "Membre" de la Spider (8 champs pour une arachnide, et pas 4) dans la liste d'initialisation du constructeur de la classe Spider.

                @Yes, man, t'es sûr de ce que tu "avances" là ??? T'es pas en train d'envoyer le PO dans le décor ???

                P.S.:

                Exemple de code utilisateur (à toi d'avoir une implémentation qui répond à cette manière d'utiliser les classes) :

                void main()
                {
                    Membre patte1(5,6,7);
                    Membre patte2(8,9,10);
                    Membre patte3(11,12,13);
                    Membre patte4(14,15,16);
                
                    Spider araignee(patte1,patte2,patte3,patte4);
                 
                 
                }



                -
                Edité par bacelar 19 mars 2019 à 15:38:44

                • Partager sur Facebook
                • Partager sur Twitter
                Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                  19 mars 2019 à 15:45:31

                  @cced : pour l'héritage, je ne suis pas à 100% sûr . C'est une piste de réflexion simplement. à priori, c'est une redéfinition. J'ai essayé de voir pour un truc plus optimisé.

                  -
                  Edité par YES, man 19 mars 2019 à 15:47:59

                  • Partager sur Facebook
                  • Partager sur Twitter
                    19 mars 2019 à 15:50:20

                    Bonjour bacelar,

                    Merci de m'aider.

                    Pour l'instant, je ne commence qu'avec 4 pattes car l'atmega 328 avec la bibliothèque Servo ne gère que 12 servos.

                    Peut-être que je ferai évoluer plus tard si je m'intéresse au atmega 2560. j'ai choisi un nom de classe générique.

                    Si je comprend ce que tu veux me dire, j'ai mal défini mon constructeur spider.

                    Je dois faire comme ceci?

                    Spider(Membre patteAvg, Membre patteArG, Membre patteAvD, Membre patteArD);


                    @YES, man,

                    Une piste de réflexion intéressante. Quand je maitriserai mieux je creuserai.

                    Edit: bacelar,

                    Tu as édité ton message pendant que je rédigeais le mien. Je serai donc sur la bonne voie.

                    Ce que je remarque dans ton exemple, c'est qu'il me faudra instancier les 4 membres dans le main avant d'instancier spider. Donc dans le main, j'aurai accès aux méthodes de la classe membre sauf si je les mets private ou protected.

                    -
                    Edité par cced 19 mars 2019 à 16:04:25

                    • Partager sur Facebook
                    • Partager sur Twitter
                      19 mars 2019 à 16:59:26

                      @cced, j'ai créé les membres dans le main pour simplifier.

                      Cette approche permet au code client de l'araignée, ici la fonction "main", de choisir les pins des différents servomoteurs. Le code de la classe Spider n'aura donc pas à gérer lui-même cet aspect mapping pin-servomoteur.

                      Et si vous voulez gérer plusieurs Spider, le main peut gérer lui-même les affectations des pins.

                      Mais il est tout à fait envisageable de faire de votre classe Spider, un objet plus "intégré".

                      Code à l'arrache:

                      class Servo
                      {
                          public:
                              Servo(int);
                      }
                      
                      class Membre
                      {
                          private:
                              Servo hanche;
                              Servo cuisse;
                              Servo mollet;
                                  
                          public:
                           
                              Membre(cont std::array<int,3>& pins):hanche{pins[0]},cuisse{pins[1]},mollet{pins[2]}{}; 
                      };
                       
                       
                      class Spider
                      {
                          public:
                              Spider(cont std::array<int,3>& avG, cont std::array<int,3>& avD, cont std::array<int,3>& apG, cont std::array<int,3>& apD):PatteAvG{avG},PatteAvD{avD},PatteApG{apG},PatteApD{apD}{};
                      
                          private:   
                      
                          Membre PatteAvG;
                          Membre PatteAvD; 
                          Membre PatteApG; 
                          Membre PatteApD; 
                           
                      };
                      ...
                      
                      void main()
                      {
                         Spider araignee({5,6,7},{8,9,10},{11,12,13},{14,15,16});
                      }


                      > j'ai choisi un nom de classe générique.

                      C'est justement pas très générique d'avoir un nombre fixe de patte.

                      Si votre constructeur de Spider prend en paramètre un std::vector<Membre>, vous n'aurait pas à toucher à votre code pour gérer un nombre arbitraire de membres.

                      Pour la signature de votre constructeur, attention au passage par valeur et pas par référence. En faisant cela, vous faite une copie de l'objet passé en argument, lors de l'appel.

                      Cela sera problématique car le servo du main et la copie passée au constructeur de Spider auront leurs champs hanche, cuisse et mollet attachés aux mêmes pins.

                      Cela se règle en passant par référence les paramètres. Il y a de technique pour éviter ce type d'étourderie, rendre la classe membre non-copiable, mais on verra plus tard.

                      Spider(Membre& patteAvg, Membre& patteArG, Membre& patteAvD, Membre& patteArD);



                      Il faudrait savoir qui à l'ownership des "membres", une fois passés au constructeur du Spider. En clair, qui est en charge de "détruire" les membres. Soit c'est la fonction main, et il faut donc faire en sorte que l'araignée n'est pas le droit de les détruire (des champs "Membre" de types pointeurs et non objets "complets"), soit c'est devenu la propriété de l'araignée et il faut interdire à la fonction "main" de les utiliser après les avoirs "donnés" à l'araignée via le constructeur : utilisation du move-sémantique.

                      Avec la version plus "intégrée" de la classe Spider, elle est responsable de tout, donc moins de complexité, mais la probabilité que le constructeur de Spider parte en sucette est aussi largement augmentée.

                      >Je serai donc sur la bonne voie

                      Oui

                      > j'aurai accès aux méthodes de la classe membre sauf si je les mets private ou protected

                      ???

                      Il n'y a pas de "private ou protected" pour des variables locales.

                      Techniquement, comme c'est le main qui a construit les membres, il est à même d'interagir avec les membres de l'araignée sans passer par l'araignée, mais cela risque de poser des problèmes si le code de l'araignée n'a pas été conçu pour avoir des membres utilisable par un "marionnettiste" (le code du main qui peut interagir avec les membres sans passer par le "cerveau" de l'araignée).

                      Pour éviter cela, si le code de l'araignée n'est pas fait pour, elle peut demander, via la signature de son constructeur, à avoir le contrôle "total" des membres, en utilisant le move-sémantique : cf. le laïus sur l'ownership ci-avant.

                      La conception d'une classe demande à bien savoir ce qu'elle fournit comme service et comment le code client des objets de cette classe doivent s'en servir. Cela rend les choix entre les types de passage de paramètre et autres détails bien plus évidents.

                      • Partager sur Facebook
                      • Partager sur Twitter
                      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                        19 mars 2019 à 18:19:44

                        bacelar,

                        Merci pour ces explications complètes et techniques pour un débutant comme moi.

                        Ce que je souhaite, c'est rendre l'utilisation simple dans le main. C'est à dire appeler des méthodes de spider du type:

                        araignee.marche(//des paramètres)
                        
                        araignee.debout(//des paramètres) 

                        etc... mais aussi pouvoir contrôler un membre. Avec les attributs en public c'était facile:

                        araignee.patteAvG.bouge(//des paramètres)



                        Mais ce n'est pas orienté objet et je crois comprendre que ce n'est pas la bonne façon de faire.

                        Je vais étudier std::vector et move-sémantique afin de voir comment optimiser tout ça.

                        -
                        Edité par cced 19 mars 2019 à 18:29:51

                        • Partager sur Facebook
                        • Partager sur Twitter
                          19 mars 2019 à 19:03:28

                          Il "faut" juste prendre le pli.

                          Vos méthodes "marche" et "debout" sont de bons exemples de ce que l'on peut demander à une instance de Spider.

                          La classe va se démerder avec les champs "Membres" (et bien d'autres champs potentiels) pour faire ces actions, tout en conservant l'équilibre de "l'animal", et tout autre comportement que le classe implémente (économie d'énergie, contrainte mécanique, etc....).

                          Mais en créant la patteAvG dans le main, la fournir à l'araignée via un argument du constructeur de Spider, et continuer à l'utiliser en lousdé directement, sans passer par l'araignée, c'est possible (si on ne met pas en place une politique d'ownership stricte) mais vous pourrez par mégarde : foutre la patte dans l’œil de l'araignée, la déstabilisé et elle se casse la figure, casser sa jonction patte-corps etc...

                          En raffinant les services offerts par Spider, on peut faire aussi simple, mais de manière plus "safe".

                          Il suffit d'implémenter des fonctions/méthodes comme :

                          Spider::bougePatteAvG(parms ...)

                          Et l'araignée pourra accompagner ce mouvement avec les autres partie de son corps, voir refuser le mouvement si l'araignée ne peut pas l'effectuer (même si juste la patte le peut).

                          Après, vous pouvez raffiner "bouge" pour donner un numéro de patte à la place d'avoir une méthode par patte, donc gestion d'un nombre arbitraire de pattes.

                          Voir ne pas spécifier de patte et laisser l'araignée choisir quelles pattes est la plus à même de faire l'action.

                          etc....

                          etc....

                          • Partager sur Facebook
                          • Partager sur Twitter
                          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                            19 mars 2019 à 21:26:20

                            Merci pour ces  précisions, c'est exactement ce que je cherche à mettre en place.

                            En reprenant l'exemple donné, je souhaiterai par exemple une fonction:

                            Spider::bougePatte(int patteNum, int angleHanche, int angleCuisse, int angleMollet);

                            Dans cette fonction j'aurai positionné les autres pattes de façon à pouvoir bouger celle concernée suivant ses paramètres, de façon à ce que l'araignée reste équilibrée.

                            Dans la tête, j'ai les idées mais dans la pratique, implémenter tout ça ce n'est pas simple quand on débute.



                            -
                            Edité par cced 19 mars 2019 à 21:26:56

                            • Partager sur Facebook
                            • Partager sur Twitter
                              19 mars 2019 à 23:52:08

                              Ca viendra. ;)

                              Rome s'est pas faite en un jour.

                              Pour votre méthode "bougePatte", vous pouvez un peu "l'améliorer", si vous fixez le nombre de base d'une Spider, en utilisant un enum à la place d'un int pour le premier paramètre.

                              Vous pouvez aussi utiliser un type plus "pertinent" pour les 3 rotations, car dans l'espace 3D, c'est bien plus précis d'utiliser un vecteur 3D plus un scalaire pour spécifier une rotation.

                              Comme vos articulations doivent avoir des contraintes mécaniques (degré de liberté, etc...), piloter l'araignée via des angles n'est peut-être pas une solution "simple".

                              Demander à l'araignée de bouger de telle manière qu'une section d'une patte face un angle précis avec la section qui la précède serait plus "fonctionnel". Pensez aussi à l'IK (Inverse Kinetic) pour ne pas avoir à piloter l'araignée de l'extérieur mais qu'elle fasse ces actions avec le maximum de latitude.

                              Pensez à l'API public de votre classe comme un fournisseur de service, pas un moyen de micro-commander toutes les actions possible de l'araignée. Le code client de la classe Spider est plus un dresseur de l'araignée qu'un marionnettiste de celle-ci.

                              Une fois cette API publique définit, commencez à implémenter les fonctions internes utiles à l'araignée les plus simples, comme la détermination de son centre de masse, etc..., puis implémentez les fonctions plus complexes en utilisant les fonctions plus simples déjà implémentées avant. Etc... jusqu'à l'implémentation de l'API publique.

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                              Accéder à un objet dans une classe

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              • Editeur
                              • Markdown