Partage
  • Partager sur Facebook
  • Partager sur Twitter

Une classe vecteur qui ne marche pas.

undefined reference to '...'

Sujet résolu
    1 août 2007 à 14:14:22

    Bonjour,

    pour m'entrainer avec les classes, j'ai essayé de coder une classe Vecteur. A priori, rien de difficile, d'ailleurs, il n'y a rien de difficile...
    Mais il reste quand même un petit problème, que je ne situerais pas dans le code en lui même, mais plutôt dans les fichiers:

    /tmp/ccJT9yXA.o: In function `main':
    main.cc:(.text+0xd2): undefined reference to `transformation::operator+(transformation::Vecteur const&, transformation::Vecteur const&)'

    Voilà les sources:
    main.cc
    #include <iostream>
    #include "transformation.hh"

    namespace trans=transformation;

    int main(int argc,char* argv[]){

            trans::Vecteur u(3.2,-1.3);
            trans::Vecteur v(0.5);

            u+v; /*C'est cette ligne de code qui pose problème car le linker semble ne pas connaitre trans::operator+*/

            return 0;
    }
     


    transformation.hh:
    #ifndef __transformation__
    #define __transformation__

    namespace transformation{

            class Vecteur{

              public:

                    Vecteur(double=0,double=0);
                    Vecteur& operator+=(const Vecteur&);
                    Vecteur& operator-=(const Vecteur&);

              private:

                    double mx;
                    double my;
            };

            Vecteur operator+(const Vecteur&,const Vecteur&);
            Vecteur operator-(const Vecteur&,const Vecteur&);
    }

    #endif
     


    transformation.cc:
    #include "transformation.hh"

    using namespace transformation;

    Vecteur::Vecteur(double x,double y):mx(x),my(y){
    }

    Vecteur& Vecteur::operator+=(const Vecteur& u){

            mx+=u.mx;
            my+=u.my;

            return *this;
    }

    Vecteur& Vecteur::operator-=(const Vecteur& u){

            mx-=u.mx;
            my-=u.my;

            return *this;
    }

    Vecteur operator+(const Vecteur& u,const Vecteur& v){

            Vecteur somme(u);

            return somme+=v;
    }

    Vecteur operator-(const Vecteur& u,const Vecteur& v){

            Vecteur difference(u);

            return difference-=v;
    }
     


    D'avance merci :)
    • Partager sur Facebook
    • Partager sur Twitter
      1 août 2007 à 14:33:48

      Tu définis l'opérateur += et non pas l'opérateur +, regarde ta ligne :

      u+v;


      Alors non seulement tu utilises un opérateur que tu n'as pas définit mais en plus tu ne récupères pas la valeur de retour de ton addition...

      EDIT : j'ai mal vu, en fait je pense que ces deux méthodes sont mal définies :

      Vecteur operator+(const Vecteur&,const Vecteur&);
              Vecteur operator-(const Vecteur&,const Vecteur&);


      Déjà retourne ne référence sur un Vecteur :

              Vecteur &operator+(const Vecteur&,const Vecteur&);
              Vecteur &operator-(const Vecteur&,const Vecteur&);


      Et ensuite, définis ces deux fonctions DANS la classe Vecteur...
      • Partager sur Facebook
      • Partager sur Twitter
        1 août 2007 à 14:35:52

        Je ne récupère pas le résultat parcequ'il n'est pas important, c'est juste pour le test :)
        Mais j'ai bien définit operator+, regardes bien à la fin de transformation.cc...

        EDIT:
        Dans son livre, Stroustrup conseille de définir les opérateur qui ne modifie pas un objet en dehors de la classe (comme operator+ et operator-, operator<<, etc), contrairement à operator+= qui doit modifier un objet.
        De plus je ne peux pas retourner une référence sur un objet qui est détruit à la fin de operator+ sinon le programme risque de planter non ?

        Merci quand même.
        • Partager sur Facebook
        • Partager sur Twitter
          1 août 2007 à 14:52:11

          Voilà j'ai trouvé ton problème... Il vient tout simplement du constructeur :

          Vecteur(double=0,double=0);


          Tu dis que ta fonction prend deux doubles c'est bien... Et tu dis que par défaut ils sont égaux à zéro... Le problème c'est que si tu veux leur donner une valeur par défaut, il faut que tu les nommes !

          Vecteur(double x = 0, double y = 0);


          Essaye ça tu verras ça marchera beaucoup mieux... Avec ta première technique seul la première construction marche parce que tu donnes les 2 paramètres... La deuxième ne marche pas parce que pour le compilateur double=0 ça veut dire donc apparemment il l'ignore et ne crée pas 3 constructeurs séparés (1 sans paramètre, 1 avec un seul paramètre et un avec deux paramètres...).

          Personnellement, je nomme tous mes paramètres que ce soit dans la définition (j'ai pas vraiment le choix là) ou que ce soit dans la déclaration, ça évite de faire des erreurs...
          • Partager sur Facebook
          • Partager sur Twitter
            1 août 2007 à 14:57:04

            J'ai essayé en ajoutant les noms, mais ça n emarche toujours pas :(
            En effet, il est tout à fait possible d'omettre le nom des variables dans le prototype d'une fonction (exemple: ajouter(int);). Le =0 n'y change rien du tout !
            J'ai plutôt le sentiment que le problème viens de l'utilisation de l'espace de noms (il peut peut-être manquer un qqchose:: ou il y a un using namespace qqchose; en trop je sais pas.
            • Partager sur Facebook
            • Partager sur Twitter
              1 août 2007 à 15:00:58

              Sort les fonctions operator+ et operator- du namespace pour voir...
              • Partager sur Facebook
              • Partager sur Twitter
                1 août 2007 à 15:03:33

                Lorsqu'on met cette ligne problématique entre commentaires, ça compile (normal puisque c'est elle qui pose problème :) )
                Merci de ta persévérence !

                EDIT: Les fonctions d'addition et de soustraction doivent rester dans l'espace de nom car justement, ce namespace permet de regrouper explicitement la classe Vecteur et ses fonctions assistantes (operator+ et operator-).
                En virant l'espace de nom, autant mettre les fonctions dans la classe (et là, plus de problèmes)
                • Partager sur Facebook
                • Partager sur Twitter
                  1 août 2007 à 15:06:07

                  Tu as vérifié ça :

                  Citation : psychoh13

                  Sors les fonctions operator+ et operator- du namespace pour voir...



                  ???
                  • Partager sur Facebook
                  • Partager sur Twitter
                    1 août 2007 à 15:09:19

                    Salut,
                    Le problème est ici:

                    Vecteur operator+(const Vecteur& u,const Vecteur& v){

                            Vecteur somme(u);<---------- ici

                            return somme+=v;
                    }

                    Il n'y a pas de constructeur correspondant
                    • Partager sur Facebook
                    • Partager sur Twitter
                      1 août 2007 à 15:10:13

                      Ah oui aussi... J'ai ajouté le constructeur de copie...

                      Mais ça ne provoque pas l'erreur de ne pas le mettre, alors que sortir les fonctions du namespace supprime l'erreur...

                      Si vous n'écrivez pas vous-mêmes un constructeur de copie pour votre classe, il sera généré automatiquement pour vous par le compilateur. Ok, c'est sympa de sa part, mais le compilateur est... comment dire pour pas le froisser... bête
                      En fait, le constructeur de copie généré se contente de copier la valeur de tous les attributs... même des pointeurs !
                      • Partager sur Facebook
                      • Partager sur Twitter
                        1 août 2007 à 15:14:25

                        Le constructeur de copie est bien existant puisqu'il n'y a pas d'erreur de compilation
                        (en plus l'erreur se trouve bien dans le main à la ligne de l'addition car il ne connait apparemment pas operator+)
                        D'ailleurs ce constructeur est implicite, et un peu "bête" puisqu'il s'agit du constructeur de copie par défaut qui copie les membres de la classe un par un (cela pose en effet problème avec les pointeurs). Mais ici il suffit largement ;)

                        EDIT: Je sais que je suis chiant, mais sortir les fonctions du namespace n'est pas une solution ! Le problème vient de l'utilisation du namespace incorrecte, et visiblement personne sur ce topic ne connait cette erreur :D
                        • Partager sur Facebook
                        • Partager sur Twitter
                          1 août 2007 à 15:17:34

                          Est-ce que tu as essayé de sortir les fonctions operator+ et operator- de ton namespace ? (Les déclarations)

                          EDIT: ce n'est peut-être pas une solution... mais c'est peut-être quand même la seule solution...
                          • Partager sur Facebook
                          • Partager sur Twitter
                            1 août 2007 à 15:20:18

                            Ben oui, j'ai essayé en les mettant dans la classe et en supprimant le namespace, mais j'aimerais connaitre l'erreur du code que j'ai posté tout en haut :)
                            • Partager sur Facebook
                            • Partager sur Twitter
                              1 août 2007 à 15:25:12

                              BON ! Cette fois-ci je pense vraiment t'aider à 100% :D

                              Le truc c'est que les définitions de tes fonctions ne sont pas dans le namespace !

                              Il faut que tes définitions correspondent aux prototypes, donc il faut que tu écrives :

                              Vecteur transformation::operator+(const Vecteur& u,const Vecteur& v) { ... }
                              Vecteur transformation::operator-(const Vecteur& u,const Vecteur& v) { ... }


                              Et non pas :

                              Vecteur operator+(const Vecteur& u,const Vecteur& v) { ... }
                              Vecteur operator-(const Vecteur& u,const Vecteur& v) { ... }
                              • Partager sur Facebook
                              • Partager sur Twitter
                                1 août 2007 à 15:29:04

                                Effectivement ça compile !!
                                Merci beaucoup mais je ne comprend pas pourquoi ça marche... Regarde tout en haut de transformation.cc :
                                using namespace transformation;
                                Comment peut il y avoir ambiguité ?
                                Je vais relire le chapitre sur les namespace :)
                                Merci encore !
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  1 août 2007 à 15:34:40

                                  using namespace quelqueChose;


                                  À mon avis, pour les méthodes de Vecteur, comme tu définis leur "portée" grâce à Vecteur:: et que dans ce fichier (le .cc), le compilateur ne connaît que la classe Vecteur dans le namespace transformation, et bien pour lui il n'y a pas ambiguïté... Mais pour les deux fonctions, tu ne définis aucune portée et aucune classe, donc le compilateur suppose qu'elles sont définies dans l'espace globales, et donc les fonctions dans le namespace ne trouvent pas preneur... Enfin je pense Enfin c'est bizarre comme système o_O ... Vive l'Objective-C :p
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    1 août 2007 à 15:48:46

                                    en fait, si j'me trompe pas, dans tes définitions (fichier .h), tu peux parfaitement enlever les "transformation::", et seulement les inscrire dans les déclarations(fichier .cpp).
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                    Altarapp.com - Applications, Code Snippets, API Wrappers et etc, le tout en C# le plus clair du temps!
                                      1 août 2007 à 16:08:50

                                      déclaration dans les .h et définition dans les .cpp ;)


                                      tu peux dans ton .cpp définir une extension à ton espace de nommage :

                                      bidon.h
                                      // ...
                                      namespace Bidon
                                      {
                                          class ClasseBidon
                                          {
                                               // ...
                                          };
                                      }
                                      // ...
                                       

                                      bidon.cpp
                                      // ...
                                      namespace Bidon
                                      {
                                          ClasseBidon::ClasseBidon()
                                          {
                                              m_varBidon = 0;
                                          }

                                          // ...
                                      }
                                      // ...
                                       
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        1 août 2007 à 19:17:21

                                        Merci pour vos réponses, mais j'ai trouvé une solution propre et efficace:
                                        Il faut remplacer
                                        using namespace transformation;
                                        par
                                        using transformation::Vecteur;

                                        Je m'était mis dans la tête que d'écrire using namespace transformation aller me permettre de virer les transformation:: alors que se n'est pas toujours le cas !
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          2 août 2007 à 0:05:12

                                          Le using, c'est pour ... utiliser. Pour définir, il y a parfois des effets de bords moyens.

                                          PS: les signatures sont parfaites. (Pour une fois).
                                          • 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.

                                          Une classe vecteur qui ne marche pas.

                                          × 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