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

Langage C++ Discussion :

Héritage, redéfinition de méthodes et spécialisation. Comment résoudre ce cas?


Sujet :

Langage C++

  1. #1
    Membre actif
    Inscrit en
    Mai 2005
    Messages
    348
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 348
    Points : 281
    Points
    281
    Par défaut Héritage, redéfinition de méthodes et spécialisation. Comment résoudre ce cas?
    Salut à tous,

    Je continue dans mes interrogations et voudrais vous exposer le cas suivant.
    Soit ce code:

    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
    class Aliment
    { /* class abstraite */ }
     
    class Viande : public Aliment
    { /* ... */ }
     
    class Legume : public Aliment
    { /* ... */ }
     
    CuistotViande
    {
      string nom; // getter et setter inclus
      string specialite; // getter et setter inclus
     
      void Prepare(Viande * piece);
    }
     
    CuistotLegume
    {
      string nom; // getter et setter inclus
      string specialite; // getter et setter inclus
     
      void Prepare(Legume * leg);
    }
    Au delà des problèmes de conception. On voit ici que les Cuistots ont pas mal en commun. Disons que l'on veuille leur créer une classe de base "Cuistot".
    Comment s'y prendre?

    Bien entendu les variables communes ne posent pas de soucis, mais la méthode Prepare ... Si on considère la définition suivante:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    Cuistot
    {
      string nom; // getter et setter inclus
      string specialite; // getter et setter inclus
     
      void Prepare(Aliment * alim) = 0;
    }
    On ne peut pas compiler le code parce que les classes CuistotViande et CuistotLegume héritant de Cuistot n'implémentent pas
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    void Prepare(Aliment * alim);
    Alors comment décrire, pour une évolution future, disons de gestion des Cuistots, qu'un Cuistot possède forcément un nom et une spécialité et que celui ci peut préparer un aliment? En même temps, il faudrait être sur qu'on ne demande pas à un CuistotViande de préparer un navet.

    Est ce que des templates pourraient aider ?

    Merci

  2. #2
    Membre régulier Avatar de cynique
    Profil pro
    Inscrit en
    Septembre 2007
    Messages
    60
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2007
    Messages : 60
    Points : 72
    Points
    72
    Par défaut
    Citation Envoyé par Sunsawe Voir le message
    Alors comment décrire, pour une évolution future, disons de gestion des Cuistots, qu'un Cuistot possède forcément un nom et une spécialité et que celui ci peut préparer un aliment? En même temps, il faudrait être sur qu'on ne demande pas à un CuistotViande de préparer un navet.

    Est ce que des templates pourraient aider ?

    Merci
    Ca dépend de ce que tu vas faire avec.

    En effet, ton problème vient de "un cuistot peut préparer un aliment". Oui, c'est vrai, mais tu as aussi "un cuistot de viande peut préparer une pièce de la viande" et "un cuistot de légumes peut préparer une légume".

    Pour moi, ça veut dire qu'un cuistot de légumes n'est pas un cuistot.

    Si ça n'était pas un problème, tu pourrais créer un système de templates:

    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
     
    class CuistotBase
    {
      // propriétés, getters, setters, pas de fonction "Prepare"
    };
     
    template<typename Ingredient>
    class Cuistot : public CuistotBase
    {
      void Prepare( Ingredient &ingredient );
    };
     
    Cuistot<Legume> legumier;
    Cuistot<Viande> viandier;
     
    typedef Cuistot<Aliment> CuistotUniversel;
     
    CuistotUniversel universelier;
     
    Legume haricot;
    Viande cotedeboeuf;
     
    legumier.Prepare( haricot );  // ca marche
    legumier.Prepare( cotedeboeuf ); // ca ne marche pas
     
    viandier.Prepare( haricot );  // ca ne marche pas
    viandier.Prepare( cotedeboeuf ); // ca marche
     
    universelier.Prepare( haricot );  // ca marche
    universelier.Prepare( cotedeboeuf ); // ca marche aussi
    Mais ça reste un peu inflexible, et on ne peut pas gestionner une std::list<CuistotBase> avec des Aliments. Ce n'est pas assez meilleur que la solution similaire sans templates:

    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
     
    class CuistotBase
    {
      // propriétés, getters, setters, pas de fonction "Prepare"
    };
     
    class CuistotViande : public CuistotBase
    {
      void Prepare( Viande &piece );
    };
     
    class CuistotLegume : public CuistotBase
    {
      void Prepare( Legume &legume );
    };
     
    class CuistotUniversel : public CuistotBase
    {
      void Prepare( Aliment &piece );
    };
     
    CuistotLegume legumier;
    CuistotViande viandier;
    CuistotUniversel universelier;
     
    Legume haricot;
    Viande cotedeboeuf;
     
    legumier.Prepare( haricot );  // ca marche
    legumier.Prepare( cotedeboeuf ); // ca ne marche pas
     
    viandier.Prepare( haricot );  // ca ne marche pas
    viandier.Prepare( cotedeboeuf ); // ca marche
     
    universelier.Prepare( haricot );  // ca marche
    universelier.Prepare( cotedeboeuf ); // ca marche aussi
    Il me semble qu'on voit ici un exemple du Design Pattern "Visitor", ou peut-être "Double Dispatch".

  3. #3
    Invité
    Invité(e)
    Par défaut
    Tiens, c'est mon problème de classes parallèles, ça...

    Tu pourrais avoir une fonction

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    virtual TCuistotBase::Prepare(TAliment *Aliment)
    que tu surclasses (avec la même signature, de toutes facons la viande et les légumes sont des aliments), pour tes deux classes de cuistot. La vérification du fait qu'un cuistot viande cuisine de la viande serait faite dans le corps de la fonction prépare, ainsi que les mesures à prendre si lui on donne des légumes à préparer.

    Il va alors te falloir un moyen d'identifier le type de chaque aliment (champ type, cast, à ta guise), c'est rendu nécessaire par le fait que les classes cuistot sont associées à des membres d'une hierarchie de classe différente (les aliments).


    Donc quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    TCuistotViande::Prepare(TAliment *aliment) {
      if(TypeAliment(aliment)!=typeViande) {
         Chouiner();
      }
      else {
         PreparerLaViande();
      }
    }
    où TypeAliment(), type, fonction, peu importe est ton système d'identification

    Les template sont une autre façon d'aborder le problème. Dans ce contexte, tu crée des classes "cuistot", paramétrées par leur spécialité (l'aliment).

    A mon avis, les templates sont utiles si tous tes cuistots sont à peu près pareils, au type de l'aliment près: cuistots viandes et cuistots légumes ont les mêmes méthodes, implémentées de la même manière. Si maintenant, les cuistots viande ont des méthodes différentes de celles des cuistots légumes, ou si chaque nouvelle paire (aliment, cuistot) se traduit pas des implémentations très différentes des autres, alors il vaut mieux passer par la hiérarchie de classes.

    Personnellement, je découragerais l'usage combiné des deux, ca devient très vite très difficile à relire...

    Francois

  4. #4
    Membre actif
    Inscrit en
    Mai 2005
    Messages
    348
    Détails du profil
    Informations forums :
    Inscription : Mai 2005
    Messages : 348
    Points : 281
    Points
    281
    Par défaut
    merci pour vos réponses, ça donne des idées au cas où il ne resterait plus que ça comme solution.

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

Discussions similaires

  1. Héritage et redéfinition de méthode
    Par bomehc dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 29/06/2012, 16h23
  2. Réponses: 10
    Dernier message: 12/09/2008, 08h31
  3. héritage et redéfinition de méthodes
    Par Braillane dans le forum Langage
    Réponses: 4
    Dernier message: 07/01/2007, 18h47
  4. [Débutant] Héritage & appel de méthodes
    Par KooX dans le forum Langage
    Réponses: 4
    Dernier message: 11/05/2004, 23h37
  5. [Héritage] Redéfinition méthode
    Par petit-ourson dans le forum Langage
    Réponses: 9
    Dernier message: 06/05/2004, 16h06

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