This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
in204:tds:sujets:td6:part3 [2020/10/13 16:58] bmonsuez |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Partie III – Augmenter l’expressivité des exceptions====== | ||
- | |||
- | [[in204:tds:sujets:td6|TD6]] | ||
- | |||
- | Nous souhaitons créer une nouvelle classe d’exception qui dérive de la classe exception et qui compte le nombre de fois qu’une exception est capturée. | ||
- | Nous proposons que cette exception extended_exception dérive de la classe de base std::exception et fournisse en complément des méthodes offertes par la classe de base les méthodes suivantes : | ||
- | |||
- | <code cpp> | ||
- | #include<exception> | ||
- | ... | ||
- | |||
- | class extended_exception : public std::runtime_error | ||
- | { | ||
- | public: | ||
- | void catched(); | ||
- | // Est appelé chaque fois que l’on souhaite indiqué à la classe qu’elle a été | ||
- | // capturée. | ||
- | int getCatchNumber() const; | ||
- | // Retourne le nombre de fois que l’exception a été capturée. | ||
- | }; | ||
- | </code> | ||
- | |||
- | ===== Question n°1 ===== | ||
- | |||
- | Proposer une implantation de cette classe. | ||
- | |||
- | <hidden Correction> | ||
- | |||
- | Nous proposons d'ajouter un compteur qui est incrémenté à chaque fois que l'exception a été capturée, ie. que la méthode ''catched'' a été appellée. Par défaut ce compteur est initialisé à zéro. | ||
- | <code cpp> | ||
- | #include<exception> | ||
- | ... | ||
- | |||
- | class extended_exception: public std::runtime_error | ||
- | { | ||
- | private: | ||
- | private unsigned m_catched = 0; | ||
- | public: | ||
- | void catched() { m_catched ++; } | ||
- | // Est appelé chaque fois que l’on souhaite indiqué à la classe qu’elle a été | ||
- | // capturée. | ||
- | int getCatchNumber() const { return m_catched; } | ||
- | // Retourne le nombre de fois que l’exception a été capturée. | ||
- | }; | ||
- | </code> | ||
- | |||
- | Il est nécessaire de définir les constructeurs pour cette classe : | ||
- | <code cpp> | ||
- | class extended_exception: public std::runtime_error | ||
- | { | ||
- | ... | ||
- | public: | ||
- | explicit extended_exception(const std::string& aMessage): | ||
- | runtime_error(aMessage) | ||
- | {} | ||
- | explicit extended_exception(const char* aMessage): | ||
- | runtime_error(aMessage) | ||
- | {} | ||
- | ... | ||
- | </code> | ||
- | |||
- | </hidden> | ||
- | |||
- | ===== Question n°2 ===== | ||
- | |||
- | Nous proposons de créer une classe exception ''extended_divide_by_zero'' qui se comporte comme la classe ''divide_by_zero'' mais qui dérive de la classe ''extended_exception''. | ||
- | |||
- | Réaliser une implantation de la classe extended_divide_by_zero. | ||
- | |||
- | <hidden Correction> | ||
- | |||
- | La nouvelle classe ''extended_divide_by_zero'' dérive directement de la classe ''extended_exception''. Ce qui nous donne le code suivant : | ||
- | |||
- | <code cpp> | ||
- | class extended_divide_by_zero: public extended_exception | ||
- | { | ||
- | public: | ||
- | division_by_zero(): extended_exception("Division by zero") | ||
- | {} | ||
- | }; | ||
- | </code> | ||
- | |||
- | </hidden> | ||
- | |||
- | ===== Question n°3 ===== | ||
- | |||
- | Nous proposons de modifier la fonction ''divide'' pour qu’elle lance non plus une exception ''divide_by_zero'' mais ''extended_divide_by_zero''. | ||
- | |||
- | Nous souhaitons tester cette nouvelle fonction avec le code suivant : | ||
- | |||
- | <code cpp> | ||
- | double successive_division(double i) nexcept(false) | ||
- | |||
- | void test_succesive_division() noexcept | ||
- | { | ||
- | double i; | ||
- | std::cout << "The numerator: "; | ||
- | std::cin >> i; | ||
- | try { | ||
- | successive_division(i); | ||
- | } | ||
- | catch (extended_division_by_zero e) { | ||
- | e.catched(); | ||
- | std::cout << "Division by zero occurred after " | ||
- | << e.getCatchNumber() | ||
- | << " divisions" << std::endl; | ||
- | } | ||
- | } | ||
- | |||
- | double successive_division(double i) | ||
- | noexcept(false) | ||
- | { | ||
- | double j; | ||
- | std::cout << "Next divisor (-1 to stop sequence): "; | ||
- | std::cin >> j; | ||
- | if (j == -1) | ||
- | return i; | ||
- | try { | ||
- | successive_division(j); | ||
- | return divide(i,j); | ||
- | } | ||
- | catch(division_by_zero e) | ||
- | { | ||
- | throw extended_division_by_zero(); | ||
- | } | ||
- | catch (extended_division_by_zero e) | ||
- | { | ||
- | e.catched(); | ||
- | throw e; | ||
- | } | ||
- | } | ||
- | </code> | ||
- | |||
- | Commentez le résultat de l’exécution. | ||
- | |||
- | <hidden Correction> | ||
- | |||
- | Si nous effectuons un appel à la fonction avec la séquence de chiffres suivante : | ||
- | ''20 4 4 1 3 0 3 6 -1'', nous allons avoir 5 captures de l'exception de type ''extended_divide_by_zero''. Cependant, nous allons avoir comme message que l'exception s'est produite après ''5'' divisions. Ce qui est conforme. | ||
- | |||
- | Ceci est effectivement logique, puisque quand nous effectuons la capture : | ||
- | |||
- | <code cpp> | ||
- | try { | ||
- | successive_division(j); | ||
- | return divide(i,j); | ||
- | } | ||
- | catch(extended_divide_by_zero e) { | ||
- | e.catched() ; | ||
- | throw e; | ||
- | } | ||
- | ... | ||
- | </code> | ||
- | |||
- | l'argument de la clause ''catch'' est ''extended_divide_by_zero'', ce qui signifie que nous **dupliquons** l'argument. Nous créons une copie de l'ancienne exception qui ensuite sera détruite. Ensuite, nous augmentons la valeur du champ ''m_catched'' qui a été recopié. En conséquence, nous comptons bien le nombre de fois que l'exception a été capturée à partir du moment où elle a été générée. | ||
- | |||
- | Cependant, nous pouvons éviter de recopier l'exception en effectuant un passage non pas par recopie mais par référence : | ||
- | |||
- | <code cpp> | ||
- | try { | ||
- | successive_division(j); | ||
- | return divide(i,j); | ||
- | } | ||
- | catch(extended_divide_by_zero& e) { | ||
- | e.catched() ; | ||
- | throw e; | ||
- | } | ||
- | ... | ||
- | </code> | ||
- | |||
- | Dans ce cas, l'exception n'est pas recopiée et supprimée mais modifiée et ensuite propagée. | ||
- | |||
- | </hidden> | ||