Table of Contents

Partie I – Création d’une classe dérivée

TD2

Dupliquez vos projets de compteurs en C++ que vous avez réalisé la semaine dernière. Pour ceux qui n’ont pas de projets compteurs fonctionnels, vous pouvez partir de la solution présente en ligne.

Question n° 1

A partir de la classe MyCounter que vous avez développé la semaine, une nouvelle MyBiDiCounter. Cette classe doit ajouter deux méthodes à la classe de base :

decrement()
    si counter > 0
    	counter <- counter – 1
    sinon
        counter = max;
print()
    affiche "Compteur : " counter "/" max (retour à la ligne)

Correction

Correction

Nous créons dans le fichier counter.hpp et ensuite de la classe MyCounter la classe MyBiDiCounter suivante:

class MyBiDiCounter: public MyCounter
{
public:
    void decrement() 
    {
        if(counter > 0) 
            counter --;
        else
            counter = max;
    }
 
    void print() const
    {
        std::cout << "Compteur: " << counter << "/" << max << std::endl;
    }
};

La classe MyBiDiCounter hérite de la classe MyCounter. Comme le qualificateur devant MyCounter est public,

  • l'ensemble des méthodes et champs publics de MyCounter sont visibles dans MyBiDiCounter et sont

aussi visibles par le code manipulant des objets de type MyBiDiCounter,

  • l'ensemble des méthodes et champs privés de MyCounter ne sont pas visibles dans MyBiDiCounter

La méthode print ne modifiant pas le contenu du compteur porte le qualificateur const.

Cependant le code précédent ne peut pas compiler, en effet, les méthodes decrement et print accèdent aux champs counter et max de la classe de base MyCounter. Mais ces champs sont déclarés dans la classe de base comme private, ils ne sont donc pas visibles en dehors de la classe MyCounter.

Ceci signifie que pour compiler, il est nécessaire de modifier la classe MyCounter comme suit:

class MyCounter
{
protected:   // En lieu et place de private
    uint counter;
    uint max;
public:
    ...
};

Question n°2

Tester votre nouveau compteur MyBiDiCounter en utilisant la fonction de test suivante.

void testMyBiDiCounter()
{
    MyBiDiCounter counterA;
    counterA.setMax(4);
    counterA.reset();
    counterA.print();
    for(int i=0; i < 6; i++)
    {
        counterA.increment();
        counterA.print();
    }
    for(int i=0; i < 6; i++)
    {
        counterA.decrement();
        counterA.print();
    }
}

Correction

Correction

Il s'agit de vérifier la bonne compilation et la bonne exécution.

Question n°3

On avait créé des constructeurs pour la classe MyCounter. Est-il possible de les appeler pour créer la classe MyBiDiCounter ?

Correction

Correction

En fait, il faut faire la distinction entre le constructeur par défaut. Dans ce cas, comme aucun constructeur n'est défini, C++ génère automatiquement le constructeur suivant :

class MyBiDiCounter: MyCounter
{    
    ...
public:
    MyBiDiCounter(): public MyCounter() {}
    ...
};

De même, il génère automatiquement le constructeur de recopie :

class MyBiDiCounter: public MyCounter
{ 
    ...
public:   
    MyBiDiCounter(const MyBiDiCounter& aCounter): MyCounter(aCounter) {}
    ...
};

Cependant, les constructeurs spécialisés ne peuvent pas être appellés. En effet, il y a peut-être des champs complémentaires dans la classe dérivée et dès lors, comment peut-on initialiser automatiquement ces champs complémentaires dans un constructeur spécialisé.

Il est donc nécessaire de redéfinir ces constructeurs spécialisés comme suit :

class MyBiDiCounter: public MyCounter
{ 
    ...
public:   
    explicit MyBiDiCounter(uint theMaxValue): MyCounter(theMaxValue) {}
    MyBiDiCounter(uint theCounterValue, uint theMaxValue): 
        MyCounter(theCounterValue, theMaxValue) {}
    ...
};