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

Langage C++ Discussion :

Double inclusion mais une seule possible.


Sujet :

Langage C++

  1. #1
    Membre régulier Avatar de Sahengette
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 94
    Points
    94
    Par défaut Double inclusion mais une seule possible.
    Bonjour,
    je suis face à un problème :
    J'ai une classe A, qui fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    #ifndef A_HPP
    #define A_HPP
    //A.hpp
    class A
    {
    /*...*/
    }
    #endif
    Et je veux l'utiliser dans mon main
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include "A.hpp"
    int main()
    {
    /* ... */
    return 0;
    }
    Donc ca, super ca fonctionne.

    Maintenant j'ai une deuxieme classe, B, qui a besoin de A :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    //A.hpp
    #include "A.hpp"
    class B {
    private : 
       A m_ObjetA;
    };
    Et ca ne marche pas, c'est normal, le main inclut déjà une fois A et la protection anti-multi-inclusions empêche d'inclure plus d'une fois.
    La seule solution est d'enlever la protection, mais dés que je l'enleve, ca ne marche plus car dans mon programme la classe A est*en collision avec une autre classe et ca crée une inclusion en boucle ...

    Comment je dois faire pour inclure A dans B sans casser la protection anti inclusions multiples ?

    Merci

  2. #2
    Membre éprouvé
    Avatar de mitkl
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2010
    Messages
    364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2010
    Messages : 364
    Points : 1 081
    Points
    1 081
    Par défaut
    tu devrais largement t'en sortir grâce aux forward declarations : http://cpp.developpez.com/faq/cpp/?p...TES_ou_inclure
    Si vous ne savez toujours pas ce qu’est la récursivité, relisez cette phrase.

    Mon blog sur la programmation et l'informatique !

  3. #3
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Inutile, il n'y a pas de cycle, là.

    Normalement, ça devrait marcher sans problème.
    As-tu essayé de compiler ce que tu nous a montré comme code ?

  4. #4
    Membre régulier Avatar de Sahengette
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 94
    Points
    94
    Par défaut
    Oui mais j'ai expliqué qu'il y a une autre classe, qui elle crée un cycle infini avec B, donc imposible d'enlever la protection, et les forwards declarations sont insuffisantes car je veux une instance de l'objet avec toutes ces méthodes, quand je compile j'ai une erreur :
    erreur: field ‘m_ObjetA’ has incomplete type

  5. #5
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Est-ce qu'on pourrait avoir le code des classes, même en exemple ?
    Parce que donner en exemple un code qui fonctionne, ça n'aide pas à comprendre le problème ...

  6. #6
    Membre régulier Avatar de Sahengette
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 94
    Points
    94
    Par défaut
    J'ai une classe Shader une classe Renderer et le main :
    Shader a besoin de Renderer car Shader déclare Renderer comme classe amie.
    Renderer a besoin de Shdaer car un de ses attributs est un Objet Shader.
    Dans le main pour l'instant j'utilise seulement la classe Shader, donc j'ai seulement l'include pour l'en tete des shaders (j'experimente encore la classe Renderer), je cherche une solution donc pour inclure deux fois Shader (dans le main et dans l'en tete de Renderer), et parceque plus tard je serais forcement confronté à ce problème car ma classe Shader tendera à être utilisé dans beaucoup d'endroit, donc beaucoup d'inclusions nécessaires, mais une seule possible.

  7. #7
    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,

    Je suis désolé, mais, tel que tu présentes le code, je ne vois pas où il peut y avoir d'inclusion cyclique!!!

    Et, dans ce cas, l'inclusions de A.hpp et de B.hpp dans main.cpp ne posera aucun problème


    Si inclusion cycllique il y a, il faut:
    1. t'assurer qu'il soit cohérent d'envisager que toutes les classes connaissent effectivement les autres
    2. recourir pour toutes les classes aux déclaration anticipées des autres dans leur fichier d'en-tête (*.hpp)
    3. inclure le fichier d'en-tête des autres classes uniquement dans le fichier d'implémentation (*.cpp)
    4. veiller à n'utiliser que des pointeurs et / des références vers les autres classes dans le fichier d'en-tête
    5. veiller à ce que la définition de toute fonctions qui doit avoir connaissance des autres classes se trouve dans le fichier d'implémentation

    Voici un exemple de quatre classes (A, B, C et D) n'ayant aucun lien d'héritage entre elles, et devant chacune connaitre les autres:
    A.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
    30
    31
    32
    33
    34
    35
    36
    37
    #ifndef A_HPP
    #define A_HPP
    class B;
    class C;
    class D;
    class A
    {
        public:
            /* sont autorisées les implémentations des fonctions qui n'ont 
             * pas besoin de connaitre les autres classes, comme
             */
            void setB(B* toset){myB = toSet;}
            B* retunBpointer(){return myB;}
            B const & returnBconstRef() const{return *myB;}
            /* sont autorisée les déclarations des fonctions qui mainipule des
             * pointeurs ou des référence vers les autres classes, mais qui ont
             * besoin de connaitre la classe en question : l'implémentation
             * devra se trouver dans le fichier d'implémentation ( A.cpp)
             */
             void useCpointer(C * touse) /* const */;
             void useDref( D /* const */ & ) /* const */;
             /* sont interdites : les fonction qui manipulent les objet directement
              * par valeur (par opostion à par pointeur et ou par référence)
              *  
              * décommente ceci et ta compilation échouera :D
              *
              */
               // B getB()/* const */{return myB;}
               // void useC( C touse) ;
               // void useD( D touse); 
               // C useDreturnsC( D touse) ;
        private:
            B  * myB;
            C  * myC;
            D  * myD;
    };
    #endif // A_HPP
    A.cpp
    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
     
    /* l'inclusion de la déclaration de A */
    #include <A.hpp>
    /* pour pouvoir utiliser B, C et D */
    #include <B.hpp>
    #include <C.hpp>
    #include <D.hpp>
    void A::useCpointer(C * touse) /* const */
    {
        touse->doSomething(/* params */ );
    }
    void A::useDref( D /* const */ & touse ) /* const */
    {
        touse.doTruc(/* params */ );
    }
    B.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
    /* rien n'empêche de manipuler une collection de pointeur  sur une autre
     *  classe ... Tant que l'on respecte les règles :d
     */
    #ifndef B_HPP
    #define B_HPP
    #include <vector>
    class A;
    class C;
    class D;
    class B
    {
        typedef std::vector<C*> vector; // par facilité uniquement :D
         public:
            typedef typename vector::iterator iterator; // idem
            typedef typename vector::const_iterator const_iterator; // idem
            /* tant que l'on n'a pas besoin de connaitre le contenu de  C,
             * on peut l'utiliser ici
             */
             void addC( C* toadd) {items_.push_back(toadd);}
             iterator begin(){return items_.begin();}
             /* mais si l'on doit connaitre le contenu de C, il faut le faire dans B.cpp
             */
            const_iterator find(std::string const & toFind) const;
        private:
            vector items_; 
            C * myC;
            D * myD;
    };
    #endif // B_HPP
    B.cpp
    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
     
    #include <B.hpp>
    #include <A.hpp>
    #include <C.hpp>
    #include <D.hpp>
     
    B::const_iterator find(std::string const & toFind) const
    {
        const_iterator it = items_.begin();
        while(it!=items_.end())
        {
            if(it->name() == toFind)
                return it;
        }
        return items_.end();
    }
    les fichiers pour C et D seraient à l'avenant

    Nota: L'inclusion cyclique peut etre difficile à surprendre :
    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
    class A
    {
        private:
            D * myD;
    };
    class B
    {
        private:
            A * myA;
    };
    class C
    {
        private:
            B * myB;
    };
    class D
    {
        private:
            C * myC;
    };
    il n'est pas inutile d'envisager une erreur de conception dans ce cas là, car, hors cas particulier, ce sera souvent le cas
    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

  8. #8
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Citation Envoyé par Sahengette Voir le message
    Shader a besoin de Renderer car Shader déclare Renderer comme classe amie.
    Non, Shader.h n'a pas besoin d'inclure Renderer.h, car une déclaration d'amitié agit comme une déclaration anticipée implicite.

    Code Shader.h : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    #ifndef _SHADER_H_
    #define _SHADER_H_
     
    class Shader
    {
       friend class Renderer; // OK!
    };

  9. #9
    Membre régulier Avatar de Sahengette
    Homme Profil pro
    Inscrit en
    Octobre 2011
    Messages
    79
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Octobre 2011
    Messages : 79
    Points : 94
    Points
    94
    Par défaut
    Vous avez tous raison, en fait il n'y a pas de solution car il n'y a pas de problème .
    Shader n'a pas besoin de Renderer, par contre mon compilateur refuse que je le fasse sans déclaration anticipée :
    erreur: déclaration amie ne nomme pas une classe ou une fonction
    c'est normal ?

  10. #10
    Membre éclairé
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Points : 879
    Points
    879
    Par défaut
    Il faut bien marquer "friend class XXX".
    Enfin, je suppose que l'erreur vient de là, mais comme nous n'avons toujours pas le code ...

Discussions similaires

  1. Appel de plusieurs pages .js, mais une seule exécutée.
    Par andyroddick dans le forum Général JavaScript
    Réponses: 21
    Dernier message: 02/07/2010, 16h17
  2. Réponses: 11
    Dernier message: 22/04/2008, 15h32
  3. [WPF-Blend] Plusieurs objets mais une seule animation
    Par Tuizi dans le forum Framework .NET
    Réponses: 12
    Dernier message: 11/12/2007, 17h10
  4. 3 tables liées mais une seule ligne de retour ?
    Par seb_perl dans le forum Requêtes
    Réponses: 2
    Dernier message: 06/01/2007, 12h20

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