====== Partie III – Augmenter l’expressivité des exceptions====== [[in204:tds:sujets:td7|TD8]] 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 : #include ... 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. }; ===== Question n°1 ===== Proposer une implantation de cette classe. 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. #include ... 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. }; Il est nécessaire de définir les constructeurs pour cette classe : 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) {} ... ===== 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. La nouvelle classe ''extended_divide_by_zero'' dérive directement de la classe ''extended_exception''. Ce qui nous donne le code suivant : class extended_divide_by_zero: public extended_exception { public: division_by_zero(): extended_exception("Division by zero") {} }; ===== 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 : 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; } } Commentez le résultat de l’exécution. 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 : try { successive_division(j); return divide(i,j); } catch(extended_divide_by_zero e) { e.catched() ; throw e; } ... 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 : try { successive_division(j); return divide(i,j); } catch(extended_divide_by_zero& e) { e.catched() ; throw e; } ... Dans ce cas, l'exception n'est pas recopiée et supprimée mais modifiée et ensuite propagée.