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 :

Heritage multiple et dynamic_cast


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut Heritage multiple et dynamic_cast
    Bonjour,
    J'ai uen classe "c" qui hérite de "a" et de "b", et je voudrait utiliser le dynamic_cast comme expliqué ici : http://cpp.developpez.com/faq/cpp/?p...S_crosscasting
    mais ca ne marche pas...
    voici un 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
    class a 
    {
    public :
    void test() {if(1) action();}
    virtual void action();
    };
    class b
    {
    public:
    void affiche();
    };
    //-- la classe c qui herite de a et b
    class c : public a, public b
    {
    public:
    void action();
    };
    bon, jusque là, rien de special, j'ai une methode virtuel (action) dans le cas d'un objet de la classe c, en utilisant test() ca sera bien le action de la classe c (ca semble marcher, j'ai testé)

    et là, j'ai besoin de caster cet objet crée, pour le stocker dans deux vecteurs (qui contiennent des objets a et b par ailleur)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    a* obj = new c;
    vecta.push_back(obj);
    vectb.push_back(dynamic_cast<b*>(obj));
    et ca plante,
    pour info, voici comment sont définis les vecteurs :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    std::vector<a*> vecta;
    std:vector<b*> vectb;
    je pense avoir fais comme dans la FAQ, mais ca plante.
    note : je ne peux vraiment pas changer le type des vecteurs, car il y a plei n d'autres objets (heritant de a et b, mais pas les deux a la fois) qui y sont stocké dedans...

    Merci.

  2. #2
    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 : 50
    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
    Par défaut
    Et si tu ajoutes une fonction virtuelle dans la classe B ?

    D'autre part, un tel dynamic_cast devrait toujours gérer le cas où le résultat est NULL, c'est à dire si la cast a échoué.
    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.

  3. #3
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Et si tu ajoutes une fonction virtuelle dans la classe B ?
    Ca ne change absolument rien.

    Et même si ca avait permis de corriger le probleme, je n'aurais pas été tres ravi de créer une fonction virtuelle qui ne corresponds a rien dans la classe b...

  4. #4
    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,

    Pour que l'héritage public puisse s'effectuer sans trop de problème, il faut au minimum que le destructeur de la classe de base soit:
    • soit publique et virtuel
    • soit protégé et non virtuel
    Comme tu prévois de gérer des objets de la classe dérivés dont la mémoire est allouée dynamiquement, mais que tu prévois de maintenir les pointeurs comme s'il s'agissait de l'une des classes de base, il faut impérativment que les destructeurs soient publiques et virtuels

    La seule présence de cette seule fonction virtuelle devrait suffire à permettre le transtypage dynamique

    Ainsi, normalement, le code suivant devrait fonctionner correctement:
    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
    class A
    {
        public:
             virtual ~A(){}
            void foo(){std::cout<<"A::foo()"<<std::endl;}
    };
    class B
    {
        public:
            void bar(){std::cout<<"B::bar()"<<std::endl;}
        protected:
             ~B(){}
    };
    class C : public A, public B
    {
        public:
            virtual ~C(){}
    };
    int main()
    {
        A *a = new C;
        B *b = dynamic_cast<B*>(a);
        if(b)
            b->bar();
        else
            std::cout<<"erreur de transtypage"<<std::endl;
        delete a;
        b =NULL;
        a = NULL;
        return 0;
    }
    en affichant effectivement B::bar()

    Ceci grâce à la présence du destructeur virtuel dans les classes A et B (le destructeur de la classe C devrait pouvoir ne pas être déclaré explicitement virtuel de par le fait que les destructeurs des deux classes mères le sont)

    Nota: si tu viens à ne pas déclarer le destructeur de l'une des classes mère (ou en tous cas une fonction du type de base servant à la création de départ de ton objet) virtuel(le) (ou si tu laisse le compilateur rajouter de lui-même le destructeur de la classe mère, ce qui revient à ne pas le déclarer virtuel), tu te trouvera effectivement dans l'impossibilité d'effectuer le transtypage d'un pointeur sur un objet A vers un pointeur sur un objet B, au prétexte que
    main.cpp|24|error: cannot dynamic_cast 'a' (of type 'class A*') to type 'class B*' (source type is not polymorphic)|
    En effet, le code ci-dessus ne fonctionne pas uniquement si tu n'a aucune fonction virtuelle dans la classe A, mais peut fonctionner si tu vient à remplacer le destructeur virtuel public de la classe B par un destructeur non virtuel et protégé (et encore, uniquement parce que tu n'essaye pas d'invoquer delete sur le pointeur de type B, car toute tentative en ce sens se solderait par une erreur te rappelant que ~B est protégé )
    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

  5. #5
    Membre éclairé
    Inscrit en
    Septembre 2003
    Messages
    391
    Détails du profil
    Informations forums :
    Inscription : Septembre 2003
    Messages : 391
    Par défaut
    Merci koala01,
    c'est vraiment une reponse trés detaillé.
    j'avais pas repris les destructeurs dans mon example dans mon message.
    j'ai appris un truc !
    je pensais pas passer un destructeur en public...


    Merci.

  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 hpfx Voir le message
    Merci koala01,
    c'est vraiment une reponse trés detaillé.
    j'avais pas repris les destructeurs dans mon example dans mon message.
    j'ai appris un truc !
    je pensais pas passer un destructeur en public...


    Merci.
    Mais de rien... Ceci dit, dans le cadre d'un transtypage polymorpe, il faut surtout une deuxième chose si le destructeur est public (ce qui devient obligatoire si tu veux t'assurer le fait que la destruction d'un objet dont la mémoire a été allouée dynamiquement puisse se faire en invoquant le delete correspondant sur un pointeur sur le type de base), c'est la virtualité.

    De plus, si tu ne définis pas explicitement le destructeur d'une classe, celui que le compilateur implémente de manière implicite est d'office publique (pour permettre d'y accéder lorsque l'instance doit être détruite) mais... non virtuel
    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

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

Discussions similaires

  1. [C#] Heritage multiple -> comment faire autrement
    Par schnourf dans le forum Windows Forms
    Réponses: 14
    Dernier message: 03/10/2006, 15h14
  2. heritage multiple
    Par r0d dans le forum C++
    Réponses: 6
    Dernier message: 21/04/2006, 09h40
  3. [POO] Héritage multiple Parent
    Par djshaker dans le forum Langage
    Réponses: 15
    Dernier message: 15/03/2006, 17h35
  4. Réponses: 9
    Dernier message: 25/05/2005, 18h17
  5. [Kylix] heritage multiple et interfaces :(
    Par le_barbu dans le forum EDI
    Réponses: 4
    Dernier message: 26/01/2004, 19h30

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