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

Langage C++ Discussion :

Problème de modélisation


Sujet :

Langage C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Septembre 2008
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 29
    Points : 27
    Points
    27
    Par défaut Problème de modélisation
    Bonjour a tous une nouvelle fois et toujours autant de questions...


    J'ai essayé de trouver des réponses dans la FAQ mais je n'arrive pas a poser un nom sur mon problème.

    J'ai une classe mère que nous appelerons :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class CCompetence
    {
    public :
       CCompetence();
     
    private:
       CDescription m_description; //contient un nom et une description en char*
       long val;
    };
    Et 3 classes dérivées CCompCombat, CCompMagie, CCompSocial comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class CCompCombat:public CCompetence
    {
    ...
    };

    Et une dernière classe CPersonnage :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class CPersonnage
    {
    public:
       CPersonnage();
     
       mInitDataCompetence();
     
    private
       CCompetence *m_competence;
    };

    Voila mon problème à la création d'un personnage, j'alloue un certains nombres de compétences dont la quantité est définit (par exemple) dans un fichier texte qui est lu.
    ensuite je fait appel a la méthode d'initialisation des compétences mInitDataCompetence qui finit de lire ce fichier et spécifie pour chaque objet CCompetence quelle est son type (Combat, Magie, Sociale). Or je ne peux pas transformer le m_competence[i] en une classe CCompMagie puisque celle-ci est du type CCompetence...

    Je ne veux pas mettre dans ma classe personnage trois composition :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CCompCombat *m_comp_combat;
    CCompMagie *m_comp_magie;
    CCompSocial *m_comp_social;

    Est ce que j'ai loupé un truc dans ma conception ou bien y'a t-il un principe dont je n'ai pas/plus connaissance (et j'ai plus trop de connaissances sur le sujet donc je me reforme sur un petit projet sympa...). J'ai pensé regardé du coté des fonctions virtuels mais ca ne m'arrange en rien

    Je crois que mon problème vient du fait que mes héritages ne sont pas forcément bon... ?

  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
    C'est le genre de moment où l'on peut se demander si l'on a bien fait d'utiliser ainsi l'héritage: Tes compétences réagissent-t-elles vraiment différemment selon qu'elles soient de magic, combat ou sociales? Ou ne s'agit-t-il que d'une classification arbitraire permettant de les classer dans des listes?

    Dans le second cas, une seule classe et une enum devraient suffire...
    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
    Nouveau membre du Club
    Inscrit en
    Septembre 2008
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 29
    Points : 27
    Points
    27
    Par défaut
    il est vrai que j'ai pensé a mettre une données membres m_type_compétence mais je pensais qu'en segmentant mes classes je m'y retrouverait mieux par la suite (en terme de lisibilité du code et de savoir ce que je dois implémenter et dans quelle fichier).

    Ai je le droit d'un point de vue objet d'écrire qqch comme cela (en enlevant les héritages au préalable):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class CCompetence
    {
    public:
       contrcuteur;
     
    private:
       long m_type_competence; //un enum sur mes 3 types de compétences
     
       union {
       CCompCombat m_comp_combat;
       CCompMagie   m_comp_magie;
       CCompSocial   m_comp_social;
      } m_cls_type_competence
    };
    ou bien est ce plutôt du C ?

    PS : je ne dis pas que cela est très propre bien sûr et je ne sais même pas comment le compilo va réagir si je tente d'écrire ca !

  4. #4
    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
    Les unions ne sont autorisés que pour les types POD (Plain Old Data). Franchement, je te le déconseille.

    Et ça m'étonnerait que ça change grand-chose au niveau lisibilité.

    Enfin au maximum, si tu veux utiliser un héritage et faire tes listes, tu peux toujours faire ça:
    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
    struct listes
    {
    	std::vector<CCompCombat*> compsCombat;
    	std::vector<CCompMagie*> compsMagie;
    	std::vector<CCompSociale*> compsSociales;
    };
     
    class CCompetence
    {
    public:
    	virtual void AjouterAListe(struct listes &);
    };
     
    ...
     
    void CCompCombat::AjouterAListe(struct listes &)
    {
    	listes.compsCombat.push_back(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.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Il n'y a pas de moyen de transformer dynamiquement le type d'un objet en C++.
    Je vois 3 solutions :
    1/ Créer directement le bon type de compétences soit à la première lecture du fichier, soit à la seconde et dans la première tu ne fais que mémoriser les contraintes sur le nombre de compétences et lesquels.

    2/ Tu utilises le pattern Pont : CCompetence contient les données et les comportements commun à toutes les compétences, et ICompetenceImpl contient les compétences spécialisées :
    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
     
    class Competence : private noncopyable
    {
    public :
        void propriete_commune()
        {// do it}
        void propriete_differenciee()
        {m_impl->action();}
     
        void attribuer_competence(enum comp_)
        {
           switch(comp_){
                  case combat:
                       m_impl = new CCompetenceImplCombat;// ou utilisation d'une factory
                       break;
                    //etc...
           }
        }
    private:
        ICompetenceImpl *m_impl;
    };
    class ICompetenceImpl
    {
    public :
         void action()
         {
                 do_action();
         }
         virtual ~ICompetenceImpl()=0;
    private:
         virtual void do_action()=0;
    };
     
    class CCompetenceImplCombat : public ICompetenceImpl
    {
    public :
         virtual ~CCompetenceImplCombat(){}
    private:
         virtual void do_action()
         {// just do it}
    };
    3/ Tu utilises le pattern décorateur pour enrichir ta classe CompetenceCombat à la second lecture :
    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
     
    // pendant la construction de tes competence :
    void CPersonnage::mInitDataCompetence()
    {
       // pour une competence combat :
       m_competence = new CCompetenceCombat(m_competence);
    }
     
    class CCompetence
    {
    public:
        virtual ~CCompetence(){}
        void action()
        {
           do_action();
        }
    private:
        virtual void do_action()
        {}
    };
    class CCompetenceDecorateur : public CCompetence, private noncopyable
    {
    private:
        virtual void do_action()
        {
            p_base->do_action();
        }
    private:
       CCompetence *p_base;
    }
     
    class CCompetenceDecorateurCombat : public CCompetenceDecorateur
    {
    private:
        virtual void do_action()
        {
            // do specific action
        }
    }
    Le décorateur est intéressant si tu veux combiner dynamiquement plusieurs compétences, chacune venant décorer la précédente.

  6. #6
    Nouveau membre du Club
    Inscrit en
    Septembre 2008
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 29
    Points : 27
    Points
    27
    Par défaut
    J'ai pas tout compris sur le décorateur(je lis la FAQ) par contre la olution n°2 me convient tout a fait.

    En effet ma classe principale contient des données communes a toutes les classes dérivées. par contre c'etait le mécanisme d'appel à des fonctions virtuels que je ne trouvais pas.

    J'avais bien crée une fonction d'init prenant un enum mais je voulais faire un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    CCompetence::CCompetence(enum type)
    {
       switch(type)
          case COMBAT:
          this = CCompCombat(...);
     
    }
    qui est bien sûr interdit et n'a aucun sens !!!

    Cette solution me permet donc de garder seulement un SEUL objet CCompetence* dans ma classe CPersonnage.

    Merci beaucoup

  7. #7
    Nouveau membre du Club
    Inscrit en
    Septembre 2008
    Messages
    29
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 29
    Points : 27
    Points
    27
    Par défaut
    une dernière question :

    comment puis implémenter le desctructeur de ma classe ICompetenceImpl (qui est virtuelle pure) alors qu'il n'y a aucun destructeur dans les classes dérivées qui "matche" le même nom ?

    Je sens que je vais avoir un "unresolved symbol"

    Apres réflexion :
    j'ai trouvé, une fonction virtuelle pure ne signifie pas : aucune impémentation !!! J'ai donc impémenté (à vide bien sûr) mon destructeur virtuelle pure !

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par CSIE_Angel#5 Voir le message
    j'ai trouvé, une fonction virtuelle pure ne signifie pas : aucune impémentation !!!
    Ca a du sens pour le destructeur. Donner une implémentation à une fonction virtuelle pure autre que le constructeur a en revanche rarement du sens.

  9. #9
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Ca a du sens pour le destructeur. Donner une implémentation à une fonction virtuelle pure autre que le constructeur a en revanche rarement du sens.
    Il y a un cas où je trouve que ça en a : Quand on s'attend à ce que l'implémentation de la fonction virtuelle pure dans la classe dérivée appelle la version de la classe de base. Par exemple :
    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
     
    class Base
    {
    public:
      virtual void serialize(archive &a) = 0
      {
        a.serialize(i);
      }
    private:
      int i;
    };
     
    class Derives : public Base
    {
    public:
      virtual void serialize(archive &a)
      {
        a.serialize(j);
        Base::serialize(a);
      }
    private:
      int j;
    };
    On pourrait bien entendu avoir dans base une fonction protected serializeBase qui fasse ça, mais tant qu'à faire, on a déjà à disposition une fonction parfaite pour mettre le code de sérialisation de la base, autant l'utiliser.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Il y a un cas où je trouve que ça en a : Quand on s'attend à ce que l'implémentation de la fonction virtuelle pure dans la classe dérivée appelle la version de la classe de base.
    Salut,
    Dans ces cas, le pattern NVI peut être utile :
    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
    class Base
    {
    public:
      void serialize(archive &a);
      {
        a.serialize(avant);
        do_serialize(a);
        a.serialize(apres);
      }
    private :
        virtual void do_serialize(archive &a)=0;
    private:
      int avant;
      int apres;
    };
     
    class Derives : public Base
    {
    private:
      virtual void do_serialize(archive &a)
      {
        a.serialize(j);
      }
    private:
      int j;
    };
    L'avantage, c'est qu'ainsi une classe dérivée n'a pas à se rappeler qu'elle doit appeler la méthode de la classe de base.
    Ensuite, c'est pour ça que j'avais qualifié de rarement, ce qui veut dire que des fois, oui

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Dans ces cas, le pattern NVI peut être utile
    En l'occurrence, j'utiliserais volontiers ce pattern pour sérialiser des metadata associées aux classes (par exemple, le nom de la classe qui permet de recréer le bon type d'objet à la désérialisation, un checksum...). Mais pour ce qui est de sauver les données de la classe de base, je préfère ne pas le faire, car ce pattern s'alourdi si on a plusieurs niveaux de hiérarchie.

    Citation Envoyé par 3DArchi Voir le message
    Ensuite, c'est pour ça que j'avais qualifié de rarement, ce qui veut dire que des fois, oui
    Oui, je l'avais bien compris ainsi, et je voulais juste donner un des cas rares où je trouvais ça justifié.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    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
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Dans ces cas, le pattern NVI peut être utile :
    <snip>
    L'avantage, c'est qu'ainsi une classe dérivée n'a pas à se rappeler qu'elle doit appeler la méthode de la classe de base.
    Ensuite, c'est pour ça que j'avais qualifié de rarement, ce qui veut dire que des fois, oui
    Le problème, c'est que ce principe s'écroule dès qu'on a plusieurs étages.

    Dommage qu'il n'y ait que les constructeurs et les destructeurs qui appellent la classe de base automatiquement...
    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.

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

Discussions similaires

  1. problème de modélisation dimensionnelle (hiérarchie)
    Par kince dans le forum MS SQL Server
    Réponses: 3
    Dernier message: 07/04/2007, 09h48
  2. Problème de modélisation avec Case Studio
    Par soso78 dans le forum Décisions SGBD
    Réponses: 6
    Dernier message: 15/06/2006, 18h13
  3. Problème de modélisation
    Par Tyler Durden dans le forum Décisions SGBD
    Réponses: 2
    Dernier message: 10/06/2006, 16h18
  4. [Class/PHP/Postgres] Problème de modélisation...
    Par k-reen dans le forum PostgreSQL
    Réponses: 4
    Dernier message: 27/02/2003, 08h49

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