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 / transtypage


Sujet :

C++

  1. #1
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut héritage / transtypage
    salut à tous.

    j'ai un problème conceptuel, je vous explique ce que je veux faire :

    J'ai une classe P (qui contient diverses variables)

    Ensuite je définis des classes A B et C dérivées de P dans lesquelles j'ai :

    static const int IdType=1 dans A
    static const int IdType=2 dans B
    static const int IdType=3 dans C

    je crée des instances de A B et C que je place dans un tableau de P*
    ceci est possible car mes instances de A B et C sont dérivées de P. j'utilise cette technique pour mettre des instances de classes différentes dans une même structure. je trouvais ça astucieux mais je rencontre un problème par la suite, quand j'accès à mon tableau de P*, je ne parviens pas à récupérer la valeur de IdType pour savoir de quelle classe est l'élément. en effet mon élément est vu en tant que P (qui n'a pas d'attribut IdType).

    Ma question est donc : comment récupérer mes éléments du tableau sous leur vrai type ?

    je ne sais pas si j'ai été clair dans mes explications, j'espère que vous pourrez m'aider, merci :

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2005
    Messages
    1 064
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2005
    Messages : 1 064
    Points : 1 053
    Points
    1 053
    Par défaut
    Hum, déclarer IdType dans P? Et pas en static tant qu'on y est...

  3. #3
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    Tout d'abord, merci pour ta réponse. Oui sans le static ça marcherait, mais dans mon cas je dois le laisser. Explication :

    Mon programme fera des milliers d'instanciations de A B et C, des constructions et destructions à tout bout de champ, un truc qui mouline beaucoup, et je dois économiser au maximum :
    - l'espace dans la ram
    - la rapidité

    Si j'enlève static, IdType sera recréé à chaque construction et détruit à chaque destruction, ça ralentit le programme ET prend davantage de mémoire.

    Voilà le static est indispensable dans mon cas. Il doit bien y avoir un moyen de m'en sortir pour créer 3 variables plutôt que des centaines de milliers (je n'exagère pas du tout).

  4. #4
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut
    Une autre solution consiterait à utiliser une fonction getType qui permettrai de récuperer la valaur correspondant au type. Le problème, c'est que pour que cela marche, il faudrait que cette fonction soit virtuelle, ce qui est susceptible de poser problème en ce qui concerne la vitesse d'exécution de ton code.

    La seule autre solution que je vois, c'est d'utiliser l'operateur typeid.
    "Toujours en faire plus pour en faire moins"

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

    Informations professionnelles :
    Activité : aucun

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

    Citation Envoyé par everyone
    Early optimisation is the root of all evil
    Je suis d'accord qu'il peut sembler important de gagner du temps et de l'espace mémoire partout où c'est possible, mais, quand même...

    Une énumération ne prend "que" la place d'un int, et, au pire, il y aurait même moyen de s'organiser pour faire tenir trois valeurs dans un char...

    Je suis d'accord que, pour plusieurs (centaines de) millier, cela *peut* finir par faire beaucoup, mais, selon moi, il y a surement bien d'autres endroits où les optimisations peuvent être bien plus nécessaires

    Dés lors, pourquoi ne pas "tout simplement" envisager de mettre un membre du type enum protégé dans l'interface
    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

  6. #6
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    Une énumération ne prend "que" la place d'un int, et, au pire, il y aurait même moyen de s'organiser pour faire tenir trois valeurs dans un char...
    oui, bon, j'ai juste mis IdType pour expliquer le problème. mais il n'y a pas que ça, il y a plein de valeurs et même un tableau de vecteurs, je ne peux pas me permettre de les recopier dans chaque instance.

    je vais me documenter sur les fonctions virtuelles comme me l'a suggéré bountykiller. si ça ralentit juste un peu ce sera quand même mieux que de recopier autant de variables inutilement

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Mais, de deux choses l'une:

    • Soit, les différentes valeurs (ou tableau de valeurs) sont uniques pour chaque instance de ta classe, et, à ce moment là, tu n'auras pas le choix: il faudra que ces différentes valeurs apparaissent dans ta classe,
    • Soit ces différentes valeurs (ou tableau de valeurs) sont gérés de manière externe à ta classe, et à ce moment là, il y a sans doute intérêt à envisager une autre classe qui les gérera (quitte à en transmettre l'instance dans les différentes méthodes )


    La question à se poser est donc "Ma classe peut-elle se contenter d'obtenir les valeurs en cas de besoin, ou faut il qu'elle en dispose de manière "inconditionnelle" "
    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

  8. #8
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    j'ai tenté avec le virtuel. je vais résumer mes classes :

    dans la suite, entier est un alias de unsigned short int.

    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 P
    {
      public :
        entier X : 3;
        entier Y : 3;
        virtual entier GetId();
        virtual entier GetValeur();
        P();
        virtual ~P();
        inline P(entier x, entier y);
    };
     
    class A : public P
    {
      public :
        static const entier Id=1;
        static const entier Valeur=10;
        static const bool MultVect=false;
        static vect Vecteurs[];
        inline A(entier x, entier y);
        inline entier GetId();
        inline entier GetValeur();
    };
    ça ne marche pas.
    mes questions :

    1) j'ai été obligé de créer le destructeur virtuel pour P je ne sais pas pourquoi, sans, ça me fait une erreur. alors j'ai mis un destructeur vide ... ça me semble bizarre j'ai dû faire une connerie quelque paert non ?

    2) Il me force aussi à définir les fonctions GetId et GetValeur pour P mais je ne veux pas m'en servir, je veux juste utiliser celles de A à la place de celles de P, comment faire ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Si tu ne dispose pas, dans ta classe P, des données qui puissent permettre de définir les méthodes GetId et GetValeur, il faut les déclarer en tant que méthodes virtuelles pures.

    Sois cependant attentif au fait que toute classe contenant, même par héritage, une méthode virtuelle pure (non redéfinies dans les classes filles) fera que la classe sera d'office abstraite (impossible à instancier sous cette forme).

    Pour information, une méthode virtuelle pure se crée sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    class P
    {
        public:
            P();//méthode non virtuelle
            virtual ~P(); //méthode virtuelle "simple"
            virtual entier GetId()=0;//méthode virtuelle pure
    }
    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

  10. #10
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut
    Citation Envoyé par Michel_57 Voir le message
    mes questions :

    1) j'ai été obligé de créer le destructeur virtuel pour P je ne sais pas pourquoi, sans, ça me fait une erreur. alors j'ai mis un destructeur vide ... ça me semble bizarre j'ai dû faire une connerie quelque paert non ?
    Non, c'est normal. En, fait, à partir du moment ou tu déclares 1 fonction comme virtuelle, le compilateur suppose que cette classe sera héritée. Il faut alors déclarer le destructeur comme virtuel lui aussi pour que ce soit le bon destructeur qui soit appelé au moment de la destruction de ton objet, et éviter d'avoir des fuites mémoires ou autre.
    (Rmq: il me semble que cela ne donne lieu qu'à un warning et non une erreur, mais cela dépend probablement du compilateur que tu utilise).

    Citation Envoyé par Michel_57 Voir le message
    2) Il me force aussi à définir les fonctions GetId et GetValeur pour P mais je ne veux pas m'en servir, je veux juste utiliser celles de A à la place de celles de P, comment faire ?
    La réponse a été donné plus haut. tu dois déclarer tes fonctions comme virtuelles pure (ou abstraite) en ajoutant = 0 à la fin de leur déclaration.
    "Toujours en faire plus pour en faire moins"

  11. #11
    Membre régulier

    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    133
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 133
    Points : 113
    Points
    113
    Par défaut
    j'ai suivi vos conseils, et ça m'a enlevé toutes mes erreurs mais une nouvelle erreur est apparue.
    dans une de mes fonctions je copiais une instance de P avec un P* p=new P; suivi d'un memcpy, mais il n'autorisait pas l'instantiation de classe abstraite. j'ai alors grugé en faisant un P* p=(P*)malloc(sizeof(q)); puis memcpy, et maintenant ça compile. J'espère que ce que j'ai fait est bon.
    je ferai des tests demain, et si tout va bien je pourrai mettre le tag résolu.

    merci à vous et bonne nuit !

  12. #12
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    dans une de mes fonctions je copiais une instance de P avec un P* p=new P;
    Pour recopier un objet proprement, il te faut déclarer un constructeur de recopie, c'est beaucoup plus sûr.

    P* p=(P*)malloc(sizeof(q)); puis memcpy
    C'est sûr qu'en théorie ça marche, mais en pratique, c'est risqué !!

    Parceque quand tu fais ça, aucun constructeur n'est appaellé, donc aucun membre n'est initialisé, et du coup, l'appel à des méthodes sur cet objet peut donner tout et n'importe quoi.

  13. #13
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 646
    Points : 240
    Points
    240
    Par défaut
    Citation Envoyé par bountykiler Voir le message
    Le problème, c'est que pour que cela marche, il faudrait que cette fonction soit virtuelle, ce qui est susceptible de poser problème en ce qui concerne la vitesse d'exécution de ton code.
    Excusez moi de vous demander pardon, mais juste en passant. Ca ralentit enormement le code? je ne comprend pas pourquoi ca doit ralentir l'execution?
    Ca prend quoi de plus? un test + un appel?
    En fait c'est juste que j'en utilise et je voudrais savoir si ca ralentit beaucoup ou pas, genre si y a un ratio?
    Merci

  14. #14
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Pour ce que j'en sais, pour les fonctions virtuelles, ça marche comme ça :

    - pour chaque classe définissant des fonctions virtuelles, une "VTable" contenant les adresses des implémentations propre à cette classe des fonctions virtuelles est crée

    - si une classe hérite d'une autre, elle hérite aussi de sa VTable au cas où des fonctions ne seraient pas re-définie dans la classe fille

    - lors de la création d'un objet, l'adresse de sa VTable est stockée avec lui

    Ainsi, lors de l'appel à une fonction virtuelle, le programme va lire l'adresse de la bonne implémentation à utiliser dans la VTable de l'objet et l'appeller.

    Tout ça, c'est des mécanismes qui dépendent du compilateur, mais je pense que l'esprit général est là.

    Du coup, à chaque appel de fonction virtuelle, tu as :
    - un déréferencement pour lire la VTable
    - un déréferencement pour executer la bonne fonction pointée par la VTable

    Ce qui peut être relativement lourd : par exemple, si tu appelle une fonction virtuelle qui ne fait que une addition, le temps de retrouver son adresse peut etre supérieur au temps d'execution de l'addition, ce qui est un peu dommage.


    Merci de me corriger si je me trompe...

  15. #15
    Membre éprouvé
    Profil pro
    Inscrit en
    Mai 2006
    Messages
    780
    Détails du profil
    Informations personnelles :
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Mai 2006
    Messages : 780
    Points : 1 174
    Points
    1 174
    Par défaut
    c'est pas ton pauvre int qui va te ralentir. Par contre ta fonction virtuelle et tes allocations dynamiques...

    Fait ton code déjà et voit les performances ( premature optimizations is the root of all evil, tout ça.. )

  16. #16
    Membre actif
    Profil pro
    Inscrit en
    Juin 2002
    Messages
    646
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2002
    Messages : 646
    Points : 240
    Points
    240
    Par défaut
    ok merci buzzkaido, je vois un peu mieux le truc maintenant

  17. #17
    Membre habitué
    Lycéen
    Inscrit en
    Juillet 2007
    Messages
    148
    Détails du profil
    Informations personnelles :
    Âge : 32

    Informations professionnelles :
    Activité : Lycéen

    Informations forums :
    Inscription : Juillet 2007
    Messages : 148
    Points : 145
    Points
    145
    Par défaut
    Citation Envoyé par buzzkaido Voir le message
    Ce qui peut être relativement lourd : par exemple, si tu appelle une fonction virtuelle qui ne fait que une addition, le temps de retrouver son adresse peut etre supérieur au temps d'execution de l'addition, ce qui est un peu dommage.


    Merci de me corriger si je me trompe...
    Et si on déclare la fonction en inline?

  18. #18
    Membre régulier
    Homme Profil pro
    Développeur .NET/C/C++
    Inscrit en
    Septembre 2007
    Messages
    71
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur .NET/C/C++
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2007
    Messages : 71
    Points : 122
    Points
    122
    Par défaut
    Citation Envoyé par bogoss91 Voir le message
    Et si on déclare la fonction en inline?
    De toute façon, à partir du moment ou une fonction est déclarée comme virtuelle, on vérifie le type de la variable et la fonction à appelé au moment de l'exécution, et cela a un cout. le fait de déclarer cette fonction comme inline ne change rien au fait que cette vérification est nécessaire, et donc au surcout qu'elle engendre.
    Je vais d'ailleurs de trouver un eexplication intéressante à ce sujet ici
    "Toujours en faire plus pour en faire moins"

  19. #19
    Membre éclairé
    Avatar de buzzkaido
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juillet 2004
    Messages
    821
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2004
    Messages : 821
    Points : 734
    Points
    734
    Par défaut
    Euh, je dis peut-etre une betise, mais le but des fonctions virtuelles est d'appeller differentes implémentations de la même fonction selon le contexte.

    Or ce contexte (dans quel objet est-on) n'est connu qu'à l'execution, et pas à la compilation (sinon il suffit de dériver sans fonctions virtuelles)

    A prtir de ce moment, le compilateur ne peut tout simplement pas "inliner" une fonction virtuelle car il ne sait pas encore quelle version de cette fonction il va devoir appeler.

    D'une façon générale, une bonne architecture en C++ a des avantages :
    - bonne organisation du code
    - bonne lisibilité du code
    - bonne maintenance

    Mais a aussi des inconvénients :
    - beaucoup d'appels de fonctions qui appellent des fonctions qui appellent des fonctions...
    - beaucoup de déreferencements (pointeurs)

    Ces opérations ont un coût, c'est pourquoi il faut se poser les bonnes questions :
    - qu'est-ce que j'ai à gagner à éviter un appel de fonction en évitant les virtuelles ?
    - qu'est-ce que j'ai à perdre en compliquant le code en n'utilisant pas de fonctions virtuelles ?

    L'un dans l'autre, je te conseille de coder ton programme le plus proprement possible, sans tenir compte des contraintes, et ensuite de voir si il tourne assez vite.

    Si ce n'est pas le cas, il suffit souvent d'optimiser 2-3 petites choses tout en gardant la "bonne" architecture que tu a créé au départ.

  20. #20
    screetch
    Invité(e)
    Par défaut
    il n'y a pas a tortiller du cul, i lfaut utiliser des fonctions virtuelles. Toute tentative de contourner les fonctions virtuelles va conduire a l'implementation d'un systeme similaire mais encore plus couteux! exemple, tu ne mets pas le getId() en virtuel, tu fais un switch/case sur le type de l'objet, c'est :
    1) inextensible
    2) inefficace
    mais tu as bien supprimé l'appel virtuel, felicitation!!! :-/

    un vecteur contient des pointeurs sur des objets dont le type peut varier => methode virtuelle, c'est tout.

    Si vraiment il y a un probleme avec ca il sera temps de penser a quelque chose d'idiot plus tard.

Discussions similaires

  1. [PHP 5.0] Héritage et transtypage PDOStatement
    Par im-souf dans le forum Langage
    Réponses: 2
    Dernier message: 02/12/2011, 13h37
  2. Problème d'héritage et de transtypage
    Par Higgins dans le forum C#
    Réponses: 12
    Dernier message: 07/01/2011, 18h08
  3. transtypage, héritage et surcharge!
    Par Syphys dans le forum Langage
    Réponses: 3
    Dernier message: 16/11/2009, 14h44
  4. [C++]closure + héritage + transtypage
    Par JEG dans le forum C++Builder
    Réponses: 11
    Dernier message: 30/01/2004, 14h26
  5. Héritage entre Forms
    Par BarBal dans le forum Composants VCL
    Réponses: 7
    Dernier message: 29/08/2002, 17h44

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