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++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    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
    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.

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 599
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    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 599
    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 confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 502
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

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

    Informations forums :
    Inscription : Février 2005
    Messages : 5 502
    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
    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,

    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 éprouvé
    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
    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...

  6. #6
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    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 202
    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.

+ 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