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 [2019/11/03 13:41]
bmonsuez
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 contenue ​des fichiers ​+===== Question n°1 : Gestion simple ​des exceptions en C++ =====
  
-  - Counter.hpp, +==== Question n°1.1 ==== 
-  - Counter.cpp ​+
  
-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]].+Implanter le code suivant dans un nouveau projet
  
-Vous pouvez tout autant repartir de votre code si vous l’avez archivé.+<code cpp>
  
-====== Question n° 1 ======+#include <​iostream>​
  
-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. ​+double divide(double adouble b); 
 +void test_divide();
  
-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)''​.+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;​ 
 +  }  
 +}
  
-====== Question n° 2 ======+double divide(double a, double b) 
 +
 +  try { 
 +    if(!b) throw b;  
 +  } 
 +  catch (double b) { 
 +    std::cout << "Ne peut pas diviser par zero.\n";​ 
 +    return b; 
 +  } 
 +  return a/b; 
 +}
  
-Ajouter aux classes BaseCounter,​ ''​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''​.+void main() 
 +
 +    test_divide() 
 +}
  
-====== Question n° 3 ======+</​code>​
  
-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+==== Question n°1.2 ==== 
  
-Tester cette fonction avec des objets instances de ''​ForwardCounter''​ et ''​BackwardCounter''​ dont le code ressemble ​à la fonction suivante.+Procéder ​à une exécution et regarder ce qui se passe quand une division par 0 se produit.
  
 +<hidden Correction>​
 +
 +Lors d'une division par zéro se produit, le code 
 +<code cpp>
 +    std::cout << "Ne peut pas diviser par zero.\n";​
 +    return b;
 +</​code>​
 +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)''​.
  
 <​code>​ <​code>​
-testNext(BaseCounter&​ aCounter+try { 
-    for i = 1  to 10 +    if(!bthrow b;  
-        ​aCounter.next(); +  ​} 
-        ​aCounter.print()+  ​catch ​(double b{ 
-    ​end+    ​std::​cout << "Ne peut pas diviser par zero.\n"
 +    ​return b; 
 +  }
 </​code>​ </​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 :+Dans les autres cas, c'​est ​bien le résultat ​de la division qui est retournée par la fonction.
  
-<code cpp+</hidden
-    ​template<​class charT, class traits>  +==== Question n°1.3 ==== 
-    void print(std::​basic_ostream<​charT,​ traits>&​ &​Stream) +
-    { +
-        theStream << "​Counter"​ << m_counter << "/"​ << m_max << std::​endl;​ +
-        return theStream;​ +
-    } +
-</​code>​+
  
-Ajouter la surcharge ​de l'​opérateur ''​operator <<''​ appelant la méthode ''​print''​ précédemment définie.+Exécuter en mode débogage et placer un point d’arrêt sur le code de capture ​de l’exception.
  
-<code+<hidden Correction
-template<​class charTclass traits> operator << (std::​basic_ostream<​charTtraits>&​ aStream,  +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 entenduen fonction de votre environnementvous avez des procédures différentes pour positionner un point d'​arrêt
-    const BaseCounter&​ aBaseCounter) +
-+
-    aBaseCounter.print(aStream);​ +
-    return aBaseCounter;​ +
-+
-</​code>​+
  
-Nous souhaitons que les classes dérivées modifient le comportement de la méthode ''​print'​'​. ​ +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é).
-Par exemple pour ''​ForwardCounter'',​ nous souhaitons avoir l’affichage suivant :+
  
-<​code>​ +  * [[https://code.visualstudio.com/​docs/​cpp/​cpp-debug|Debug C++ in Visual Studio Code]]
-template<​class charT, class traits> print(std::​basic_ostream<​charT,​ traits>&​) +
-    affiche "​ForwardCounter : " m_counter "/" m_max (retour à la ligne) +
-</code>+
  
-**ATTENTION** Il n'est pas possible de créer un patron de méthodes virtuellesEn 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.+  ​[[http://​wiki.codeblocks.org/index.php/​Debugging_with_Code::​Blocks|Debugging with Code::​Blocks]]
  
-Modifier en conséquence les classes ''​BaseCounter'',​ ''​ForwardCounter'',​ ''​BackwardCounter''​ et ''​BidirectionalCounter''​.+  * [[https://​docs.microsoft.com/​fr-fr/​visualstudio/​debugger/​quickstart-debug-with-cplusplus?​view=vs-2019|Quickstart:​ Debug with C++ using the Visual Studio debugger]]
  
-====== Question n° 5 ======+  * [[https://​medium.com/​yay-its-erica/​xcode-debugging-with-breakpoints-for-beginners-5b0d0a39d711|Xcode Debugging with Breakpoints (for Beginners)]]
  
-Nous souhaitions modifier le comportement des compteurs+  * [[https://​www.cs.swarthmore.edu/​~newhall/​unixhelp/​howto_gdb.php|gdb (and ddd) Guide]]
  
-Actuellement,​ lorsque la valeur du compteur de ForwardCounter atteint la valeur max, il recommence à compter à partir de la valeur minimale.+  * [[https://​www.emacswiki.org/​emacs/​DebuggingWithEmacs|Debugging with Emacs]] 
 +</​hidden>​ 
 +===== Question n°2 : Création d’une classe d’exception =====
  
-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 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écifiquement, nous 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]]
  
-Pour ce faire, nous suggérons de modifier la méthode ​''​increment()'' ​de la manière suivante : +Cette classe devra s’appeler ​''​division_by_zero''​.
-  * ''​m_counter''​ est plus petit que ''​m_max''​ alors incrémente ''​m_counter''​. +
-  * ''​m_counter''​ est égal à ''​m_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°2.1 ====
  
-====== Question n° 6 ======+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.
  
-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.+Penser à fournir ​un message ​d’erreur cohérent.
  
-Vérifier le bon comportement ​de ''​VerboseForwardCounter'' ​avec une fonction de test de type :+<hidden Correction>​ 
 + 
 +Nous nous proposons ​de créer un fichier ​''​math.hpp'' ​qui a le contenu suivant ​:
  
 <code cpp> <code cpp>
-void testForwardCounter(const ForwardCounter&​ aCounter) +#ifndef mathHPP 
-+#define mathHPP
-    for(int i = 0 ; i < 10 ; i++) +
-        aCounter.increment();​ +
-+
-</​code>​ +
-  +
-====== Question n° 7 ======+
  
-** A faire en dehors de la séance de TD **+#​include<​exception>​ 
 +#​include<​stdexcept>​
  
 +class division_by_zero:​ public std::​runtime_error
 +{
 +public: ​
 +    division_by_zero():​ std::​runtime_error("​Division by zero")
 +    {}
 +};
  
-Actuellementlorsque la valeur du compteur de ''​BackwardCounter''​ atteint la valeur ''​m_min'',​ il recommence à compter à partir de la valeur maximale.+double divide(double adouble b);  
 +#endif 
 +</​code>​
  
-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(…)''​.+Ainsi que le fichier ​''​math.cpp'' ​qui contient ​le code de la fonction ​''​divide''​.
  
-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''​. +#include "math.hpp"
-  * ''​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.+
  
-Modifier ''​BackwardCounter''​ afin d’implanter le comportement précédemment décrit.+double divide(double a, double b)  
 +
 +  try { 
 +    if(!b) throw b;  
 +  } 
 +  catch (double b) { 
 +    std::cout << "Ne peut pas diviser par zero.\n"; 
 +    return b; 
 +  } 
 +  return a/b; 
 +}
  
-====== Question n° 8 ======+</​code>​ 
 +</​hidden>​
  
-** A faire en dehors de la séance de TD **+==== Question n°2.2 ====
  
-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.+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''​.
  
-====== Question n° 9 ======+<hidden Correction>​
  
-** A faire en dehors de la séance de TD **+La fonction modifiée s'​écrit dorénavant comme suit :
  
-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)''​.+<code cpp> 
 +inline double divide(double adouble b) 
 +
 +  try { 
 +    if(== 0 
 +        throw division_by_zero();  
 +  } 
 +  catch (division_by_zero
 +    std::cout << "Ne peut pas diviser par zero.\n"; 
 +    return 0; 
 +  } 
 +  return a/b; 
 +
 +</​code>​
  
 +</​hidden>​
  
in204/tds/sujets/td7/part1.1572788481.txt.gz · Last modified: 2019/11/03 13:41 by bmonsuez