Partage
  • Partager sur Facebook
  • Partager sur Twitter

[Théorie] Alternative au dynamic_cast<> ?

Sujet avancé

    3 avril 2008 à 17:23:35

    Bonjour tout le monde,

    J'ai une petite question concerant le dynamic_cast. J'ai une classe de base abstraite qui possède une fonction virtuelle pure. J'ai deux classes qui dérivent de cette classe abstraite et qui en plus de la fonction héritée ont d'autres fonctions membres.
    1. class Abstraite{
    2. public:
    3. virtual void fonction()=0;
    4. };
    5. class DeriveeA: public Abstraite{
    6. public:
    7. virtual void fonction();
    8. virtual int foo();
    9. };
    10. class DeriveeB: public Abstraite{
    11. public:
    12. virtual void fonction();
    13. virtual double maFonction(int);


    A partir de cette arborescence, j'ai réalisé une collection hétérogène de Abstraite*.

    1. std::vector<Abstraite*> collection;
    2. collection.push_back(new DeriveeA);
    3. collection.push_back(new DeriveeB);
    4. //...


    Je n'ai aucun problème pour utiliser la fonction membre "fonction()", mais j'aimerais pouvoir utiliser les fonctions membres de DeriveeA et DeriveeB. Pour ce faire, il y a le dynamic_cast

    1. DeriveeA* ptrA= dynamic_cast<DeriveeA*>(collection[0]);
    2. ptrA->foo();
    3. //...


    Et c'est là qu'apparaît mon problème. On dit partout que le dynamic_cast c'est mal, que c'est le signe d'une mauvaise conceptionet ainsi de suite. Ma question est donc: Comment faire autrement, de manière propre ?

    Merci d'avance à ceux qui ont une réponse à cette épineuse question.
    • Partager sur Facebook
    • Partager sur Twitter
    Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
      3 avril 2008 à 18:01:13

      En gros, tu veux connaitre le type de la classe polymorphe, pour downcaster. (je vois que tu downcast ta fonction mere en DeriveeA).

      Un truc bete et simple qui marche bien :

      1. class mere
      2. {
      3.    virtual int gettype()=0;  // methode virtuelle pure
      4. };
      5. class fille1:public mere
      6. {
      7.    int gettype(){ return 0;}   // gere ça avec un enum si ça te plait mieux
      8. }
      9. class fille2:public mere
      10. {
      11.    int gettype(){ return 1;}   // gere ça avec un enum si ça te plait mieux
      12. }
      13. // dans le code si tu veux savoir quelle est la fille :
      14. switch (obj->gettype())
      15. {
      16. case 0:
      17.    fille1* f = static_cast<fille1*>(obj);
      18.    // fait ce que tu veux sur fille1  -> come on !! viens pas la fifille !!! ahhhh !!!! hem. restons sérieux
      19.    break;
      20. // pareil pour les autres filles
      21. }




      • Partager sur Facebook
      • Partager sur Twitter

      Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

        3 avril 2008 à 18:04:59

        La réponse passe avant tout par une étude du contexte. Car techniquement, dynamic_cast est la solution à ce problème précis (sans parler de boost::polymorphic_cast, de static_cast, etc.) ; c'est juste qu'arriver à ce problème dénote souvent d'un mauvais choix en amont.

        Donc si tu veux une solution il faut nous dire ce que tu veux faire avec ce vilain down_cast.

        Et puis, tu es peut-être dans l'un des rares cas où le down_casting est justifié. C'est pas non plus une tare de l'utiliser, il n'est tout de même pas là pour rien ;)

        Citation : Pas de titre

        Un truc bete et simple qui marche bien :


        Tant qu'à faire du RTTI autant utiliser celui fourni par le langage... Vous pensez qu'il fait quoi dynamic_cast, si ce n'est exactement ça (en mieux) ? ;)
        Et puis là c'est un problème de conception, on ne cherche pas à trouver un autre moyen de faire ce que dynamic_cast fait déjà très bien, mais d'éviter d'avoir à l'utiliser.
        • Partager sur Facebook
        • Partager sur Twitter
          3 avril 2008 à 18:20:52

          Pour compléter la réponse de Laurent, j'ai une question.

          Quel est le sens de cette liste hétérogène? Et surtout quel est le sens d'appliquer au cas par cas un traitement sur ses éléments, traitement qui ne soit pas commun (virtuel) à tous les éléments ?
          • Partager sur Facebook
          • Partager sur Twitter
          C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
            3 avril 2008 à 19:08:14

            Je vais développer un peu plus l'exemple.

            Je suis gestionnaire d'un aéroport. J'ai une classe abstraite "Véhicule" avec des sous-classes "Avion" et "Voiture". Ceci est très pratique pour gérer les tâches communes, comme faire le plein d'essence, chager une roue ou réparer qui sont des tâches communes de ces "Véhicule".

            D'autre part je possède une liste de "Conducteurs" qui sont soit des "Pilotes", soit des "Chauffeurs". Egalement la liste est ici bien pratique puisqu'elle permet de gérer le salaire, les heures de travail,...

            Quand arrive le soir, j'aimerais bien ranger mes "Véhicules" dans les hangars. Pour ce faire, les pilotes rangent les avions et les chauffeurs les voitures. Pour ce faire j'aimerais bien réaliser une fonction dans la classe "Conducteur" du type "void parquer(Véhicule& v)" ou "void parquer(Véhicule* ptr)". Et ensuite spécialiser cette fonction dans "Pilote" (par exemple) de manière à ce que ce-dernier puisse ranger l'avion dans le hangar en utilisant des fonctions spécifiques aux "Avions" comme par exemple "rétro-freins" ou "réglageDérive", c'est-à-dire en transtypant le "Véhicule" en "Avion" par exemple.

            Je sais pas si mon exemple est plus clair comme ça.
            • Partager sur Facebook
            • Partager sur Twitter
            Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.
            Anonyme
              3 avril 2008 à 19:23:08

              Fonction membre template + Spécialisation dans tes classes dérivées ?
              • Partager sur Facebook
              • Partager sur Twitter
                3 avril 2008 à 19:41:45

                Cela me fait penser à une discussion [1] que j'avais eu avec Jean-Marc au sujet des hiérarchies parallèles -- j'ai l'impression que mon exemplaire de son pdf a disparu avec mon disque dur. Cela remonte un peu, et je crois bien que j'étais resté sur ma faim -- avec une solution "tordue", mais sans dynamic_cast.

                Dans ton cas, tu peux peut-être t'en sortir juste avec des visiteurs (design pattern) pour mettre en oeuvre le double-dispatch.

                [1] Si jamais le lien est corrompu, copie-colle ce qui suit: http://groups.google.fr/group/fr.comp.lang.c++/browse_frm/thread/688c0ad6f7a4935e/f426236fc36665bd
                • Partager sur Facebook
                • Partager sur Twitter
                C++: Blog|FAQ C++ dvpz|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS| Bons livres sur le C++| PS: Je ne réponds pas aux questions techniques par MP.
                  3 avril 2008 à 20:03:22

                  Mmmh pas mal le visitos patterns, je connaissais pas. Je vais essayer de voir ce que je peux en faire, mais à première vue ça devrait fonctionner.
                  • Partager sur Facebook
                  • Partager sur Twitter
                  Co-auteur du cours de C++. ||| Posez vos questions sur le forum ||| Me contacter.

                  [Théorie] Alternative au dynamic_cast<> ?

                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                  • Editeur
                  • Markdown