IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
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 :

Héritage et constructeurs


Sujet :

C++

  1. #1
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    289
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2008
    Messages : 289
    Points : 151
    Points
    151
    Par défaut Héritage et constructeurs
    bonjour,
    un problème que je n'arrive pas à solutionner.
    Soit une classe FigureGeometrique mère d'une classe Segment utilisant toutes les deux une classe Point:
    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
    30
    31
    32
    33
    34
     
    class FigureGeometrique
    {
    private:
    protected:
      Point org;
     
    public:
      FigureGeometrique(Point);
      Point get_org() const {return org;}
      virtual void dessiner();
    };
     
    class Segment:public FigureGeometrique
    {
      Point org, ext;
     
    public:
      Segment(Point, Point);
      void dessiner();
    };
     
    class Point
    {
    private:
      int x, y;
     
    public:
      Point();
      Point(int, int);
      Point(const Point&);
      int get_x() const {return x;};
      int get_y() const {return y;};
    };
    Le constructeur de la classe Segment est le suivant:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Segment::Segment(Point o, Point e):FigureGeometrique(o), ext(e)
    {
    }
    Quand j'instancie un objet de la classe Segment et que je compile, j'ai l'erreur:
    segment.o: dans la fonction « Segment::Segment(Point, Point) »:
    segment.cpp:(.text+0x3d): référence indéfinie vers « Point::Point() »
    Le compilateur recherche un constructeur de Point sans argument pour construire l'attribut ext à partir du paramètre e (si j'ai bien suivi le cours) mais je ne comprend pas le pourquoi du mécanisme. Je pensais n'utiliser que le constructeur par défaut de Point.
    J'ai implémenté un constructeur par recopie et je vois que j'y passe bien.

    Une explication?
    Merci.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Tu déclares Point après tes classes alors que tu l'utilises dans le constructeur - par copie, donc il doit connaître sa définition complète et non juste une forward-declaration.
    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.

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Tu déclares trois constructeurs pour ta classe Point : un constructeur par défaut, un constructeur prenant deux entiers comme paramètres et un constructeur de copie. Mais... as tu pensé à fournir l'implémentation de ces constructeurs, car, dans elle n'apparait pas dans le code que tu nous présente

    Si tu as fourni l'implémentation de ces constructeurs, il y a de fortes chances pour que, pour une raison ou une autre, le fichier qui contient cette implémentation n'ait -- purement et simplement -- pas été pris en compilé par ton EDI quand tu lui a demandé de construire le projet. Tu devrais donc t'assurer que le fichier d'implémentation qui contient les constructeurs de point soit... bien ajouté à ton projet

    Pour le fait que le compilateur (semble) essaye(r) d'appeler le constructeur par défaut de ta classe point, il faudrait voir comment tu fais pour créer ton segment, et quelles sont les données que tu fournis comme argument au constructeur de ta classe segment. Mais il se peut aussi que l'éditeur de liens se plante simplement dans son diagnostic lorsqu'il affiche l'erreur, et que ce soit normalement le constructeur par copie qui soit effectivement appelé (mais pour lequel l'éditeur de liens n'aurait pas trouvé le symbole équivalent).

    Enfin, je ne suis pas sur que la classe FormeGeometrique ait besoin de connaitre un point à la base. Cette classe rentrerait, à mon sens, tout droit dans la catégorie des classes abstraites : une classe qui expose l'interface commune à toutes les classes qui en dérive, mais pour laquelle il est impossible de fournir le moindre comportement cohérent, car elle ne dispose elle-même d'aucune donnée

    Mais, quoi qu'il en soit, cette classe a typiquement une sémantique d'entité, et, en tant que telle, elle ne devrait être ni copiable ni assignable
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    289
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2008
    Messages : 289
    Points : 151
    Points
    151
    Par défaut
    bonjour,
    non, décidément je ne vois pas.
    Je poste l'entièreté de mon code. Toutes les classes sont dans des fichiers .cpp et .p séparés et je compile via un makefile.

    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
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    main.cpp
    ------------
      Point p1(4, 7);
      Point p2(11, 12);
      Point p3(p1);  //pour tester le constructeur par recopie
      cout << "p3.x = " << p3.get_x() << " p3.y = " << p3.get_y() << endl;
     
      Segment S1(p1, p2);
     
    point.h
    ---------
    class Point
    {
    private:
      int x, y;
     
    public:
      Point(int, int);
      Point(const Point&);
      int get_x() const {return x;};
      int get_y() const {return y;};
    };
     
    point.cpp
    ------------
    #include "point.h"
    Point::Point(int a, int b):x(a), y(b)
    {
      cout << "constructeur de point" << endl;
    }
     
    Point::Point(const Point& p):x(p.x), y(p.y)
    {
      cout << "Point : constructeur par recopie avec " << p.x << " et " << p.y << endl;
    }
     
    figuregeometrique.h
    ---------------------------
    class FigureGeometrique
    {
    private:
    protected:
      Point org;
     
    public:
      FigureGeometrique(Point&);
      Point get_org() const {return org;}
      //virtual void dessiner();
      void dessiner();
    };
     
    figuregeometrique.cpp
    ------------------------------
    FigureGeometrique::FigureGeometrique(Point& p):org(p)
    {
      cout << "Constructeur figure geometrique" << endl;
    }
     
    void FigureGeometrique::dessiner()
    {
      cout << "dessine une figure geometrique" << endl;
    }
     
    segment.h
    --------------
    class Segment:public FigureGeometrique
    {
      Point org, ext;
     
    public:
      Segment(Point&, Point&);
      void dessiner();
    };
     
    segment.cpp
    -----------------
    Segment::Segment(Point& o, Point& e):FigureGeometrique(o), ext(e)
    {
    }
     
    void Segment::dessiner()
    {
      cout << "Je dessine un segment" << endl;
    }
    Koala01, en parallèle, je vais lire ce concept de sémantique d'entité.

    Merci.

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    Vous devez absolument revoir l'utilisation de #include.
    Là, c'est du nimportnawak.

    Le code dans "main.cpp" utilisent les classes "Point" et "Segment", vous devez ajouter les .h correspondant à ces classes au début du fichier "main.cpp" via les "#include" qui vont bien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #include "Point.h"
    #include "Segment.h"
     
    int main()
    {
      Point p1(4, 7);
      Point p2(11, 12);
      Point p3(p1);  //pour tester le constructeur par recopie
      cout << "p3.x = " << p3.get_x() << " p3.y = " << p3.get_y() << endl;
     
      Segment S1(p1, p2);
      return 0;
    }
    Idem pour "figuregeometrique.h", vous utilisez la classe "Point" dans la déclaration de la classe "FigureGeometrique", vous devez ajouter un '#include "Point.h"' en début de fichier.
    Idem pour "figuregeometrique.cpp", vous utilisez la classe "Point" et définissez l'implémentation de la classe "FigureGeometrique", vous devez ajouter les 2 "#include .." qui vont bien.
    Idem pour "segment.h", vous utilisez les classes "Point" et "FigureGeometrique" dans la déclaration de la classe "Segment", vous devez ajouter les 2 "#include .." qui vont bien.
    Idem pour "segment.cpp", vous utilisez les classes "Point" et "FigureGeometrique" et définissez l'implémentation de la classe "Segment", vous devez ajouter les 3 "#include .." qui vont bien.

    Vous êtes clairement à la rue au niveau des #include.

    P.S. : on verra après comment alléger le procédé.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Tu as vraiment oublié tous les includes dans tes fichiers ?
    Je pensais à une erreur de copier sur le forum, mais à priori non puisqu'il en traine un dans Point.cpp..
    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.

  7. #7
    Membre habitué
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    289
    Détails du profil
    Informations personnelles :
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2008
    Messages : 289
    Points : 151
    Points
    151
    Par défaut
    bonjour à tous et merci pour vos réponses,
    j'ai trouvé. J'avais laissé un attribut Point org dans la classe segment alors qu'il se trouve également dans la classe FigureGeometrique. En le supprimant ça compile et ça fonctionne correctement mais je n'arrive pas bien à m'expliquer la teneur du message d'erreur du compilateur.
    Désolé de vous avoir fait écrire pour rien en premier lieu, je n'avais pas voulu recopier l'entièreté de mon code dans ma question pour économiser de la classe et notamment les #include qui étaient bien présents.

    Merci.

  8. #8
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    Ok, j'ai relu le message initial avec son message d'erreur.
    Je pense que vous manquez quand même de pas mal de rigueur.
    Dans votre premier post :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Point
    {
    private:
      int x, y;
     
    public:
      Point();
      Point(int, int);
      Point(const Point&);
      int get_x() const {return x;};
      int get_y() const {return y;};
    };
    Il y a donc un constructeur de Point sans paramètre.
    Dans le poste suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Point
    {
    private:
      int x, y;
     
    public:
      Point(int, int);
      Point(const Point&);
      int get_x() const {return x;};
      int get_y() const {return y;};
    };
    Il n'existe plus.

    Le compilateur ne dit rien parce qu'il a la première version dans un coin. L'éditeur de lien, lui, il gueule parce qu'il ne voit pas l'implémentation de ce constructeur "Point::Point()" nulle part dans les .obj et .lib que le compilateur lui envoie.

    Le changement que vous avez fait ne fait que cacher le vrai problème. Avec l'ancienne version du code, "org" de "Segment" n'est pas initialisé via la liste d'initialisation et il devait donc utiliser le constructeur "Point::Point()" défini dans le .h mais donc l'implémentation et nulle part.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 3
    Dernier message: 06/09/2007, 14h01
  2. [POO] héritage de constructeurs
    Par benkunz dans le forum Langage
    Réponses: 2
    Dernier message: 03/04/2007, 15h29
  3. Héritage et constructeur
    Par shirya dans le forum C#
    Réponses: 2
    Dernier message: 07/02/2007, 17h23
  4. Réponses: 10
    Dernier message: 20/09/2006, 17h04
  5. [POO]héritage du constructeur de la classe parente
    Par new_wave dans le forum Langage
    Réponses: 7
    Dernier message: 10/03/2006, 14h25

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo