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 :

Soucis conceptuel : peur de l'héritage multiple


Sujet :

C++

  1. #1
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut Soucis conceptuel : peur de l'héritage multiple
    Bonjour à tous,


    J'ai créé une classe de base qui a la possibilité "d'enregistrer ses membres".
    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
     
    class CBaseData
    {
    protected:
      RegisterProperty(const std::string&, IProperty*);
    private:
      CPropertyMap<string, IProperty*> m_map;
    }
     
    class CMyData : public CBaseData
    {
    public:
      CMyData()
      {
         RegisterProperty("MonEntier", m_iProperty);
         RegisterProperty("MaChaine", m_strProperty);
      }
    private:
      CProperty<int> m_iProperty;
      CProperty<string> m_strProperty;
    }
    Maintenant je voudrais une classe qui va en plus gérer les propriétés identifiantes.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class CIdentData : public CBaseData
    {
    protected :
      RegisterIdent(const std::string& rstrIdent);
    private:
      CPropertyMap<string, IProperty*> m_idents;
    }
    Utilisation avec un véhicule possédant un identifiant unsigned long :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class CVehicle : public CIdentData
    {
    public:
      RegisterProperty("ID", m_ulId);
      RegisterProperty("NOM", m_strName);
      RegisterIdent("ID");
    private:
      CProperty<unsigned long> m_ulId;
      CProperty<string> m_strName;
    }
    J'aimerai également faire une donnée de localisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class CLocalityData : public CBaseData
    {
    public :
      CLocalityData()
      {
          RegisterProperty("LATI", m_dLati);
          RegisterProperty("LONGI", m_dLongi);
      }
    private :
      CProperty<double> m_dLati;
      CProperty<double> m_dLongi;
    }
    Mais là où ça se complique, c'est lorsque je souhaite que mon véhicule soit une donnée localisable ainsi qu'une donnée identifiable.
    J'ai pensé à plusieurs trucs :
    1)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class CVehicle : public CBaseData, public CIdentData, public CLocalityData
    {
     
    }
    Ca fait un héritage multiple en forme de losange. Est-ce que CIdentData et CLocalityData vont enregistrer leurs propriétés respectives dans le même CBaseData ?

    2)
    Je modifie ma conception pour faire hériter CBaseData de IProperty puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class CVehicle
    {
    public:
       CVehicle()
       {
           RegisterProperty("LOCALITY", m_locality);
           RegisterProperty("IDENTS", m_idents);
       }
    private:
       CLocalityData m_locality;
       CIdentData m_idents;
    }
    Mais là ce qui m'embête c'est que c'est le développeur de CVehicle qui choisit les clé "LOCALITY" et "IDENTS", j'aimera les imposer les clés pour que si un autre développeur construise un client localisable, il n'ai pas le choix que de réutiliser ces deux clés...

    3) Utiliser une hiérarchie linéaire que génèrerai
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     CIdentData
          |
    CLocalityData
          |
      CVehicle
    Mais comme CIdentData et CLocalityData dérivent de CBaseData on aura
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
     CBaseData
           |
     CIdentData
           |
     CBaseData
           |
    CLocalityData
           |
      CVehicle

    Comment puis-je faire ?
    La première solution semble bonne si seulement CVehicle, CLocalityData et CIdentData partagent le même CBaseData.
    La seconde est bonne aussi seulement si les clés peuvent être imposées
    Et la troisième j'ai aucune visu sur ce que ça produirai



    Merci beaucoup,


    Aurélien
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  2. #2
    Membre expérimenté Avatar de 10_GOTO_10
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    886
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 886
    Points : 1 526
    Points
    1 526
    Par défaut
    C'est plus une question C++ qu'une question de conception, je pense que tu auras plus de réponses dans le forum correspondant.

    Premiers éléments de réponse ici (voir en particulier le paragraphe 8.6). En gros, il faut déclarer des classes virtuelles.

  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,

    Déjà, il faut bien comprendre que la relation d'héritage est la relation la plus forte que tu puisse trouver en programmation orienté objet, et qu'elle ne devrait s'appliquer que lorsqu'il est vraiment cohérent d'un point de vue sémantique de dire que la classe dérivée EST UN objet de base.

    Cela signifie que, si tu retire ce qui fait l'objet de base de ta classe dérivée, elle ne peut tout simplement pas fonctionner...

    Ainsi, l'héritage est cohérent si tu considère une classe chien et une classe animal: un chien est un animal, et, si tu retire ce qui fait un animal d'un chien, tu as quelque chose de tout à fait inviable.

    Si, sémantiquement parlant, tu ne peux pas dire qu'une classe est une autre mais que tu peux en dire que "la classe A a toutes les caractéristiques de la classe B", tu devra te tourner plutôt vers une agrégation, voire, vers une composition.


    Dans ce que tu présente, on peut éventuellement considérer qu'un véhicule est un objet qui peut enregistrer ses membres, mais, la question à se poser sera alors
    y a-t-il un risque que je fasse passer un véhicule pour un objet qui peut enregistrer ses membres, et - surtout - que je le fasse cohabiter avec d'autres objets qui peuvent le faire mais qui ne sont pas des véhicules
    Si la réponse à cette question est définitivement oui, tu peux envisager de faire hériter véhicule de CBaseData, sinon, la composition semble plus adaptée.

    Pour l'héritage avec CLocalityData, il n'est déjà pas sémantiquement correct de dire
    un véhicule est une donnée localisable
    par contre, il est correct de dire que
    un véhicule a toutes les caractéristiques d'une données localisable
    Ce sera donc l'agrégation (ou la composition, si la "donnée localisable" ne peut pas exister en dehors du véhicule) qui devra être préférée.

    Au final, j'aurais plutôt tendance à écrire les classes sous la forme de
    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
    class CBaseData
    {
        /*... peu d'importance ici */
    };
    class CIdentData : public CBaseData
    {
        /*... peu d'importance ici*/
    };
    class CLocalityData : public CBaseData
    {
     
    };
    /*si le véhicule peut ne pas être localisable */
    class CVehicule
    {
        public:
            /* si on ne veut pas le localiser */
            CVehicule(const std::string& id):mid(id),mloc(NULL)
            {
            }
            /* si on veut le localiser */
            CVehicule(const std::string& id, const std::string& loc):mid(id)
            {
                mloc=new CLocalityData(loc);
            }
        private:
            CIdentData mid;
            CLocalityData *mloc;
    };
    /* si le véhicule est toujours localisable */
    class CVehicule
    {
        public:
            /* si on ne veut pas le localiser */
            CVehicule(const std::string& id, const std::string&):mid(id),mloc(loc)
            {
            }
        private:
            CIdentData mid;
            CLocalityData mloc;
    };
    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 expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    i beaucoup pour ces explications

    Aurélien
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

Discussions similaires

  1. composants C++ Builder et héritage multiple
    Par vedrfolnir dans le forum C++Builder
    Réponses: 2
    Dernier message: 12/10/2005, 10h04
  2. [heritage][conception]héritage multiple en java!
    Par soulhouf dans le forum Langage
    Réponses: 9
    Dernier message: 25/08/2005, 20h03
  3. L'héritage multiple est-il possible en Delphi ?
    Par SchpatziBreizh dans le forum Langage
    Réponses: 8
    Dernier message: 30/06/2005, 11h30
  4. utilisez vous l'héritage multiple ?
    Par vodosiossbaas dans le forum C++
    Réponses: 8
    Dernier message: 13/06/2005, 20h25
  5. [XML Schemas]héritage multiple
    Par nicolas_jf dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 10/06/2003, 12h55

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