1. #1
    Membre du Club
    Profil pro
    Inscrit en
    février 2012
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2012
    Messages : 71
    Points : 51
    Points
    51

    Par défaut polymorphisme sans héritage

    Bonjour, je me suis mis récemment au c++ et j'entends souvent dire que l'héritage n'est pas une bonne chose. Pourtant le polymorphisme semble être presque aussi important que la poo en c++. Donc je me demandais si l'on ne pouvais pas faire du polymorphisme sans héritage. Par exemple un tableau contenant plusieurs classes qui n'ont pas d'origine en commune ou encore une fonction opérante sur une sorte de classe standardisée sans "virtual" .
    Merci d'avance.

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    août 2004
    Messages
    5 373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    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 373
    Points : 15 062
    Points
    15 062

    Par défaut

    Il y a moyen de faire du polymorphisme sans héritage, par exemple en utilisant std::variant. Mais ce n'est pas mieux. C'est différent. C'est mieux dans certains cas (types tous connus dès le début + traitements inconnus, types de taille semblable), et c'est moins bien dans d'autres (types inconnus au début + traitements bornés, types de taille différente).

    Pour plus de détails, http://akrzemi1.developpez.com/tutor...-polymophisme/
    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 chevronné
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    avril 2016
    Messages
    468
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : avril 2016
    Messages : 468
    Points : 2 076
    Points
    2 076

    Par défaut

    Bonjour.

    Citation Envoyé par aperdemak Voir le message
    Bonjour, je me suis mis récemment au c++ et j'entends souvent dire que l'héritage n'est pas une bonne chose.
    L'héritage a des possibilités larges. Très très larges. Il ne serait pas raisonnable de dire que l'héritage ne serait jamais une bonne chose. Il y a plein de cas où l'héritage est tout à fait adapté à la situation. Il y a aussi des cas où l'héritage est mal utilisé.

    Citation Envoyé par aperdemak Voir le message
    Donc je me demandais si l'on ne pouvais pas faire du polymorphisme sans héritage.
    Oui, il y a plein de possibilités :
    • A la place du patron de conception Template Method, on peut utiliser le CRTP.
      Edit 2017-08-08-11h47 : En fait, dans le CRTP, il y a de l'héritage aussi, mais il n'y a pas de fonctions virtuelles.
    • A la place du patron de conception Stratégie, on peut utiliser les classes de politique.
    • A la place du patron de conception Visiteur, on peut utiliser std::visit sur des std::variant (voir d'abord le lien donné ci-dessus par JolyLoic qui explique cette notion via les boost::variant qui sont similaires).


    Mais l'héritage n'est pas forcément la moins bonne solution. L'héritage a ses avantages et inconvénients, tout comme les templates et std::variant :
    • Les templates sont généralement plus performants que l'héritage.
    • Les templates augmentent le temps de compilation. Donc, dans les cas où l'héritage permet de ne pas avoir de template, cela fait un avantage de l'héritage par rapport aux templates.
    • La programmation orientée objet nécessite moins de connaissances techniques propres au langage et le compilateur est moins méchant en cas de bêtise par rapport aux templates.
    • La programmation orientée objet permet de travailler directement avec la classe de base quand on manipule des objets dont on ne connaît pas le type réel. Les templates n'offrent pas directement cette possibilité, donc on doit alors passer par des std::variant.
    • Pour manipuler des données dont on ne connaît le type qu'à l'exécution, std::variant est très adapté pour manipuler des types en nombre fini et qui existent déjà sans être modifiables (ex : int et std::string). L'héritage sans visiteur, lui, est très adapté quand on veut pouvoir ajouter facilement de nouveaux types.


    Citation Envoyé par aperdemak Voir le message
    Par exemple un tableau contenant plusieurs classes qui n'ont pas d'origine en commune ou encore une fonction opérante sur une sorte de classe standardisée sans "virtual" .
    Si tu veux explicitement des données hétérogènes dans un même tableau, alors JolyLoic a très bien répondu.

    Si tu entends que, l'héritage pour les données dans les conteneurs, c'est le mal, c'est parce qu'il existe des bibliothèques avec des conteneurs d'objets hétérogènes que des développeurs utilisent comme si c'étaient des conteneurs d'objets homogènes. Ils font alors du downcasting à outrance et implémentent des fonctions de comparaison qui peuvent potentiellement comparer des choux et des carottes. Pourtant, si on veut un code commun pour plusieurs conteneurs, chacun ne manipulant qu'un seul type de donnée (par exemple std::vector<Chou> et std::vector<Carotte>), la meilleure solution est de mettre le type d'objet en argument de template du conteneur.

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    février 2012
    Messages
    71
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : février 2012
    Messages : 71
    Points : 51
    Points
    51

    Par défaut

    Bonsoir, merci pour vos réponse.
    J'aurais une autre question voici du code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MyClass
    {
     private:
      std::vector<Carrot*> carrotList;
      std::vector<Potato*> potatoList;
      ...
     public:
      void Add(?*); //ici
    }
    Comment puis je faire pour push_back l'un des attribut de MyClass en fonction du type passer en paramètre sans créer autant de méthode que d'attribut ?

  5. #5
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Ingénieur systèmes embarqués
    Inscrit en
    juin 2009
    Messages
    3 583
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Ingénieur systèmes embarqués

    Informations forums :
    Inscription : juin 2009
    Messages : 3 583
    Points : 9 408
    Points
    9 408
    Billets dans le blog
    1

    Par défaut

    Citation Envoyé par aperdemak Voir le message
    Bonjour, je me suis mis récemment au c++ et j'entends souvent dire que l'héritage n'est pas une bonne chose.
    Je crois qu'on t'a mal renseigné

    La POO est le paradigme de programmation qui utilise des objets pour modéliser les éléments du système. Ces objets sont (presque toujours) des classes. Il y a deux grands types de liens entre les classes : la composition (et sa sœur quasi-jumelle l’agrégation ; note qu'on utilise souvent le mot "composition" pour parler des deux) et l'héritage.

    Il y a une règle que tu dois retenir, et je pense que c'est une version déformée de celle-ci que tu as entendu : il faut préférer la composition à l'héritage.

    L'héritage n'est pas une mauvaise chose. Faire de la POO sans héritage est tout à fait possible. On peut faire beaucoup de choses sans héritage. Néanmoins, l'héritage est un outil extrêmement puissant et il faudrait être fou pour le bannir totalement d'un design OO. L'héritage sert notamment à réutiliser facilement du code existant, à partager du code commun et à le spécialiser dans les sous-types. De l'héritage vient aussi la capacité de tous les langages OO modernes à faire du polymorphisme. Il existe plusieurs polymorphismes (voir le début de https://www.developpez.net/forums/d1...t-correctness/ en plus des liens déjà donnés) mais quand on dit juste polymorphisme, on sous-entend très souvent polymorphisme de sous-types, justement celui utilise l'héritage et les.... sous-types Tu peux faire de la POO sans héritage ; tu peux aussi faire de la POO avec héritage mais sans polymorphisme de sous-types).

    Au final, toutes ces techniques doivent servir un objectif, elles ne sont pas des buts en elles-mêmes. Si tu n'as pas de raison de faire de la composition, n'en fais pas ; si tu n'as pas de raison de faire de l'héritage, n'en fais pas ; si tu n'as pas de raison de faire du polymorphisme, n'en fais pas.


    Parlons de ce bout de code pour finir :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class MyClass
    {
     private:
      std::vector<Carrot*> carrotList;
      std::vector<Potato*> potatoList;
      ...
     public:
      void Add(?*); //ici
    }
    Tu peux ici utiliser de la surcharge (qui est en fait un type de polymorpshime, dit ad-hoc ) pour avoir deux méthodes Add(), une prenant en paramètre des carottes, l'autre des patates. Si ton objectif n'est pas d'avoir n fonctions si tu as n vecteurs, alors il faut te poser la question : qu'est ce qu'une patate et une carotte ont de commun ? Si elles n'ont rien de commun, alors tu dois les stocker (dans des vectors) et les traiter (avec Add()) séparément. Si tu estimes que des patates et des carottes sont des légumes, alors crées une super classe Vegetable et fais de l'héritage. Tu pourras avoir avec un seul vector<Vegetable*> et une seule méthode Add(Vegetable*). Tu utiliseras alors du polymorphisme de sous-type. Attention : une fois que tu auras des légumes, tu n'auras plus vraiment des patates et des carottes. Il deviendra peu évident de traiter séparément patates et carottes.

    On en revient à "toutes ces techniques doivent servir un objectif, elles ne sont pas des buts en elles-mêmes"

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

Discussions similaires

  1. Ajouter une méthode à une classe existante, sans héritage
    Par gvdmoort dans le forum Général Java
    Réponses: 21
    Dernier message: 11/12/2012, 12h11
  2. Polymorphisme et héritage
    Par samlesu dans le forum C#
    Réponses: 12
    Dernier message: 28/02/2011, 10h38
  3. Réponses: 11
    Dernier message: 25/05/2010, 13h39
  4. polymorphisme et héritage
    Par gelomaak dans le forum Débuter
    Réponses: 4
    Dernier message: 11/12/2008, 01h16
  5. polymorphisme d' héritage
    Par loacast dans le forum C++
    Réponses: 3
    Dernier message: 30/01/2007, 12h13

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