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 avec mes constructeurs


Sujet :

C++

  1. #1
    Membre confirmé

    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    532
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2011
    Messages : 532
    Points : 604
    Points
    604
    Par défaut Problème avec mes constructeurs
    Bonjour a toutes et tous,

    Je suis actuellement en train d'apprendre le C++ et, pour appliquer ce que j'apprends j'ai voulu créer un mini RPG (Wouha l'originalité du truc, personne n'y a pensé ...). Donc voila l'idée: un petit RPG où deux personnages (en l’occurrence pour mon cas des Mages) se battent.

    J'ai créé un main.cpp (logique), une première classe appelé Mage (.h et .cpp) qui sera ma classe mère et deux autres classes filles qui hérite de ma classe Mage à savoir MageFeu et MageGlace (.h et .cpp aussi pour les deux). Normalement, jusque là je suis bon. J'ai créé les différents constructeurs, méthodes et attribut dont j'ai besoin et j'ai tester et cela fonctionne.

    Dans mon programme main, j'ai créé une fonction if pour pouvoir choisir le type de mage que l'on veut être (et aussi choisir son nom, etc ...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    cout << "Rentrez le nom du premier mage svp:" << endl;
        getline(cin, nomMage1);
        cout << "Choisissez le type de mage:" << endl;
        cin >> choixType1;
        if(choixType1 == 1)
        {
            MageFeu mage1(nomMage1);
        }
        else if(choixType1 ==2)
        {
            MageGlace mage1(nomMage1);
        }
    (bien sur je ne l'ai pas préciser, toutes les différentes variables ont été créées au préalable de ce code.

    Ensuite je crée une boucle do ... while pour réaliser le combat et c'est dans cette boucle que j'ai mes problèmes mais avant de vous parler des problèmes, je vous montre ma boucle (que beaucoup considéreront comme charger et compliqué sans doute pour rien)
    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
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
     
    do
        {
     
            cout << "TOUR " << compteur << endl <<endl;
     
        cout << nomMage1 << ", choisissez l'action a effectuer" << endl;
        cin >> choixAction1;
        switch(choixAction1)
        {
            //Si l'action choisi vaut 1, le mage1 va attaquer
            case 1:
                cout << nomMage1 << ", a vous d'attaquer. Veuillez choisir une attaque entre:" << endl << "1 - Attaque de base" << endl << "2 - Boule de Feu" << endl << "3 - Tempete de Feu" << endl << "4 - Souffle Ardent" << endl << "5 - Pluie de Braises" << endl;
                cin >> choixAttaque1;
                switch(choixAttaque1)
                {
                    case 1:
                        mage1.attaqueBase(mage2);
                    break;
                    case 2:
                        if(mage1.visuMana(mage1) > 4)
                        {
                            mage1.bouleFeu(mage2);
                            mage1.perteMana(mage1, 5);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    case 3:
                        if(mage1.visuMana(mage1) > 24)
                        {
                            mage1.tempeteFeu(mage2);
                            mage1.perteMana(mage1, 25);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    case 4:
                        if(mage1.visuMana(mage1) > 19)
                        {
                            mage1.souffleArdent(mage2);
                            mage1.perteMana(mage1, 20);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    case 5:
                        if(mage1.visuMana(mage1) > 14)
                        {
                            mage1.pluieBraises(mage2);
                            mage1.perteMana(mage1, 15);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    default:
                        cout << "Vous n'avez pas choisi d'attaque, vous passez votre tour!" << endl;
                    break;
     
                }
            break;
            //Si l'action choisi vaut 2, le mage1 va boire une potion de soin
            case 2:
                mage1.boirePotion();
                cout << "Vous buvez une potion de guerison" << endl;
            break;
            //Si il choisi autre chose, le mage1 passe sont tour
            default:
                cout << "Vous n'avez choisi aucune action, vous passez votre tour!" <<endl;
            break;
        }
     
     
        cout << nomMage2 << ", choisissez l'action a effectuer" << endl;
        cin >> choixAction2;
        switch(choixAction2)
        {
            //Si l'action choisi vaut 1, le mage2 va attaquer
            case 1:
                cout << nomMage2 << ", a vous d'attaquer. Veuillez choisir une attaque entre:" << endl << "1 - Attaque de base" << endl << "2 - Boule de Neige" << endl << "3 - Griffes de Glace" << endl << "4 - Mur de Glace" << endl << "5 - Dragon de Glace" << endl;
                cin >> choixAttaque2;
                switch(choixAttaque2)
                {
                    case 1:
                        mage2.attaqueBase(mage1);
                    break;
                    case 2:
                        if(mage2.visuMana(mage2) > 4)               //La condition appelle la méthode et fait perdre du mana au lieu de simplement comparer
                        {
                            mage2.bouleNeige(mage1);
                            mage2.perteMana(mage2, 5);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    case 3:
                        if(mage2.visuMana(mage2) > 14)
                        {
                                mage2.griffesGlace(mage1);
                                mage2.perteMana(mage2, 15);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                    break;
                    case 4:
                        if(mage2.visuMana(mage2) > 19)
                        {
                            mage2.murGlace(mage1);
                            mage2.perteMana(mage2, 20);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
                        break;
                    case 5:
                        if(mage2.visuMana(mage2) > 24)
                        {
                            mage2.dragonGlace(mage1);
                            mage2.perteMana(mage2, 25);
                        }
                        else
                        {
                            cout << "Vous n'avez pas assez de mana pour attaquer, vous passez votre tour!" << endl;
                        }
     
                    break;
                    default:
                        cout << "Vous n'avez pas choisi d'attaque, vous passez votre tour!" << endl;
                    break;
     
                }
            break;
            //Si l'action choisi vaut 2, le mage2 va boire une potion de soin
            case 2:
                mage2.boirePotion();
                cout << "Vous buvez une potion de guerison" <<endl;
            break;
            //Si il choisi autre chose, le mage2 passe sont tour
            default:
                cout << "Vous n'avez choisi aucune action, vous passez votre tour!" <<endl;
            break;
        }
     
        mage1.afficherEtat();
        mage2.afficherEtat();
     
        mage1.gainMana();
        mage2.gainMana();
     
        compteur += 1;
        }
        while(mage1.etatVie() > 0 && mage2.etatVie() > 0);
    Mon problème est lorsque je compile, le compilateur me dit que j'ai une erreur à la ligne
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mage1.attaqueBase(mage2);
    et aux autres car mon objet mage1 n'est pas créé (error: 'mage1' was not declare on the scope)

    Ma question est comment faire pour résoudre le problème (sachant que l'idée serait qu'après mon premier switch(choixAction1) et que l'utilisateur a choisi son action, il y aura une nouvelle structure if(choixType == X) pour dire si X=1 donc attaques du mage de feu, X= 2 donc attaques du mage de glace, etc ...

    Merci d'avance pour ce qui vont lire, comprendre (et cela ne doit pas etre évident), et m'aider.

    Cordialement,
    Clairetj
    Si vous voulez suivre les différents championnats de football américain en France, en Europe et dans le Monde (en tout 32 pays différents), c'est sur www.fandefootus.fr

  2. #2
    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 518
    Points
    41 518
    Par défaut
    Si tu gardes la personnalisation des sorts du mage par classe, tu vas avoir besoin d'allocation dynamique et de virtualité.

    Un truc de ce genre:
    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
    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
    #include <vector>
    #include <string>
     
    class Sort
    {
    public:
    	std::string nomSort;
    };
     
    class Mage
    {
    public:
    	virtual std::vector<Sort> getListeSorts() = 0;
    	virtual ~Mage();
    private:
    	//C'est de la virtualité, on interdit la copie
    	Mage(Mage const &);
    	Mage& operator=(Mage const &);
    };
     
    class MageFeu : public Mage
    {
    public:
    	std::vector<Sort> getListeSorts()
    	{
    		std::vector<Sort> ret;
    		Sort sortCourant;
    		sortCourant.nomSort = "Boule de feu";
    		ret.push_back(sortCourant);
    		sortCourant.nomSort = "Tempête de feu";
    		ret.push_back(sortCourant);
    		...
    		return ret;
    	};
    };
     
    class MageGlace : public Mage
    {
    public:
    	std::vector<Sort> getListeSorts()
    	{
    		std::vector<Sort> ret;
    		Sort sortCourant;
    		sortCourant.nomSort = "Cône de froid";
    		ret.push_back(sortCourant);
    		sortCourant.nomSort = "Âge de glace";
    		ret.push_back(sortCourant);
    		...
    		return ret;
    	};
    };

    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    	Mage* pMage1 = NULL;
    	cout << "Rentrez le nom du premier mage svp:" << endl;
    	getline(cin, nomMage1);
    	cout << "Choisissez le type de mage:" << endl;
    	cin >> choixType1;
    	if(choixType1 == 1)
    	{
    		pMage1 = new MageFeu(nomMage1);
    	}
    	else if(choixType1 ==2)
    	{
    		pMage1 = new MageGlace(nomMage1);
    	}
    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.

  3. #3
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    Le code suivant pose déjà problème, car
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        if(choixType1 == 1)
        {
            MageFeu mage1(nomMage1);
        } // mage1 est détruit ici
        else if(choixType1 ==2)
        {
            MageGlace mage1(nomMage1);
        }//mage1 est détruit ici
    La signature de la fonction étant manquante, je vais devoir partir dans des supputations, mais, en gros, si tu veux profiter du polymorphisme, tu es obligé de passer par l'utilisation de pointeurs ou de références, et, qui dit pointeurs, dit souvent... allocation dynamique de la mémoire.

    En outre, la phrase
    (bien sur je ne l'ai pas préciser, toutes les différentes variables ont été créées au préalable de ce code.
    me laisse à penser que tu as sans doute déclaré des variables globales mage1 et mage2, sans doute comme étant de type Mage.

    Il faut savoir que la variable mage1 que tu déclares dans le code que je viens de citer est totalement différente de ta variable mage1 globale (s'il est bien réglé, ton compilateur devrait d'ailleurs émettre un avertissement ) mais que, de plus, si tu utilises une variable par valeur, tu perds toute possibilité de recourir au polymorphisme, ce qui est malgré tout dommage, et que tu peux, en outre, te retrouver confronté à un problème nommé "slicing" qui correspond à une situation dans laquelle tu as, purement et simplement, perdu des informations (peut être essentielles!!!) propres à tes classes dérivées.


    Pour ta boucle principale, il y a de la place pour le progrès, cela étant dit sans vouloir t'offenser.

    Typiquement, ta boucle principale ne devrait pas avoir à s'inquiéter du type réel des deux personnages en présence : chaque mage sait parfaitement quelle est sa spécialisation, quel type d'attaque il peut utiliser et à quel type d'attaque il est "particulièrement vulnérable".

    Mais, encore une fois, le polymorphisme est nécessaire, et le recours aux pointeurs et aux références (éventuellement constantes) devient incontournable.

    Au final, pour les différentes attaques, tu aurais sans doute quelque chose 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
    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
     
    class Mage;
    /* Toutes les attaques, qu'elle soient de feu ou  de glace, sont des attaques
     *
     */
    class Attack{
        public:
            /* cette classe a sémantique d'entité, on en interdit donc
             * la copie et l'affectation (c++11 inside)
             */
             Attack(Attack const &) = delete;
             Attack & operator = (Attack const & ) = delete;
            virtual ~Attack();
            virtual int manaCost() const = 0;
            virtual int degat() const = 0;
            virtual void blesse(Mage & m) const;
            /* ...*/
    };
    /* Classe de base pour toutes les attaques de feu
     *
     */
    class FireAttack : public Attack{
        /* ... */
    };
    class BouleDeFeu : public FireAttack{
        public:
        /* ... */
        int manaCost() const{return 5;}
        int degats() const{return 10;}
        void blesse(Mage & m) const{m.subit(*this);}
    };
    class TempeteDeFeu : public FireAttack{
        public:
        /* ... */
        int manaCost() const{return 25;}
        int degats() const{return 30;}
        void blesse(Mage & m) const{m.subit(*this);}
    };
    /* Classe de base pour toutes les attaques de glace
     *
     */
    class IceAttack : public Attack{
        /* ... */
    };
    class BouleDeGlace : public IceAttack{
        public:
        /* ... */
        int manaCost() const{return 5;}
        int degats() const{return 10;}
        void blesse(Mage & m) const{m.subit(*this);}
    };
    class PluieDargent : public IceAttack{
        public:
        /* ... */
        int manaCost() const{return 25;}
        int degats() const{return 30;}
        void blesse(Mage & m) const{m.subit(*this);}
    };
    et pour les mages, 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
    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
    105
    106
    107
    108
    109
    110
    111
    112
    /* Classe de base pour tous les mages
     *
     */
    class Mage{
        public:
            /* cette classe a sémantique d'entité, on en interdit donc
             * la copie et l'affectation (c++11 inside)
             */
             Mage(Mageconst &) = delete;
             Mage& operator = (Mageconst & ) = delete;
            virtual ~Mage();
            virtual void subit(FireAttack const &) = 0;
            virtual void subit(IceAttack const &) = 0;
            virtual void meilleureAttaque(Mage & other){
                /* s'il a assez de mana, il choisit l'attaque la plus puissante */
                if(mana >=25){
                    attaqueForte(mage);
                }
               /* sinon, il choisi l'attaque faible, à condition d'avoir assez de
                * mana
                */
               else if(mana >=5){
                    attaqueFaible(mage);
               } /* et sinon, il n'attaque pas */
              else {
                  std::cout<<"pas assez de mana pour attaquer";
              }
            }
     
            }
            virtual void attaqueFaible(Mage & other)  = 0;
            virtual void attaqueForte(Mage & other) = 0;
        protected:
            int live;
            int mana;
    };
    /* Le mage de feu, spécialisé dans les attaques de feu
     *
     */
    class MageDeGlace : public Mage{
        public:
            /* cette classe a sémantique d'entité, on en interdit donc
             * la copie et l'affectation (c++11 inside)
             */
             Mage(Mageconst &) = delete;
             Mage& operator = (Mageconst & ) = delete;
            virtual ~Mage();
            void subit(FireAttack const & a){
                /* Le mage du feu résiste très bien au feu : il subit moitie moins
                 * de dégats
                 */
               live -= (a.degat()/2);
           }
            virtual void subit(IceAttack const &){
                /* Le mage du feu est très sensible au froid : il subit deux fois plus
                 * de dégats
                 */
               live -= (a.degat()*2);
            }
            virtual void attaqueForte(Mage & other){
                TempeteDeFeu tempete;
                if(mana>= tempete.manaCost()){
                    tempete.blesse(other);
                    mana-= tempete.manaCost();
                }
            }
            virtual void attaqueFaible(Mage & other){
                BouleDeFeu boule;
                if(mana>= boule.manaCost()){
                    boule.blesse(other);
                    mana-= boule.manaCost();
                }
            }
    };
    /* Le mage de glace, spécialisé dans les attaques de glace
     *
     */
    class MageDeFeu : public Mage{
        public:
            /* cette classe a sémantique d'entité, on en interdit donc
             * la copie et l'affectation (c++11 inside)
             */
             Mage(Mageconst &) = delete;
             Mage& operator = (Mageconst & ) = delete;
            virtual ~Mage();
            void subit(FireAttack const & a){
                /* Le mage du feu est très sensible au feu: il subit deux fois plus
                 * de dégats
                 */
               live -= (a.degat()*2);
           }
            virtual void subit(IceAttack const &){
                /* Le mage du feu résiste très bien au froid: il subit moitie moins
                 * de dégats
                 */
               live -= (a.degat()/2);
            }
            virtual void attaqueForte(Mage & other){
                PluieDargent pluie;
                if(mana>= pluie.manaCost()){
                    pluie.blesse(other);
                    mana-= pluie.manaCost();
                }
            }
            virtual void attaqueFaible(Mage & other){
                BouleDeGlace boule;
                if(mana>= boule.manaCost()){
                    boule.blesse(other);
                    mana-= boule.manaCost();
                }
            }
    };
    En travaillant de la sorte, tu pourras avoir une boucle principale sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* soit curent est un pointeur (de type Mage) qui pointe sur le mage qui peut jouer
     * soit next est un pointeur (de type Mage) qui pointe sur le mage qui est attaqué
     */
    int choix = choix();
    if(choix == 1){
        curent->attaqueForte(*next);
    }
    else if(choix == 2){
        curent->attaqueFaible(*next);
     
    }else if(choix == 3){
        curent->meilleureAttaque(*next);
    }
    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

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Un petit switch ne ferait pas de mal.

  5. #5
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

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

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Citation Envoyé par oodini Voir le message
    Un petit switch ne ferait pas de mal.
    Tu parles de son if else if ? Pas vraiment interessant s'il n'y a que deux embranchements...

  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 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par imperio Voir le message
    Tu parles de son if else if ? Pas vraiment interessant s'il n'y a que deux embranchements...
    Un switch est toujours plus intéressant qu'une if else if puisqu'on évite les autant de comparaison et qu'il s'agit d'un simple jump directement
    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
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Un switch est toujours plus intéressant qu'une if else if puisqu'on évite les autant de comparaison et qu'il s'agit d'un simple jump directement
    A vrai dire, cela dépend très fortement de beaucoup de choses...

    Le switch est, très certainement, préférable lorsque tu utilises une énumération, ne serait-ce que pour que le compilateur puisse attirer ton attention sur le fait que tu as oublié une (ou l'autre) valeur énumérée.

    Mais, pour autant que je me souvienne, la plupart des compilateurs sont parfaitement en mesure d'optimiser une série de if ... else if... de la même manière que ce qu'il font pour un switch, à test similaire du moins.

    Ceci dit, l'utilisation de switch ou de if ... else if n'est pas vraiment le problème principal et me semble quelque peu "hors scope" par rapport au problème initial :

    Le fait est que, idéalement, le PO ne devrait pas avoir à s'inquiéter du type des différents mages que sa boucle principale manipule : chaque mage est sensé savoir quelle est sa spécialité, et c'est très largement suffisant ainsi !

    La boucle principale n'a pas à s'inquiéter du type d'attaque que le mage lancera effectivement
    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

  8. #8
    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 koala01 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class BouleDeFeu : public FireAttack{
    Bouh mélanger français et anglais c'est mal

    Plus sérieusement, pourquoi de l'héritage ici ?
    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
    enum Type {
       FIRE,
       ICE
    };
    class Attack {
       std::string name,
       Type type;
       int mpCost;
       int dmg;
    };
    class Mage {
       std::string name;
       Type type;
       std::vector<Attack*> attacks;
       int mpMax;
       int currentMp;
       // ...
    };
    Il suffit ensuite d'avoir une std::map<Type, Mage> contenant un mage "type" (dans le sens "template") pour chaque Type (dans le sens feu / glace) et de cloner le bon pour le choix du joueur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int type;
    std::map<Type, Mage> mageTemplates; // remplir cette map
    std::cout << "type de mage" << std::endl;
    std::cin>> type;
    Mage mage1 = mageTemplates.find((Type)type).second; // gestion d'erreurs à faire.
    L'héritage n'apporte rien ici ?

  9. #9
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Bouh mélanger français et anglais c'est mal
    Je sais, mais je n'avais aucune idée pour les noms
    Plus sérieusement, pourquoi de l'héritage ici ?
    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
    enum Type {
       FIRE,
       ICE
    };
    class Attack {
       std::string name,
       Type type;
       int mpCost;
       int dmg;
    };
    class Mage {
       std::string name;
       Type type;
       std::vector<Attack*> attacks;
       int mpMax;
       int currentMp;
       // ...
    };
    Il suffit ensuite d'avoir une std::map<Type, Mage> contenant un mage "type" (dans le sens "template") pour chaque Type (dans le sens feu / glace) et de cloner le bon pour le choix du joueur.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int type;
    std::map<Type, Mage> mageTemplates; // remplir cette map
    std::cout << "type de mage" << std::endl;
    std::cin>> type;
    Mage mage1 = mageTemplates.find((Type)type).second; // gestion d'erreurs à faire.
    L'héritage n'apporte rien ici ?
    Je ne fais que respecter la logique de clairetj que je cite:
    Citation Envoyé par clairetj
    une première classe appelé Mage (.h et .cpp) qui sera ma classe mère et deux autres classes filles qui hérite de ma classe Mage à savoir MageFeu et MageGlace
    En outre, le fait d'avoir deux classes clairement séparées permet de spécialiser certains comportements si besoin, sans avoir à commencer à jouer avec un if(type_ == ICE) else if (type == FIRE).

    Il faut en effet te dire que tous les comportements peuvent être spécialisés, que ce soit la capacité d'apprendre certains sort, la résistance du mage à certains types de magie, les éléments d'armure qu'il est susceptible de porter et jusqu'à l'affichage lui-même (même si, pour l'instant, on est dans un contexte d'affichage en mode console).

    En plus, je sens bien venir le coup du "tiens ce serait pas mal si..." (j'ajoutais un mage de l'air, de l'eau ou un sorcier vaudou).

    Tu auras beaucoup plus facile à faire évoluer les choses, en respectant l'OCP, si tu prévois effectivement différentes classes pour tes mages (dont la classe pourrait d'ailleurs dériver de Personnage, car, après les mages, je vois bien arriver des barbares, des orques, des elfes et des nains ) dés le départ.

    Si tu ne le fais pas dés maintenant, tu devras "tout casser" pour intégrer ce genre d'évolutions
    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

  10. #10
    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
    Aucun intérêt immédiat, juste une précaution pour l'évolution de la chose donc, merci.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Aucun intérêt immédiat, juste une précaution pour l'évolution de la chose donc, merci.
    Ben, oui, et non...

    Oui, parce que l'on ne peut nier le fait que l'évolution sera grandement facilitée par le fait d'avoir des classes clairement distinctes.

    Non parce que, même si tu n'as que deux types de personnages, même si tu devait toujours rester avec ces deux seuls types, le fait est que tu peux beaucoup plus facilement définir des comportements spécifiques pour chacun d'eux, que ce soit des comportements qui font partie de l'interface commune, ou que tu envisages de rajouter des fonctions particulières à l'interface de l'un ou de l'autre type en question.

    Tu me diras que c'est toujours "pour le cas où" ou "pour prévoir les évolutions futures", mais s'il y a une chose avec laquelle il faut vraiment essayer de composer systématiquement lorsqu'on développe quelque chose, c'est avec le fait que l'on n'est sûr que d'une chose : on n'est jamais sûr de rien, car les besoins évoluent en permanence

    Quand on y pense, il n'est pas plus difficile d'écrire dés le départ du code susceptible d'évoluer (en respectant SOLID, essentiellement) en prévoyant une abstraction de base sur laquelle baser le gros de la logique que de se dire que "on verra bien quand le besoin s'en fait sentir".

    Mais le simple fait d'avoir prévu des "points de variation" dans le code rend l'intégration d'évolutions beaucoup plus facile et beaucoup moins "casse gueule".

    Tu sais, je suis le premier à sortir des YAGNI ou des KISS quand c'est nécessaire.

    Mais j'ai l'intime conviction qu'il ne faut pas se retrancher derrière ces deux phrases pour décider de ne pas fournir une abstraction chaque fois que possible
    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

  12. #12
    Membre confirmé

    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    532
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Enseignement

    Informations forums :
    Inscription : Avril 2011
    Messages : 532
    Points : 604
    Points
    604
    Par défaut
    Merci a tous pour vos réponse, je vais donc remettre un coup avec le polymorphisme même si je galère encore dans (mais bon cela ne peut pas me faire de mal).

    En parcourant les différents messages, je vois que je n'ai pas était vraiment clair sur certain de mes choix de départ et cela à laisser placer a de nombreuses suppositions donc même si, à priori j'ai trouvé réponse à ma question, je vais quand même vous expliquer les choix de départ (notamment sur l'héritage vu que cela a fait débat)

    Déjà, premier point que je lève et certains vont être déçu, non il n'y aura pas d'autres personnages comme des elfes, des nains, des orques, etc ... Il n'y aura que des mages, c'est d'ailleurs pour cela que ma classe mère s'appelle Mage (pour ceux qui connaisse, l'inspiration me vient du manga Fairy Tail mais là je m'éloigne du sujet).

    L'idée est effectivement de pouvoir créer plusieurs mages avec des types différents (feu, eau, terre, vent, foudre, j'en passe et des meilleurs ...) mais je voulais qu'ils aient tous une base commande de capacité comme avoir tous les même points de vie et mana au départ, pouvoir boire une potion et donner un coup de base, recevoir des coups, etc ... D'où la création des différents attributs et méthode dans la classe mère Mage.
    Après, spécificité oblige, chacun aurait son propre répertoire de sorts lié à son type et que personne d'autre peut utiliser d'où mon idée de définir des différents sorts dans les classes filles.

    En tout cas merci pour vos différentes réponses, et je vais m’atteler à ce problème de polymorphisme

    Merci encore,
    Cordialement,
    Clairetj
    Si vous voulez suivre les différents championnats de football américain en France, en Europe et dans le Monde (en tout 32 pays différents), c'est sur www.fandefootus.fr

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

Discussions similaires

  1. problème avec mes constantes
    Par salseropom dans le forum C
    Réponses: 6
    Dernier message: 10/05/2006, 17h37
  2. [Conception]Problèmes avec un constructeur dérivé
    Par Le Furet dans le forum Langage
    Réponses: 6
    Dernier message: 10/03/2006, 09h44
  3. [JDBC]problème avec mes id
    Par Hydre dans le forum JDBC
    Réponses: 12
    Dernier message: 29/09/2005, 13h19
  4. [std::list][find_if] problème avec mes foncteurs
    Par n!co dans le forum SL & STL
    Réponses: 12
    Dernier message: 04/02/2005, 11h56
  5. Problème avec mes tables de relation...
    Par mmike dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 02/06/2003, 15h16

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