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 :

Liaisons dynamiques sur les attributs dérivés ?


Sujet :

C++

  1. #1
    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 705
    Points
    2 705
    Par défaut Liaisons dynamiques sur les attributs dérivés ?
    Bonjour,

    Soit les déclaration de classes suivantes :

    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 classeMembre2 : public classeMembre1
    {
    ...
    }
     
    class A
    {
    classeMembre1 pouet;
    }
     
    class B : public A
    {
    classeMembre2 pouet;
    }
    Sachant que classeMembre2 descend de classeMembre1, à quoi ressemblerait ma classe B si je l'avait définie directement, sans passer par un héritage ?

    Si je fais l'appel suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dynamic_cast<A*>(instance de B)->pouet;
    cela me renverra-t-il un objet de type classeMembre1 ou classeMembre2 ?

    Merci !

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Il faut savoir ici que A::pouet et B::pouet sont deux variables différentes*: En C++, seules les fonctions peuvent être virtuelles (et covariantes), pas les variables.

    Dans l'appel de ton exemple, le dynamic_cast est inutile: Un cast implicite aurait très bien fait l'affaire, puisque c'est un upcast.
    Par contre, la variable retournée sera celle du type de pointeur, pas celle du type réel de la classe, puisqu'il n'y a pas d'accesseur virtuel.

  3. #3
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    B sera composé d'un objet de type classeMembre1, et d'un objet de type classeMembre2. Lorsque tu manipules une instance de B directement ce sera le second qui sera visible, et lorsque tu manipuleras ton B sous forme de A ce sera le premier.
    Donc dans ton exemple ce sera le classeMembre1 qui sera considéré.

  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 705
    Points
    2 705
    Par défaut
    Et si je passe par un accesseur virtuel getPouet(), cela me permettrai-il de m'assurer que je récupère le bon pouet ?

  5. #5
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Oui, mais dans ce cas les attributs renvoyés doivent être de même type, ou dériver d'une même base.

  6. #6
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 379
    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 379
    Points : 41 573
    Points
    41 573
    Par défaut
    Ou, si j'ai bien compris, être d'un type qui dérive de l'autre si le compilo supporte les retours covariants ?

  7. #7
    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 705
    Points
    2 705
    Par défaut
    En fait, comme je l'ai indiqué dans mon premier message, il y a une relation d'héritage entre le type des deux classes membres.

    Ces classes membres sont en fait des classes de fonctions (issues d'une API). Leurs classes dérivées suivent en gros le schéma de dérivation des classes contenantes.

    Quand je dois intervenir sur une instance de B, je fais appel à sa classe de fonction (classeMembre2). Mais je veux que les opérations issues de la dérivation à partir de classeMembre1 soient codées dans la classe A, afin de factoriser le code.

    Ces opérations sont lancées par disons l'appel du'ne méthode appelée doOperation().

    Tous mes objets, appartenant tous au même arbre d'héritage, sont dans une liste. Et avec un itérateur, j'appelle doOperation() sur chacun des objets (d'où le bout de code avec le dynamic_cast).

    On doit alors appeler le doOperation() sur le type réél de l'objet (utilisation donc d'un virtual), qui va appeler le doOperation() sur son parent, et qui va par la suite faire des opérations spécifique sur son type (B) avec une classe de fonction idoine (classeMembre2).

    Mais que doit utiliser le doOperation() de la classe A ?

    • Dois-je passer en paramètre un pointeur vers classeMembre2 ?
    • Dois-je utiliser en plus du membre classeMembre2 dans B un classeMembre1 dans A, alors qu'il ne sera jamais utilisé par les descendants de A ?
    • Dois-je ne définir que classeMembre1, et affecter dans B un objet de type classeMembre2 au membre déclaré comme classeMembre1 dans A, puis, dans le doOperation() de B, faire un downcasting sur le membre classeMembre1 pour appeler des fonctions spécifiques à classeMembre2 ?

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

    Informations professionnelles :
    Activité : aucun

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

    Ce qui foncitonne pour avoir un retour co-variant, c'est une organisation 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
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    class Base{};
    class Derivee:public Base
    {
        /* contenu de la classe  "données" */
    };
    class Deriv2:public Base
    {
        /* contenu de la classe "données" */
    };
     
    class Interface
    {
        public:
            Inerface(){}
            virtual ~Interface(){}
            virtual Base& Data()=0;
    };
    class Travail:public Interface
    {
        public:
            Travail(Derivee& d):Interface(),_data(d){}
            virtual ~Travail(){}
            Derivee& Data(){return _data;}
        private:
            Derivee _data;
    };
    class Trav2: public Interface
    {
        public:
            Trav2(Deriv2& d):Interface(),_data(d){}
            virtual ~Trav2(){}
            Deriv2& Data(){return _data;}
        private:
            Deriv2 _data;
    };
    L'idée est que:
    • Les classes membres doivent toutes dériver d'une base commune (OK, fourni par ton API)
    • Les classes de travail doivent toutes dériver d'une interface commune
    • Le renvoi co-variant doit etre une référence ou un pointeur
      • du type de base pour l'interface
      • du type de donnée pour les autres
    • tu n'a pas de relation directe entre les deux classes de travail (autre le fait de l'héritage d'une classe commune)
    • Les fonctions qui n'ont pas besoin d'avoir acces à (ici _data) sont définies dans l'interface
    • Les fonctions qui ont besoin d'avoir acces à (ici _data) sont définies dans les classes de travail et virutelle pures dans l'interface
    • Rien ne t'empeche d'avoir plusieurs niveau d'imbriquation entre les différentes classes "données" ni entre l'interface et la classe de travail


    [EDIT]La seule chose à laquelle le code proprosé n'a pas porté attention est le fait qu'il faudra au minimum une fonction qui ne soit pas virutelle en ligne, sinon l'éditeur de lien ne trouvera pas la vtable

  9. #9
    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 705
    Points
    2 705
    Par défaut
    J'ai commencé un autre code dans lequel la classe membre n'apparaît qu'une seule fois sous forme d'une référence.

    Dans la classe mère, je fais normalement appel aux fonction de la classe membre.

    Dans les classes dérivées, je transtype (dynamic_cast) tout d'abord la classe membre vers le type qui correspond à la classe dérivée. Ensuite, je peux faire appel aux fonctions spécifiques à la classe membre dérivée.

    Ainsi, la seule occupation mémoire est celle d'un pointeur commun à toutes les classes dérivées...

    Je vous dirai si ça marche. :-)

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 01/07/2008, 16h51
  2. Réponses: 1
    Dernier message: 19/04/2007, 02h37
  3. Réponses: 2
    Dernier message: 17/04/2007, 17h14
  4. [SQL] Besoin d'aide sur les attributs pour une requete
    Par bobobobo01 dans le forum Langage SQL
    Réponses: 2
    Dernier message: 27/11/2006, 21h39
  5. question sur les attributs javascript
    Par PAYASS59 dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 20/04/2005, 13h34

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