Citation Envoyé par koala01 Voir le message
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 )
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
 
#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 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
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
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
Bonsoir,
Il m'a fallu du temps pour lire ce que tu as écris Koala.En tant que débutante je n'ai compris que la moitié ; mais tu m'as incité à chercher plus loin pour mieux comprendre , je m'y mets sur le code pour le corriger