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 :

2 classes qui font référence l'une à l'autre


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Par défaut 2 classes qui font référence l'une à l'autre
    J'ai 2 classes qui font référence l'une de l'autre, comme l'exemple ici.

    La classe B contient un objet de type A et la classe A contient un pointeur de type B. Je veux initialiser le pointeur de type B de la classe A lors de la création de l'objet B. Je fais donc ainsi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    B::B() :
    	a(this)
    {
    }
    Et ca m'affiche un warning:

    warning C4355: 'this' : used in base member initializer list
    Ce warning signale que tant que B n'a pas été construit totalement, A ne peut pas faire appel à une fonction de B sous peine de risque de plantage.
    A peut donc appeler une fonction de B qu'en dehors de son constructeur (peut-être que je ne pense pas à un cas de figure et que ça peut planter d'une autre manière).
    Ce qui donne:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    B b;
    b.GetA().DoSomething();
    Cependant le warning me gène même si j'aurais envie de l'écrire de cette manière, faire le lien dès la construction de l'objet. Il vaut mieux faire le lien en 2 temps?
    Du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    B b;
    b.InitA();
    b.GetA().DoSomething();
    Dans ce cas là, je ne peux pas mettre comme membre de A une référence de B (ce qui est plus propre à mon goût).

    Des commentaires?

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    En fait, ce n'est pas dans le constructeur que tu ne peux pas utiliser this, mais dans la liste d'initialisation...

    En effet, tant que tu est dans la liste d'initialisation, l'objet en cours de construction n'existe pas encore, et c'est normal: tous ses membres ne sont pas encore construits.

    Par contre, une fois que tu as passé l'accolade ouvrante, this est pleinement fonctionnel

    Cela signifie que tu dois créer ton constructeur de B sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    B::B():_a() // appel du constructeur de défaut construction pour _a
    {
        _a.setParent(this); //si pas d'amitié entre A et B
        /* ou, s'il y a amitié
        _a.b = this;
        */
    }
    Maintenant, étant donné que tu es dans le cadre d'une aggrégation, ta variable _a n'existe que... tant que la variable de type B existe.

    Dés lors, ne serait il pas opportun de "déléguer" l'invocation des différents comportements de _a à la classe B, de manière à ne pas devoir demander l'acces à _a, et donc, d'être toujours en mesure de travailler avec ton objet de type B (et surtout, ne pas devoir "récupérer" ton B au départ de ton A)
    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

  3. #3
    Membre éclairé Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Cela signifie que tu dois créer ton constructeur de B sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    B::B():_a() // appel du constructeur de défaut construction pour _a
    {
        _a.setParent(this); //si pas d'amitié entre A et B
        /* ou, s'il y a amitié
        _a.b = this;
        */
    }
    Je voulais dire dans le constructeur de A. Du style:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    A::A(B* pB) :
    	m_pB(pB)
    {
    	pB->Display(); // Erreur car B n'a pas fini d'être construit
    }
    Citation Envoyé par koala01 Voir le message
    Maintenant, étant donné que tu es dans le cadre d'une aggrégation, ta variable _a n'existe que... tant que la variable de type B existe.

    Dés lors, ne serait il pas opportun de "déléguer" l'invocation des différents comportements de _a à la classe B, de manière à ne pas devoir demander l'acces à _a, et donc, d'être toujours en mesure de travailler avec ton objet de type B (et surtout, ne pas devoir "récupérer" ton B au départ de ton A)
    Dans mon cas je voudrais justement travailler sur des A.

    Un exemple concret: A = case et B = damier

    Le pion sait sur quelle case il se trouve (pointeur ou référence sur un case). A partir de là, je veux déplacer mon pion sur le damier. D'où l'intéret de l'implémentation décrite ci-dessus.

  4. #4
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Je ne comprends pas bien ta conception.

    Je suppose que l'objet damier existe déjà.

    Admettons que tu as un objet case (je ne suis pas sûr qu'un objet case soit nécessaire), cette case peut très bien ne pas avoir de pion dessus.

    En fait, ce que tu veux, c'est qu'un pion soit toujours sur une case. Mais l'idée que pion construise une case me paraît étonnante.

    Je verrais plutôt les choses dans cet ordre :
    - je crée mon objet damier
    - je lui ajoute une case
    - le cas échéant, je crée un pion sur cette case. Comme cette case existe déjà, je la passe au constructeur de pion, et je n'ai pas de problème.

    Après, pour le message du compilateur, c'est un warning. Tu ne fais rien de mal, tant que tu n'utilises pas le this dans le constructeur appelé. Mais comme tu peux être sûr que quand quelqu'un reprendra ton code, il fera n'importe quoi en ne faisant pas attention, ce warning me semble légitime .

  5. #5
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Après, pour le message du compilateur, c'est un warning.
    J'aime pas les warnings. Bien souvent, il ont tendance à mettre en évidence un bug futur.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  6. #6
    Membre expérimenté
    Inscrit en
    Octobre 2007
    Messages
    285
    Détails du profil
    Informations personnelles :
    Âge : 44

    Informations forums :
    Inscription : Octobre 2007
    Messages : 285
    Par défaut
    Citation Envoyé par ram-0000 Voir le message
    J'aime pas les warnings. Bien souvent, il ont tendance à mettre en évidence un bug futur.
    Ou pour reprendre une phrase clé d'un de mes anciens professeurs :
    Un warning est une erreur en puissance
    A méditer...

  7. #7
    Membre éclairé Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    Je ne comprends pas bien ta conception.

    Je suppose que l'objet damier existe déjà.

    Admettons que tu as un objet case (je ne suis pas sûr qu'un objet case soit nécessaire), cette case peut très bien ne pas avoir de pion dessus.

    En fait, ce que tu veux, c'est qu'un pion soit toujours sur une case. Mais l'idée que pion construise une case me paraît étonnante.

    Je verrais plutôt les choses dans cet ordre :
    - je crée mon objet damier
    - je lui ajoute une case
    - le cas échéant, je crée un pion sur cette case. Comme cette case existe déjà, je la passe au constructeur de pion, et je n'ai pas de problème.

    Après, pour le message du compilateur, c'est un warning. Tu ne fais rien de mal, tant que tu n'utilises pas le this dans le constructeur appelé. Mais comme tu peux être sûr que quand quelqu'un reprendra ton code, il fera n'importe quoi en ne faisant pas attention, ce warning me semble légitime .
    Je crée exactement dans le même ordre que tu as décris:
    - Je crée mon damier
    - Je lui ajoute toutes les cases qu'il lui faut
    - Je crée mes pions que je pose sur un case (le pion a une référence sur la case)

    Je veux travailler au niveau des pions (ce qui me paraît le plus logique). Donc mon pion récupère un pointeur vers la case sur laquelle elle se trouve. C'est donc pour ça que ma case doit également avoir un pointeur vers le damier pour faire sers déplacements et tout ce qui s'en suit. J'aurais d'ailleurs préféré une référence vu qu'une case est un élément du damier et que ça en changera pas, mais vu le problème décrit dans le topic, la référence n'est pas possible sans warning.

    Citation Envoyé par JeromeBcx Voir le message
    Ou pour reprendre une phrase clé d'un de mes anciens professeurs :

    A méditer...
    Oui, il suffit qu'un jour quelqu'un reprenne le code et fait appel à une fonction de B dans une fonction qui s'exécute dans le constructeur de A, alors c'est le plantage assuré.

    Je pense que je vais donc passer par le pointeur au lieu d'une référence:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Case
    {
    private:
        //Damier& m_rDamier;  // A supprimer
        Damier* m_pDamier;
    };
    et dans le constructeur de Damier, initialiser la référence sur lui même dans la Case comme Koala m'a conseillé au début du topic.

    Edit:

    Quoiqu'il en soit, bien sûr que je ne peux appeler une méthode de Damier qu'après le constructeur de Case.

  8. #8
    Membre Expert
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Par défaut
    Pourquoi tu as besoin de construire les cases dans la liste d'initialisation du constructeur de damier ?

    Surtout, ça m'étonne, parce qu'un damier a plusieurs cases... J'imagine que les cases d'un damier sont stockées dans un vector ou similaire. Et que du coup, au moment où tu les crées, le damier existe déjà et qu'il n'y a pas de problème.

    Ou alors, j'ai encore loupé un truc...

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

Discussions similaires

  1. classes qui font référence l'une à l'autre
    Par hbenji dans le forum C++
    Réponses: 2
    Dernier message: 03/03/2013, 21h57
  2. [XL-2003] Liste des cellules qui font référence à une cellule donnée
    Par CUCARACHA dans le forum Macros et VBA Excel
    Réponses: 1
    Dernier message: 03/02/2010, 16h29
  3. Réponses: 2
    Dernier message: 24/06/2009, 12h30
  4. Réponses: 3
    Dernier message: 08/12/2007, 13h52
  5. Réponses: 10
    Dernier message: 27/03/2007, 20h19

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