User Tools

Site Tools


in204:tds:sujets:td7: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:td7:part1 [2020/10/20 07:08]
bmonsuez [Question n° 2]
in204:tds:sujets:td7:part1 [2022/11/18 10:48] (current)
Line 1: Line 1:
-====== Partie I – Surcharge ​des compteurs ​======+====== Partie I – Manipulation ​des Exceptions======
  
-Nous repartons à partir du code des compteurs que nous avons effectué lors de la première séance. ​+[[in204:​tds:​sujets:​td7|TD7]]
  
-Vous pouvez téléchargé le contenu ​des fichiers ​+===== Question n°1 : Gestion simple ​des exceptions en C++ =====
  
 +==== Question n°1.1 ==== 
  
-  - [[in204:​tds:​sujets:​td7:​counter_hpp|Counter.hpp]],+Implanter le code suivant dans un nouveau projet
  
-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]].+<code cpp>
  
-Vous pouvez tout autant repartir de votre code si vous l’avez archivé.+#include <​iostream>​
  
-===== Question n° 1 ======+double divide(double a, double b); 
 +void test_divide();​
  
-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. ​+void test_divide() 
 +
 +  double ij; 
 +  for(;;
 +    std::cout << "Le numerateur (0 pour arreter): "; 
 +    std::cin >> i; 
 +    if(i == 0) 
 +      break; 
 +    std::cout << " Le denominateur : "; 
 +    std::cin >> j; 
 +    std::cout << "​Resultat:​ " << divide(i,j) << std::​endl;​ 
 +  }  
 +}
  
-Typiquementpour 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)''​.+double divide(double adouble b) 
 +
 +  try { 
 +    if(!bthrow b;  
 +  } 
 +  catch (double b
 +    std::cout << "Ne peut pas diviser par zero.\n"; 
 +    return b; 
 +  } 
 +  return a/b; 
 +}
  
-<hidden Correction>​+void main() 
 +
 +    test_divide() ; 
 +}
  
-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>​ </​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''​).+==== Question n°1.2 ==== 
  
-Ceci à deux conséquences : +Procéder ​à une exécution et regarder ​ce qui se passe quand une division par 0 se produit.
-  * 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> +<​hidden ​Correction>
-===== 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''​. +Lors d'une division par zéro se produitle code 
- +
-<hidden Correction>​ +
-Pour la classe ''​ForwardCounter'',​ il suffit de redéfinir les méthodes virtuelles ''​next()''​ et ''​next(unsigned)''​ comme suit :+
 <code cpp> <code cpp>
-class ForwardCounterBaseCounter +    std::cout << "Ne peut pas diviser par zero.\n"; 
-+    ​return b
-    ... +</​code>​ 
-public: +est exécuté et la fonction retourne ''​0''​. Ceci signifie que l'​exception de type ''​double''​ ayant pour valeur ''​0''​ a été générée et a été capturée par la clause ''​catch(double)''​.
-    ..+
-    ​virtual void next()  +
-    { +
-        increment()+
-    } +
-    ​virtual void next(unsigned aNumberOfSteps) +
-    { +
-        while(aNumberOfSteps-- > 0+
-            increment()+
-    } +
-    ​... +
-};     +
-</​code> ​+
  
-et par analogie pour la classe ''​BackwardCounter''​ : +<​code>​ 
- +try 
-<​code ​cpp+    ​if(!bthrow b;  
-class ForwardCounter:​ BaseCounter +  
-+  ​catch ​(double b{ 
-    ​... +    ​std::cout << "Ne peut pas diviser par zero.\n"​
-public: +    ​return b; 
-    ... +  
-    virtual void next() +</​code>​
-    { +
-        decrement(); +
-    +
-    ​virtual void next(unsigned aNumberOfSteps+
-    ​+
-        while (aNumberOfSteps-- > 0) +
-            decrement()+
-    ​+
-    ... +
-};    ​ +
-</​code> ​+
  
 +Dans les autres cas, c'est bien le résultat de la division qui est retournée par la fonction.
  
 </​hidden>​ </​hidden>​
-===== Question ​n° ======+==== Question ​n°1.3 ==== 
  
-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+Exécuter en mode débogage ​et placer ​un point d’arrêt sur le code de capture de l’exception.
  
-Tester ​cette fonction ​avec des objets instances de ''​ForwardCounter''​ et ''​BackwardCounter''​ dont le code ressemble à la fonction suivante.+<hidden Correction>​ 
 +L'​objectif de cette question est de vous faire manipuler vos outils pour utiliser l'​environnement de dévogage de votre environnement de développement. Bien entendu, en fonction ​de votre environnement,​ vous avez des procédures différentes pour positionner un point d'arrêt
  
 +Pour mémoire, voici quelques références pour placer des points d'​arrêts sur les différents outils (sans garantie aucune d'​exhaustivité).
  
-<code+  * [[https://code.visualstudio.com/docs/​cpp/​cpp-debug|Debug C++ in Visual Studio Code]]
-testNext(BaseCounter&​ aCounter) +
-    for i = 1  to 10 +
-        aCounter.next(); +
-        aCounter.print(); +
-    end +
-</code> +
-  +
-===== Question n° 4 ======+
  
-L’ancienne méthode ''​print()''​ est définie au niveau de la classe de base ''​BaseCounter''​Nous souhaitons la redéfinir par une méthode virtuelle ​:+  * [[http://​wiki.codeblocks.org/​index.php/​Debugging_with_Code::​Blocks|Debugging with Code::Blocks]]
  
-<code cpp> +  * [[https://docs.microsoft.com/​fr-fr/​visualstudio/​debugger/​quickstart-debug-with-cplusplus?​view=vs-2019|Quickstart:​ Debug with C++ using the Visual Studio debugger]]
-    template<​class charT, class traits>  +
-    void print(std::​basic_ostream<​charT,​ traits>&​ aStream) +
-    { +
-        aStream << "​Counter"​ << counter << "/" << max << std::​endl;​ +
-    } +
-</code>+
  
-Ajouter la surcharge de l'​opérateur ''​operator <<''​ appelant la méthode ''​print''​ précédemment définie.+  * [[https://​medium.com/​yay-its-erica/​xcode-debugging-with-breakpoints-for-beginners-5b0d0a39d711|Xcode Debugging with Breakpoints (for Beginners)]]
  
-<​code>​ +  * [[https://www.cs.swarthmore.edu/​~newhall/​unixhelp/​howto_gdb.php|gdb ​(and dddGuide]]
-template<​class charT, class traits> operator << (std::​basic_ostream<​charT,​ traits>&​ aStream,  +
-    const BaseCounter&​ aBaseCounter) +
-+
-    aBaseCounter.print(aStream)+
-    return aStream; +
-+
-</​code>​+
  
-Nous souhaitons que les classes dérivées modifient le comportement de la méthode ''​print''​.  +  * [[https://​www.emacswiki.org/​emacs/​DebuggingWithEmacs|Debugging with Emacs]] 
-Par exemple pour ''​ForwardCounter'',​ nous souhaitons avoir l’affichage suivant ​:+</​hidden>​ 
 +===== Question n°2 Création d’une classe d’exception =====
  
-<code> +Nous envisageons désormais faire les choses correctement. Nous souhaitons définir une classe exception qui dérive de la classe [[https://​en.cppreference.com/​w/​cpp/​error/​exception|std::​exception]] se trouvant définie dans le fichier d'​entête [[https://​en.cppreference.com/​w/​cpp/​header/​exception|<exception>]]. Plus spécifiquementnous souhaitons la faire dériver de la classe ​ [[https://​en.cppreference.com/​w/​cpp/​error/​runtime_error|std::runtime_error]] qui elle-même dérive de [[https://en.cppreference.com/​w/​cpp/​error/​exception|std::​exception]]. ​
-template<​class charTclass traits> print(std::basic_ostream<​charT,​ traits>&​) +
-    affiche "​ForwardCounter ​" counter "/" max (retour à la ligne) +
-</code>+
  
-**ATTENTION** Il n'est pas possible de créer un patron de méthodes virtuelles. En fait, il 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.+Cette classe ​devra s’appeler ​''​division_by_zero''​.
  
-Modifier en conséquence les classes ''​BaseCounter'',​ ''​ForwardCounter'',​ ''​BackwardCounter''​ et ''​BidirectionalCounter''​.+==== Question n°2.1 ====
  
-===== Question n° 5 ======+Créer la classe ''​division_by_zero''​. Elle pourra être définie dans un fichier d’entête ''​math.hpp''​ qui contiendra aussi l’entête de la fonction ''​divide''​. Le fichier associé ''​math.cpp''​ contiendre la code de la fonction divide.
  
-Nous souhaitions modifier le comportement des compteurs+Penser à fournir un message d’erreur cohérent.
  
-Actuellement,​ lorsque la valeur du compteur de ForwardCounter atteint la valeur max, il recommence à compter à partir de la valeur minimale.+<hidden Correction>​
  
-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(…)''​.+Nous nous proposons de créer un fichier ​''​math.hpp'' ​qui a le contenu suivant :
  
-Pour ce faire, nous suggérons de modifier la méthode ''​increment()''​ de la manière suivante : +<code cpp> 
-  * ''​counter''​ est plus petit que ''​max''​ alors incrémente ''​counter''​. +#ifndef mathHPP 
-  * ''​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.+#define mathHPP
  
-Modifier ''​ForwardCounter''​ afin d’implanter le comportement précédemment décrit.+#​include<​exception>​ 
 +#​include<​stdexcept>​
  
-===== Question n° 6 ======+class division_by_zero:​ public std::​runtime_error 
 +
 +public:  
 +    division_by_zero():​ std::​runtime_error("​Division by zero"​) 
 +    {} 
 +};
  
-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.+double divide(double a, double b);  
 +#endif 
 +</​code>​
  
-Vérifier ​le bon comportement de ''​VerboseForwardCounter'' ​avec une fonction ​de test de type :+Ainsi que le fichier ​''​math.cpp'' ​qui contient le code de la fonction ''​divide''​.
  
 <code cpp> <code cpp>
-void testForwardCounter(const ForwardCounter&​ aCounter)+#include "​math.hpp"​ 
 + 
 +double divide(double a, double b
 { {
-    for(int i = 0 ; i < 10 ; i+++  try { 
-        ​aCounter.increment();+    if(!bthrow b;  
 +  } 
 +  catch (double b
 +    std::cout << "Ne peut pas diviser par zero.\n";​ 
 +    return b; 
 +  } 
 +  return a/b;
 } }
 +
 </​code>​ </​code>​
-  +</​hidden>​
-===== Question n° 7 ======+
  
-** A faire en dehors de la séance de TD **+==== Question n°2.2 ====
  
 +Modifier les fonctions ''​divide''​ et ''​test_divide''​ pour prendre ne plus lancer et capturer une exception de type ''​double''​ mais de type ''​division_by_zero''​.
  
-Actuellement,​ lorsque la valeur du compteur de ''​BackwardCounter''​ atteint la valeur ''​m_min'',​ il recommence à compter à partir de la valeur maximale.+<hidden Correction>​
  
-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(…)''​.+La fonction modifiée s'écrit dorénavant comme suit :
  
-Pour ce faire, nous suggérons de modifier la méthode ''​decrement()''​ de la manière suivante : +<code cpp> 
-  ​* ''​m_counter''​ est plus petit que ''​m_max''​ alors incrémente ''​m_counter''​. +inline double divide(double a, double b) 
-  * ''​m_counter''​ est égal à ''​m_max''​ 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. +{ 
- +  ​try { 
-Modifier ''​BackwardCounter''​ afin d’implanter le comportement précédemment décrit. +    if(== 0)  
- +        throw division_by_zero(); ​ 
-===== Question n° 8 ====== +  } 
- +  catch (division_by_zero) { 
-** A faire en dehors de la séance de TD ** +    ​std::​cout << "Ne peut pas diviser par zero.\n"; 
- +    ​return 0; 
-Modifier la classe ''​BidirectionnalCounter''​ 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+  } 
- +  ​return a/b; 
-===== Question n° 9 ====== +} 
- +</​code>​
-** 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>​
  
in204/tds/sujets/td7/part1.1603177723.txt.gz · Last modified: 2020/10/20 07:08 by bmonsuez