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 :

Problème d'héritage d'une ABC


Sujet :

C++

  1. #1
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut Problème d'héritage d'une ABC
    Salut les C++,

    j'ai plusieurs classes disposant de beaucoup de membres communs et d'une méthode commune: la méthode display(...).

    J'ai donc fait une classe de base dont toutes les classes héritent mais le problème est que je n'arrive pas a surcharger la méthode display(...) correctement:

    C'est la méthode display(...) de la classe parente qui est appeler lors de ce bout de pseudo-code:

    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
     
    #include <vector>
     
    #include "BaseClass.h"
     
    #include "ClassDerived.h"
     
    int main(int argc, char *argv[]) {
     
     
      std::vector<BaseClass> container ;
     
      for (int c=0 ; c < 1 ; c++) {
     
         ClassDerived instance(...) ;
     
         container.push_back(instance) ;
      }
     
      while (true) {
     
        int counter = 0 ;
     
        for (auto &instance : container) {
           instance.display() ; 
        }
     
      }
     
      return 0 ;
    }
    Alors comment définir la méthode display(...) dans la classe de base (BaseClass), dans le but que la méthode de la classe fille soit appeler ? A cause du conteneur.

    Car j'aimerai pouvoir stocker mes objets de types différents dans un conteneur unique.

    Je m'en sort pas avec tous ces mot-clefs (virtual, override, final, ...) au niveau de l'héritage.

    Par ailleurs j'aimerai que mes attributs privée restent privée dans la classe héritée, sans que le compilateur s'en plaigne.

    Alors quelle forme d'héritage utiliser: public, private ou protected ?

    Merci pour vos lumière si vous comprenez le fond de ma question.

    Merci pour vos réponses éclairées illuminant les ténèbres de ignorance.
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    Pour que les méthodes des descendants soient appelées, elles doivent être virtual.
    Dans un container tous les objets doivent avoir le même type. Alors pour mettre des objets dont le point commun est le type de base, on doit mettre dans le containers des objets référençant le type de base. Le plus simple est d'utiliser des pointeurs.
    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 Base {
    public:
       virtual void display() {}
    };
    class Derive1 : public Base {
    public:
       Derive1( int,int,int);
       void display() override {
          cout << "derivee #1";
       }
    };
    vector<unique_ptr<Base>> container;
    container.push_back( make_unique<Derive1>( 1,2,3 ) );
    container.push_back( make_unique<Derive2>() );
     
    for ( auto &d : container )
       d->display();

  3. #3
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    Autre remarque, partager du code n'est jamais un bon argument pour l'héritage autre que privé.
    Et dans votre cas d'utilisation, vous ne pouvez pas utiliser l'héritage privé.
    Je pense qu'il faire attention à votre conception et pas faire de l'héritage à tort et à travers.
    L'héritage, c'est le truc à faire en dernier recourt.

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

    Informations professionnelles :
    Activité : aucun

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

    La première chose qui me choque, moi, c'est std::vector<BaseClass> container ; : si tu veux pouvoir utiliser des comportements polymorphes (comprend: des fonctions dont tu redéfinis le comportement au niveau des classes dérivées), tu dois:
    1. définir les fonctions en question comme étant virutelles (mais ca, dalfab l'a déjà dit) et
    2. accéder aux différentes instances des classes dérivées sous la forme de pointeur ou de référence et uniquement sous ces formes

    Avec ton tableau destiné à revevoir des objets de type BaseClass, chaque fois que tu essaye de faire un push_back pour un élément dont le type est l'une des classes dérivées, tu observe un effet de slicing: tu n'ajoute en réalité que la partie correspondant à la classe de base de l'objet que tu essaye de rajouter dans ton tableau.

    Du coup, il devient impossible d'observer le moindre comportement polymorphe, et c'est normal : les objets contenus dans ton tableau ne sont pas considérés comme étant du type dérivé mais... comme étant du type de base.

    En outre, il faut savoir que toutes les fonctions de tous de tous les types de collection qui ont pour objectif d'ajouter un élément à la collection créent en réalité une copie de l'élément qu'elles ajoutent à la collection. Or, dés que tu décide de recourir à l'héritage publique entre deux classes, tu dois partir du principe que toutes les classes intervenant dans la hiérarchie de classes ont sémantique d'entité et qu'il devrait donc être impossible d'en faire une copie (et / ou d'affecter une instance à une autre, d'ailleurs)

    La solution pour résoudre tous ces problèmes est relativement simple : il "suffit" de maintenir un pointeur sur les différents éléments du tableau plutôt que de maintenir l'objet en lui-même. Mais, pour éviter que le pointeur en question ne risque d'être "invalidé" lorsque l'on sort de la portée dans laquelle l'élément est réellement créé, il faudra sans doute passer par l'allocation dynamique de la mémoire, si bien que tu as sans doute intérêt à utiliser des pointeurs intelligents (std::unique_ptr, par exemple), afin d'éviter de foutre "trop le bordel" au niveau de la mémoire.
    Au final, ton code devrait sans doute ressembler à quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    int main(int arc, char ** argv){
        std::vector<std::unique_ptr<BaseClass>> tab;
        tab.emplace_back(std::make_unique<DerivedClass>(/* params éventuels */) );
        /* ... */
        for(auto const & it : tab){
            it.get()->draw();
        }
        return 0;
    }
    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 expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut pas de C++14 dans g++ 4.8.4
    Merci les gars,

    j'ai pu implémenter l'héritage de tous mes objets d'une classe de base Polyhedron.

    Mais sous cette forme:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    std::vector<Polyhedron*> polyhedrons ;
     
    Sphere* polyhedron = new Sphere(...) ;
     
    polyhedrons.push_back(polyhedron) ;
    Car make_unique n'est pas définis dans la norme c++11...
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  6. #6
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    Le remplacement de make_unique n'est pas new bidule, mais unique_ptr(new bidule).
    un vecteur de pointeur nu n'indique pas qui doit détruire les pointés

    d'un autre coté, make_unique se crée en quelques lignes, si on retire la forme pour les tableaux.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    template< class T, class... Args >
    unique_ptr<T> make_unique( Args&&... args ) {
        return unique_ptr<T>(new T(std::forward<Args>(args)...));
    }
    Une bonne partie de C++14 peut se reconstruire rapidement. D'ailleurs, le site cppreference.com donne souvent des implémentations possibles.
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  7. #7
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut Nouveau problème.
    Salut les gars,

    j'ai un nouveau problème d'héritage de classe de base.

    Celui ci est analogue au premier c.a.d surcharger une méthode hérité mais cette fois la méthode hérité peut prendre n'importe quelle types d'arguments alors que le premier problème c'était les mêmes.

    Je désire donc que ma classe de base implémente une méthode générique que l'on puisse override avec un méthode de la classe fille qui prendrai des arguments totalement différents selon la classe fille.

    Est ce que cela est possible en c++ et si oui comment ?

    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
     
     
    class Base {
     
      public :
     
         virtual display(void) ; // No problem
     
         virtual reconfigure(...) ; // Here the problem
    } ;
     
    class Derived1 : public Base {
     
      public :
     
       void display(void) override ;
     
       void reconfigure(type1 arg1, type2, arg2, ...) override ;
    } ;
     
    class Derived2 : public Base {
     
      public:
     
       void display(void) override ;
     
       void reconfigure(type3 arg1, type4 arg2, ...) override ;
    } ;
    J'ai besoin de l'implémenter dans la classe de base pour pouvoir inclure mes classes filles dans un conteneur du type de la classe de base.

    Merci pour vos réponses éclairées illuminant les ténèbres de mon ignorance.
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 965
    Points
    32 965
    Billets dans le blog
    4
    Par défaut
    Non c'est pas possible. Si c'est pas les mêmes arguments, c'est pas la même signature et donc pas la même fonction.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    Et j'ai du mal à imaginer une conception objet qui aurait besoin de telles caractéristiques.

  10. #10
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    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 369
    Points : 41 518
    Points
    41 518
    Par défaut
    De plus, comment l'appellerais-tu?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  11. #11
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    Et bien en faîtes c'est une méthode

    reconfigure(...)

    qui prend les mêmes arguments que le constructeur de chaque objet dériver de Polyhedron et fait pratiquement la même chose: je régénère le buffer sans toucher a la position actuel grâce aux matrices dans la GPU...

    Mais je pense m'en sortir grâce au constructeur de copie ?!?
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  12. #12
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    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 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Si tu peux appeler le constructeur de copie, alors tu connais le type. Donc, tu n'as pas besoin que ta méthode soit virtuelle.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  13. #13
    Membre expérimenté
    Avatar de Luke spywoker
    Homme Profil pro
    Etudiant informatique autodidacte
    Inscrit en
    Juin 2010
    Messages
    1 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Etudiant informatique autodidacte

    Informations forums :
    Inscription : Juin 2010
    Messages : 1 077
    Points : 1 742
    Points
    1 742
    Par défaut
    Si parce que je désire placer des objets de types différents tous héritiers de la classe Polyhedron dans un conteneur de type Polyhedron justement...
    Pour faire tes armes:
    Use du présent pour construire ton futur sinon use de ce que tu as appris auparavant.
    Et sois toujours bien armé avant de te lancer.
    Le hasard ne sourit qu'aux gens préparés...
    Site: Website programmation international (www.open-source-projects.net)
    Site: Website imagerie 3D (www.3dreaming-imaging.net)
    Testez aux moins pendant une semaine l'éditeur avec terminaux intégrées it-edit Vous l'adopterai sûrement !
    FUN is HARD WORK !!!

  14. #14
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 071
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 071
    Points : 12 116
    Points
    12 116
    Par défaut
    Bin non, parce que vous ne pouvez pas avoir des objets de type différents dans un conteneur.
    Si vous voulez du polymorphisme, il faut passer par des pointeurs (de préférences intelligents).

    Je ne comprends pas pourquoi reconfigure fait partie de la classe Polyhedron.
    Si chaque sous-classe de Polyhedron à des arguments de constructeur différents:
    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
     
    class Base {
      public :
         virtual display(void) ; // No problem
    } ;
     
    class Derived1 : public Base {
      public :
       void display(void) override ;
    } ;
     
    class Derived2 : public Base {
      public:
       void display(void) override ;
    } ;
     
    Derived1 reconfigure(type1 arg1, type2 arg2, ...) {return Derived1(arg1,arg2,...);} ;
    Derived2 reconfigure(type3 arg1, type4 arg2, ...) {return Derived2(arg1,arg2,...);} ;
    Mais c'est toujours aussi abscons, car si vous avez des pointeurs sur Polyhedron dans un conteneur, c'est pour leur appliquer tous le même traitement, donc avec les mêmes arguments pour "reconfigure" (qui est un constructeur caché ???).

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 28/01/2015, 09h27
  2. Problème d'héritage avec une classe abstraite
    Par Ph.denis dans le forum C++
    Réponses: 7
    Dernier message: 22/03/2008, 10h37
  3. aidee :problème héritage d une fonction
    Par mitnick2006 dans le forum C++
    Réponses: 8
    Dernier message: 02/06/2007, 22h16
  4. Réponses: 3
    Dernier message: 22/03/2007, 11h06
  5. Problème d'héritage d'une méthode protégée
    Par shenron666 dans le forum C++
    Réponses: 9
    Dernier message: 28/04/2005, 23h17

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