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 :

Problème conception : contourner les pointeurs ?


Sujet :

C++

  1. #1
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2012
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2012
    Messages : 24
    Points : 17
    Points
    17
    Par défaut Problème conception : contourner les pointeurs ?
    Bonjour à tous,

    Voilà je vous écris car j'ai un petit soucis de conception...

    Je veux créer un plateau de jeu générique qui pourrait s'adapter à différents jeux. Celui-ci est représenté par un vecteur de type template T : vector<T>.

    Petit souci : comment tester si une case de plateau est occupée ou non ? La seule idée qui me vient en tête c'est d'au lieu d'utiliser un vecteur d'objet je ferais mieux d'utiliser un vecteur de pointeur sur ces objets : vector<T*>, comme ca je pourrais tester vector<T*>.at(i)==0 ce qui signifique que la case est vide...

    Mais bon je trouve ça un peu moche d'utiliser les pointeurs (ai-je tort ?) donc voilà je voulais savoir si quelqu'un voyait une autre alternative à mon problème...

    Merci d'avance

  2. #2
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Hello,

    Ça dépend entièrement de la façon dont tu représentes les données.
    Ça peut aller d'un vector d'enum où l'index dans le vector détermine la position
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    enum Piece {
        Aucune,
        Piece1,
        Piece2
    };
     
    std::vector<Piece> plateau;
    // tester si une pièce est dans la case (4,5)
    bool pieceIn4_5 = plateau[4*largeur+5] != Aucune;
    A un vector de Piece contenant leur position
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    struct Piece {
        Position position;
        // ...
    };
    std::vector<Piece> pieces;
    // tester si une pièce est dans la case (4,5)
    using std::begin;
    using std::end;
    bool pieceIn4_5 = std::find_if(begin(pieces), end(pieces), [](const Piece& p)->bool {
        return p.position == Position(4,5);
    }) != end(pieces);
    Il est aussi possible d'avoir plusieurs représentations des données en simultané. Il faut juste bien faire attention à les garder synchronisées.

    Réfléchi bien à la (ou les) façon de représenter les données la plus efficace (et simple d'utilisation).
    Citation Envoyé par gabgab Voir le message
    Mais bon je trouve ça un peu moche d'utiliser les pointeurs (ai-je tort ?) donc voilà je voulais savoir si quelqu'un voyait une autre alternative à mon problème...
    Avec ce genre de représentation tu sera obligé d'utiliser des pointeurs, mais ce n'est pas dérangeant.

  3. #3
    Membre à l'essai
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2012
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2012
    Messages : 24
    Points : 17
    Points
    17
    Par défaut
    Tout d'abord merci pour ton aide.

    Le truc qui me dérange dans ta réponse, c'est que j'ai l'impression que tu ne prends pas en compte les templates. En effet en suivant ton exemple j'aurais un plateau de type Piece uniquement.
    Après une solution possible serait de déclarer un type pièce template...

  4. #4
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Bonjour

    Tu peux regarder du coté de boost::optional, std::optional (refusé pour C++14) ou équivalent.

  5. #5
    Expert confirmé
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Points : 4 442
    Points
    4 442
    Par défaut
    Citation Envoyé par gabgab Voir le message
    Le truc qui me dérange dans ta réponse, c'est que j'ai l'impression que tu ne prends pas en compte les templates. En effet en suivant ton exemple j'aurais un plateau de type Piece uniquement.
    Je donnais juste des exemples avec un type concret car c'est plus facile à relire, mais il est tout à fait possible d'avoir des templates.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    template <class T>
    class Plateau {
    public:
        typedef T piece_type;
     
        // ...
    private:
        // au choix, en fonction de la représentation des données
        // tu peux aussi avoir quelque chose de complètement différent.
        std::vector<piece_type*> m_pieces;
        std::vector<std::optional<piece_type>> m_pieces;
        std::vector<piece_type> m_pieces;
        std::vector<std::reference_wrapper<piece_type>> m_pieces;
    };
    Le problème n'est pas l'utilisation de templates, mais de savoir comment représenter les données pour que ce soit simple et rapide à utiliser.

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 967
    Points
    32 967
    Billets dans le blog
    4
    Par défaut
    il n'y a rien de moche à utiliser des pointeurs et il ne faut pas avoir peur des pointeurs.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Membre chevronné Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Points : 2 160
    Points
    2 160
    Par défaut
    Il n'y a pas de raison d'utiliser des pointeurs bruts ici. Selon la sémantique de T (et de part le statut de std::optional), j'hésiterai entre un std::vector<???::optional<T>> et un std::vector<std::unique_ptr<T>>.

    Si std::optional ou équivalent est disponible alors, j'utiliserai :
    - std::vector<???::optional<T>> si T a une sémantique de copie.
    - std::vector<std::unique_ptr<T>> si T a une sémantique d'entité.

    L'utilisation basique reste la même : ???::optional et std::unique_ptr peuvent être utilisés tous les deux comme booléen et on peut accéder à la valeur par déréférencement.

  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
    Salut,

    La première question à se poser est surtout de savoir quelle sera la nature de l'objet qui prendra place sur le plateau.

    Je m'explique : imaginons que tu crées un échiquier. Les pièces que tu placeras sur ton plateau seront sans doute des objets présentant des comportements polymorphes, parce que la "pièce" peut représenter un pion, une tour, un cavalier,un fou, une dame ou un roi et que chaque pièce spécifique aura des comportements spécifiques.

    Tu te trouves donc avec des classes qui ont, très clairement, sémantique d'entité pour lesquelles ils sera difficile d'utiliser un identifiant unique (à cause du nombre d'éléments qu'il faudrait identifier de manière unique).

    Tu n'auras donc pas le choix : il faudra que les cases de ton plateau manipulent un pointeur vers les différentes pièces. (*)

    Pour d'autres jeux (puissance 4, otello, scrabble, ...), les éléments qui prennent place sur le plateau peuvent parfaitement être représentés par des classes ayant sémantique d'entité :

    Si je prend le cas de otello, les jetons ont une face blanche et une face noire, mais il n'y a strictement aucun besoin de partir sur une hiérarchie de classes pour les pions : les pions de ces jeux (si tant est qu'on utilise une classe et non une simple énumération ) se satisfait parfaitement d'une sémantique de valeur.

    A ce moment là, tu peux parfaitement envisager de créer une simple énumération dans laquelle tu places les différentes valeurs possibles et à laquelle tu rajoutes une valeur qui représente... l'absence de pion / couleur / lettre (biffer la mention inutile ).

    Si tu veux, vraiment, avoir un plateau générique, il faut prendre, ad minima, des deux possibilités en compte, ce qui ferait sans doute ressembler ton plateau à quelque chose comme
    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
     
    /* !!! C++11 inside !!! */
    struct EntityTag{};
    struct ValueTag{};
     
    struct OthelloTag{
        using gameTag = ValueTag;
    };
    struct ChessTag{
        using gameTag = EntityTag;
    };
    template <typename BoardType>
    class Board{
        public:
            using boardTag = BoardType::gameTag;
            template <typename T = boardTag,
                            typename = typename
                            <std::enable_if<std::is_same<T,ValueTag>::value>::type>
            void foo(T const & /* , ... */ ){
     
            }
            template <typename T = boardTag,
                            typename = typename
                            <std::enable_if<std::is_same<T,EntityTag>::value>::type>
            void foo(T const & /* , ... */ ){
     
            }
           /* ... */
    }
    Ou, si tu ne disposes pas de C++11, il faudra partir sur une spécialisation de ta classes, sous une forme proche de
    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
    struct EntityTag{};
    struct ValueTag{};
    template <typename Tag, typename PieceBaseType>
    class Board;
    template<
    class Board<ValueTag, void>{
        public:
        /* ici, on travaille avec des éléments qui ont sémantique de valeur */
        /* ... */
    };
    template<typename PieceBaseType>
    class Board<EntityTag, PieceBaseType>{
        public:
        /* ici, on travaille avec des éléments qui ont sémantique d'entité */
        /* ... */
    };
    (ce ne sont que deux possibilités parmi d'autres, je n'ai pas réfléchi très longtemps au problème )

    (*) Lorsque tu dois manipuler des éléments qui ont sémantique d'entité, tu peux toujours envisager le recours à l'idiôme de l'objet nul (Nul Object idiomen anglais ).

    En effet, ce n'est pas parce que ton plateau manipule des pointeurs en interne qu'il doit obligatoirement renvoyer un pointeur : Si tu peux définir un type qui représente "l'absence de pièce", tu es sauvé

    Pour faire simle, l'idée est d'intégrer, dans ta hiérarchie de classes, une classe qui répond "false" (ou une valeur connue pour être invalide) à toutes les questions que l'on peut lui poser :
    • mayHaveChildren false
    • hasChildren false
    • color colorNone
    • coordinate Corrdinate(0,0) (ou la valeur qui indique que la coordonnée n'existe pas)
    • canMove false
    • ...
    Ainsi, dans chaque classe qui manipule en interne un pointeur vers la classe de base de ta hiérarchie de classes, tu peux rajouter un membre de ce type "qui n'est pas un élément valide", et décider de renvoyer ce membre là à chaque fois que tu veux signifier le fait que "il n'y a rien à cet endroit là"

    C'est, à peu de chose près, ce qui se fait avec les itérateurs (les fonctions end() essentiellement )
    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

Discussions similaires

  1. Conception: stocker les pointeurs de fonction
    Par progfou dans le forum C++
    Réponses: 4
    Dernier message: 11/04/2008, 17h44
  2. probléme avec les pointeurs
    Par killer_instinct dans le forum C++
    Réponses: 6
    Dernier message: 11/12/2006, 11h37
  3. Problèmes avec les thread et les pointeurs
    Par raspac dans le forum POSIX
    Réponses: 2
    Dernier message: 22/10/2006, 17h35
  4. Réponses: 4
    Dernier message: 13/08/2004, 18h39
  5. [TTreeView] Problème avec les pointeurs d'objet
    Par BlackWood dans le forum Composants VCL
    Réponses: 2
    Dernier message: 02/07/2004, 14h31

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