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++

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    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 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,

    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 averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    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 émérite
    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
    Points : 2 799
    Points
    2 799
    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 : 61
    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
    Points : 50 367
    Points
    50 367
    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
    En attente de confirmation mail
    Inscrit en
    Octobre 2007
    Messages
    285
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : Octobre 2007
    Messages : 285
    Points : 348
    Points
    348
    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 averti Avatar de Trunks
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2004
    Messages
    534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    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 émérite
    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
    Points : 2 799
    Points
    2 799
    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...

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    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...
    Je suis d'accord avec toi.
    Mon erreur avait été de réduire mon exemple au minimum (j'ai mis qu'une variable au lieu d'un vecteur) et de croire que l'objet est construit à la fin du constructeur alors qu'il l'est à la fin de la liste des initialisateurs.

    Comme quoi, je continue d'apprendre encore et toujours

    Je vais essayer, mais normallement ça devrait marcher

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Bon ça marche, le seul truc est qu'apparemment je dois réécrire l'opérateur = sinon:

    Compiling...
    main.cpp
    A.cpp
    B.cpp
    c:\program files\microsoft visual studio\vc98\include\xutility(39) : error C2582: 'A' : 'operator =' function is unavailable
    c:\program files\microsoft visual studio\vc98\include\vector(170) : see reference to function template instantiation 'void __cdecl std::fill(class A *,class A *,const class A &)' being compiled
    c:\program files\microsoft visual studio\vc98\include\xutility(25) : error C2582: 'A' : 'operator =' function is unavailable
    c:\program files\microsoft visual studio\vc98\include\vector(174) : see reference to function template instantiation 'class A *__cdecl std::copy_backward(class A *,class A *,class A *)' being compiled
    Generating Code...
    Error executing cl.exe.
    Il n'est pas capable de le faire automatiquement? (car je recopie seulement les données membres, ici m_rB)
    Du coup ça donne:

    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
    #ifndef B_H
    # define B_H
     
    # include "A.h" 
    # include <vector>
     
    class B 
    {
    public:
    	B(int val);
     
    	void Display() const;
     
    private:
    	std::vector<A> m_va;
    	int m_val;
    };
     
    #endif /* !B_H */
    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 "B.h" 
    #include <iostream>
     
    B::B(int val) :
    	m_val(val)
    {
    	A a(*this);
    	m_va.push_back(a);
    }
     
    void B::Display() const
    {
    	std::cout << "I'm B: " << m_val <<std::endl;
    }
    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
    #ifndef A_H
    # define A_H
     
    class B; 
     
    class A 
    {
    public:
    	A(B& b);
     
    	A& operator=(const A& a);
    	void Display() const;
     
    private:
        B& m_rB; 
    }; 
     
    #endif /* !A_H */
    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
    #include "A.h" 
    #include "B.h" 
    #include <iostream>
     
    A::A(B& b) :
    	m_rB(b)
    {
    	Display();
    }
     
    A& A::operator=(const A& a)
    {
    	this->m_rB = a.m_rB;
    	return *this;
    }
     
    void A::Display() const
    {
    	std::cout << "I'm A" << std::endl;
     
    	m_rB.Display();
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    #include "B.h"
     
    int main()
    {
    	B b(7);
     
    	return 0;
    };

  11. #11
    Membre émérite
    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
    Points : 2 799
    Points
    2 799
    Par défaut
    L'opérateur = par défaut n'est pas défini si tu as un membre de type référence (je ne sais plus la raison exacte, par contre).

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par white_tentacle Voir le message
    L'opérateur = par défaut n'est pas défini si tu as un membre de type référence (je ne sais plus la raison exacte, par contre).
    Ok, merci à vous tous comme d'habitude le thread m'auras appris à apprendre de nouvelles choses

    Problème résolu

  13. #13
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Citation Envoyé par JeromeBcx Voir le message
    Ou pour reprendre une phrase clé d'un de mes anciens professeurs :

    A méditer...
    Si tu es le créateur des deux classes et que tu sais que le constructeur ne fait qu'initialiser une référence, il n'y a aucun problème.
    J'ai assez souvent fait ça pour certaines classes, notamment quand l'une était contenue par valeur :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class B;
     
    class A
    {
    	B& parent;
    public:
    	A(B& parent) ; parent(parent) {}
    };
     
    class B
    {
    	A a;
     
    	B() : a(*this) {}
    };
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Si tu es le créateur des deux classes et que tu sais que le constructeur ne fait qu'initialiser une référence, il n'y a aucun problème.
    J'ai assez souvent fait ça pour certaines classes, notamment quand l'une était contenue par valeur
    Donc tu ignores le warning car tu sais que tu utilisation est correcte.
    Le truc qui me dérangeait dans cette implémentaton (juste une variable et non un vecteur comme vu plus tard dans le thread) était l'affichage du warning. Car on a tendance à dire qu'un programme ne devrait pas contenir de warning s'il a été corretement implémenté.

  15. #15
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    C'est là qu'apparait une merveille de Visual, les pragmas sur les warnings.
    Tu entoures explicitement le constructeur en question avec les pragmas suivants:
    Code C : 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
    class B;
     
    class A
    {
    	B& parent;
    public:
    	A(B& parent) ; parent(parent) {}
    };
     
    class B
    {
    	A a;
     
    	//Empile les réglages courants pour les warnings
    	#pragma warning(push)
    	//Désactive le warning pour "this"
    	#pragma warning(disable:4355)
     
    	B() : a(*this) {}
     
    	//Et on restaure les anciens réglages!
    	#pragma warning(pop)
    };
    L'avantage, c'est que si on a this dans n'importe quel autre constructeur, on aura le warning.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Merci pour ta réponse. Car pour l'implémentation en question, selon moi c'est la manière la plus propre de faire.

    Par contre ça ne marche que sur VC++, sur un autre IDE ou un autre compilateur, j'aurais toujours le warning.

    Mais bon, tant que l'implémentation est la plus cohérente possible, le warnin devrait être acceptable.

  17. #17
    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'ai "décroché" à la lecture de toutes les réponses, donc, il faudra m'excuser si la solution a déjà été proposée... Mais:

    Un pion peut parfaitement n'être sur aucune case (s'il a été pris, par exemple) et le pion ne devrait à l'extrême limite discuter qu'avec le damier.

    De son coté, une case ne doit savoir que s'il y a un pion dessus (éventuellement la couleur du pion) et ne doit aussi discuter qu'avec le damier...

    Dés lors, pourquoi ne pas partir sur un design proche du mediateur

    Je m'explique:

    Le pion n'appartient pas au damier, il appartient... au joueur. (pour être complet: deux joueurs ont chacun leurs pions et interviennent sur le damier dans une partie)

    Ce qui importe au pion, c'est:
    1. De connaitre sa couleur
    2. de savoir s'il est sur une case, et, si oui, les coordonnées de cette case
    3. D'être tenu au courent de son dépalcement
    4. de savoir si, par hasard, ce ne serait pas une dame


    La logique veut que ce soit le joueur qui "a la main" au... damier de bouger un pion précis vers une case précise

    C'est le... damier qui vérifie d'abord si le déplacement est conforme (respect des diagonales), et qui se charge de demander (en respectant les règles de déplacement) à chaque case sur lesquelles le pion devrait passer si la case accepte d'être "traversée" et à la case de destination si... elle accepte de recevoir le pion... et, si tout est OK, de donner sa nouvelle position au pion, en modifiant l'état des différentes cases traversées.

    De son coté, la case doit "simplement" savoir s'il y a un pion sur elle et la couleur de celui-ci:

    Le... damier peut lui poser deux questions:
    1. Un pion de <telle couleur> peut-il passer au dessus de toi?
    2. Un pion peut-il venir sur toi

    A la première question, elle répond oui si il y a un pion de la couleur adverse sur elle
    A la deuxième, elle répond oui si il n'y a pas de pion sur elle
    et peut lui donner deux ordres:
    1. Considère que tu as un pion de <telle couleur> sur toi
    2. considère qu'il n'y a pas de pion sur toi

    Au premier ordre, elle se place dans un état où elle sait qu'elle a un pion de <telle couleur> sur elle, et au deuxième, elle se place dans un état où elle sait qu'elle est libre

    Enfin, les pions sont "donnés" au joueur, sans qu'il soient sur le damier, et c'est le joueur qui se charge "d'enregistrer" ses pions auprès de ce dernier qui... leur assigne leur case de départ...

    Au final, tu aurais quelque chose ressemblant à:
    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
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    enum Couleur
    {
        Noir,
        Blanc,
        Aucun // pour permettre à la case de répondre à la question de
                 // savoir si il y a une piece sur elle
    };
    struct Coordonnee
    {
        int posX;
        int posY;
        Coordonnee():posX(),posY(){}
    };
    class Pion
    {
        public:
            Pion(Couleur coul):coul(coul),coord()
            Coordonnee& const coordonnee() const{return coord;}
            void setCoordonnee(int ligne, int colonne)
            {
                coord.posX = ligne;
                coord.posY = colonne;
            }
        private:
            Coordonnee coord;
    }
    class Case
    {
        public:
            Case(int ligne, int colonne):coul(Aucun), coord(ligne, colonne){}
            void setCouleur(Couleur c){coul=c;}
            bool AccepteSurvol(Couleur c) const 
            {return (coul!=Aucun && c!=coul);}
            bool AccepteArrivee() const {return coul==Aucun;}
            Coordonnee const & coorodonnee() const{return coord;}
        private:
            Couleur coul;
            Coordonnee coord;
            /* la gestion de la coordonnée d'une case n'est peut 
             *etre pas nécessaire
             */
    };
    bool AtCoord(Pion const & p, Coordonnee const& c)
    {return p.coordonnee().posX==c.posX && p.coordonnee().posY==c.posY;}
    class Joueur
    {
        public:
            Joueur(Couleur coul, Damier* dam):coul(coul), dam(dam)
            {
                 // je crois qu'il y a 12 pions par joueur... 
                 // à modifier si c'est un autre nombre
                 for(int i= 0; i<12:++i) 
                     pions.push_back(Pion(coul));
                 dam->register(pions, coul);
            }
            bool deplace(Coordonnee const& depart, coordonnee const & arrivee)
            {
                /* 1- recherche du pion se trouvant sur depart... renvoie 
                 *    false si non trouvé
                 */
                return dam->Move(adresse_pion_trouve,arrivee)
            }
        private:
            Damier* dam;
            std::vector<Pion> pions;
    }
    class Damier
    {
        public:
            Damier()
            {
                // je crois que c'est 8 cases sur 8
                for(int ligne = 1;ligne <9;++ligne ) 
                    for (int colonne j = 1;i<9;++i)
                        cases.insert(
                        std::make_pair(std::make_pair(ligne,colonne),
                                             Case(ligne, colonne))):
            }
            void register(std::vector<Pion> tab)
            {
                /*placement des pions sur l'échiquier et enregistrement des pions*/
            }
            bool Move(Pion * p, Coordonnee const & arrivee)
            {
               /* 1- vérification du trajet 
                * 2- dépalcement du pion
                * 3- "désenregistrement" des pions bouffés
                * renvoie faux si le mouvement n'est pas accepté, vrai s'il 
                * a pu avoir lieu
                */
            }
        private:
            std::map<std::pair<int, int>,Case) cases;
            std::vector<Pion*> pions;
            void unregister(Pion* p)
            {
                /* 1- signale au pion qu'il n'est plus sur une case */
                p->setCoordonnee(0,0)
                /* 2- recherche et suppression du pointeur du vecteur (sans
                 * désallocation)
                 */
            }
     
    };
    [EDIT]J'oubliais de présenter la classe "partie"... Elle dispose d'un damier, de deux joueurs et s'occupe de gérer le déroulement du jeu
    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

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

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2004
    Messages : 534
    Points : 412
    Points
    412
    Par défaut
    Citation Envoyé par koala01 Voir le message
    J'ai "décroché" à la lecture de toutes les réponses, donc, il faudra m'excuser si la solution a déjà été proposée...
    En occurrence, oui la solution m'a été donné (d'où le caractère résolu).

    Cependant, tu m'as donné une autre manière de concevoir le déroulement du jeu et cette dernière est bien plus simple par rapport à celle que j'avais imaginée, j'avais pas mal de références croisées.
    Mon pion communiquait avec la case, du coup la case (pour avoir les coordonnées) devait communiquer avec le damier.

    Pour celà, je te remercie
    Je vais revoir ma conception

  19. #19
    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 Trunks Voir le message
    En occurrence, oui la solution m'a été donné (d'où le caractère résolu).
    Hehé... une chance que j'avais présenté mes excuses anticipées
    Cependant, tu m'as donné une autre manière de concevoir le déroulement du jeu et cette dernière est bien plus simple par rapport à celle que j'avais imaginée, j'avais pas mal de références croisées.
    Mon pion communiquait avec la case, du coup la case (pour avoir les coordonnées) devait communiquer avec le damier.

    Pour celà, je te remercie
    Je vais revoir ma conception
    Encore une fois, ma signature a raison
    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

+ 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