Partage
  • Partager sur Facebook
  • Partager sur Twitter

Constructeurs d'une classe dans une autre

    26 avril 2022 à 18:39:41

    Bonjour, je suis entrain de coder un petit projet pour m'entraîner en C++. J'ai défini deux objets (Vector et Ball) avec les constructeurs, getters et setters.

    Vector.cpp

    #include <iostream>
    #include <math.h>
    
    #include "Vector.hpp"
    
    Vector::Vector()
    {
        x_ = 0;
        y_ = 0;
    }
    
    Vector::Vector(double _x, double _y)
    {
        x_ = _x;
        y_ = _y;
    }
    
    void Vector::setX(double _x)
    {
        x_ = _x;
    }
    
    void Vector::setY(double _y)
    {
        y_ = _y;
    }
    
    void Vector::setVector(Vector vect)
    {
        x_ = vect.getX();
        y_ = vect.getY();
    }
    
    void Vector::setVector(double _x, double _y)
    {
        x_ = _x;
        y_ = _y;
    }
    
    double Vector::norm()
    {
        return sqrt(pow(x_,2) + pow(y_,2));
    }
    
    std::ostream& operator<<(std::ostream &_flow, Vector _vect)
    {
        _flow << "(x = " << _vect.getX() << ", y = " << _vect.getY() << ")" << std::endl;
        return _flow;
    }

    Ball.cpp

    #include <iostream>
    
    #include "Vector.hpp"
    #include "Ball.hpp"
    
    Ball::Ball()
    {
        mass_   = 1;
        radius_ = 1;
        color_  = 0;
        Vector position_(0,0);
        Vector velocity_(0,0);
    }
    
    Ball::Ball(double _mass, double _radius, int _color, Vector _position, Vector _velocity)
    {
        mass_   = _mass;
        radius_ = _radius;
        color_  = _color;
        Vector position_(_position.getX(), _position.getY());
        Vector velocity_(_velocity.getX(), _velocity.getY());
    }
    
    Ball::Ball(double _mass, double _radius, int _color, double _p_x, double _p_y, double _v_x, double _v_y)
    {
        mass_   = _mass;
        radius_ = _radius;
        color_  = _color;
        Vector position_(_p_x, _p_y);
        std::cout << position_.getX() << std::endl;
        Vector velocity_(_v_x, _v_y);
    }
    
    void Ball::setMass(double _mass)
    {
        mass_ = _mass;
    }
    
    void Ball::setRadius(double _radius)
    {
        radius_ = _radius;
    }
    
    void Ball::setColor(int _color)
    {
        color_ = _color;
    }
    
    void Ball::setPosition(Vector _position)
    {
        position_.setVector(_position);
    }
    
    void Ball::setPosition(double _p_x, double _p_y)
    {
        position_.setVector(_p_x, _p_y);
    }
    
    void Ball::setVelocity(Vector _velocity)
    {
        velocity_.setVector(_velocity);
    }
    
    void Ball::setVelocity(double _v_x, double _v_y)
    {
        velocity_.setVector(_v_x, _v_y);
    }
    
    std::ostream& operator<<(std::ostream &_flow, Ball _ball)
    {
        _flow << "Mass = "     << _ball.getMass()     << std::endl;
        _flow << "Radius = "   << _ball.getRadius()   << std::endl;
        _flow << "Color = "    << _ball.getColor()    << std::endl;
        _flow << "Position = " << _ball.getPosition();
        _flow << "Velocity = " << _ball.getVelocity();
    
        return _flow;
    }


    J'ai voulu tester toutes les méthodes, mais j'ai un problème avec le constructeurs de Ball. J'initialise une "ball1" et j'essaye de visualiser tous ses attributs :
    main.cpp

    #include <iostream>
    
    #include "Vector.hpp"
    #include "Ball.hpp"
    
    int main()
    {
    
        Ball ball1(0.99, 0.8, 4, 1.8, 1.9, 1, 2);
    
        std::cout << ball1 << std::endl;
    }

    Mais là sans que je ne comprenne pourquoi, chaque attribut est bien initialisé sauf position_ et velocity_. J'ai vérifié le constructeur de Vector fonctionne bien, et quand j'utilise ball1.setPosition( , ) cette fois les valeurs de position/velocity sont bien changées. J'en ai déduit que c'était un problème de constructeurs pour Ball.
    Si quelqu'un a une idée je suis preneur :)
    Merci


    • Partager sur Facebook
    • Partager sur Twitter
    0100001001101001011011100110000101101001011100100110010100001010
      26 avril 2022 à 18:56:10

      position_ et velocity_ sont des variables locales, pas des variables membres.
      • Partager sur Facebook
      • Partager sur Twitter
        26 avril 2022 à 19:59:14

        Merci pour ta réponse mais je ne comprends pas. Comment fait on pour déclarer un objet en tant que membres d'une autre classe. Et ensuite pouvoir le modifier etc ?
        • Partager sur Facebook
        • Partager sur Twitter
        0100001001101001011011100110000101101001011100100110010100001010
          26 avril 2022 à 20:21:24

          De le même façon que tu as déclaré tes autres variables membres.
          • Partager sur Facebook
          • Partager sur Twitter
            26 avril 2022 à 20:35:26

            Alors, je ne vois pas trop comment utiliser les constructeurs de Vector dans le constructeurs de Ball ?
            position_(0,0);
            velocity_(0,0);
            ça serait ça la bonne façon de construire ? J'ai cependant une erreur si je fais ça
            • Partager sur Facebook
            • Partager sur Twitter
            0100001001101001011011100110000101101001011100100110010100001010
              26 avril 2022 à 20:39:38

              Utilise la "liste d'initialisation". C'est fait pour, et c'est le seul mécanisme qui permette cela.
              • 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.
                26 avril 2022 à 21:03:01

                lmghs a écrit:

                Utilise la "liste d'initialisation". C'est fait pour, et c'est le seul mécanisme qui permette cela.


                OK ça a marché merci beaucoup, mais je me demandais, il n'y a vraiment pas d'autres façon de faire afin de l'initialiser dans le bloc de la fonction ?

                -
                Edité par Nababe 26 avril 2022 à 21:03:20

                • Partager sur Facebook
                • Partager sur Twitter
                0100001001101001011011100110000101101001011100100110010100001010
                  26 avril 2022 à 21:27:21

                  Nababe a écrit:

                  lmghs a écrit:

                  Utilise la "liste d'initialisation". C'est fait pour, et c'est le seul mécanisme qui permette cela.

                  OK ça a marché merci beaucoup, mais je me demandais, il n'y a vraiment pas d'autres façon de faire afin de l'initialiser dans le bloc de la fonction ?

                  Il existe une bonne façon, celle que t'as donné lmghs. Mais tu peux (dans ton cas, ça ne marche pas toujours), utiliser une mauvaise façon:
                  Ball::Ball(double _mass, double _radius, int _color, Vector _position, Vector _velocity)
                  {
                      mass_   = _mass;
                      radius_ = _radius;
                      color_  = _color;
                      position_ = _position;
                      velocity_ = _velocity;
                  }

                  Ainsi, tu mets du code dans le corps du constructeur. Mais en fait tu as initialisé 2 fois tes 5 membres! Tes membres doivent être créés et initialisés avant le corps, ensuite tu en changes la valeur. C'est quand même dommage!
                  En utilisant la liste d'initialisation, tu crées et initialises chacun de tes membres une seule fois.

                  Ball::Ball(double _mass, double _radius, int _color, Vector _position, Vector _velocity)
                      : mass_{_mass}
                      , radius_{_radius}
                      , color_{_color}
                      , position_{std::move(_position)}
                      , velocity_{std::move(_velocity)}
                  {
                  }
                  • Partager sur Facebook
                  • Partager sur Twitter

                  En recherche d'emploi.

                    26 avril 2022 à 21:37:52

                    OK je vois, donc tout sauf la "liste d'initialisation" est plus ou moins à bannir pour faire les choses correctement.

                    Petite questions cependant :
                    Dans une "liste d'initialisation" tu peux changer les () par des {} ?
                    Et le std::move ici apporte quoi en plus ?

                    • Partager sur Facebook
                    • Partager sur Twitter
                    0100001001101001011011100110000101101001011100100110010100001010
                      26 avril 2022 à 21:54:32

                      Dalfab a écrit:

                      Mais en fait tu as initialisé 2 fois tes 5 membres

                      (1 initialisation et une affectation)

                      Nababe a écrit:

                      OK je vois, donc tout sauf la "liste d'initialisation" est plus ou moins à bannir pour faire les choses correctement.

                      Il ne faut pas oublier l'initialisation lors de la déclaration. (Meme si lmghs n'aime pas) 

                      struct Vector {
                          double _x = 0.0;
                          double _y = 0.0;
                      };

                      Nababe a écrit:

                      Dans une "liste d'initialisation" tu peux changer les () par des {} ?

                      Et le std::move ici apporte quoi en plus ?

                      oui.

                      Et move evite la copie dans ce code.

                      • Partager sur Facebook
                      • Partager sur Twitter
                        26 avril 2022 à 22:27:20

                        > Et move evite la copie dans ce code.

                        Dans ce code précis, il n'y a pas d'objets à charge déportée. Les moves finissent aussi en copies.

                        > à bannir pour faire les choses correctement.

                        Ici les setters aussi n'ont pas le moindre sens. Tes données n'ont pas d'invariants, et encore moins de services. OSEF si l'utilisateur va taper dedans.

                        > Il ne faut pas oublier l'initialisation lors de la déclaration. (Meme si lmghs n'aime pas)

                        J'ai repensé à notre discussion cet aprèm suite à l'annonce de GCC 12 par redhat. Il y a une amélioration de la détection des membres non initialisés.

                        • 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.
                          26 avril 2022 à 22:40:50

                          lmghs a écrit:

                          > Et move evite la copie dans ce code.

                          Dans ce code précis, il n'y a pas d'objets à charge déportée. Les moves finissent aussi en copies.

                          Vrai.

                          lmghs a écrit:

                          > Il ne faut pas oublier l'initialisation lors de la déclaration. (Meme si lmghs n'aime pas)

                          J'ai repensé à notre discussion cet aprèm suite à l'annonce de GCC 12 par redhat. Il y a une amélioration de la détection des membres non initialisés.

                          Pas vu passer.

                          • Partager sur Facebook
                          • Partager sur Twitter
                            27 avril 2022 à 10:14:20

                            lmghs a écrit:

                            Ici les setters aussi n'ont pas le moindre sens. Tes données n'ont pas d'invariants, et encore moins de services. OSEF si l'utilisateur va taper dedans.


                            Sans les setters je ne vois pas trop comment je vais pouvoir les modifier dans la suite du programme (en les mettant en attributs publics ?)

                            -
                            Edité par Nababe 27 avril 2022 à 10:14:49

                            • Partager sur Facebook
                            • Partager sur Twitter
                            0100001001101001011011100110000101101001011100100110010100001010
                              27 avril 2022 à 13:32:48

                              Pourquoi la balle changerait de masse ou de couleur?

                              Et ensuite, si la position devait etre modifiée par l'extérieur, pourquoi la position devrait passer par un setter? Au lieu de

                              balle.position += balle.velocity * dt;

                              Un setter n'est pas un gage de bonne conception. C'est généralement tout le contraire. https://www.infoworld.com/article/2073723/why-getter-and-setter-methods-are-evil.html (une infinité de débats sur le sujet sur OC et ailleurs)

                              A la place ce qui aurait du sens, c'est fournir un service

                              Ball:update_position(double dt) {
                                  position += velocity * dt;
                              }

                              Et même chose pour les forces qui vont agir sur la vélocité.

                              Autant sur la balle on peut se poser une question car on peut imaginer des services propres à tout mobile.

                              Sur le vecteur par contre... Où sont les services autres que de stocker des coordonnées? Et éventuellement supporter une algèbre (pour les additionner, soustraire, multiplier, etc). Ici, il y a (AMA) un bon désign de vecteur mathématique: https://marzer.github.io/muu/structmuu_1_1vector.html

                              • 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.
                                27 avril 2022 à 13:52:02

                                On peut imaginer différents events (bonus par exemple) qui donnerait des caractéristiques à la balle et donc pourquoi pas changerait de couleur. Mais je comprends le principe de ne pas mettre des setters pour tout et n'importe quoi, il faut plutôt privilégié des méthodes qui modifient les attributs certes mais dans des cas précis comme ton exemple

                                Ball:update_position(double dt);


                                Merci pour ces explications, je vais tacher de rendre le code plus propre !

                                • Partager sur Facebook
                                • Partager sur Twitter
                                0100001001101001011011100110000101101001011100100110010100001010
                                  27 avril 2022 à 14:24:00 - Message modéré pour le motif suivant : Message complètement hors sujet


                                    27 avril 2022 à 16:47:57 - Message modéré pour le motif suivant : Message complètement hors sujet


                                    Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait
                                      27 avril 2022 à 17:02:00 - Message modéré pour le motif suivant : Message complètement hors sujet


                                        27 avril 2022 à 17:12:32 - Message modéré pour le motif suivant : Message complètement hors sujet


                                        Ce qui se conçoit bien s'énonce clairement. Et les mots pour le dire viennent aisément.Mon nouveau livre : Coder efficacement - Bonnes pratiques et erreurs  à éviter (en C++)Avant de faire ce que tu ne pourras défaire, penses à tout ce que tu ne pourras plus faire une fois que tu l'auras fait

                                        Constructeurs d'une classe dans 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