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 :

pb references croisées


Sujet :

C++

  1. #1
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

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

    Informations forums :
    Inscription : Février 2008
    Messages : 308
    Points : 622
    Points
    622
    Par défaut pb references croisées
    Salut!

    J'ai un problème avec des references croisées, des classes qui utilisent des fonctions l'une de l'autre de cette manière :
    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
    class ClassB;
     
    class ClassA
    {
          protected :
     
                    ClassB* p_classB;
     
          public :
     
                    ClassA();
                    ~ClassA();
     
                    void fonction_de_A();
     
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "ClassA.h"
     
    ClassA::ClassA(){
     
    }
     
    ClassA::~ClassA(){
     
    }
     
    void ClassA::fonction_de_A(){
        p_classB->fonction_de_B();
    }
    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 "ClassA.h"
     
    class ClassB
    {
          protected :
     
                    ClassA* classA;
     
          public :
     
                    ClassB();
                    ~ClassB();
     
                    void fonction_de_B();
     
    };
    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
    #include "ClassB.h"
     
    ClassB::ClassB(){
     
    }
     
    ClassB::~ClassB(){
    }
     
    void ClassB::fonction_de_B(){
     
    }
     
    void ClassB::une_autre_fonction_de_B(){
     
       classA->une_autre_fonction_de_A();
     
    }
    c'est une version simplifié, en réalité il 'y encore d'autre classes entre A et B (on pourrait dire que A utilise B qui utilise C qui utilise A...). On suppose aussi que les pointeurs sont bien initialisés hein ^^

    j'obtient le message suivant :
    error: invalid use of undefined type `struct ClassB'
    error: forward declaration of `struct ClassB'
    je suppose que c'est parce que la définition ne définit pas la fonction fonction_de_B() ???

    comment faire???

  2. #2
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Moi, ce que je fais, c'est

    B.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class A;
    class B
    {
    };
    A.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class B;
    class A
    {
    };
    B.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #include "B.h"
    #include "A.h"
    A.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #include "A.h"
    #include "B.h"

  3. #3
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    La déclaration anticipée de la classe B dans "ClassA.h" ne te dispense pas d'inclure "ClassB.h" dans ton fichier "ClassA.cpp"...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  4. #4
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

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

    Informations forums :
    Inscription : Février 2008
    Messages : 308
    Points : 622
    Points
    622
    Par défaut
    Merci beaucoup!!

    c'est un truck que j'ai déjà fait en plus, mais j'avoue que je m'embrouille toujours un peut avec les références croisées...

    tout marche nickel!!

  5. #5
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    D'ailleurs quelqu'un peut m'expliquer l'utilité d'inclure le .h d'une autre classe dans un fichier d'en-tête de classe ?

    Dans la FAQ aussi il y a ça, or si on ne fait que pointer ou référencé cette classe, dans le .h il est de trop, je trouve. Ca créera des problèmes avec les autres fichiers qui inclueront le fichier .h et il y aura parfois double inclusion si on fait pas attention.

    L'article de la FAQ: http://cpp.developpez.com/faq/cpp/?p...erence_croisee

    Il serait pas plus judicieux de toujours utiliser le forward déclaration dans un .h ?

  6. #6
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    D'ailleurs quelqu'un peut m'expliquer l'utilité d'inclure le .h d'une autre classe dans un fichier d'en-tête de classe ?
    D'avoir des entêtes complets, c'est à dire que ton CPP utilisateur (pas celui qui implémente le .H, celui qui l'UTILISE) ne requiert qu'un seul #include, et que forcément les contraintes d'ordre d'inclusion sont d'ores et déjà réglées par le développeur du module.
    Cela évite les erreurs absconses parce qu'il manque un entête étrange venu d'ailleurs, et qu'en plus, il faut l'inclure après un autre entête venu du même endroit.
    Cela peut avoir une importance assez énorme dans le cadre d'une bibliothèque plutôt volumineuse, afin d'assurer toutes les dépendances et/ou de simplifier l'utilisation de la librairie.

    Attention, toutefois : un entête complet ne veut pas dire un fourre-tout. Il doit contenir TOUS les entêtes dont il a spécifiquement besoin pour qu'il n'y aie AUCUNE déclaration manquante, mais il ne doit JAMAIS y avoir d'inclusions inutiles faites juste "par flemme" ! Si tu veux un entête "unique", alors on passe dans le registre des entêtes précompilés, et c'est totalement différent.

    Citation Envoyé par JulienDuSud Voir le message
    Il serait pas plus judicieux de toujours utiliser le forward déclaration dans un .h ?
    Non, parce que dans le cas de certaines déclarations de classes (notamment avec le code inline), tu te retrouverais à devoir inclure des entêtes qui, à priori, n'ont aucun rapport avec la choucroute.
    Typiquement, c'est un coup à vouloir utiliser une fonction A dans ta librairie, donc un entête "A.h", et à devoir inclure manuellement (et sans trop savoir pourquoi...) l'entête "Z.h" alors que tu te contrefiches de la fonction Z.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  7. #7
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Je vois ce que tu veux dire, mais je n'arrive pas à voir pourquoi cela poserait un problème, dans le sens où:

    Si B nécessite A dans une de ses méthodes publiques, l'utilisateur externe n'a pas forcément besoin d'inclure A, je vois pas où tu veux en venir...

    Si B renvoit A dans une de ses méthodes publiques, alors là oui, C (qui utilise B) aura besoin d'inclure A, mais vu qu'il utilisera A (qu'il récupère via la méthode de B), il est normal qu'il ait à l'inclure et que ça soit pas fait "magiquement". Car ça se trouve, il a juste besoin d'une référence vers cet objet, et ça sera idiot de l'obliger à tout recompiler en cas de modification de A.

    J'ai toujours fait comme ça dans mes projets, et je n'ai pas eu le genre de problèmes que tu décris: si j'utilises une classe, je l'inclus. Si j'ai besoin d'une référence, je la déclare.

  8. #8
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    J'ai toujours fait comme ça dans mes projets, et je n'ai pas eu le genre de problèmes que tu décris: si j'utilises une classe, je l'inclus. Si j'ai besoin d'une référence, je la déclare.
    Si tu fais effectivement ça, tu as des entêtes complets... Si par contre tu dépends de l'ordre d'inclusion au sein du CPP utilisateur (et, je répète, PAS celui d'implémentation), alors ils ne sont pas complets.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  9. #9
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    D'ailleurs quelqu'un peut m'expliquer l'utilité d'inclure le .h d'une autre classe dans un fichier d'en-tête de classe ?

    Dans la FAQ aussi il y a ça, or si on ne fait que pointer ou référencé cette classe, dans le .h il est de trop, je trouve. Ca créera des problèmes avec les autres fichiers qui inclueront le fichier .h et il y aura parfois double inclusion si on fait pas attention.

    L'article de la FAQ: http://cpp.developpez.com/faq/cpp/?p...erence_croisee

    Il serait pas plus judicieux de toujours utiliser le forward déclaration dans un .h ?
    Salut,
    Dans l'exemple de l'item de la F.A.Q que tu pointes, B.h inclut A.h car la classe B contient un membre de type A par valeur.
    Sinon, si une classe B ne présente une classe A qu'à travers des références ou des pointeurs, effectivement, une déclaration anticipée suffit.

    Citation Envoyé par JulienDuSud Voir le message
    Si B renvoit A dans une de ses méthodes publiques, alors là oui, C (qui utilise B) aura besoin d'inclure A, mais vu qu'il utilisera A (qu'il récupère via la méthode de B), il est normal qu'il ait à l'inclure et que ça soit pas fait "magiquement". Car ça se trouve, il a juste besoin d'une référence vers cet objet, et ça sera idiot de l'obliger à tout recompiler en cas de modification de A.
    Il faut faire attention de ne pas aller à l'encontre de la loi de DEMETER. Schématiquement, une méthode de la classe A ne devrait pas utiliser les méthodes de la classe C d'une instance obtenue via un paramètre ou un membre interne (sauf s'il s'agit d'une création) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void A::methode(B b_)
    {
        C &c = b_.get_some_c();
        c.do_something();// violation de demeter
    }

  10. #10
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Dans l'exemple de l'item de la F.A.Q que tu pointes, B.h inclut A.h car la classe B contient un membre de type A par valeur.
    Sinon, si une classe B ne présente une classe A qu'à travers des références ou des pointeurs, effectivement, une déclaration anticipée suffit.
    Ah juste, j'avais pas fait gaffe.

    En fait c'est le problème de l'OP qui m'a choqué, et j'ai même pas lu la FAQ croyant que c'était ce qu'il reprenait (ce qu'il a fait d'ailleurs... même si pour moi c'est pas bien de le faire quand on a que des références).

    Loi de Demeter
    Je suis tout à fait d'accord sur le principe de cette loi, mais en pratique je la trouve irréalisable.

    Même en admettant que les listes et assimilés (et leurs contenu) ne forment qu'un seul objet (mais 2 indirections), cette loi est bien trop restrictive et amène souvent à de la redondance de code au niveau de la classe passerelle vis à vis de la classe source. D'ailleurs, en pratique cela donne trop de responsabilités à une classe.

    Mais on change de sujet, mais je serais ravis de discuter de cette loi et de sa pertinence dans un gros projet, si tu le veux.

  11. #11
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    Même en admettant que les listes et assimilés (et leurs contenu) ne forment qu'un seul objet (mais 2 indirections), cette loi est bien trop restrictive et amène souvent à de la redondance de code au niveau de la classe passerelle vis à vis de la classe source. D'ailleurs, en pratique cela donne trop de responsabilités à une classe.
    La suite sur demeter ici.

  12. #12
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2008
    Messages
    308
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France

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

    Informations forums :
    Inscription : Février 2008
    Messages : 308
    Points : 622
    Points
    622
    Par défaut
    Citation Envoyé par JulienDuSud Voir le message
    En fait c'est le problème de l'OP qui m'a choqué, et j'ai même pas lu la FAQ croyant que c'était ce qu'il reprenait (ce qu'il a fait d'ailleurs... même si pour moi c'est pas bien de le faire quand on a que des références).
    le code que je donne ne sort pas de la FAQ, j'ai juste reproduit la structure de mes classe en simplifiant et en changeant les noms...

    Citation Envoyé par JulienDuSud Voir le message
    Je suis tout à fait d'accord sur le principe de cette loi, mais en pratique je la trouve irréalisable..
    je ne pense pas que ça soit irréalisable, se forcer a suivre cette loi n'est pas plus compliqué que de ne pas utiliser de variables globales. le code est parfois beaucoup plus compliqué mais globalement je pense que ça simplifie les choses.

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

Discussions similaires

  1. [Toutes versions] References croisée des objets utilisés
    Par dumas.blr dans le forum Modélisation
    Réponses: 3
    Dernier message: 14/09/2013, 14h25
  2. Réponses: 1
    Dernier message: 08/02/2010, 19h56
  3. Includes croises et forward reference
    Par kitsune dans le forum MFC
    Réponses: 7
    Dernier message: 11/09/2007, 07h48
  4. Requète croisée et affichage
    Par BakaOnigiri dans le forum SQL
    Réponses: 2
    Dernier message: 31/10/2002, 12h28
  5. [VB6]Passage par référence d'une prop. d'objet à une fct
    Par -gYs- dans le forum VB 6 et antérieur
    Réponses: 15
    Dernier message: 02/09/2002, 09h55

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