Analyse d'un Code en C++

EXERCICE CORRIGE C++
// Fichier d’entête eleve.h
class Eleve {
    protected:
        char[25] matricule;
        char[25] nom;
        float note1;Analyse d'un Code en C++
        float note2;
        static int nombre_eleves;
    public:
        ~Eleve(); // destructeur
        Eleve();
        Eleve(const Eleve &e);
        Eleve(char* nom, float note1=0, float note2=0);
        virtual void affichage() const;
        char* getNom() const { return this→nom; }
        void setNom(char* nom) { strcpy((*this).nom, nom); }
        friend int operator==(const Eleve &e1, const Eleve &e2);
};

// Fichier d’implémentation eleve.cxx
#include "eleve.h"
#include 
#include 
#include 
using namespace std;

int Eleve::nombre_eleves = 0;

Eleve::~Eleve() {}

Eleve::Eleve() {
    this->matricule = nombre_eleves;
    (this->).nom[0] = ' \0';
    this->note1 = 0;
    this->note2 = 0;
    nombre_eleves++;
}

Eleve::Eleve(char* nom, float n1, float n2) {
    (*this).matricule = nombre_eleves;
    strcpy((*this).nom, nom);
    (*this).note1 = n1;
    (*this).note2 = n2;
    nombre_eleves++;
}

Eleve::Eleve(Eleve &e) {
    (*this).matricule = e.matricule;
    strcpy((*this).nom, nom);
    (*this).note1 = e.n1;
    (*this).note2 = e.n2;
    nombre_eleves++;
}

void Eleve::affichage() {
    cout << "Eleve[";
    cout << this->matricule << ",";
    cout << this->nom << ",";
    cout << this->note1 << ",";
    cout << this->note2;
    cout << "]";
}

// on n’a pas mis “Eleve::” devant “operator==”
// parce qu’elle n’est pas une fonction membre. C’est
// une fonction amie.
int Eleve::operator==(const Eleve &e1, const Eleve &e2) {
    return strcmp(e1.matricule, e1.matricule) == 0;
}

// Fichier d’entête eleveEtranger.h
#include "eleve.h"

class EleveEtranger : public Eleve {
    private:
        char* nationality;
    public:
        void affichage();
        ~EleveEtranger(); // destructeur
        EleveEtranger();
        EleveEtranger(const EleveEtranger &e);
        EleveEtranger(char* nom, char* nationality, float note1=0, float note2=0);
        char* getNationality() const;
        void setNationality(char* n);
};

// Fichier d’implémentation eleveEtranger.cxx
#include "eleveEtranger.h"
#include 
#include 
#include 
using namespace std;

EleveEtranger::EleveEtranger() : Eleve() {
    (this->nationality)[0] = ' \0';
}

EleveEtranger::EleveEtranger(char* nom, char* nationality, float n1, float n2) : Eleve(nom, n1, n2) {
    strcpy((*this).nationality, nationality);
}

char* EleveEtranger::getNationality() {
    return (*this).nationality;
}

void EleveEtranger::setNationality(char* n) {
    strcpy((*this).nationality, n);
}

void EleveEtranger::affichage() {
    cout << "EleveEtranger[";
    cout << this->matricule << ",";
    cout << this->nom << ",";
    cout << this->note1 << ",";
    cout << this->note2 << ",";
    cout << this->nationality << "]";
}

// Fichier d’entête employe.h
class Employe {
    protected:
        char[25] matricule;
        char[25] nom;
        float salaire;
        static int nombre_employes;
    public:
        ~Employe(); // destructeur
        Employe();
        Employe(const Employe &e);
        Employe(char* nom, float salaire=0);
        char* getMatricule() const;
        char* getNom() const { return this->nom; }
        void setNom(char* nom);
        virtual void affichage() const;
};
Partie I : Analyse du Code la  Classe Eleve
1) Quelle est la signification de const dans l’entête du constructeur de recopie et des fonctions ?
2) Citer les attributs pour lesquels il n’y a pas d’accesseur.
3) Y a-t-il une méthode de classe (fonction membre statique) ?
4) Quel est l’intérêt de la variable statique nombre_eleves ?
5) Quelle est la signification de virtual dans l’entête de la fonction membre affichage ? Expliquer pourquoi on peut redéfinir (surcharge fonctionnelle) affichage() dans les classes dérivées de Eleve.
6) Pourquoi on ne peut pas redéfinir getNom() et setNom() dans les classes dérivées de Eleve.
7) La classe Eleve contient-elle une méthode abstraite ? Expliquer pourquoi la classe Eleve est instanciable (est une classe concrète).
8) Expliquer pourquoi la déclaration suivante est correcte : Eleve e("DUPON"). Si le deuxième et le troisième argument du constructeur à trois arguments de Eleve n’étaient pas optionnels, cette déclaration serait-elle correcte ?
9) Que faut-il faire pour rendre la méthode affichage() abstraite ? Qu’est-ce qu’une classe abstraite ? Une classe abstraite est-elle inconstatable ?
10) Modifier la définition de l’opérateur == en le considérant comme une méthode.
11) Y a-t-il une méthode dont un argument est passé par valeur ? par référence ? par pointeur ? On rappelle que :
    (1) Dans le passage par valeur, le corps de la méthode travaille sur une copie de l’argument. Le constructeur de recopie est utilisé pour faire une copie de l’argument.
    (2) Dans le passage par référence, le corps de la méthode travaille sur l’original de la variable référencée.
    (3) Dans le passage par pointeur, le corps de la méthode travaille sur l’original de la variable pointée.
    (4) La principale différence entre le passage par référence et le passage par pointeur provient de ce que le passage par référence est géré par le compilateur alors que le passage par pointeur est géré par le programmeur.

Corretion :

Partie I : Analyse du Code la Classe Eleve

  1. Quelle est la signification de const dans l’entête du constructeur de recopie et des fonctions ?
    • const indique que la méthode ne modifie pas les données membres de l'objet. Pour un constructeur de recopie, cela signifie que les objets utilisés comme source pour la copie ne seront pas modifiés. Par exemple :
      Eleve(const Eleve &e);
      Cela signifie que le constructeur de recopie peut accéder aux données de e sans les modifier.
    • Pour les autres fonctions comme getNom() const, cela garantit que l'appel de cette fonction ne modifiera pas l'objet :
      char* getNom() const;
  2. Citer les attributs pour lesquels il n’y a pas d’accesseur.
    • Les attributs sans accesseur (getter) direct sont :
      • matricule
      • note1
      • note2
      • nombre_eleves (bien qu'étant un attribut statique, il peut ne pas être nécessaire d'avoir un accesseur public)
  3. Y a-t-il une méthode de classe (fonction membre statique) ?
    • Non, il n'y a pas de méthode statique déclarée dans la classe Eleve. L'attribut nombre_eleves est statique, mais il n'y a pas de méthode statique pour l'accéder ou le modifier.
  4. Quel est l’intérêt de la variable statique nombre_eleves ?
    • La variable statique nombre_eleves compte le nombre d'instances de la classe Eleve créées. Chaque fois qu'un nouvel objet Eleve est instancié, nombre_eleves est incrémenté. Cela permet de suivre le nombre total d'élèves.
  5. Quelle est la signification de virtual dans l’entête de la fonction membre affichage ? Expliquer pourquoi on peut redéfinir (surcharge fonctionnelle) affichage() dans les classes dérivées de Eleve.
    • Le mot clé virtual permet la redéfinition de la méthode dans les classes dérivées. En utilisant virtual, la méthode affichage() peut être surchargée dans une classe dérivée comme EleveEtranger :
      virtual void affichage() const;
      Cela permet le polymorphisme, où l'appel de affichage() sur un pointeur ou une référence à Eleve appelle la version appropriée de la méthode dans la classe dérivée.
  6. Pourquoi on ne peut pas redéfinir getNom() et setNom() dans les classes dérivées de Eleve.
    • Les méthodes getNom() et setNom() ne sont pas marquées comme virtual, donc elles ne peuvent pas être redéfinies dans les classes dérivées. Sans le mot clé virtual, la liaison de la méthode se fait statiquement (au moment de la compilation), et non dynamiquement (au moment de l'exécution).
  7. La classe Eleve contient-elle une méthode abstraite ? Expliquer pourquoi la classe Eleve est instanciable (est une classe concrète).
    • Non, la classe Eleve ne contient pas de méthode abstraite. Une méthode abstraite est déclarée avec = 0 à la fin de son prototype. Comme il n'y a pas de telles méthodes, Eleve est une classe concrète et peut être instanciée.
  8. Expliquer pourquoi la déclaration suivante est correcte : Eleve e("DUPON"). Si le deuxième et le troisième argument du constructeur à trois arguments de Eleve n’étaient pas optionnels, cette déclaration serait-elle correcte ?
    • La déclaration est correcte car le constructeur de Eleve avec un argument pour le nom a des valeurs par défaut pour les autres arguments :
      Eleve(char* nom, float note1=0, float note2=0);
      Si les valeurs par défaut n'étaient pas fournies, la déclaration ne serait pas correcte car le constructeur exigerait trois arguments :
      Eleve e("DUPON", 0.0, 0.0); // Exemple de syntaxe correcte sans valeurs par défaut
  9. Que faut-il faire pour rendre la méthode affichage() abstraite ? Qu’est-ce qu’une classe abstraite ? Une classe abstraite est-elle instanciable ?
    • Pour rendre la méthode affichage() abstraite, il faut la déclarer comme suit :
      virtual void affichage() const = 0;
      Une classe abstraite contient au moins une méthode abstraite. Elle ne peut pas être instanciée directement. Pour utiliser une classe abstraite, il faut dériver une nouvelle classe et implémenter toutes les méthodes abstraites.
  10. Modifier la définition de l’opérateur == en le considérant comme une méthode.
    • Pour modifier l'opérateur == en tant que méthode de la classe, on doit le déclarer dans la classe et le définir ainsi :
      
      class Eleve {
      public:
          bool operator==(const Eleve &e) const {
              return strcmp(this->matricule, e.matricule) == 0;
          }
      };
  11. Y a-t-il une méthode dont un argument est passé par valeur ? par référence ? par pointeur ?
    • Passage par valeur : Les arguments nom, note1, et note2 dans le constructeur par défaut passent par valeur.
    • Passage par référence : Le constructeur de recopie utilise le passage par référence :
      Eleve(const Eleve &e);
    • Passage par pointeur : Les arguments char* nom et char* nationality dans certains constructeurs et méthodes utilisent le passage par pointeur.

Voici un rappel sur les types de passage d'arguments :

  • Passage par valeur : Le corps de la méthode travaille sur une copie de l’argument. Par exemple :
    Eleve::Eleve(char* nom, float n1, float n2);
  • Passage par référence : Le corps de la méthode travaille sur l'original de la variable référencée. Par exemple :
    Eleve(const Eleve &e);
  • Passage par pointeur : Le corps de la méthode travaille sur l'original de la variable pointée. Par exemple :
    char* getNom() const;

Fin classe Eleve.

  • Aucune note. Soyez le premier à attribuer une note !

Ajouter un commentaire

Anti-spam