User Tools

Site Tools


in204:tds:sujets:td8:part1

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
in204:tds:sujets:td8:part1 [2020/11/02 16:12]
bmonsuez [Question n°2]
in204:tds:sujets:td8:part1 [2022/11/18 10:49] (current)
Line 1: Line 1:
-====== ​Création & Manipulation de Processus léger ​======+====== ​Partie I – Surcharge des compteurs ​======
  
-[[in204:​tds:​sujets:​td8|TD8]]+Nous repartons à partir du code des compteurs que nous avons effectué lors de la première séance. ​
  
-===== Références=====+Vous pouvez téléchargé le contenu des fichiers ​
  
-[[http://​en.cppreference.com/​w/​cpp/​thread/​thread|std::​thread]] 
  
-===== Question n°1 =====+  - [[in204:​tds:​sujets:​td8:​counter_hpp|Counter.hpp]],​
  
-Créer ​un processus léger ​qui est associé ​à une fonction ​simple.+vous permettant d’avoir accès au code qui correspondrait normalement à ce qui avait été réalisé à la fin de la seconde séance [[in204:​tds:​sujets:​td2|TD2]]. 
 + 
 +Vous pouvez tout autant repartir de votre code si vous l’avez archivé. 
 + 
 +===== Question n° 1 ====== 
 + 
 +Ajouter à la classe ''​BaseCounter''​ deux nouvelles méthodes virtuelles pures ''​next()'',​ resp. ''​next(unsigned)''​. Ces deux méthodes purement virtuelles ont pour objet d’appeler les méthodes par défaut pour passer à la valeur suivante.  
 + 
 +Typiquement,​ pour un compteur ​qui compte, ce seront les méthodes ''​increment()''​ et ''​increment(unsigned)''​. Pour un compte qui décompte, ce seront les méthodes ''​decrement()''​ et ''​decrement(unsigned)''​. 
 + 
 +<hidden Correction>​ 
 + 
 +Il suffit d'​ajouter dans la section ''​public''​ de la classe ''​BaseCounter''​ les deux méthodes suivantes : 
 + 
 +<code cpp> 
 +class BaseCounter 
 +
 +... 
 +public: 
 +... 
 +    virtual void next() = 0; 
 +    virtual void next(unsigned) = 0; 
 +... 
 +};   
 +</​code>​ 
 + 
 +Les méthodes sont déclarées comme virtuelles, ce qui signifie qu'une entrée ​est définie dans la table des méthodes virtuelles. Cependant, comme nous ne définissons la méthode mais uniquement sa déclaration,​ nous mettons le pointeur qui pointe sur le code de la méthode dans la table des méthodes virtuelles ​à zéro (ou à ''​NULL''​). 
 + 
 +Ceci à deux conséquences : 
 +  * d'une part, il n'y a pas besoin de fournir un code associé aux méthodes, ce sont les classes dérivées qui devront le définir, 
 +  * d'​autre part, aucune instance de la classe ne pourra être créée, puisqu'​il existe une méthode qui n'est pas définie, ie. un pointeur de la table des méthodes virtuelles qui n'est pas initialisé. 
 + 
 +</​hidden>​ 
 +===== Question n° 2 ====== 
 + 
 +Ajouter aux classes ''​ForwardCounter''​ et ''​BackwardCounter'',​ deux nouvelles méthodes ''​next()'',​ resp. ''​next(unsigned)''​. Cette méthode ''​next()''​ (resp. ''​next(unsigned)''​) appellera la méthode ''​increment()'',​ (resp. ''​increment(unsigned)''​) pour la classe ''​ForwardCounter''​. cette méthode ''​next()''​ (resp. ''​next(unsigned)''​) appellera la méthode ''​decrement()'',​ resp. ''​decrement(unsigned)''​ pour la classe ''​BackwardCounter''​. 
 + 
 +<hidden Correction>​ 
 +Pour la classe ''​ForwardCounter'',​ il suffit de redéfinir les méthodes virtuelles ''​next()''​ et ''​next(unsigned)''​ comme suit : 
 +<code cpp> 
 +class ForwardCounter:​ BaseCounter 
 +
 +    ... 
 +public: 
 +    ... 
 +    virtual void next()  
 +    { 
 +        increment();​ 
 +    } 
 +    virtual void next(unsigned aNumberOfSteps) 
 +    { 
 +        while(aNumberOfSteps-- > 0) 
 +            increment();​ 
 +    } 
 +    ... 
 +};     
 +</​code>​  
 + 
 +et par analogie pour la classe ''​BackwardCounter''​ : 
 + 
 +<code cpp> 
 +class BackwardCounter:​ BaseCounter 
 +
 +    ... 
 +public: 
 +    ... 
 +    virtual void next() 
 +    { 
 +        decrement();​ 
 +    } 
 +    virtual void next(unsigned aNumberOfSteps) 
 +    { 
 +        while (aNumberOfSteps-- > 0) 
 +            decrement();​ 
 +    } 
 +    ... 
 +};     
 +</​code>​  
 + 
 +Il se pose la question de la classe ''​BiDiCounter''​. En effet, ''​BiDiCounter''​ hérite à la fois de ''​ForwardCounter''​ mais aussi de ''​BackwardCounter''​ dans le cas de l'​héritage multiple. Donc nous avons deux fonctions ''​next()''​ qui sont candidates pour la redéfinition de la fonction ​''​next()''​ de la classe de base ''​BaseCounter''​. Dans ce cas, nous devons rédéfinir de manière non ambigue la fonction ''​next()''​ et devons ainsi écrire : 
 + 
 +<code cpp> 
 +class BiDiCounter:​ BaseCounter 
 +
 +    ... 
 +public: 
 +    ... 
 +    virtual void next() 
 +    { 
 +        ForwardCounter::​next();​ 
 +    } 
 +    virtual void next(unsigned aNumberOfSteps) 
 +    { 
 +        ForwardCounter::​next(aNumberOfSteps);​ 
 +    } 
 +    ... 
 +};     
 +</​code>​  
 + 
 +qui appelle dès lors l'​implantation fournie par la classe ''​ForwardCounter''​. 
 + 
 + 
 +</​hidden>​ 
 +===== Question n° 3 ====== 
 + 
 +==== Question n° 3.1 ===== 
 + 
 +Ajouter un opérateur ''​operator <<''​ pour afficher un compteur de type ''​BaseCounter''​ dans le flux. 
 + 
 + 
 +<hidden Correction>​
  
 <code cpp> <code cpp>
 #​include<​iostream>​ #​include<​iostream>​
-#include<thread>+... 
 +class BaseCounter 
 +
 +protected:​ 
 +    ... 
 +    friend std::​basic_ostream<charT, charTraits>& operator << ( 
 +        std::​basic_ostream<​charT,​ charTraits>&,​ const BaseCounter&​ aCounter);​ 
 +};
  
-void simple_method()+template<​class charT, class charTraits>​  
 +std::​basic_ostream<​charT,​ charTraits>&​ operator << ​(std::​basic_ostream<​charT,​ charTraits>&​ aStream, 
 +    const BaseCounter&​ aCounter)
 { {
- int i = 5; +    aStream ​<< ​aCounter.counter ​<< "/" << ​aCounter.max;​ 
- int x = 10; +    return aStream;
- int result = i * x; +
- std::​cout ​<< ​"This code calculated the value " +
- << result ​<< " ​from thread ID: " ​ +
- << ​std::​this_thread::​get_id() << "​\n"​;+
 } }
  
 +</​code>​
 +</​hidden>​
  
-int main()+==== Question n° 3.2 ===== 
 + 
 +Ecrire une fonction qui prendre comme paramètre une référence à la classe ''​BaseCounter''​ et qui fait appel à la méthode ''​next''​ un certain nombre de fois.  
 + 
 +Tester cette fonction avec des objets instances de ''​ForwardCounter''​ et ''​BackwardCounter''​ dont le code ressemble à la fonction suivante. 
 + 
 + 
 +<​code>​ 
 +testNext(BaseCounter&​ aCounter) 
 +    for i = 1  to 10 
 +        aCounter.next();​ 
 +        print aCounter 
 +    end 
 +</​code>​ 
 +  
 +<hidden Correction>​ 
 + 
 +Définissez dans le fichier ''​Counter.cpp''​ une fonction ''​testNext''​ qui correspond au code suivant  
 +<code cpp> 
 +void testNext(BaseCounter&​ aCounter)
 { {
- std::​thread simpleThread(&​simple_method); +    for(int i10i++) 
- std::cout <"Main thread is executing and waiting\n"​+    { 
- simpleThread.join(); +        ​aCounter.next(); 
- std::cout << ​"​Alternate thread has terminated.\n"​+        std::cout << ​aCounter << std::endl
- return 0;+    }
 } }
 +</​code>​
 +
 +Définissez dans le fichier ''​Counter.hpp''​ le prototype de la fonction :
 +
 +<code cpp>
 +void testNext(BaseCounter&​)
 +</​code>​
 +
 +Et enfin dans le fichier ''​main.cpp''​ :
 +
 +<code cpp>
 +
 +int main()
 +{
 +    ForwardCounter forward(10);​
 +    BackwardCounter backward(7);​
 +    ​
 +    testNext(forward);​
 +    testNext(backward);​
 +}    ​
 +</​code>​
 +</​hidden>​
 +
 +===== Question n° 4 ======
 +
 +Nous souhaitons que les classes dérivées modifient le comportement de l'​opérateur d'​écriture sur le flux. 
 +Par exemple pour ''​ForwardCounter'',​ nous souhaitons avoir l’affichage suivant :
  
 +<​code>​
 +template<​class charT, class traits> std::​basic_ostream<​charT,​ traits>​(std::​basic_ostream<​charT,​ traits>&,​ BaseCounter&​ aCounter)
 +    affiche "​ForwardCounter : " counter "/"​ max (retour à la ligne)
 </​code>​ </​code>​
  
-Exécuter le code et analyser la sortieCommenter celle-cinotamment au regard de la documentation ​de la classe ​[[http://en.cppreference.com/​w/​cpp/​thread/​thread|std::​thread]].+**ATTENTION** Il n'est pas possible de créer un patron de méthodes virtuellesEn faitil faut modifier ​la méthode ''​print''​ de ''​BaseCounter''​ pourqu'​elle récupère le nom de la classe ​effective, par exemple ​en appelant une méthode ''​getClassName''​ qui retourne le nom de la classe effective, soit ''​BaseCounter''​ pour la classe ''​BaseCounter'',​ ''​ForwardCounter''​ pour la classe ''​ForwardCounter''​ et ainsi de suite.
  
 +Modifier en conséquence les classes ''​BaseCounter'',​ ''​ForwardCounter'',​ ''​BackwardCounter''​ et ''​BidirectionalCounter''​.
 <hidden Correction>​ <hidden Correction>​
  
-Un objet ''​std::​thread"​' ​correspondant à un processus léger est créé et est associé au code la méthode ''​simple_method''​. Ce processus démarre immédiatement ​et lance le calculL'​exécution du code principal se poursuit ​et le message ​''​Main thread is executing and waiting'' ​est affiché. La ligne suivant attend ​que l'exécution du processus léger associé à l'​objet ​''​std::​thread'' ​termineUne fois que ce processus a terminél'​exécution du processus principal continueaffiche le message ''​Alternate thread has terminated''​ et rend la main.+La solution la plus simple est de définir une méthode virtuelle qui retourne le nom de la classe de l'objet. Cette méthode est définie dans la classe de base ''​BaseCounter'' comme une méthode purement virtuelle, ce qui oblige de définir cette méthode dans les classes dérivées. 
 + 
 +L'​opération de conversion ''​operator <<''​ du compteur vers une représentation textuelle appelle ​la méthode ​virtuelle exposée par ''​BaseCounter''​ et redéfinie par les classes dérivant de ''​BaseCounter''​ pour obtenir ​le nom de la classe effective. 
 + 
 +Ceci a pour conséquence de modifier le code des classes ''​BaseCounter'',​ ''​ForwardCounter'',​ ''​BackwardCounter'' ​et ''​BiDiCounter'' ​ainsi que celui de l'opérateur ​''​operator << (std::basic_ostream<​charT,​ charTraits>&,​ const BaseCounter&​)'' ​comme suit : 
 + 
 +<code cpp> 
 + 
 +class BaseCounter 
 +
 +    ​... 
 +protected:​ 
 +    virtual const char* getClassName() const = 0; 
 +    ... 
 +}; 
 + 
 +template<​class charTclass charTraits>​  
 +std::​basic_ostream<​charTcharTraits>&​ operator << (std::​basic_ostream<​charT,​ charTraits>&​ aStream, 
 +    const BaseCounter&​ aCounter) 
 +
 +    aStream << aCounter.getClassName() << ":"​ << aCounter.counter << "/"​ << aCounter.max;​ 
 +    return aStream; 
 +
 + 
 +class ForwardCounter : public virtual BaseCounter 
 +
 +protected:​ 
 +    virtual const char* getClassName() const { return "​ForwardCounter";​ } 
 +    ... 
 +}; 
 + 
 +<code cpp> 
 +class BackwardCounter : public virtual BaseCounter 
 +
 +protected:​ 
 +    virtual const char* getClassName() const { return "​BackwardCounter";​ } 
 +    ... 
 +}; 
 + 
 + 
 +class BiDiCounter : public ForwardCounter,​ public BackwardCounter 
 +
 +protected:​ 
 +    virtual const char* getClassName() const { return "​BiDiCounter "; } 
 +    ... 
 +}; 
 +</​code>​
  
 </​hidden>​ </​hidden>​
  
  
-===== Question ​n°2 =====+===== Question ​n° 5 =====
 + 
 +Nous souhaitions modifier le comportement des compteurs.  
 + 
 +Actuellement,​ lorsque la valeur du compteur de ForwardCounter atteint la valeur max, il recommence à compter à partir de la valeur minimale. 
 + 
 +Nous aimerions pouvoir rendre ce comportement « adaptable », c’est-à-dire que nous ne souhaitons pas modifier les méthodes ''​increment(…)''​ mais simplement le comportement quand la valeur maximale est atteinte et ce pour toutes les méthodes ''​increment(…)''​. 
 + 
 +Pour ce faire, nous suggérons de modifier la méthode ''​increment()''​ de la manière suivante : 
 +  * ''​counter''​ est plus petit que ''​max''​ alors incrémente ''​counter''​. 
 +  * ''​counter''​ est égal à ''​max''​ la méthode appelle une méthode virtuelle ''​reachMaximum()''​ qui décide ce qu’il faut faire lorsque la valeur maximale du compteur est atteinte. 
 + 
 +Modifier ''​ForwardCounter''​ afin d’implanter le comportement précédemment décrit. 
 + 
 +===== Question n° 6 ====== 
 + 
 +Dériver de la classe ''​ForwardCounter''​ une classe ''​VerboseForwardCounter''​ qui lorsque la valeur maximale affiche un message avant de remettre la valeur du compteur à 0.
  
-Ecrire un programme qui lance les deux calculs suivants en parallèle, ​le premier dans un processus léger secondaire, le premier dans le processus léger principal ​:+Vérifier ​le bon comportement de ''​VerboseForwardCounter''​ avec une fonction de test de type :
  
 <code cpp> <code cpp>
-void worker_process(int numberOfIterations)+void testForwardCounter(const ForwardCounter&​ aCounter)
 { {
- for (int i = 1; i < numberOfIterations; i++) +    ​for(int i = ; i < 10 ; i++) 
- +        ​aCounter.increment();
- std::cout << "​Worker Thread: " << ​ i << "​\n"​; +
- }+
 } }
 </​code>​ </​code>​
  
-et+<hidden Correction>​ 
 + 
 +La méthode la plus simple est de transformer la méthode ''​increment''​ définie dans ''​ForwardCounter''​ en méthode virtuelle. 
 <code cpp> <code cpp>
-void main_process()+ 
 +class ForwardCounter : public virtual BaseCounter
 { {
- for (int i = 1i < 1000; i+++protected:​ 
-+    virtual const char* getClassName() const { return "​ForwardCounter"​
- std::​cout ​<< "​Primary Thread: " << i << "​\n"​+ 
- } +public: 
-}+    void increment(
 +    
 +        if (counter ​max) 
 +            counter = counter + 1
 +        else 
 +            ​counter = 0; 
 +    ​} 
 + 
 +   ​... ​
 </​code>​ </​code>​
-  + 
-Tester le code.+Ce qui permet ensuite de redéfinir dans la classe ''​VerboseForwardCounter''​ comme suit : 
 + 
 +<code cpp> 
 + 
 + 
 +class VerboseForwardCounter : ForwardCounter 
 +
 +public: 
 +    void virtual increment() 
 +    { 
 +        if (counter < max) 
 +            counter = counter + 1; 
 +        else 
 +        { 
 +            std::cout << "​Maximal value: " << max << " has been reached." << std::​endl;​ 
 +            counter = 0; 
 +        } 
 +    } 
 + 
 +    VerboseForwardCounter() : ForwardCounter() {} 
 +    VerboseForwardCounter(const ForwardCounter&​ aCounter) : ForwardCounter(aCounter) {} 
 +    explicit VerboseForwardCounter(unsigned theMaxValue) : VerboseForwardCounter(0,​ theMaxValue) {} 
 +    VerboseForwardCounter(unsigned theCounter, unsigned theMaxValue) : ForwardCounter(theCounter,​ theMaxValue) {} 
 + 
 +}; 
 + 
 +</​code>​ 
 + 
 +Dès lors, l'​appel de la fonction ''​testNext''​ retournera bien le message chaque fois que la valeur maximale est atteinte. 
 + 
 + 
 +</​hidden>​
  
 +===== Question n° 7 ======
 +
 +** A faire en dehors de la séance de TD **
 +
 +
 +Actuellement,​ lorsque la valeur du compteur de ''​BackwardCounter''​ atteint la valeur ''​0'',​ il recommence à compter à partir de la valeur maximale.
 +
 +Nous aimerions pouvoir rendre ce comportement « adaptable », c’est-à-dire que nous ne souhaitons pas modifier les méthodes ''​decrement(…)''​ mais simplement le comportement quand la valeur minimale est atteinte et ce pour toutes les méthodes ''​decrement(…)''​.
 +
 +Pour ce faire, nous suggérons de modifier la méthode ''​decrement()''​ de la manière suivante :
 +  * ''​counter''​ est plus grand que ''​0''​ alors décrémente ''​counter''​.
 +  * ''​counter''​ est égal à ''​0''​ la méthode appelle une méthode virtuelle ''​reachMinimum()''​ qui décide ce qu’il faut faire lorsque la valeur maximale du compteur est atteinte.
 +
 +Modifier ''​BackwardCounter''​ afin d’implanter le comportement précédemment décrit.
 +
 <hidden Correction>​ <hidden Correction>​
  
-Nous pouvons écrire le code suivant qui crée deux processus légers, le premier exécutant la fonction ​''​worker_process'' ​avec comme paramètre ​''​10000'' ​et le second exécutant la fonction ​''​main_proc''​.+Nous ajoutons une methode virtuelle dans ''​BackwardCounter'' ​dénomée ​''​reachMinimum()'' ​qui est appellée par ''​decrement()'' ​lorsque le compteur atteint la valeur zéroLe comportement par défaut consiste à remettre le compteur à la valeur maximale. Ceci donne le code suivant :
  
 <code cpp> <code cpp>
-int main()+class BackwardCounter : public virtual BaseCounter
 { {
- std::thread worker_proc(&​worker_process,​ 10000); +protected: 
- std::thread main_proc(&​main_process); +    virtual const char* getClassName() const { return "​BackwardCounter"​} 
- worker_proc.join(); + 
- main_proc.join(); +    virtual void reachMinimum() 
-}+    { 
 +        counter = max
 +    } 
 + 
 +public: 
 +    void decrement() 
 +    { 
 +        if (counter > 0) 
 +            counter = counter - 1
 +        ​else 
 +        { 
 +            reachMinimum(); 
 +        } 
 +    } 
 +    ... 
 +};    ​
 </​code>​ </​code>​
  
-L'​exécution commence par la tâche ''​worker_proc''​ et nous devons voir certains messages de la tâche ''​main_proc'',​ nous voyons cependant que les messages ne sont pas très entrelacés,​ ce qui est du au fait que l'on alloue un temps d'​utilisation de la console à chacun des deux processus légers.+</​hidden>​
  
-Pour mettre un peu d'​entrelacement,​ nous pouvons ajouter un peu de temps entre les affichaches,​ par exemple 1ns pour le premier processus et 10ns pour le second. Ceci nous donne le code suivant:+===== Question n° 8 ======
  
-<code cpp> +** A faire en dehors de la séance de TD **
-#​include<​iostream>​ +
-#​include<​thread>​ +
-#include <​chrono>​+
  
 +Modifier la classe ''​BiDiCounter''​ pour rendre son comportement « adaptable », c'​est-à-dire que nous pouvons spécifier comment le compteur continue de compter lorsque la valeur maximale et la valeur minimale sont atteintes.
  
 +<hidden Correction>​
  
-void worker_process(int numberOfIterations)+De fait, il est plus intéressant de rendre le comportement « adaptable » de à la fois ''​ForwardCounter''​ et ''​BackwardCounter''​. ''​ForwardCounter''​implante la méthode ''​reachMaximum''​ et ''​BackwardCounter''​ la méthode ''​reachMinimun''​. 
 + 
 +class ForwardCounter : public virtual BaseCounter
 { {
- for (int i = 1; i < numberOfIterations;​ i++) +protected:​ 
- { +    virtual const char* getClassName() const return ​"ForwardCounter"; }
- std::cout << ​"Worker Thread: " << i << "\n"; +
- std::​this_thread::​sleep_for(10ns);​ +
-+
-}+
  
-void main_process()+    virtual ​void reachMaximum() 
 +    { 
 +        counter = 0; 
 +    } 
 + 
 +public: 
 +    void increment() 
 +    { 
 +        if (counter < max) 
 +            counter = counter + 1; 
 +        else 
 +            reachMaximum();​ 
 +    } 
 +    ... 
 +}; 
 + 
 +</​code>​ 
 +</​hidden>​ 
 + 
 +===== Question n° 9 ====== 
 + 
 +** A faire en dehors de la séance de TD ** 
 + 
 +Supprimmer tous les fonctions ''​increment''​ et ''​decrement''​ dans les classes ''​BaseCounter'',​ ''​ForwardCounter'',​ ''​BackwardCounter''​ et ''​BidirectionnalCounter''​ et remplacer les par les opérateurs ''​operator ++()'',​ ''​operator ++(int)'',​ ''​operator += (unsigned)''​ et si nécessaire les opérateurs ''​operator --()'',​ ''​operator --(int)''​ et ''​operator -=(unsigned)''​. 
 + 
 + 
 +<hidden Correction>​ 
 + 
 +Nous ajoutons les opérateurs ''​++''​ à la classe ''​ForwardCounter''​ et ''​--''​ à la classe ''​BackwardCounter''​. Ce qui nous donne les codes suivants : 
 + 
 +<code cpp> 
 +class ForwardCounter : public virtual BaseCounter
 { {
- for (int i 1i < 1000; i++) +protected:​ 
-+    ... 
- using namespace std+    virtual void reachMaximum(
- std::cout << "​Primary Thread: " << i << "​\n"​+    { 
- std::​this_thread::​sleep_for(1ns); +        counter ​0; 
-+    } 
-}+    ... 
 +public: 
 +    ... 
 +    ForwardCounter&​ operator ​++(
 +    
 +        if (counter < max) 
 +            counter = counter + 1
 +        ​else 
 +            reachMaximum()
 +        ​return *this; 
 +    } 
 +    ForwardCounter operator ++(int) 
 +    { 
 +        ForwardCounter result(*this); 
 +        ​operator++();​ 
 +        return result; 
 +    ​} 
 +    ... 
 +};
  
-int main()+class BackwardCounter : public virtual BaseCounter
 { {
- std::thread worker_proc(&​worker_process,​ 10000); +protected: 
- std::thread main_proc(&main_process); +    ... 
- worker_proc.join(); +    virtual void reachMinimum() 
- main_proc.join(); +    { 
-}+        counter = max
 +    } 
 + 
 +public: 
 +    ... 
 +    BackwardCounteroperator --() 
 +    { 
 +        if (counter > 0) 
 +            counter = counter - 1
 +        ​else 
 +            reachMinimum(); 
 +        ​return *this; 
 +    } 
 +    BackwardCounter operator --(int) 
 +    { 
 +        BackwardCounter result(*this); 
 +        ​operator--();​ 
 +        return result; 
 +    ​} 
 +    ... 
 +};
 </​code>​ </​code>​
  
-</​hidden>​+Attention pour ''​BiDiCounter'',​ il faut redéfinir les opérateurs,​ puisque le type des opérateurs est lié au type de la classe. Donc nous devons ajouter à ''​BiDiCounter''​ le code suivant :
  
 +<code cpp>
 +class BiDiCounter : public ForwardCounter,​ public BackwardCounter
 +{
 +   ...
 +public:
 +    ...
 +    BiDiCounter&​ operator ++()
 +    {
 +        ForwardCounter::​operator++();​
 +        return *this;
 +    }
 +    BiDiCounter operator ++(int)
 +    {
 +        BiDiCounter result(*this);​
 +        ForwardCounter::​operator++();​
 +        return result;
 +    }
 +    BiDiCounter&​ operator --()
 +    {
 +        BackwardCounter::​operator--();​
 +        return *this;
 +    }
 +    BiDiCounter operator --(int)
 +    {
 +        BiDiCounter result(*this);​
 +        BackwardCounter::​operator--();​
 +        return result;
 +    }
 +    ...
 +};
 +</​code>​
 +
 +</​hidden>​
  
in204/tds/sujets/td8/part1.1604333554.txt.gz · Last modified: 2020/11/02 16:12 by bmonsuez