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 :

[Downcasting] Violation de Principes Orienté Objet ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut [Downcasting] Violation de Principes Orienté Objet ?
    Bonjour à tous,

    Je possède une classe de base assez conséquente (appelons là Base) et une multitude de classes filles (Fille1, Fille2, Fille3, Fille4) qui implémentent les fonctions virtuelles de Base via un template method.
    Seulement, chaque classe fille a son petit truc à soi, comme ActivateFonction1(), etc...

    Ainsi, dans mes fenêtres WxWidget qui possèdent une Base*, je suis obligé à chaque fois de downcaster pour pouvoir me servir des petits trucs de chaque Fille.

    Vous en pensez quoi ? Mauvaise conception ou phénomène inéluctable ?

  2. #2
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Si c'est du downcasting dynamique, je pense c'est possible que ce soit une mauvaise conception.
    Si c'est statique, il est probable selon moi que ce soit un phénomène inéluctable.
    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.

  3. #3
    Membre éclairé Avatar de befalimpertinent
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    561
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Gironde (Aquitaine)

    Informations forums :
    Inscription : Avril 2007
    Messages : 561
    Par défaut
    C'est vrai que ça sent le problème de conception à plein nez !
    N y a t'il vraiment aucun moyen d'utiliser le polymorphisme pour l'appel de tes fonctions ActivateFonction1(), ... ?

  4. #4
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Si c'est du downcasting dynamique, je pense c'est possible que ce soit une mauvaise conception.
    Si c'est statique, il est probable selon moi que ce soit un phénomène inéluctable.
    C'est du statique, car je suis sûr du downcasting...

    Citation Envoyé par befalimpertinent Voir le message
    C'est vrai que ça sent le problème de conception à plein nez !
    N y a t'il vraiment aucun moyen d'utiliser le polymorphisme pour l'appel de tes fonctions ActivateFonction1(), ... ?
    Si, de mettre ActivateFonction1() dans la classe mère, mais ça n'a aucun sens pour les autres classes Filles... Résultat : effet de bord global pour une modification locale...

    En fait si, il y aurait une solution à base du pattern Stratégie peut-être. C'est à dire encapsuler ce qui varie avec la composition. J'aurai un comportement ne rien faire si j'appelle la fonction ActivateFiltrage() par exemple, ou bien un comportement de filtrage.
    Mais bon ça fait un peu "forcer" la conception à rentrer dans un moule pour éviter de downcaster... C'est pas forcément très propre non plus...

    Mon problème est un problème général en fait : comment fait t-on pour manipuler un objet qui implémente des fonctions membres qui lui sont propres en plus de l'interface de la classe de base ?
    Réponse : on peut pas sans downcaster...

    Je vais continuer à creuser ma conception pour essayer de contourner ce problème ...

  5. #5
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    A chaque fois que j'ai pense que le downcasting etait une bonne solution, les evolutions ulterieures m'ont montre que ce que je voulais en fait etait du dispatch multiple. Ta description est trop vague pour en etre sur, mais j'envisagerais la chose. La technique habituelle pour implementer du dispatch multiple en C++ est generalement expliquee en conjonction avec le pattern visiteur.

  6. #6
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Je connaissais pas le dispatch multiple, je suis en train de bosser dessus, j'ai trouvé ICI des choses intéressantes. Je suis preneur de toutes autres infos...

    @ Jean-Marc : Il y a quand même des cas où le downcasting est obligatoire non ? Où on est obligé de connaitre exactement le type manipulé ?

  7. #7
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Salut,

    Qu'est-ce qui déclenche un appel aux méthodes spécifiques des classes filles ?
    Est-ce que cette prise de décision ne pourrait pas être encapsulée dans une abstraction de plus haut niveau qui n'aurait justement pas connaissance de l'existence des spécificités des classes filles ?
    Je pense par exemple peut-être tout simplement à une méthode virtuelle DoPreSomething() qui serait appelée quelque part avant le DoSomething() de ton template method.
    Ensuite il faudrait encapsuler tout ce qui concerne ActivateFunction1() (le test pour savoir si faut l'appeler et toutes les données nécessaires pour ça) dans l'implémentation de DoPreSomething() pour Fille1.

    En résumé à mon avis il manque peut-être un niveau d'abstraction.
    (et sans doute une factorisation dans Base de données qui devraient être laissées dans les classes filles pour pouvoir y encapsuler les traitements spécifiques, mais là sans plus d'informations c'est de la boule de crystal )

    MAT.

  8. #8
    Membre Expert
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Par défaut
    Citation Envoyé par Mat007 Voir le message
    En résumé à mon avis il manque peut-être un niveau d'abstraction.
    (et sans doute une factorisation dans Base de données qui devraient être laissées dans les classes filles pour pouvoir y encapsuler les traitements spécifiques, mais là sans plus d'informations c'est de la boule de crystal )
    Hum... ça m'intéresse d'avoir ton avis, j'ai peut-être raté quelque chose.
    OK je voulais essayer de faire comprendre le problème sans trop exposer mes vrais classes (c'est toujours plus difficile à comprendre pour les autres) mais bon j'y vais.

    J'ai une classe de base abstraite Camera, simple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Camera {
    public:
        // constructeur  + destructeur + méthodes communes à toutes les caméras
        Image  LoadImage (int numero) {return m_Image; }
     
    protected:
        virtual void ImportImage (int numero) = 0; // A implémenter dans les classes filles
        Image m_Image; //Stocke la dernière image importée
    };
    Comme je gère plein de caméras différentes, avec plein de façon différentes de récupérer les données, j'encapsule le rapatriement des images depuis un endroit donné dans ImportImage().

    Les caméras sont nombreuses : CameraVisible, CameraInfraRouge, etc...
    Seulement certaines d'entre elles sont un tout petit peut différente, elles se voient appliquer un filtre, et il faut donc multiplier l'image par un facteur global à calculer. D'autres calculs aussi. Ce qui nous donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class CameraVisible : public Camera {
    public:
        // constructeurs etc...
        void SetFilterOn();
        void SetFilterOff();
     
        void SetFluxOn();
        void SetFluxOff();
     
    protected:
        virtual void ImportImage (int ); //implémenté dans le .cpp
    };
    Un exemple de mon programme pourrait être celui-ci : j'ai 6 fenêtres windows possédant chacune un pointeur vers une Camera.
    • S'il agit d'une CameraVisible, la fenêtre doit laisser la possibilité dans les menus déroulants d'actionner SetFilterOn()
    • S'il agit d'une Camera "normale", alors ces menus sont grisés pour montrer que cette opération n'est pas disponible...


    Je pense avoir ici bien illustré mon problème... J'espère que vous aurez beaucoup de critiques et de solutions à proposer, j'adore apprendre...


  9. #9
    Membre Expert

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Par défaut
    Si tu as peu d'opérations particulières tu peux éventuellement les remonter sur l'interface/classe de base (SetFilterOn() par exemple ne fera rien quand une caméra n'a pas de filtre).
    Il faut sans doute ajouter des accesseurs un peu moches pour gérer les entrées dans le menu (genre un splendide bool HasFilter() const) ou bien préciser au moment de l'enregistrement d'une caméra auprès de la fenêtre quelles opérations elle supporte.

    Par contre si tu as beaucoup d'opérations différentes et/ou que tu penses devoir en rajouter en rajoutant des nouvelles implémentations de caméras (et que ça risque d'arriver assez souvent) ça serait plus pratique de les délocaliser dans un visiteur.

    Citation Envoyé par GoF
    Use the Visitor pattern when

    * an object structure contains many classes of objects with differing interfaces, and you want to perform operations on these objects that depend on their concrete classes.

    * many distinct and unrelated operations need to be performed on objects in an object structure, and you want to avoid "polluting" their classes with these operations. Visitor lets you keep related operations together by defining them in one class. When the object structure is shared by many applications, use Visitor to put operations in just those applications that need them.

    * the classes defining the object structure rarely change, but you often want to define new operations over the structure. Changing the object structure classes requires redefining the interface to all visitors, which is potentially costly. If the object structure classes change often, then it's probably better to define the operations in those classes.
    MAT.
    (comme quoi ma boule de crystal ne fonctionne pas du tout... )

  10. #10
    Expert confirmé

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Par défaut
    Citation Envoyé par poukill Voir le message
    @ Jean-Marc : Il y a quand même des cas où le downcasting est obligatoire non ? Où on est obligé de connaitre exactement le type manipulé ?
    D'une part, les preuves d'inexistance sont particulierement difficile a faire, c'est pour cela que j'ai qualifie en parlant de mon experience. J'ai du mal a savoir a quel point elle se generalise Surtout que meme si ce dont on a besoin, c'est du dispatch multiple, les problemes d'implementation peuvent inciter a preferer une solution a base de downcasting. C'est lie a une problematique bien connue.

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

Discussions similaires

  1. Définitions de programmation impérative et orientée objet
    Par sjrd dans le forum Langages de programmation
    Réponses: 10
    Dernier message: 10/09/2005, 19h32
  2. Stack OverFlow ou Violation d'adresse - Orienté Objet
    Par JakeGrafton dans le forum Langage
    Réponses: 7
    Dernier message: 31/05/2005, 16h34
  3. [DEBUTANT] Conseil sur la programmation orienté objet
    Par etiennegaloup dans le forum Langage
    Réponses: 7
    Dernier message: 27/05/2005, 12h59
  4. Réponses: 2
    Dernier message: 01/05/2005, 14h43
  5. [SGBDOO] Base de données orientée objet
    Par Jaona dans le forum Décisions SGBD
    Réponses: 19
    Dernier message: 14/04/2003, 11h07

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