Salut,
Bon, il y a vraiment de la place pour le progrès
Ce n'est pas dit méchamment, bien sur, c'est pour t'inciter à admettre que tu as grandement intérêt à lire un minimum les réponses et à faire, peut etre bêtement dans un premier temps exactement ce que l'on te dit
D'abord, pourrais tu nous faire un copier coller des (mettons) dix premières lignes d'erreur que t'envoie code::blocks ( En bas de la fenêtre code::blocks, dans l'onglet "build messages", clique droit sur une des lignes de l'erreur, et cliquer sur "copy content to clipboard, puis, sur le forum, <CTRL>+ V pour coller les lignes d'erreur, les resélectionner toutes et cliquer sur le bouton
# en haut du formulaire pour ajouter les balises [ CODE ] qui assureront une mise en forme utile pour la relecture

)
Ensuite, ton prof n'en a peut etre pas conscience, mais C++ est un langage qui n'a strictement plus rien à voir avec C!!!
Tout au plus permet-il dans un soucis de compatibilité de récupérer du code écrit en C, mais, a priori, rien de ce que tu code ne devrait recourir aux mécanismes issus de C
Ainsi, on t'a parlé de la classe string, disponible dans l'espace de noms std par simple inclusion du fichier d'en-tête <string>...
Commence déjà par utiliser cette classe à chaque fois que tu veux travailler avec des chaines de caractères, tu verras, ca te changera la vie
Ta classe Personnel pourrait donc ressembler à (je ne m'intéresse qu'aux chaines de caractères

)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
#include <string>
// je n'aime pas vraiment la directive using namespace ;)
//using namespace std;
class Personnel
{
int NoCarteIdentite;
std::string Nom;
std::string Prenom;
public:
Personnel();
Personnel(int nc, std::sttring const & nom, std::string const & prenom);
~Personnel();
void saisie();
void affichage();
}; |
Le constructeur sera alors avantageusement modifié de manière à utiliser les listes d'initialisation :
Personne::Personnel(int carteIdentite, std::sttring const & nom, std::string const & prenom):NoCarteIdentite(carteIdentite),Nom(nom),Prenom(prenom){}
Tu remarqueras au passage que cela ne prend pas énormément plus de temps d'écrire "nom" ou "prenom" pour les paramètres, mais que cela te facilitera aussi la vie, ne serait-ce que parce que meme code::blocks te fournit un "tooltips" qui t'indique les paramètres que tu dois ajouter lors de l'appel de la fonction.
Le fait de nommer correctement tes variables et tes arguments te permettra, si tu reviens sur ce code d'ici trois mois, de te rappeler beaucoup plus facilement à quoi servent tes variables et tes arguments
Et, accessoirement, cela permettra aux intervenants du forum de comprendre ton code sans devoir passer dix minutes à déchiffrer ce que tu as écrit afin de te venir en aide
N'oublies pas que tous les intervenants du forum (moi y compris

) sont des gens qui viennent ici sur leur temps libre, et que, comme toi, ils ont peut etre envie de profiter du beau soleil printanier
Enfin, bref, continuons...
La fonction Personnel::saisie ne rime strictement à rien !!!
Tu fournis toutes les informations que la fonction saisie demande directement dans le constructeur de Personnel, il ne sert donc strictement à rien de permettre de les modifier (car, a priori, Roland Dupont n'a aucune raison de s'appeler un jour Isabelle Dubois, ni de changer de numéro de carte d'identité

)
De plus, tu donnes à ta classe Personnel une responsabilité qu'elle n'a absolument pas à avoir:
La classe Personnel doit, en effet, s'occuper de gérer les informations du personnel, une fois qu'un objet de ce type a été créé, mais, une fois que l'objet a été créé, il est déjà beaucoup trop tard pour demander le nom, le prénom et le numéro de carte d'identité

:
Ce sont des informations dont on a absolument besoin pour pouvoir créer un objet de type personnel
Intéressons nous maintenant aux autres classes, et, surout, à leur fonction affiche() (je considère que tu auras suivi mon conseil quant à la fonction saisie

)
Mais, avant toute chose, je vais jouer à un petit jeu de question (que je te pose) et de réponses (que tu me donnerait sans doute dans une discussion en directe)

... Tu vas voir, c'est édifiant
Je te demanderais d'abord 'pourquoi as tu fait hériter ta classe Employe de ta classe Personnel
Tu me répondrais surement "Ben parce qu'un employé EST-UN membre du personnel, pardi", et cela peut se comprendre
Je te demandrais ensuite "Cela veut il bien dire que tu souhaites maintenir une collection de "membres du personnel" dans laquelle tu souhaites pouvoir placer indifféremment les différents type de membre du personnel qui existent (ex : des employés, des ouvriers, des cadres, ... )
Et je présumes que ta réponse serait proche de "Mais oui, bien sur!!!"
Je te demanderais alors "Et je présumes, enfin, que tu veux pouvoir transmettre un Employe à une fonction en le faisant passer pour un membre du personnel, tout en obtenant (pour la fonction membre affiche, par exemple) le comportement qui est propre à la classe Employe

"
Et là, tu me prendrait pour un dieu omniscient et tu me répondrait "Koala, t'es vraiment trop fort, tu as tout deviné tout de suite" (he... y a pas de mal à se lancer des fleurs, vu que personne ne le fera à ma place

(par contre, je m'attend à recevoir les pots assez rapidement

) )
Ma modestie naturelle reprendrait alors le dessus, et je t'expliquerais bien humblement que je ne suis "que" un mec tout à fait normal qui a appris, avec le temps, à décoder les besoins fonctionnels des gens qui posent une question sur le forum
Puis, redevenant sérieux, je te dirais "En fait, je voulais simplement vérifier que nous étions réellement dans un cadre dans lequel l'héritage public est applicable, et cela semble etre le cas... Sauf que... ca ne marchera jamais... "
Hé oui, on en est bien là... ton code, tel qu'il est écrit, il ne marchera jamais... ou du moins, jamais comme tu l'espères (

)
Pire, tu risques d'avoir quelques soucis au moment de la libération des ressources, et ce ne seront pas les moindres (re

)
Il y a trois mots qui, à eux seuls, expliquent la cause du problème que les autres intervenants n'ont sans doute pas remarqué (à cause d'une lecture trop hative, sans doute) et donnent en meme temps la solution :
virtualité des fonctions
Hé oui... Est il besoin de rappeler que, à l'inverse de certains autres langages (de très bonne facture au demeurant), C++ a décidé de ne pas faire payer le prix de la virtualité implicite des fonctions
Si une fonction doit voir son comportement modifié en fonction du type réel de l'objet au départ duquel elle est invoquée, (autrement dit : si une fonction a vocation à être redéfinie dans les classes dérivées), il faut indiquer
explicitement au compilateur que la fonction est virtuelle.
Ainsi, le constructeur de la classe Personnel doit etre virtuel, autrement, lorsqu'il sera appelé depuis un pointeur de type Personnel qui pointe en réalité sur un objet de type Employe, il ne fera le ménage que de la partie "Personnel" de l'employé, en "laissant trainer" tout ce qui est propre à la partie Employe
De même, la fonction affiche doit aussi être déclarée virtuelle, autrement, le fait de l'avoir redéfinie dans la classe Employe "cachera" la fonction d'origine, laissant à penser que "tout va bien" lorsqu'elle est invoquée depuis (un pointeur ou une référence sur) un objet employé, mais n'affichera que les information propre au membre du personnel quand elle sera invoquée depuis (un pointeur ou une référence sur) un objet "passant pour etre du type Personnel"...
Autrement dit, voici ce qui pourrait se passer. Nous pourrions avoir un code proche de:
i
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| nt main()
{
Employe employe(/* paramètres requis */);
Employe & refEmploye = employe; // le cas d'une référence du type réel
Employe * ptrEmploye = &employe; // le cas d'un pointeur du type réel
Personnel & refPersonnel = employe; // on peut le faire : un employe est bien un membre du personnel
Personnel * ptrPersonnel = &employe; // idem
employe.affiche(); // OK, affiche correctement les données de l'employe (voir sortie plus bas)
refEmploye.affiche() ; // OK, diem
ptrEmploye->affiche(); // toujours pas de problème ;)
refPersonnel.affiche(); // KO.. c'est la version de Personnel::affiche() qui est utilisée
ptrPersonnel->affiche(); // KO idem
return 0;
} |
qui donnerait une sortie proche de
1 2 3 4 5
| NCI= 125Nom= DupontPrenom= Jeannb_h= 45tarif = 18.5
NCI= 125Nom= DupontPrenom= Jeannb_h= 45tarif = 18.5
NCI= 125Nom= DupontPrenom= Jeannb_h= 45tarif = 18.5
NCI= 125Nom= DupontPrenom= Jean
NCI= 125Nom= DupontPrenom= Jean |
M'est avis que tu aimerais, en travaillant avec un pointeur ou une référence de type Personnel, obtenir exactement la meme sortie que si tu avais travaillé avec l'objet de type Employe, non
La solution est toute simple, modifions quelque peu la définition de la classe Personnel :
1 2 3 4 5 6 7 8 9 10 11
| class Personnel
{
int NoCarteIdentite;
std::string Nom;
std::string Prenom;
public:
Personnel();
Personnel(int nc, std::sttring const & nom, std::string const & prenom);
virtual ~Personnel();
virtual void affichage();
}; |
Et cela suffirait déjà, mais, à l'instar de beaucoup de mes collègues, je préfères répéter le mot clé virtal dans les classes dérivées (bien que la norme nous autorise à ne pas le faire

), simplemnt pour que le lecteur du code puisse se rendre compte qu'il s'agit d'une fonction destinée à être redéfinie sans devoir aller voir la classe parent
Modifions donc la définition de la classe Employe (et de la classe Cadre) de la même manière
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Employe:public Personnel
{
float nb_h,tarif;
public:
Employe();
Employe(int carteIdentite,std::string const & nom,
std::string const & prenom,float nh,float,tar);
virtual ~Employe();
virtual void affichage();
};
class Cadre:public Employe
{
float salaire,prime;
public:
Cadre();
Cadre(int carteIdentite, const std::string const & nom,
std::string const & prenom,float sal,float pri);
virtual ~Cadre();
virtual void affichage();
}; |
Et là, ca commence enfin à ressembler à quelque chose... Au moins, le programme réagira-t-il exactement comme on est en droit de s'y attendre
Il ne te reste "plus qu'à" trouver le moyen de donner la responsabilité de la saisie à "autre chose" qu'aux classes (descendant de ) Personnel...
La clé se trouve dans ce que l'on appelle un "desing pattern" nomme Fabrique (Factory en anglais )
Mais, pour ne quand meme pas faire tout ton boulot, je vais te laisser chercher un peu

Partager