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 :

Polymorphisme : collection hétérogène sélective


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut Polymorphisme : collection hétérogène sélective
    Bonjour,

    A partir d'une classe mère, je me constitue une collection hétérogène d'instances filles, et souhaite la parcourir de manière sélective, ç-à-d en n'appelant la fonction polymorphique que d'une seule d'entre elles.

    En partant de l'exemple simple ci-dessous :
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
     
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    class Mere
    {
    protected:
        int valeurA;
        int valeurB;
     
    public:
        Mere(int const& a, int const& b) : valeurA(a), valeurB(b) {} 
        ~Mere(){} 
     
        virtual double ValeurResultante(void) = 0;
    };
     
    class Fille1 : public Mere
    {
    public:
        Fille1(int const& a, int const& b) : Mere(a, b) {} 
        ~Fille1(){} 
     
        double ValeurResultante(void){return valeurA + valeurB;}; // addition
    };
     
    class Fille2 : public Mere
    {
    public:
        Fille2(int const& a, int const& b) : Mere(a, b) {} 
        ~Fille2(){} 
     
        double ValeurResultante(void){return valeurA * valeurB;}; // multiplication
    };
     
    int main(void)
    {
    	vector<Mere *>collectionHeterogene;
     
    	collectionHeterogene.push_back(new Fille1(3,4));
    	collectionHeterogene.push_back(new Fille2(3,4));
     
    	double sommeValeurResultante(0);
    	for (size_t i(0); i < collectionHeterogene.size(); ++i)
    		sommeValeurResultante += collectionHeterogene[i]->ValeurResultante();
     
    	cout << "Somme des valeurs resultantes = " << sommeValeurResultante << endl;
     
    	return 0;
    }
    je parcours dans ce cas Fille1 et Fille2 en appelant la fonction polymorphique ValeurResultante() (et j'obtiens 19), mais je souhaiterais ne parcourir que Fille1 (pour obtenir 7)...

    En fouillant un peu, j'ai entendu parler de dynamic_cast ou double dispatch (visitor pattern); est-ce que ce sont de bonnes pistes ? si oui, comment les utiliser concrètement ? (parce que je n'y arrive pas ), sinon qu'est-il possible d'envisager (en maintenant 1 collection hétérogène) ?

    Merci et bonne fin de week-end (pour ceux qui sont en congé ce lundi de Pentecôte...)

  2. #2
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    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 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Ça marchera avec dynamic_cast, mais c'est une mauvaise idée.

    Car à la base, la question est pourquoi ne veut-tu appeler la fonction que pour fille1 ? Tu brises tous les principes objet en voulant différencier tes traitements en fonction du type réel de l'objet. C'est signe généralement d'une mauvaise conception.

    Après, difficile sur une cas abstrait comme ici de proposer une alternative correcte. Ici, ajouter une fonction virtuelle dans la classe de base qui retourne 0 partout mais ValeurResultante pour fille1 résoudrait le problème, et aurait peut-être l'avantage par rapport au dynamic_cast que le nom de la fonction rendrait les choses plus lisibles.
    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 régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Merci; je craignais un peu ta réponse. Je souhaitais ne constituer qu'une seule collection hétérogène pour effectivement n'obtenir qu'une seule ValeurResultante() pour tous les objets, mais si par la suite j'ai besoin de ventiler le détail du résultat par catégorie (classe fille) je ne voyais pas comment faire, sauf à créer une collection de Fille1, et une de Fille2. Mais du coup je perd l'intérêt du polymorphisme... A noter que l'exemple pris ici simplifie à l'extrême un code contenant une vingtaine de classes sur 4 niveaux d'héritage et 5 fonctions virtuelles différentes, d'où mon besoin d'une implémentation commode.

    Sinon, pourquoi dit-on souvent que dynamic_cast est une mauvaise solution ? parce que finalement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    double sommeValeurResultanteFille1(0);
    for (size_t i(0); i < collectionHeterogene.size(); ++i)
    {
    	Fille1 *fille1 = dynamic_cast<Fille1 *>(collectionHeterogene[i]);
    	if (fille1 != nullptr)	
    		sommeValeurResultanteFille1 += fille1->ValeurResultante();
    }
     
    cout << "Somme des valeurs resultantes Fille1 = " << sommeValeurResultanteFille1 << endl;
    marche plutôt bien, et reste assez compréhensible.

    Bonne soirée

  4. #4
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    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 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Le problème du dynamic_cast n'est pas la lisibilité... C'est hélas très lisible...

    Le problème c'est qu'il va à l'encontre de l'open-closed principle, qui dit en gros que pour faire évoluer du code, dans l'idéal, il faut lui ajouter des choses, mais pas en modifier. Quand tu ajoutes une classe dérivant d'une classe existante, normalement, tout va bien, le seul fichier à modifier est celui qui défini ta nouvelle classe. Les modifications sont centralisées.

    Mais si tu as mis du dynamic_cast un peu partout, là, quand tu ajoutes une classe, tu dois repasser sur tous les cas d'utilisation de cette classe, afin de savoir à chaque endroit si tu entres dans un des cas prévus, ou s'il te faut en prévoir un nouveau. Finalement, tu perds tout l'intérêt d'avoir mis des fonctions virtuelles dans ta classe de base.
    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.

  5. #5
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Je ne comprends pas tout à fait pourquoi il faudrait modifier le code de base si on rajoute une classe:
    - si c'est une classe dérivée de fille1 elle sera "comptée" lors du parcours de la collection (c'est en général le sens de l'héritage, de toute façon, donc c'est probablement le comportement désirable)
    - si c'est une classe dérivée de fille2 ou directement de mère, elle sera ignorée (c'est en général également un comportement désirable).
    Non?

  6. #6
    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 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Et si c'est une classe dérivée de Fille1 dont on ne veut pas le compte, ou de Mere ou Fille2 dont on veut le compte, faut ajouter un "cas particulier".
    Et que de toutes façons, vouloir faire une action particulière sur certains éléments d'une collection hétérogène : à quoi sert la collection dans ce cas ?! à (moitié à) rien.
    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.

  7. #7
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Et si c'est une classe dérivée de Fille1 dont on ne veut pas le compte, ou de Mere ou Fille2 dont on veut le compte, faut ajouter un "cas particulier".
    Et que de toutes façons, vouloir faire une action particulière sur certains éléments d'une collection hétérogène : à quoi sert la collection dans ce cas ?! à (moitié à) rien.
    J'allais te répondre qu'il serait étrange de créer une classe dérivée de Fille1 sans vouloir la compter parmi les Fille1, mais il est vrai que c'est précisément ce que cherche à faire dasycarpum en faisant une collection de Mere sans vouloir les compter toutes.

    Cela étant, la collection hétérogène est un cas suffisamment utile pour qu'en effet le pattern "visiteur" y soit consacré. A ce sujet, dasycarpum, il y a une page sur le site: http://pcaboche.developpez.com/artic...e/?page=page_5

    Si cela te pose des problèmes d'implémentation dans ton cas, comme ton message initial le suggérait, quelles sont-elles?

  8. #8
    Membre régulier
    Profil pro
    Responsable d'un système d'information métier
    Inscrit en
    Janvier 2011
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Responsable d'un système d'information métier
    Secteur : Administration - Collectivité locale

    Informations forums :
    Inscription : Janvier 2011
    Messages : 114
    Points : 113
    Points
    113
    Par défaut
    Merci à tous pour vos éléments de réponse, cela m'éclaire un peu plus sur les tenants et aboutissants d'une collection hétérogène, ainsi que les risques encourus dans la gestion du code à mettre en place des règles particulières. Et merci aussi à stendhal666 pour sa page sur les visiteurs, c'est effectivement bien expliqué.

    Bonne soirée,

    dasycarpum

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

Discussions similaires

  1. Problème de tri sur collection d'enfants hétérogènes
    Par touftouf57 dans le forum XSL/XSLT/XPATH
    Réponses: 1
    Dernier message: 04/02/2013, 01h21
  2. [NHibernate] Collection est polymorphisme
    Par MacReiben dans le forum NHibernate
    Réponses: 0
    Dernier message: 05/10/2011, 14h22
  3. Polymorphisme et Collection
    Par minilapin dans le forum Général VBA
    Réponses: 2
    Dernier message: 07/04/2011, 11h20
  4. surcharge et collection hétérogène
    Par Bulkilol dans le forum C++
    Réponses: 6
    Dernier message: 30/04/2008, 23h29
  5. [VB6] Modifier la clé d'un élément d'une collection
    Par Ricou13 dans le forum VB 6 et antérieur
    Réponses: 3
    Dernier message: 21/11/2002, 14h49

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