This is an old revision of the document!
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)
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
,
aussi visibles par le code manipulant des objets de type 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();
}
}
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
?
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) {}
...
};