Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

Reference indéfini vers ..


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Reference indéfini vers ..
    Bonjour ,

    Lorsque je compile , il me reste 2 erreurs que je n'arrive pas a solutionner .

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #ifndef PERSONNE_HPP_
    #define PERSONNE_HPP_
     
    #include <string>
     
    class Personne
    {
      private:
      std::string nom;
      std::string prenom;
      int age;
     
      public:
      Personne();
      void afficher();
      std::string get_nom();
      std::string get_prenom();
      int get_age();
     
      void set_nom(std::string a);
      void set_prenom(std::string b);
      void set_age(int c);
     
    };
     
    #endif /* PERSONNE_HPP_ */


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include "personne.h"
    #include <iostream>
    #include <string>
     
     
    std::string nom,prenom;
    int age;
     
    Personne:<img src="images/smilies/icon_razz.gif" border="0" alt="" title=":P" class="inlineimg" />ersonne()
    {
    	nom = "";
    	prenom = "";
    	age=0;
    }
     
    void Personne::afficher()
    {
    	std::cout << "Nom: " << nom << std::endl;
    	std::cout << "prenom: " << prenom << std::endl;
    	std::cout << "Age: " << age << std::endl;
    }
     
    std::string get_nom(){return nom;}
    std::string get_prenom(){return prenom;}
    int get_age(){return age;}
     
    void set_nom(std::string a){nom = a;}
    void set_prenom(std::string b){prenom = b;}
    void set_age(int c){age = c;}


    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    #include "personne.h"
    #include <iostream>
    #include <string>
    using namespace std;
     
    int main()
    {
     Personne chris;
     string a,b;
     int c;
     cout << "Entrez nom famille:" << endl;
     cin >> a;
     chris.set_nom(a);
     cin.ignore();
     cout << "Entrez prenom: " << endl;
     cin >>b;
     chris.set_prenom(b);
     cin.ignore();
     cout << "Entrez age: " << endl;
     cin >>c;
     chris.set_age(c);
     cin.ignore();
     
     chris.afficher();
     
     return 0;
    }


    Et donc j'ai ces 2 erreurs :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    18:17:19 **** Incremental Build of configuration Debug for project personne ****
    make all 
    Building target: personne
    Invoking: GCC C++ Linker
    g++  -o "personne"  ./main.o ./personne.o   
    ./main.o*: Dans la fonction «*main*»*:
    /home/chris/Projets_C++/personne/Debug/../main.cpp:13*: référence indéfinie vers «*Personne::set_nom(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)*»
    /home/chris/Projets_C++/personne/Debug/../main.cpp:17*: référence indéfinie vers «*Personne::set_prenom(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >)*»
    /home/chris/Projets_C++/personne/Debug/../main.cpp:21*: référence indéfinie vers «*Personne::set_age(int)*»
    makefile:44: recipe for target 'personne' failed
    collect2: error: ld returned 1 exit status
    make: *** [personne] Error 1
    "make all" terminated with exit code 2. Build might be incomplete.
     
    18:17:20 Build Failed. 2 errors, 0 warnings. (took 745ms)


    Merci de votre aide .

  2. #2
    Membre habitué
    Bonjour,

    Je n'ai pas testé le code mais plusieurs choses m'interpellent ici. Dans un premier temps, pourquoi, dans ton *.cpp de ta classe, tu re-inclus std::string ? Compte tenu du fait qu'il est déjà dans le *.hpp et que ce dernier est inclus dans le *.cpp, il est ici inutile. Cependant, c'est juste un sujet mineur ; ceci n'engendrera aucun bug.
    Dans la même lignée, pourquoi utiliser des #ifndef ... #define ... #endif ? Remplace tout ça par un simple #pragma once et ça ira bien. Mais là aussi, c'est juste de la mise en forme.
    Chose plus important par contre, toujours dan ton *.cpp, pourquoi diantre re-déclarer "nom, prénom et age" ??? Ces éléments sont des variables membres de ta classe, ils n'ont rien à faire en global dans ton *.cpp !!

    Aussi, préfère les listes d'initialisation pour tes constructeurs.
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // a ne pas faire !
    Personne:<img src="images/smilies/icon_razz.gif" border="0" alt="" title=":P" class="inlineimg" />ersonne()
    {
    	nom = "";
    	prenom = "";
    	age=0;
    }
     
    // c'est mieux comme ça !
    Personne<img src="images/smilies/icon_razz.gif" border="0" alt="" title=":P" class="inlineimg" />ersonne():
    	nom{},
    	prenom{},
    	age{} {}



    Concernant la classe. Cette dernière est "inutile" dans le sens où les méthodes n'ont ici pour but que de modifier tous les membres. Ici, j'aurais simplement créé une structure du type :
    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    struct Personne {
    	std::string nom{};
    	std::string prenom{};
    	unsigned short int age{};	//255 est en général suffisant pour un age...
    };


    Préfère une approche procédurale lorsque possible. C'est bien souvent suffisant et plus simple à mettre en œuvre.

    Aussi, évite d'utiliser les using namespace std; ça t'évitera bien des soucis par la suite...

    Et dernier point, les références indéfinies sont souvent liées à une problématique de compilation. A voir quelles sont tes options de compilation mais il faut que tu appelles tous tes *.cpp. Par exemple : make -o test *.cpp -W -Wextra --std=c++14

    Tiens nous au courant de tes avancées.

  3. #3
    Rédacteur/Modérateur

    - tes fonctions set_nom etc ne sont pas implémentées dans la classe
    - seuls le constructeur et afficher le sont
    - tu déclares des globales dans personne.cpp
    - tu n'as aucune const-correctness
    - std::string s'initialise par défaut à une chaîne vide
    - using namespace std; est à bannir
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Nouveau membre du Club
    Merci a tous les deux .
    Vous me dites de ne pas redeclarer mes variables nom, penom et age dans le .cpp mais , ne faut il pas respecter le principe d'encapsulation des données et accéder à celles-ci au travers des assesseurs ? ou je m'embrouille un peu ...
    J'ai implémenté les méthodes comme tu me l'a dit dans mon .cpp et apres reflexion , je viens de m'apercevoir que pour mes methodes get et set , il me manque aussi la référence à la classe et c'est peu etre pour ca que ca compile pas .
    Daccord pour ne pas utiliser using namespace std dans le header mais meme dans les autres fichier , je dois m'en abstenir ?

  5. #5
    Membre expert
    ne faut il pas respecter le principe d'encapsulation des données et accéder à celles-ci au travers des assesseurs ?
    Où est l'encapsulation lorsque tous les membres privées ont des fonctions pour les y accéder et les modifier ? L'interface d'une classe se réfléchit en termes de service: ce qu'elle devrait faire, et non pas à comment elle devrait le faire. Une classe qui expose intensivement des accesseurs n'est rien de plus qu'un aggloméra de donnée: elle n'expose aucun service, autant tout mettre en public.

    Daccord pour ne pas utiliser using namespace std dans le header mais meme dans les autres fichiers , je dois m'en abstenir ?
    Dans les .cpp ce n'est pas très grave, cela ne se propage pas aux autres fichiers. Mais il y a toujours des risques de conflit de nom avec un using namespace. Personnellement, je m’abstiens, surtout que je trouve plus clair de toujours préfixer par le namespace std::.

  6. #6
    Membre habitué
    Alors les using namespace ne sont surtout pas à mettre dans les hpp. La bonne pratique est de ne pas du tout les utiliser, mais si, pour une raison x ou y tu le fais en pleine conscience des impacts, c'est à mettre dans le cpp uniquement ; jamais dans les headers.

    En ce qui concerne les "setters" et "getters", il s'agit de fonctions et non de variables.
    Dans ton cas, les setters sont void set_nom(std::string const & val); etc... et les getters std::string const & get_nom() const; etc... En aucun cas il ne s'agit de variables globales !

    Bref, je t'invite à suivre un cours sur la programmation. Je laisse le soin aux personnes compétentes de ce forum pour te guider vers des ouvrages ou tout autre ressources pertinentes à ce sujet. Il est important de partir avec de bonnes bases. Tâche de ne pas "rusher" ces dernières.
    Selon moi, quelque soit ta méthode d'apprentissage, dans tous les cas, tâche de toujours réaliser un code propre, lisible, constant dans sa mise en forme. Ces quelques principes, appuyés par l'expertise des membres de ce forum, m'ont permis de prendre une belle maturité et assurance dans l'écriture de mes sources.

    Bon courage !

  7. #7
    Nouveau membre du Club
    Je vous remercie de vos conseils et de vos encouragements .