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 :

‘Arbre’ does not name a type


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Points : 63
    Points
    63
    Par défaut ‘Arbre’ does not name a type
    Bonjour tout le monde,

    J'ai un peu de mal en C++ et je n'arrive pas à trouver l'erreur du projet que je viens tout juste de commencer

    Je souhaite créer une classe Arbre et une classe Foret.
    Un Arbre contient une Foret .
    Une Foret contient une Foret et un Arbre.

    Voici les 4 classes correspondantes :

    arbre.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef _ARBRE_H
    #define	_ARBRE_H
     
    #include "foret.hpp"
     
    class Arbre{
          private :
                  Foret foret();
     
          public :
                 Arbre(char *);
    };
    #endif	/* _ARBRE_H */
    arbre.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    #include "arbre.hpp"
     
    Arbre::Arbre(char* chemin) {}
    foret.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
    #ifndef _FORET_H
    #define	_FORET_H
     
    #include"arbre.hpp"
     
    class Foret {
    	private :
    	    Arbre premierArbre("plop");
    	    Foret rest();
     
    	public:
    	    Foret();
     
    };
    #endif	/* _FORET_H */
    foret.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #include "foret.hpp"
     
    Foret::Foret() {
     
    }
    Quand je compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    gcc -Wall -pedantic -c arbre.cpp -o arbre.o
    In file included from arbre.hpp:4,
                     from arbre.cpp:1:
    foret.hpp:9: erreur: ‘Arbre’ does not name a type
    Après une bonne heure de recherche je dois me résoudre à ne pas trouver l'erreur qui doit être très bète.


    Auriez-vous une idée ?


    PS : Si vous voyez des choses moches ou pas propre dans ces 4 fichiers, n'hésitez pas à critiquer même si ça n'a rien à voir.

  2. #2
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Hello,
    Deja, il me semble que tu va avoir un probleme d'inclusion multiple dans ton code (regarde la FAC pour ca, y'a une explication je crois). Ensuite, la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Arbre premierArbre("plop");
    n'a pas de sens dans la declaration d'une classe. A la rigueur,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Arbre premierArbre(const  char*);
    mais je ne sais pas trop ce que tu veux faire

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Points : 63
    Points
    63
    Par défaut
    Je pensais que l'inclusion multiple serait réglée avec les "#ifndef".

    Pour le "plop" ce n'est qu'un exemple pour tester le programme. Je ne pense pas que ce soit lui qui pose problème actuellement.

    Sinon ce que je veux faire : une structure d'arbre.
    Chaque Arbre contiendra un noeud et des fils.
    L'ensemble des fils d'un arbre est une Foret.

    Cela permet d'avoir des fonctions (de recherche, d'inclusion) relativement simple à coder bien que coûteuse car récursive.

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

    Informations professionnelles :
    Activité : aucun

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

    Le problème d'inclusion multiple n'est que partiellement géré par les gardes anti inclusion...

    Ils permettent uniquement d'éviter les inclusions multiples lorsque qu'un même fichier d'en-tête est inclus plusieurs fois, de manière directe ou indirecte, dans un autre fichier...

    Ici, tu te trouve dans le cadre, non pas d'une inclusion multiple, mais bien d'une inclusion circulaire:

    Arbre.h inclus foret.h, qui inclus Abre.h qui inclus...

    Le pire de l'histoire, c'est qu'on peut effectivement envisager le fait que, si la foret a réellement besoin de connaitre l'arbre, l'arbre ait effectivement besoin de connaitre la foret...(on parle de référence croisée entre deux classes)

    Par chance, il se fait que, si, pour définir ta classe Foret, tu peux - effectivement - avoir besoin de la définition de la classe Arbre, tu peux te contenter d'une déclaration anticipée de Foret pour définir la classe Arbre:

    La définition de Foret ne sera utile à Arbre que lorsque tu voudra accéder à des données de la foret au départ de l'arbre
    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

  5. #5
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Un arbre devra posséder une référence sur sa forêt.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    #ifndef _ARBRE_H
    #define	_ARBRE_H
     
    #include "foret.hpp"
     
    class Arbre{
          private :
                  Foret& foret;
     
          public :
                 Arbre(char *);
    };
    #endif	/* _ARBRE_H */

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par poukill Voir le message
    Un arbre devra posséder une référence sur sa forêt.
    Ou un pointeur, si l'on envisage le fait qu'un arbre puisse ne pas faire partie d'une foret ...

    (au fait, personne n'a remarqué l'horreur suivante dans le code SAKDOSS : )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class Arbre{
          private :
                  Foret foret(); //<<ouch
    Veux tu réellement déclarer une fonction privée nommée foret et renvoyant une instance de foret

    Cela me semble vraiment suspect
    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

  7. #7
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par koala01 Voir le message
    (au fait, personne n'a remarqué l'horreur suivante dans le code SAKDOSS : )
    Si, regarde mon code. J'ai mis une variable à la place de sa fonction !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par poukill Voir le message
    Si, regarde mon code. J'ai mis une variable à la place de sa fonction !
    Je voulais, en fait, dire que personne ne l'avait relevé
    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

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Points : 63
    Points
    63
    Par défaut
    Merci pour vos réponses.

    Je ne connaissais pas la déclaration anticipée. Et j'ai effectivement fait une erreur plutôt moche.


    Juste une petite question. J'obtient les deux fichiers .hpp que voici en suivant le lien de la FAQ sur la déclaration anticipée :

    arbre.hpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #ifndef _ARBRE_H
    #define	_ARBRE_H
     
    #include "foret.hpp"
     
    class Arbre{
          private :
                  Foret* foret;
     
          public :
                 Arbre(char *);
    };
    #endif	/* _ARBRE_H */
    foret.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
    #ifndef _FORET_H
    #define	_FORET_H
     
    class Arbre;
     
    class Foret {
    	private :
    	    Arbre* premierArbre;
    	    Foret* reste;
     
    	public:
    	    Foret();
     
    };
    #endif	/* _FORET_H */
    La ligne class Arbre; dans le fichier Foret.hpp me donne un peu l'impression de faire du bidouillage.

    Ca ne choque pas ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    J'aurais personnellement fait l'inverse:

    une déclaration anticipée de foret dans arbre.hpp et inclusion de arbre.hpp dans foret.hpp, voire, carrément, étant donné que les références circulaires sont toutes les deux des pointeurs, déclaration anticipée de "l'autre classe" dans les deux fichiers d'en-tête et inclusion des deux fichiers d'en-tête dans les fichiers d'implémentation

    Et, non, cela ne choque absolument pas...

    En effet, il faut faire la distinction entre la déclaration d'une classe et sa définition:

    La déclaration d'une classe (class MaClass; ) permet juste au compilateur qu'il existe une classe du nom indiqué (MaClass, en l'occurence), alors que la définition de la classe permet au compilateur d'en connaitre le contenu.

    Tant que le compilateur peut se contenter de savoir qu'une classe existe, la déclaration suffit

    Il peut s'en contenter si:
    • tu déclares une référence ou un pointeur sur un objet du type concerné et si
    • tu n'essaye pas d'accéder à l'un des membres ou à l'une des fonctions membres de la classe
    La raison est bien simple: un pointeur a une taille donnée (typiquement un nombre de bytes suffisant pour représenter l'ensemble des adresses mémoires accessibles), et une référence n'est - par définition - qu'un alias d'un objet existant par ailleurs, et n'utilise donc pas de mémoire propre (en réalité, si on regarde du coté du code assembleur généré, on se rend compte que c'est souvent géré comme un pointeur ) .

    Le compilateur est donc en mesure de déterminer précisément la taille qu'il doit prévoir pour permettre la représentation d'un pointeur ou d'une référence.

    Par contre, dés le moment où il s'agit de créer une instance de l'objet, ou d'accéder à un membre ou à une fonction membre de l'objet, le compilateur doit savoir quelle taille réserver en mémoire pour représenter l'objet et quel décalage appliquer, de l'adresse "de début" de l'objet, pour accéder au membre ou à la fonction membre que l'on souhaite exécuter: il a donc besoin de connaitre la totalité de la classe
    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

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Points : 63
    Points
    63
    Par défaut
    Daccord. Merci pour cette explication.

    Je vais effectivement utiliser la déclaration anticipée dans les deux classes.

    J'ai cependant encore un problème.

    Si par exemple dans la classe Arbre je veux ajouter une fonction qui retourne la Foret pointée par l'attribut "foret".
    Je suis obligé de faire retourner à la fonction le pointeur "foret" ?
    J'ai essayé de retourner directement la valeur pointée par "foret" et ça me met ce type d'erreur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    gcc -c arbre.cpp -o arbre.o
    arbre.cpp: In member function ‘Foret Arbre::getForet()’:
    arbre.cpp:4: erreur: return type ‘struct Foret’ is incomplete
    Ce n'était pas très claire, voici les deux classes que j'ai modifiées :

    arbre.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
    #ifndef _ARBRE_H
    #define	_ARBRE_H
     
    class Foret;
     
    class Arbre{
          private :
                  Foret* foret;
     
          public :
                 Arbre(char *);
    	     Foret getForet();
    };
    #endif	/* _ARBRE_H */
    arbre.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    #include "arbre.hpp"
     
    Arbre::Arbre(char* chemin) {}
    Foret Arbre::getForet(){return *foret;}
    Ma question est donc :
    Puis-je retourner la Foret pointée par "foret" ou suis-je obligé de ne retourner que le pointeur "foret" ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    L'idéal, c'est de renvoyer une... référence sur la foret, voire une référence constante sur la foret...

    Tu peux, bien sur, si tu le souhaites, renvoyer un pointeur sur foret, mais une chose est sur, si tu essaye de renvoyer une instance de foret, il faut la définition complete

    Les possibilités qui te sont offertes sont donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    /* soit tu renvoie un pointeur */
    Foret* getForet(){return foret;}
    /* soit tu renvoie une référence (constante ou non) sur la foret */
    Foret & getForet(){return *foret;}
    Foret const & getForet() const{return *foret;}
    /* !!! il faut prévoir de lancer une exception si, pour une raison ou 
     * une autre, le pointeur foret est à NULL
     */
    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

  13. #13
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2005
    Messages
    121
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2005
    Messages : 121
    Points : 63
    Points
    63
    Par défaut
    Ca marche.

    Merci bien pour l'aide, et surement à bientôt.
    Je pense que je serais amené à revenir sur ce forum dans les jours qui viennent...

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

Discussions similaires

  1. does not name a type
    Par emmesse dans le forum Débuter
    Réponses: 3
    Dernier message: 27/08/2014, 16h23
  2. error: ‘i1’ does not name a type
    Par JackStrieger dans le forum C++
    Réponses: 3
    Dernier message: 15/01/2014, 15h23
  3. [QtKeychain] 'Q_CORE_EXPORT_INLINE' does not name a type
    Par sliverTwist dans le forum Débuter
    Réponses: 18
    Dernier message: 06/03/2013, 15h45
  4. Colonne’ does not name a type
    Par tamtoum1987 dans le forum C++
    Réponses: 7
    Dernier message: 23/03/2012, 09h19
  5. error : does not name a type // je n'y comprends rien
    Par djobanaille dans le forum C++
    Réponses: 6
    Dernier message: 19/11/2005, 10h25

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