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 :

héritage et pointeur générique de type classe mere


Sujet :

C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut héritage et pointeur générique de type classe mere
    Bonjour,

    C'est peut etre un peu tordu, mais ca me parait pratique de pouvoir faire ça, est-ce possible ? :

    Soit une classe mere A qui possede une fonction public : f_public()
    Soit des classes B et C qui héritent de A
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
          A
       ------
       |    |
       B    C
    Maintenant, j'ai un callback qui prend en parametre un pointeur sur une classe de type void * :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static void callback( void * MaClasse)
    Au debut de mon callback, je dois donc caster MaClasse pour pouvoir appeller f_public(). Mais comme f_public() fait partie de A, je voudrais faire en sorte que mon callback accepte indifférement une classe de type B ou C.
    Comment faire quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    static void callback( void * MaClasse){
        A *classe = (A*)MaClasse;
        classe->f_public();
    }
    Sachant donc que MaClasse peut etre de type B ou C et non A

    Merci

    Edit :
    Ou alors une autre solution éventuelle ? :
    Lorsque je définit le param de mon callback, si j'ai un pointeur de type :
    B *classe
    Est ce qu'il y a un moyen d'avoir le pointeur vers la classe mere a partir de classe.
    Comme ca je pourrait toujours envoyer un pointeur de type A* quelque soit le type de ma sous-classe.

  2. #2
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    f_public doit être virtual…

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 35
    Points : 38
    Points
    38
    Par défaut
    J'ai peut être mal compris, mais ce que tu cherches à faire est très facile, c'est même l'un des principes de base du C++

    Déjà, évite d'utiliser des pointeurs void en C++, C'EST MAL. (Ça mange les enfants et tout...)

    Il te suffit de définir ta fonction comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static void callback(A *MaClasse)
    {
        MaClasse->f_public();
    }
    Tu peux ensuite l'appeler avec une instance de B ou de C comme argument ! Ça marchera puisque comme B et C héritent de A, toute objet de type B ou de type C est aussi de type A.
    C'est magique le C++

    D'ailleurs, la syntaxe suivante est parfaitement valide:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    B *b = new B;
    C *c = new C;
    A *a;
     
    a = b;     // valide
    a = c;     // valide
    Mais évidemment b=a serait invalide...

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    35
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 35
    Points : 38
    Points
    38
    Par défaut
    Citation Envoyé par JeitEmgie Voir le message
    f_public doit être virtual…
    J'ai pensé aussi au début qu'il cherchait à utiliser une fonction virtuelle, mais sa fonction f_public est visiblement une fonction de A uniquement.

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par P@ulo Voir le message
    Déjà, évite d'utiliser des pointeurs void en C++, C'EST MAL. (Ça mange les enfants et tout...)
    Ce n'est pas moi qui ai écrit ce callback. Mais de tout façon un paramètre de callback, pour être générique, je ne vois pas comment faire autrement qu'avec un void *
    Tu peux ensuite l'appeler avec une instance de B ou de C comme argument ! Ça marchera puisque comme B et C héritent de A, toute objet de type B ou de type C est aussi de type A.
    C'est magique le C++
    Merci, je vais essayer ca !

    J'ai pensé aussi au début qu'il cherchait à utiliser une fonction virtuelle, mais sa fonction f_public est visiblement une fonction de A uniquement.
    Effectivement, ma fonction n'est définie que dans A

  6. #6
    Alp
    Alp est déconnecté
    Expert éminent sénior

    Avatar de Alp
    Homme Profil pro
    Inscrit en
    Juin 2005
    Messages
    8 575
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Juin 2005
    Messages : 8 575
    Points : 11 860
    Points
    11 860
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    Ce n'est pas moi qui ai écrit ce callback. Mais de tout façon un paramètre de callback, pour être générique, je ne vois pas comment faire autrement qu'avec un void *
    Les templates ?

    En C tu n'as que void*, en C++ c'est bien plus simple. Tu as même des bibliothèques qui font déjà tout le boulot à ta place, comme boost.function.

  7. #7
    Expert confirmé
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 937
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 937
    Points : 4 358
    Points
    4 358
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    Ce n'est pas moi qui ai écrit ce callback. Mais de tout façon un paramètre de callback, pour être générique, je ne vois pas comment faire autrement qu'avec un void *

    Merci, je vais essayer ca !


    Effectivement, ma fonction n'est définie que dans A
    la définir "virtual" garantit simplement que le jour où vous implémentez f_public() dans une sous-classe de A, la callback continue à fonctionner comme on l'espère : càd en appelant la f_public() de la classe dont l'objet en paramètre est effectivement membre…

    sinon vous avez juste créé un problème caché : cela ne fonctionne QUE parce que f_public() est implémentée uniquement dans la classe dont vous faites le cast dans la callback…

    au niveau déclaration, la callback pourrait tout aussi bien accepter un paramètre (A *maClasse)… si vous déclarez "class B : public A" et non "class B : A"…

    sans "virtual" et avec des f_public() dans les sous-classes, il faudrait activer RTTI pour pouvoir appeler dans la callback la "bonne" f_public()…

  8. #8
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Citation Envoyé par Alp Voir le message
    Les templates ?

    En C tu n'as que void*, en C++ c'est bien plus simple. Tu as même des bibliothèques qui font déjà tout le boulot à ta place, comme boost.function.
    Ok. Mais ce callback est passé à une librairie tierce écrite en C, donc c'est pour ça que le type du parametre doit etre un void *

    JeitEmgie : merci pour les précisions.

  9. #9
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Attention, quand tu enregistres le B* ou le C* pour qu'il soit passe ensuite comme void* a ta fonction, il faut d'abord le caster en A* avant de laisser faire la conversion implicite en void*. Si tu ne le fais pas et tu n'as pas d'heritage multiple, il y a un risque certain que ca ait l'air de marcher -- jusqu'au moment d'une demo critique uniquement! Murphy se rappellera alors a toi . Si tu as de l'heritage multiple, le risque de devoir attendre la demo au client pour voir le probleme se manifester descend a 50% ou moins encore.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

  10. #10
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Merci à tous pour ces conseils bien utiles

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    613
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 613
    Points : 406
    Points
    406
    Par défaut
    Jean-Marc.Bourguet : suite à ta derniere remarque, je me demande si ce que j'avais fait est correct ? :

    Soit un tableau de pointeur :

    A * TabClasses[2]
    Et je stocke dans ce tableau soit des classe B ou C :
    exemple :
    TabClasses[0] = new B()

    Est ce que ceci est correct ? :
    B *b = (B*)TabClasses[0]
    Je peux acceder aux fonctions de B apres ça ?

    merci

  12. #12
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Ce que dit Jean-Marc, c'est que si tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void* p = new B();
    A* a = static_cast<A*>(p);
    avec B qui hérite de A, alors tu invoques un comportement indéfini (ou non spécifié, je ne sais pas quelle est la bonne terminologie ici).
    Boost ftw

  13. #13
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par pasdeface Voir le message
    Jean-Marc.Bourguet : suite à ta derniere remarque, je me demande si ce que j'avais fait est correct ? :

    Soit un tableau de pointeur :

    A * TabClasses[2]
    Et je stocke dans ce tableau soit des classe B ou C :
    exemple :
    TabClasses[0] = new B()

    Est ce que ceci est correct ? :
    B *b = (B*)TabClasses[0]
    Je peux acceder aux fonctions de B apres ça ?
    Pour autant que TabClasses[0] ne soit pas un autre descendant de A, oui.

    Citation Envoyé par loufoque Voir le message
    Ce que dit Jean-Marc, c'est que si tu fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    void* p = new B();
    A* a = static_cast<A*>(p);
    avec B qui hérite de A, alors tu invoques un comportement indéfini (ou non spécifié, je ne sais pas quelle est la bonne terminologie ici).
    indefini (cad que n'importe quoi peut arriver a partir du moment ou c'est execute, y compris des effets non causaux, possibles parce que les optimiseurs peuvent supposer que ca n'arrive pas; non specifie en gros c'est quand il y a plusieurs comportements corrects et qu'on n'en impose aucun, le choix ne doit meme pas etre consistant d'une evaluation a l'autre, exemple: l'ordre d'evaluation des parametres). Il faut faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    void* pV = static_cast<A*>(new B());
    A* pA = static_cast<A*>(pV);
    Pour voir pourquoi c'est indefini, imaginons que B herite (avec de l'heritage multiple) directement de A1 et de A2; ce qui veut dire qu'en transformant un pointeur vers B en un pointeur vers A1 ou A2, il est necessaire d'introduire un offset. Donc apres:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    void* pV = new B();
    A1* pA1 = static_cast<A1*>(pV);
    A2* pA2 = static_cast<A2*>(pV);
    il y a au maximum une des variables pA1 et pA2 qui a un contenu correct. Dans le cas de l'heritage simple, on pourrait toujours s'arranger pour que l'offset soit nul, mais la norme ne l'impose pas. Un systeme pourrait vouloir toujours garder le vptr en premiere position par exemple et donc introduire un offset quand on herite d'une classe sans fonctions virtuelles en definissant une classe qui en a.
    Les MP ne sont pas là pour les questions techniques, les forums sont là pour ça.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 21/05/2014, 14h17
  2. appel d'une methodes classe fille de type classe mere
    Par Mephista dans le forum Langage
    Réponses: 8
    Dernier message: 29/10/2011, 23h05
  3. Réponses: 3
    Dernier message: 23/09/2010, 16h52
  4. Réponses: 6
    Dernier message: 22/07/2010, 15h17
  5. Pointeur générique vers d'autres types d'objets
    Par LapinGarou dans le forum MFC
    Réponses: 11
    Dernier message: 15/09/2006, 16h48

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