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 :

Pti dev, aide pour finalisation


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 66
    Par défaut Pti dev, aide pour finalisation
    Bonjour

    Etudiant en bts, je vais bientôt passer mes PTI, et voulait savoir si quelques bonnes âmes pouvaient jeter un œil sur mon "programme" en c++.

    Déjà, voila un .rar avec tout ce qu'il faut dedans.
    http://garrethvfou.free.fr/Meujeu/PT...ymorphisme.rar

    Alors, ce qui m'intéresse, c'est de savoir :
    - Si je respecte bien l'encapsulation,
    - Si il y a du code inutile et redondant
    - Si je pourrais mettre + de commentaires (là il y en a quasiment pas, mais je vois pas trop où en mettre, le programme restant relativement simple)
    - Me rappeler pourquoi les classes Magiciens et Guerrier sont en virtual, mais pas la classe Personnage qui pourtant, le devrait aussi, non ? Ou alors, pourquoi ne peut on pas mettre Magicien et Guerrier en normal aussi ?
    - Si vous voyez tout autre chose qui pourrait m'aider ...


    Voila, merci beaucoup d'avance ! Je reste à votre disposition pour toutes questions

  2. #2
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    Citation Envoyé par Xenofexs Voir le message
    - Me rappeler pourquoi les classes Magiciens et Guerrier sont en virtual, mais pas la classe Personnage qui pourtant, le devrait aussi, non ? Ou alors, pourquoi ne peut on pas mettre Magicien et Guerrier en normal aussi ?
    Heu si tu les as mis en virtual tu doit bien avoir une raison, non ?

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 66
    Par défaut
    Biensur, mais c'était il y a quelque temps. C'est pour pouvoir utiliser la fonction monChoix, qui transmet deux paramètres qui sont des objets.
    Sans le polymorphisme, je ne pouvais pas.
    Mais si comme vous devez le remarquer, si on me pose la question directement à l'examen, mon explication sera un peu soft ... un petit rappel me serait bien utile .
    Surtout comme je l'ai marqué, pourquoi Personnage n'a pas besoin d'être virtualisé ? Et ce que j'ai fait, du coup, ça respecte toujours l'encapsulation ?
    Si vous pouviez DL le source pour jeter un oeil, ça serait sympa

    Merci d'avance

  4. #4
    Membre expérimenté
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 38
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Par défaut
    Pour l'héritage virtuel la FAQ l'explique très bien.

    Au niveau de la conception déjà la classe joueur me fais un peu peur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    class Joueur : virtual public Personnage, public Guerrier, public Magicien
    Premièrement Guerrier et Magicien hérite déjà de Personnage donc pourquoi l'hérité une troisième fois ? (de plus si tu lis la FAQ tu verras que Guerrier et Magicien devrai être, eux, hérité en virtual).

    Mais surtout ton héritage signifie que joueur est à la fois un Guerrier et un Magicien (ce qui n'est pas le cas).

    la déclaration de tes joueur
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Joueur Andristin ("Andristin", "Guerrier", 50);
    Joueur Edward ("Edward", "Magicien", 50);
    Devrai ressemblé plutôt à :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Personnage *Andristin  = new Guerrier("Andristin", 50);
    Personnage *Edward = new Magicien("Edward ", 50);
    Dans ton code tu n'utilise pas du tout le polymorphisme alors qu'il te serai très utile dans ton cas.

    Pour cela il faut que tu n'aies plus a utiliser getType() (sauf éventuellement pour afficher des info).

    EDIT: grillé. reste qu'il y a (d'après moi) un problème de conception.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 66
    Par défaut
    Déjà, merci beaucoup pour vos réponses, j'ai commencé les changement et me suis replongé dans vos liens FAQ C++.

    Pour le site, oui et non. J'ai repris uniquement la base (soit le fait d'avoir une classe Personnage, Magicien et Guerrier) mais c'est tout.
    Sur le site, pas de polymorphisme, pas de classe joueur donc, pas de "round" ni de choix pour le déroulement du combat. etc.

    Pour ce qui est de la conception du programme ... je sais pas, je n'ai pas eu de cours, je pensais que c'était pas trop mal. Hélas je n'ai pas le temps de tout refaire, là. Mais merci pour l'info, je m'y replongerai aussi pour faire quelque chose de correct après l'épreuve (pour ma propre connaissance, quoi )

    Pour le destructeur, il est bien nécessaire ? Car, comme le souligne atttchoum, je n'utilise pas de " new " pour créer mes objets.

    Pour les std::string, quel intérêt de les passer par constantes et références? Qu'est ce que ça fait concrètement ? Et aussi, comment l'écrire dans le .cpp ?


    Encore merci en tout cas, j'ai corrigé les petits trucs, genre indentation, simplification des " == true " etc

  6. #6
    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
    Citation Envoyé par Xenofexs Voir le message
    Pour le destructeur, il est bien nécessaire ? Car, comme le souligne atttchoum, je n'utilise pas de " new " pour créer mes objets.
    Un constructeur est nécessaire dés le moment où... tu veux construire un objet, que ce soit en utilisant l'allocation dynamique de la mémoire ou non

    car, même si tu écris un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    joueur j1("arthur","magicien");
    tu ... appelle un constructeur
    Pour les std::string, quel intérêt de les passer par constantes et références? Qu'est ce que ça fait concrètement ? Et aussi, comment l'écrire dans le .cpp ?
    Il est préférable de passer les types définis par l'utilisateur (std::string est un type défini par l'utilisateur, même s'il est fourni par le standard ) par référence afin d'éviter les copies inutiles qui peuvent demander beaucoup de temps ou de ressources.

    Il est préférable de passer un objet constant chaque fois qu'il ne doit pas être modifié pour assurer la "const correctness".

    De plus, l'utilisation de référence constante permet d'utiliser des "variables anonyme temporaire" (le code que je donne en exemple crée une variable de type std::string anonyme contenant "arthur" qui n'existe que... pour la durée de l'exécution du constructeur )
    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

  7. #7
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Royaume-Uni

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Par défaut
    Citation Envoyé par Xenofexs Voir le message
    - Me rappeler pourquoi les classes Magiciens et Guerrier sont en virtual, mais pas la classe Personnage qui pourtant, le devrait aussi, non ? Ou alors, pourquoi ne peut on pas mettre Magicien et Guerrier en normal aussi ?
    Je ne sais pas trop ce que tu entends pas "classe virtuelle", mais je suppose que tu fais allusion au mot clé "virtual" qui l'on voit ici :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Guerrier : virtual public Personnage
    {
        ...
    };
    Ce mot clé s'applique ici non pas à la classe Guerrier, mais à la classe Personnage.
    Tu indique au compilateur que tu veux faire un héritage virtuel (un peu d'anglais, ça fait pas de mal, pas trouvé dans la FAQ C++ de Developpez).
    Dans le cadre de ton programme, c'est nécessaire pour que la classe Joueur puisse fonctionner correctement. En effet, son diagramme d'héritage a la forme d'un losange (ou d'un diamant, c'est comme on veut), et ça créé des ambiguïté pour le compilateur.
    Si tu lis l'anglais, c'est bien mieux expliqué dans le lien ci dessus.

    Mais je ne suis pas sûr qu'il soit nécessaire de ré-écrire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Joueur : virtual public Personnage, public Guerrier, public Magicien
    {
        ...
    };
    Ceci devrait suffire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Joueur : public Guerrier, public Magicien
    {
        ...
    };
    Par contre, la classe Personnage dont tu hérite dans Guerrier et Magicien n'a pas de destructeur virtuel (en français cette fois), et ça c'est assez grave.

    Maintenant place au pinaillage :

    D'abord, l'indentation n'est pas toujours top. En lisant main.cpp, j'ai d'abord cru que tu avais écris un while() en dehors de toute fonction, avant de me rendre compte que c'était juste une erreur d'indentation. Ca ne tue pas, mais c'est quand même gênant pour qui ne connais pas le code.

    Ensuite, quand une méthode retourne un std::string membre de la classe (ou tout autre type d'objet lourd à copier), on préfère le retourner par référence constante plutôt que par valeur. Ca évite des copies inutile est c'est totalement transparent pour l'utilisateur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class Personnage
    {
            ...
            const std::string& getType();
            const std::string& getNom();
            ...
    };
    On peut aller plus loin, et déclarer ces fonctions comme constantes, car elles ne modifient pas l'objet Personnage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Personnage
    {
            ...
            void coupDePoing(Personnage &cible) const;
            bool estVivant() const;
            const std::string& getType() const;
            const std::string& getNom() const;
            ...
    };
    Pareil pour :
    • Joueur::afficherEtat()
    • Guerrier::grosCoupDepee()
    • Magicien::bouleDeFeu()


    Autre détail : les variables globales. Dans ton cas les deux variables :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int i=1;
    bool boucle=true;
    ... n'ont strictement rien à faire dans la portée globale.
    Tu ne les utilises nulle part ailleurs que dans la fonction main(), donc autant les déclarer là bas, c'est plus sûr :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main()
    {
        int i=1;
        bool boucle=true;
     
        ...
    }
    Enfin, vraiment un détail :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while ((Edward.estVivant()==true) && (Andristin.estVivant()==true) && boucle==true) {
        ...
    }
    ... ça se simplifie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    while (Edward.estVivant() && Andristin.estVivant() && boucle) {
       ...
    }

  8. #8
    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, et bienvenue sur le forum.

    1- Le constructeur de personnage ne prenant pas d'argument est, au mieux inutile, au pire, dangereux...:

    Comme il n'y a aucun moyen de modifier le nom du personnage (ce qui est quelque part logique ), tu ne devrais pas permettre de... créer un personnage qui n'a pas au minimum un nom

    (il en va de même pour les classes magicien et guerrier )

    2- Si je suis d'accord avec le fait qu'un magicien ou qu'un guerrier est un personnage, je ne suis pas particulièrement d'accord avec l'idée de faire hériter joueur de ces deux classes: un joueur n'est pas un magicien ou un guerrier, mais un joueur est représenté par un personnage qui peut être soit un magicien soit un guerrier (si c'est le prof qui a indiqué qu'un joueur devait hériter de l'un ou de l'autre, tu peux lui dire que sa conception est foireuse de ma part )

    Comme le joueur peut, à peu près à tout moment, décider d'abandonner un personnage afin d'en créer un autre, et que l'on ne peut pas savoir à la base quel type il décidera de créer, il faudrait avoir dans la classe joueur:
    • une chaine de caractère (std::string) représentant le pseudo du joueur, et
    • une méthode permettant de le récupérer (c'est la seule information qui sera nécessaire pour la création du joueur)
    • un pointeur sur "personnage", et deux fonctions permettant de les gérer: creerPersonnage(std::string const & nom, type) et detruirePersonnage(), la première ne pouvant agir que... si le joueur n'a pas encore (ou plus) de personnage


    Si tu pars sur cette base (beaucoup plus saine), il n'y a plus aucun intérêt à faire en sorte d'avoir un héritage virtuel

    3- De prime abord, je n'utiliserais pas une chaine de caractères pour représenter le type de personnage, mais plutôt une énumération, par exemple, et je ne vois, pour être honnête, pas l'intérêt de la fonction permettant de récupérer le type...

    Les raisons pour laquelle j'éviterais la chaine de caractère sont:
    • que tu va permettre la création d'un nombre finis de types différents (pour l'instant, tu n'as que "guerrier" et "magicien", mais, si tu décide de permettre d'autres type ("voleur","paladin",...), tu voudra veiller à... ce que seuls ces types soient utilisés )
    • la comparaison de chaines de caractères est sans doute ce qui prend le plus de temps: il faut comparer chaque caractère avec celui se trouvant à la même place dans la deuxième chaine, jusqu'à trouver une différence
    • les tests à choix multiple (switch... case) ne fonctionnent qu'avec... des valeurs numériques entières. Pour l'instant, un if... else suffit, mais, si tu rajoute des types de personnage, le switch case sera bien plus lisible et sans doute plus efficace sur un grand nombre de types différents

    La raison pour laquelle je ne suis pas persuadé de l'intérêt d'une fonction permettant de récupérer le type de personnage est, simplement, que pour la plus grande partie du jeu, tu va considérer tes magiciens et tes guerriers comme... des personnages, et ils seront (principalement) utilisé comme tels: que ce soit un magicien ou un guerrier, il pourra attaquer et subir des dégâts (et, qu'il s'agisse d'un guerrier ou d'un magicien, s'il n'a pas d'arme, il risque encore bien d'utiliser... le coup de poing )

    Par contre, il serait sans doute intéressant d'avoir une fonction "attaquer" dans la classe de base.

    Cette fonction serait virtuelle et redéfinie de manière à appeler le gros coup de poing du guerrier ou la boule de feu du magicien, en fonction du perso

    Il est vrai que, dans certains cas, tu devras peut être effectivement disposer du type réel du personnage.

    Dans le cas où le seul polymorphisme est insuffisant (tu peux avoir une fonction virtuelle "équiper" qui est redéfinie pour le guerrier et pour le magicien de manière à vérifier que tu n'essaye pas d'équiper un objet destiné à "l'autre type" de personnage ), le pattern "visiteur" te viendra sans doute bien à point
    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. [XL-2002] Besoin d'aide pour finaliser Macro mise en forme + bordure
    Par warrio67 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 12/03/2010, 05h23
  2. [XL-2007] Aide pour finaliser un code
    Par eliot.raymond dans le forum Macros et VBA Excel
    Réponses: 15
    Dernier message: 21/05/2009, 13h56
  3. Aide pour finaliser une macro
    Par NEC14 dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 07/08/2008, 08h02
  4. une toute petits aide pour finaliser tout sa
    Par yoan_111 dans le forum ASP
    Réponses: 6
    Dernier message: 16/12/2005, 16h04

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