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:37]
bmonsuez [Question n° 4]
in204:tds:sujets:td7:part1 [2022/11/18 10:48] (current)
Line 1: Line 1:
-Nous repartons à partir du code des compteurs que nous avons effectué lors de la première séance. ​+====== Partie I – Manipulation ​des Exceptions======
  
-Vous pouvez téléchargé le contenue des fichiers ​+[[in204:​tds:​sujets:​td7|TD7]]
  
-  - Counter.hpp,​ +===== Question n°1 : Gestion simple des exceptions en C++ =====
-  - 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]].+==== Question n°1.1 ==== 
  
-Vous pouvez tout autant repartir de votre code si vous l’avez archivé.+Implanter le code suivant dans un nouveau projet
  
-====== Question n° 1 ======+<code cpp>
  
-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. ​+#include <​iostream>​
  
-Typiquement,​ pour un compteur qui compte, ce seront les méthodes ''​increment()''​ et ''​increment(unsigned)''​. Pour un compte qui décomptece seront les méthodes ''​decrement()''​ et ''​decrement(unsigned)''​.+double divide(double adouble b)
 +void test_divide();
  
-====== Question n° 2 ======+void test_divide() 
 +
 +  double i, j; 
 +  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;​ 
 +  }  
 +}
  
-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''​.+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; 
 +}
  
-====== Question n° 3 ======+void main() 
 +
 +    test_divide() ; 
 +}
  
-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. +</​code>​
  
-Tester cette fonction avec des objets instances de ''​ForwardCounter''​ et ''​BackwardCounter''​ dont le code ressemble à la fonction suivante.+==== Question n°1.2 ==== 
  
 +Procéder à une exécution et regarder ce qui se passe quand une division par 0 se produit.
  
-<code> +<hidden Correction>
-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 :+
  
 +Lors d'une division par zéro se produit, le code 
 <code cpp> <code cpp>
-    ​template<​class charT, class traits>  +    std::cout << "Ne peut pas diviser par zero.\n"; 
-    void print(std::basic_ostream<​charT,​ traits>&​ &​Stream) +    return ​b;
-    { +
-        theStream ​<< "Counter" ​<< m_counter << "/"​ << m_max << std::endl+
-        return ​theStream; +
-    }+
 </​code>​ </​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)''​.
-Ajouter ​la surcharge de l'opérateur ​''​operator <<'' ​appelant ​la méthode ​''​print'' ​précédemment définie.+
  
 <​code>​ <​code>​
-template<​class charT, class traits> operator << (std::​basic_ostream<​charT,​ traits>&​ aStream, ​ +try { 
-    ​const BaseCounter&​ aBaseCounter+    ​if(!bthrow b;  
-+  } 
-    ​aBaseCounter.print(aStream)+  catch (double b) 
-    return ​aBaseCounter+    ​std::cout << "Ne peut pas diviser par zero.\n"
-}+    return ​b
 +  }
 </​code>​ </​code>​
  
-Nous souhaitons que les classes dérivées modifient ​le comportement ​de la méthode ''​print''​ +Dans les autres cas, c'est bien le résultat ​de la division qui est retournée par la fonction.
-Par exemple pour ''​ForwardCounter'',​ nous souhaitons avoir l’affichage suivant :+
  
-<code+</hidden
-template<​class charT, class traits> print(std::​basic_ostream<​charT,​ traits>&​) +==== Question n°1.3 ==== 
-    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.+Exécuter en mode débogage et placer ​un point d’arrêt sur le code de capture ​de l’exception.
  
-Modifier en conséquence les classes ''​BaseCounter'', ​''​ForwardCounter''​, ''​BackwardCounter''​ et ''​BidirectionalCounter''​.+<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 entenduen fonction de votre environnementvous avez des procédures différentes pour positionner un point d'arrêt
  
-====== Question n° 5 ======+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é).
  
-Nous souhaitions modifier le comportement des compteurs+  * [[https://​code.visualstudio.com/​docs/​cpp/​cpp-debug|Debug C++ in Visual Studio Code]]
  
-Actuellement,​ lorsque la valeur du compteur de ForwardCounter atteint la valeur max, il recommence à compter à partir de la valeur minimale.+  * [[http://​wiki.codeblocks.org/​index.php/​Debugging_with_Code::​Blocks|Debugging with Code::​Blocks]]
  
-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(…)''​.+  * [[https://​docs.microsoft.com/​fr-fr/​visualstudio/​debugger/​quickstart-debug-with-cplusplus?​view=vs-2019|Quickstart:​ Debug with C++ using the Visual Studio debugger]]
  
-Pour ce faire, nous suggérons de modifier la méthode ''​increment()''​ de la manière suivante ​: +  * [[https://medium.com/​yay-its-erica/​xcode-debugging-with-breakpoints-for-beginners-5b0d0a39d711|Xcode Debugging with Breakpoints ​(for Beginners)]]
-  * ''​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.+  * [[https://​www.cs.swarthmore.edu/​~newhall/​unixhelp/​howto_gdb.php|gdb (and ddd) Guide]]
  
-====== Question ​n° 6 ======+  * [[https://​www.emacswiki.org/​emacs/​DebuggingWithEmacs|Debugging with Emacs]] 
 +</​hidden>​ 
 +===== Question ​n°2 : Création d’une classe d’exception ​=====
  
-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.+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]]
  
-Vérifier le bon comportement ​de ''​VerboseForwardCounter'' ​avec une fonction de test de type :+Cette classe devra s’appeler ''​division_by_zero''​. 
 + 
 +==== Question n°2.1 ==== 
 + 
 +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. 
 + 
 +Penser à fournir un message d’erreur cohérent. 
 + 
 +<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.1572788226.txt.gz · Last modified: 2019/11/03 13:37 by bmonsuez