====== Partie I – Création d’une classe dérivée ======
[[in204:tds:sujets:td2|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 [[in204:tds:td2:counter|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 :
* Une première méthode decrement qui décrémente le compteur, cette méthode correspond au pseudo-code suivant :
decrement()
si counter > 0
counter <- counter – 1
sinon
counter = max;
* Une seconde méthode print qui affiche l’état du compteur de la manière suivante.
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'',
* 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();
}
}
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) {}
...
};