Publicité
+ Répondre à la discussion
Affichage des résultats 1 à 14 sur 14
  1. #1
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut Héritage et polymorphisme

    Bonjour, j'essaye actuellement de bien comprendre le polymorphisme et l'héritage, pour cela je veux résoudre un exercice type : les employés d'une entreprise.

    On souhaite gérer les différents employés d'une entreprise. Pour chacun on conserve son numéro de sécurité sociale et son nom. On souhaite également connaitre son emploi. L'entreprise a un patron, des vendeurs et des caissières. chaque employé, sauf le patron à un supérieur hiérarchique. Le patron touche son salaire ainsi qu'une prime de risque. Les vendeurs touchent une commission en plus de leur salaire. Les caissière touchent simplement leur salaire. Pour chaque employé on désir avoir les fonctions suivantes:
    - un constructeur
    - sePresenter qui permet d'écrire sur le terminal le numéro SS de l'employé, son nom et son emploi
    - revenu qui calcul le revenu de l'emplyé: salaire + prime ou commission s'il y a lieu
    -getsuperieur qui donne le supérieur hierarchique.

    Inclure une classe nommée CSS pour gérer le numéro de sécurité sociale.

    Concevez et programmez les différentes classes permettant de traiter le problème. Pensez au destructeurs et constructeurs de copie si besoin est. Aucune gestion d'erreur n'est demandée.

    Voila j'ai à peu près modéliser le problème comme suite :

    class employé :
    - CSS secu
    - string nom
    - string emploi
    +employe() constructeur
    +sePresenter() Virtuel pure donc classe abstraite
    +revenu() virtuel pure
    + getsuperieur() virtuel pure
    ~employe() destructeur virtuel

    class patron:
    - double salaire
    - double prime
    +patron()
    +sePresenter()
    +revenu()
    +getsuperieur
    ~patron()

    class vendeur:
    - double salaire
    - double commission
    +vendeur()
    +sePresenter()
    +revenu()
    +getsuperieur
    ~vendeur()

    class caissiere:
    - double salaire
    +caissiere()
    +sePresenter()
    +revenu()
    +getsuperieur
    ~caissiere()

    Voila j'ai ainsi pu programmer les différentes classes. Mais il reste quelque chose qui me taquine. En effet, le salaire étant présent dans les trois sous-classes, je me demande s'il n'était pas plus judicieux de l'envoyer dans la classe employé .

    Si quelqu'un peut m’éclaircir sur ce point ce serait cool.

    Merci

  2. #2
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2010
    Messages
    565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mai 2010
    Messages : 565
    Points : 1 145
    Points
    1 145

    Par défaut

    Il paraîtrait logique de le mettre dans la classe mère pour que les classes l'ait directement. Ça évitera d'avoir à le refaire dans chaque classe. Tu aurais pu faire une classe abstraite au lieu d'une interface pour la classe mère, ça t'aurais éviter d'avoir à redéfinir les fonctions dans chaque classe fille car je présume que le code pour getSuperieur doit être le même à chaque fois...

  3. #3
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Merci pour la réponse rapide . J'avais un doute parce que dans un livre, j'ai trouvé un exercice similaire mais il mettait le salaire dans les sous classes sous prétexte qu'il en avait besoin pour calculer le revenu, bref ça m'a parut bizarre.

    Sinon pour le constructeur de copie, comment savoir s'il y en a besoin ou pas ? D'après ce que j'ai compris, dès qu'il y a des pointeurs il faut penser au constructeur de copie. Ce qui me fait penser qu'on en a besoin surtout pour la classe mère ( employé) , je me trompe ?

  4. #4
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2010
    Messages
    565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mai 2010
    Messages : 565
    Points : 1 145
    Points
    1 145

    Par défaut

    Un bon exemple de constructeur par copie :

    Code :
    1
    2
    3
    4
    5
     
    std::string s1 = "tralala"; // surcharge de l'opérateur égal
     
    std::string s2(s1); // constructeur par copie
    std::string s3 = s2; // surcharge de l'opérateur égal
    Donc après à toi de voir si dans ton code tu en as besoin. Dans le cas de ton programme, je ne vois pas trop l'intérêt étant donné que chaque personne est unique (il me semble). Dire nouveau venu = george ne me semble guère utile. Après rien ne t'empêches de surcharger une fonction de classe mère (n'oublies pas de la mettre virtual dans ce cas-là) dans une classe fille si son fonctionnement diffère.

  5. #5
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Merci beaucoup j'ai compris l'idée en ce qui concerne les constructeur de recopie.

    Donc pour l'héritage c'est vraiment strict : chaque attribut qui se répète dans les sous classes doit être factorisé dans la classe de base.

    Merci, je vais pouvoir programmer mes classes sans hésitation.

    Bonne journée

  6. #6
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2010
    Messages
    565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : mai 2010
    Messages : 565
    Points : 1 145
    Points
    1 145

    Par défaut

    C'est pas une obligation, c'est juste pour éviter d'avoir à répéter sans cesse le même code qu'on le fait (et ça fait aussi partie du principe de l'héritage).

  7. #7
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Oui, je comprend que c'est pas une obligation, mais dans un exercice comme ça, ça montre qu'on a compris le concept quoi

  8. #8
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 740
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 740
    Points : 17 222
    Points
    17 222

    Par défaut

    Citation Envoyé par gbsatti Voir le message
    Voila j'ai ainsi pu programmer les différentes classes. Mais il reste quelque chose qui me taquine. En effet, le salaire étant présent dans les trois sous-classes, je me demande s'il n'était pas plus judicieux de l'envoyer dans la classe employé .
    Citation Envoyé par imperio Voir le message
    Il paraîtrait logique de le mettre dans la classe mère pour que les classes l'ait directement. Ça évitera d'avoir à le refaire dans chaque classe. Tu aurais pu faire une classe abstraite au lieu d'une interface pour la classe mère, ça t'aurais éviter d'avoir à redéfinir les fonctions dans chaque classe fille car je présume que le code pour getSuperieur doit être le même à chaque fois...
    Citation Envoyé par gbsatti Voir le message
    Merci pour la réponse rapide . J'avais un doute parce que dans un livre, j'ai trouvé un exercice similaire mais il mettait le salaire dans les sous classes sous prétexte qu'il en avait besoin pour calculer le revenu, bref ça m'a parut bizarre.
    En fait, si tu parles du salaire de base qui est commun (hors variation sur le montant, s'entend ) à toutes les classes, il est, en effet, logique de le placer dans la classe de base, car on peut estimer qu'il s'agit d'une information majeure propre à la classe "employé"
    Sinon pour le constructeur de copie, comment savoir s'il y en a besoin ou pas ? D'après ce que j'ai compris, dès qu'il y a des pointeurs il faut penser au constructeur de copie. Ce qui me fait penser qu'on en a besoin surtout pour la classe mère ( employé) , je me trompe ?
    En fait, il faut s'intéresser à la sémantique des classes que tu définis :

    Il existe deux grands "groupes" de classes en fonction de la sémantique qu'elles ont :

    Les classes à sémantique de valeur, dont il est possible d'avoir, à un instant T, plusieurs instances en mémoire présentant exactement les même valeurs.

    C'est le cas, par exemple, des classes "couleurs", "point", "réservoir à essence", "adresse", etc. Bref, tout ce qui peut exister en plusieurs exemplaires scrupuleusement identiques.

    Ces classes sont, généralement:
    • constantes : si tu modifies une des valeurs qui les représente, tu obtiens un objet totalement différent
    • copiable : tu peux souhaiter avoir un couleur qui est la même que celle du voisin
    • assignable : tu peux décider de repeindre une pièce dans une autre couleur que celle d'origine
    • comparables (au minimum par égalité)
    • peu encline à intervenir dans une relation d'héritage (ni en tant que classe de base, ni en tant que classe dérivée)
    C'est à ce genre de classe que Coplien fait référence dans sa fameuse forme canonique orthodoxe, et c'est à ce genre de classe que s'applique la fameuse "règle des trois grands":

    Si, parmi les trois fonctions importantes que sont le constructeur par copie, l'opérateur d'affectation et le destructeur, il y en a une dont le comportement doit être définis (comprend : dont tu ne peux pas te contenter d'utiliser le comportement par défaut implémenté par le compilateur), alors, il faudra envisager de définir les trois

    Ensuite, il y a les classes ayant sémantique d'entité, dont chaque instance est identifiée de manière unique et non ambigüe.

    C'est le cas de classes comme "personne", "véhicule", "compte bancaire". Bref, toutes les classes pour lesquelles chaque instance doit être scrupuleusement unique pour avoir la certitude que si tu modifie une des données (parmi celles qui peuvent être modifiées) d'une instance quelconque, la modification s'applique effectivement à cette instance particulière.

    Ces classes sont généralement
    • modifiables (du moins, pour tout ce qui n'intervient pas dans la définition de ce qui permet de les identifier de manière unique et non ambigüe)
    • non copiable : tu n'apprécierais pas trop que quelqu'un ait un compte en banque portant le même numéro que le tien et que ton salaire soit versé... sur le compte de cette personne
    • non assignable, pour la même raison
    • non comparable : au pire, on peut comparer les différentes valeurs qui les composent une à une, mais il n'y a aucun sens à comparer l'intégralité
    • des candidats idéaux à intervenir dans une relation d'héritage (soit comme classe de base, soit comme classe dérivée)
    Pour ce type de classes, il y a généralement lieu de faire en sorte que les constructeur par copie et l'opérateur d'affectation soient inaccessibles.

    En C++ (avant la nouvelle norme), cela se traduisait souvent par le fait de déclarer le constructeur par copie et l'opérateur d'affectation comme étant privés sans les définir.

    En C++11, il est possible de simplement les déclarer comme "deleted", sous une forme proche de
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    class MyBaseClass
    {
        public:
            /* un constructeur "classique" */
            MyBaseClass(/* ...*/ );
            /* le constructeur par copie que l'on annule */
            MyBaseClass(MyBaseClass const &) = delete;
            /* l'opérateur d'affectation que l'on annule aussi */
            MyBaseClass & operator=(MyBaseClass const &) = delete;
            /* le destructeur se doit d'être virtuel, pour permettre
             * la destruction des objets dérivés (ou d'être non virtuel et 
             * protégé)
             */
            virtual ~MyBaseClass();
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  9. #9
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Merci pour l'explication vraiment bien détaillée , je pense avoir bien compris l'idée.

    Sinon que veux-tu dire par "hors variation du montant" ? Car d'après l'énoncé, je pense que le salaire peut varier en fonction en fonction de chaque employé ( il peut paraître logique que le salaire du patron ne soit pas le même que celui de la caissière par exemple)

  10. #10
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 740
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 740
    Points : 17 222
    Points
    17 222

    Par défaut

    Citation Envoyé par gbsatti Voir le message
    Sinon que veux-tu dire par "hors variation du montant" ? Car d'après l'énoncé, je pense que le salaire peut varier en fonction en fonction de chaque employé ( il peut paraître logique que le salaire du patron ne soit pas le même que celui de la caissière par exemple)
    C'est exactement ce que je voulais dire : c'est une donnée commune, mais le montant du salaire peut varier d'un type d'employé à l'autre.

    Il faudra donc prévoir de fournir cette information au niveau du constructeur de la classe mère, et voir s'il est plus cohérent de le fixer au niveau du constructeur des classes dérivées ou, au contraire, de permettre de le définir séparément pour chaque employé

    Il serait d'ailleurs tout à fait envisageable d'avoir une optique différente en fonction du type d'employé, en offrant un salaire fixe aux caissières, mais en permettant de définir le salaire des vendeurs et du patron, par exemple
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  11. #11
    gl
    gl est déconnecté
    Rédacteur/Modérateur

    Homme Profil pro
    Inscrit en
    juin 2002
    Messages
    2 096
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Isère (Rhône Alpes)

    Informations forums :
    Inscription : juin 2002
    Messages : 2 096
    Points : 4 160
    Points
    4 160

    Par défaut

    Citation Envoyé par imperio Voir le message
    Un bon exemple de constructeur par copie :

    Code :
    1
    2
     
    std::string s3 = s2; // surcharge de l'opérateur égal
    Non, c'est là aussi le constructeur de copie qui est utilisé, cette ligne est équivalente à
    Pour utiliser la surcharge de l'opérateur =, il faudrait écrire :
    Code :
    1
    2
    std::string s3;
    s3 = s2;

  12. #12
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Ok je vois ce que tu veux dire, donc si par exemple je veux fixer le salaire des caissières à 1300€ par exemple. Je dois appeler le constructeur de la classe mère en initialisant le salaire à 1300.
    Code :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    employe(CSS s, string n,string e, double s)
    { 
        secu=s;
        nom=n;
        emploi=e;
        salaire=s;
    }
     
    caissiere(CSS s, string nom, string emploi, double salaire, double p)
    {
        employe(s,n,"caissiere",1300)
        prime=p;
    }
    c'est ça ?

  13. #13
    Modérateur
    Avatar de koala01
    Profil pro Philippe Dunski
    Inscrit en
    octobre 2004
    Messages
    9 740
    Détails du profil
    Informations personnelles :
    Nom : Philippe Dunski
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 740
    Points : 17 222
    Points
    17 222

    Par défaut

    A peu de choses près, les erreurs en moins, oui, c'est ca

    En fait, cela ressemblerait à quelque chose comme
    Code :
    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
    class Employe
    {
        public:
            Employé( CSS const & secu, std::string const & nom,
                           std::string const & prenom, double salaire):
                           secu_(secu), nom_(name), prenom_(firstName),
                           salaire_(salaire){}
             virtual ~Employe();
             /* tout le reste */
        private:
            CSS secu_;
            std::string nom_;
            std::string prenom_;
            double salaire_;
    };
    class Caissiere : public Employe
    {
        public:
            /* pour les caissières, le salaire est fixé arbitrairement à 1500,00€ */
            Caissiere(CSS const & secu, std::string const & nom,
                          std::string const & prenom): Employe(nom, prenom, 1500.0){}
            /* ce qui est propre aux caissières */
    };
    class Vendeur : public Employe
    {
        public:
            /* pour les vendeurs (comme pour le patron), le salaire est le 
             * fruit d'âpres négociations ;)
             */
            Vendeur(CSS const & secu, std::string const & nom
                         std::string const & prenom, double salaire)
                         Vendeur(secu, nom, prenom, salaire){}
            /* ce qui est propre aux vendeurs */
    };
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  14. #14
    Invité régulier
    Inscrit en
    novembre 2008
    Messages
    47
    Détails du profil
    Informations forums :
    Inscription : novembre 2008
    Messages : 47
    Points : 9
    Points
    9

    Par défaut

    Merci, j'ai vu mon erreur, en fait il ne faut pas passer le salaire en paramètre pour les caissières si je veux le "forcer" à 1300. C'est un peu comme l'emploi dans les sous classes patron,vendeur et caissière. Si j'ai bien compris, il faut en quelque sort cacher l'opération de sorte à ce qu'on ne puisse plus le redéfinir, et ce pour chaque nouvelle caissière.

    Merci en tout cas ton aide m'a été précieuse.

    Je met en résolu.

    Bonne journée

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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •