Précédent   Forum du club des développeurs et IT Pro > C et C++ > C++
C++ Forum d'entraide technique sur le langage C++. Avant de poster -> F.A.Q C++
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 06/01/2013, 13h41   #1
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2013, 13h51   #2
imperio
Membre éclairé
 
Avatar de imperio
 
Homme Guillaume Gomez
Étudiant
Inscription : mai 2010
Messages : 161
Détails du profil
Informations personnelles :
Nom : Homme Guillaume Gomez
Localisation : France

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

Informations forums :
Inscription : mai 2010
Messages : 161
Points : 329
Points : 329
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...
imperio est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/01/2013, 14h18   #3
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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 ?
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2013, 14h34   #4
imperio
Membre éclairé
 
Avatar de imperio
 
Homme Guillaume Gomez
Étudiant
Inscription : mai 2010
Messages : 161
Détails du profil
Informations personnelles :
Nom : Homme Guillaume Gomez
Localisation : France

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

Informations forums :
Inscription : mai 2010
Messages : 161
Points : 329
Points : 329
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.
imperio est déconnecté   Envoyer un message privé Réponse avec citation 11
Vieux 06/01/2013, 15h23   #5
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2013, 15h25   #6
imperio
Membre éclairé
 
Avatar de imperio
 
Homme Guillaume Gomez
Étudiant
Inscription : mai 2010
Messages : 161
Détails du profil
Informations personnelles :
Nom : Homme Guillaume Gomez
Localisation : France

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

Informations forums :
Inscription : mai 2010
Messages : 161
Points : 329
Points : 329
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).
imperio est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/01/2013, 15h30   #7
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
Oui, je comprend que c'est pas une obligation, mais dans un exercice comme ça, ça montre qu'on a compris le concept quoi
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2013, 18h25   #8
koala01
Modérateur
 
Avatar de koala01
 
Philippe Dunski
Inscription : octobre 2004
Messages : 8 603
Détails du profil
Informations personnelles :
Nom : Philippe Dunski
Âge : 41

Informations forums :
Inscription : octobre 2004
Messages : 8 603
Points : 13 243
Points : 13 243
Envoyer un message via MSN à koala01 Envoyer un message via Skype™ à koala01
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é"
Citation:
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
je ne répondrai à aucune question technique par E-mail, message visiteur ou message privé
Vous avez obtenu votre réponse pensez au bouton en bas de page
koala01 est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 06/01/2013, 21h27   #9
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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)
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/01/2013, 21h57   #10
koala01
Modérateur
 
Avatar de koala01
 
Philippe Dunski
Inscription : octobre 2004
Messages : 8 603
Détails du profil
Informations personnelles :
Nom : Philippe Dunski
Âge : 41

Informations forums :
Inscription : octobre 2004
Messages : 8 603
Points : 13 243
Points : 13 243
Envoyer un message via MSN à koala01 Envoyer un message via Skype™ à koala01
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
je ne répondrai à aucune question technique par E-mail, message visiteur ou message privé
Vous avez obtenu votre réponse pensez au bouton en bas de page
koala01 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 06/01/2013, 22h42   #11
gl
Rédacteur/Modérateur
 
Homme
Inscription : juin 2002
Messages : 2 034
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 34
Localisation : France, Hauts de Seine (Île de France)

Informations forums :
Inscription : juin 2002
Messages : 2 034
Points : 3 828
Points : 3 828
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;
gl est déconnecté   Envoyer un message privé Réponse avec citation 30
Vieux 07/01/2013, 03h14   #12
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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 ?
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/01/2013, 03h31   #13
koala01
Modérateur
 
Avatar de koala01
 
Philippe Dunski
Inscription : octobre 2004
Messages : 8 603
Détails du profil
Informations personnelles :
Nom : Philippe Dunski
Âge : 41

Informations forums :
Inscription : octobre 2004
Messages : 8 603
Points : 13 243
Points : 13 243
Envoyer un message via MSN à koala01 Envoyer un message via Skype™ à koala01
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
je ne répondrai à aucune question technique par E-mail, message visiteur ou message privé
Vous avez obtenu votre réponse pensez au bouton en bas de page
koala01 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 07/01/2013, 10h39   #14
gbsatti
Invité régulier
 
Inscription : novembre 2008
Messages : 47
Détails du profil
Informations forums :
Inscription : novembre 2008
Messages : 47
Points : 8
Points : 8
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
gbsatti est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Cette discussion est résolue.
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 09h51.


 
 
 
 
Partenaires

Hébergement Web