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 de cast ou de design


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut Problème de cast ou de design
    Bonjour,

    Si on a les classes suivantes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Fille : public Mere
    {
      void methodePropreALaFille();
    };
    Admettons à présent que j'ai une fonction:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void function(Mere& m);
    Et que dans le corps de cette fonction j'ai besoin d'appeler la fonction propre à la fille sachant que j'appelle la fontion de cette manière:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ...
    Fille f = Fille();
    function(f);
    Dans function():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void function(Mere& m)
    {...
      m.methodePropreALaFille();// comment faire pour réaliser cette appel?
    ...
    }
    Dois-je faire un dynamic cast avant d'appeler la méthode ou y a-t-il quelque chose de plus intéligent à faire (et qui necessite surtout pas de cast)?

    Merci de votre aide.

  2. #2
    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
    Il y a mieux, en effet, mais j'aurai un peu de mal à l'expliquer avec toute la précision nécessaire.

    L'idée est d'utiliser la surcharge.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void function(Mere& m) {
        /**/
    }
    void function(Fille& f) {
        f.methodePropreALaFille();
    }
    L'autre possibilitée, c'est de passer par une fonction virtuelle, mais ca n'a pas forcément de sens.

    En général, ce problème apparait quand tu as en réalité plusieurs filles de mere, et que certaines ont un traitement particulier.
    auquel cas, il peut être intéressant d'introduire une classe intermédiaire pour ces filles là.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct mere {}
    struct fille1 : mere {}
    struct fille2 : mere {}
    struct fille3 : mere {
        void truc();
    }
    struct fille4 : mere {
        void truc();
    }
    deviendrait alors:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct mere {}
    struct fille1 : mere {}
    struct fille2 : mere {}
    struct trucoidal : mere {
        virtual void truc();
    }
    struct fille3 : trucoidal {
        void truc();
    }
    struct fille4 : trucoidal {
        void truc();
    }

  3. #3
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Citation Envoyé par leternel Voir le message
    L'idée est d'utiliser la surcharge.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void function(Mere& m) {
        /**/
    }
    void function(Fille& f) {
        f.methodePropreALaFille();
    }
    Justement je souhaite garder uniquement ce prototype : void function(Mere& m)

    Citation Envoyé par leternel Voir le message
    En général, ce problème apparait quand tu as en réalité plusieurs filles de mere, et que certaines ont un traitement particulier.
    auquel cas, il peut être intéressant d'introduire une classe intermédiaire pour ces filles là.
    C'est le cas en fait, mais j'ai juste voulu simplifier l'exemple.

    Citation Envoyé par leternel Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    struct mere {}
    struct fille1 : mere {}
    struct fille2 : mere {}
    struct fille3 : mere {
        void truc();
    }
    struct fille4 : mere {
        void truc();
    }
    deviendrait alors:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    struct mere {}
    struct fille1 : mere {}
    struct fille2 : mere {}
    struct trucoidal : mere {
        virtual void truc();
    }
    struct fille3 : trucoidal {
        void truc();
    }
    struct fille4 : trucoidal {
        void truc();
    }
    Je vois pas trop l'intérêt, j'ai l'impression que le problème est juste déplacé.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 153
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 153
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Je vois pas trop l'intérêt, j'ai l'impression que le problème est juste déplacé.
    L'intérêt c'est de passer non pas un Mere& mais un Trucoidal& en paramètre.
    L'héritage revient à factoriser des comportements et services. Devoir faire appel à une méthode spécifique à un type fille n'est pas du tout normal et montre au moins un gros manque architectural.
    Si ta méthode doit faire appel à une méthode de fille
    - elle doit prendre un fille en paramètre
    --> sinon elle traite comment les cas où c'est pas une fille mais fille2 ?!?
    - la méthode de fille n'est pas spécifique à fille mais spécialisée
    --> on factorise alors le comportement et service à travers cette méthode
    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.

  5. #5
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    En fait, le problème qui se pose ici est assez courant, et il vient du fait que le protocole (ensemble des fonctions et variables publiques de la classe) de la classe mère est différent de celui de la classe fille. Ça viole le LSP, et donc, ça pose potentiellement tout un tas de problèmes (celui évoqué ici n'en est qu'un parmi bien d'autres).

    Donc effectivement, comme toujours, la solution consiste à ajouter un niveau d'indirection. Visiteur est généralement approprié.

    Parfois il n'est pas nécessaire de respecter LSP, mais c'est assez rare. Il s'agit de cas où on est sûr que le code qui utilise ces classes ne déclarera jamais un objet de type Mere, et donc qu'il n'utilisera que les classes héritées. Mais en dehors de ce cas rare, respecter LSP permet un confort non négligeable dans le cycle de développement. Confort dont on ne prend pas forcément conscience, puisque les problèmes ne posent pas... mais je m'égare...

  6. #6
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Dans mon cas, je ne cherche pas à respecter LSP, car les classe Filles sont des implémentations différentes de la classe mère (qui n'est jamais instanciée et ne le sera jamais).

    En fait, mon idée c'est plutôt:
    * j'ai une classe mère abstraite : Mere
    * j'ai des classes filles qui implémentent Mere: Fille1, Fille2, Fille3
    * j'ai des fonctions qui utilisent Fille1 ou Fille2 ou Fille3 quasiment de la même manière, et donc pour factoriser je fait:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void function(Mere& m)
    {...// code polymorphe qui fonctionne que ce soit Fille1, 2 ou 3
    }
    Sauf que dans cette fonction je voudrait faire un seul appel de méthode spécifique à Fille2 par exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void function(Mere& m)
    {...// tout le code idem que précédemment
    m.methodeDeFille2();
    }
    Je trouverais dommage de devoir dupliquer du code à cause d'une seule méthode:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    void function(Fille1& f);
    void function(Fille2& f);
    void function(Fille3& f);
    Et donc avoir 3 fonctions avec 99% de code identique.

  7. #7
    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 LinuxUser Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void function(Mere& m)
    {...
      m.methodePropreALaFille();// comment faire pour réaliser cette appel?
    ...
    }
    Ah, un grand classique !
    Plusieurs techniques :
    • Le pattern template method : une fonction membre virtuelle dans la classe mère qui appelle une ou plusieurs fonctions virtuelles à définir dans les classes filles. C'est très utilisé pour modifier des comportements d'algos. Par contre, ça ne marche que si les comportements sont factorisables.
    • Le pattern visiteur : l'arme absolue pour ces problèmes de downcasting. Ça permet de pouvoir donner une implémentation différente pour chaque classe fille.

    Iil y a déjà eu pas mal de question là dessus, une petite recherche sur le forum avec le mot clé downcasting devrait de donner pas mal d'infos (je me souviens avoir posé moi-même des questions là dessus il fut un temps).

  8. #8
    Membre éclairé Avatar de LinuxUser
    Inscrit en
    Avril 2007
    Messages
    857
    Détails du profil
    Informations forums :
    Inscription : Avril 2007
    Messages : 857
    Par défaut
    Citation Envoyé par poukill Voir le message
    • Le pattern template method : une fonction membre virtuelle dans la classe mère qui appelle une ou plusieurs fonctions virtuelles à définir dans les classes filles. C'est très utilisé pour modifier des comportements d'algos. Par contre, ça ne marche que si les comportements sont factorisables.
    • Je me suis pas encore penché sur les templates, peut être est-ce le moment?
      Citation Envoyé par poukill Voir le message
    • Le pattern visiteur : l'arme absolue pour ces problèmes de downcasting. Ça permet de pouvoir donner une implémentation différente pour chaque classe fille.
    Je vais me documenter à ce sujet plutôt.
  9. Citation Envoyé par poukill Voir le message
    Iil y a déjà eu pas mal de question là dessus, une petite recherche sur le forum avec le mot clé downcasting devrait de donner pas mal d'infos (je me souviens avoir posé moi-même des questions là dessus il fut un temps).
    Ok, merci beaucoup.

  • #9
    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 LinuxUser Voir le message
    Je me suis pas encore penché sur les templates, peut être est-ce le moment?
    Attention, le template method est un pattern, le nom est trompeur... Rien à avoir avec les template C++.

  • #10
    Membre Expert
    Profil pro
    Inscrit en
    Mars 2007
    Messages
    1 415
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2007
    Messages : 1 415
    Par défaut
    Citation Envoyé par LinuxUser Voir le message
    Je me suis pas encore penché sur les templates,
    Je vote pour le visiteur comme te l'as conseillé Poukill, c'est un pattern utile à connaître.

  • + Répondre à la discussion
    ActualitésFAQ C++Tutoriels C++Livres C++Outils & compilateurs C++Sources C++Qt

    Discussions similaires

    1. [CASTS]problème de cast de Time
      Par DeVoN dans le forum Langage
      Réponses: 7
      Dernier message: 22/02/2006, 17h24
    2. [JDBC Driver][JSTL] Problème de cast de données
      Par GyLes dans le forum PostgreSQL
      Réponses: 1
      Dernier message: 27/09/2005, 10h00
    3. problème de cast!
      Par LaseLiep dans le forum Langage
      Réponses: 3
      Dernier message: 03/06/2005, 09h30
    4. Problème de cast/serialization/externalization ?
      Par Linlin dans le forum CORBA
      Réponses: 1
      Dernier message: 06/12/2004, 16h46
    5. [C#] Problème de casting de @IDENTITY
      Par bilb0t dans le forum Accès aux données
      Réponses: 7
      Dernier message: 03/09/2004, 09h42

    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