User Tools

Site Tools


in204:tds:sujets:td7:part3

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
in204:tds:sujets:td7:part3 [2019/11/03 12:51]
bmonsuez created
in204:tds:sujets:td7:part3 [2022/11/18 10:48] (current)
Line 1: Line 1:
-====== Partie III – Algorithmes génériques ​======+====== Partie III –  ​Augmenter l’expressivité des exceptions======
  
-Dans la conclusion du cours, nous affirmons quun intérêt du polymorphisme,​ c’est ​de pouvoir écrire un algorithme « générique », c’est à dire un algorithme ​qui pourra fonctionner pour des objets représentant des données ​de plusieurs types+[[in204:​tds:​sujets:​td7|TD8]] 
-Nous considérons un algorithme ​de tri très simple qui fonctionne sur des entiers ​:+ 
 +Nous souhaitons créer une nouvelle classe dexception 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> <code cpp>
-void insertion_sort(std::vector<​int>&​ anArray)+#​include<​exception>​ 
 +... 
 + 
 +class extended_exception : public ​std::runtime_error
 { {
- for (int i = 0anArray.size(); i++) +  public: 
-+    void catched(); 
- for (int j i + 1; j anArray.size(); j+++      // Est appelé chaque fois que l’on souhaite indiqué à la classe qu’elle a été 
- +      // capturée.  
- if (anArray[i] > anArray[j]+   int getCatchNumber() const; 
- std::swap(anArray[i], anArray[j])+      // 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>​ </​code>​
  
 +Commentez le résultat de l’exécution.
  
-Cet algorithme fonctionne uniquement pour des entiers. Nous nous proposons de transformer cette fonction afin qu’elle puisse aussi bien trier des entiers mais aussi des réels ou des complexes.+<hidden Correction>​
  
-===== Question n° =====+Si nous effectuons un appel à la fonction avec la séquence de chiffres suivante : 
 +''​20 4 4 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.
  
-Pour ce faire, nous concevons une classe « abstraite » ayant comme nom ''​Base''​ qui expose les fonctions nécessaires à l’écriture de l’algorithme de tri. +Ceci est effectivement logiquepuisque quand nous effectuons la capture :
  
 <code cpp> <code cpp>
-void insertion_sort(std::​vector<​Base*>&​ anArray);+  try { 
 +    successive_division(j); 
 +    return divide(i,​j);​ 
 +  } 
 +  catch(extended_divide_by_zero e) { 
 +    e.catched() ;  
 +    throw e;  
 +  } 
 +  ...
 </​code>​ </​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>​
  
in204/tds/sujets/td7/part3.1572785470.txt.gz · Last modified: 2019/11/03 12:51 by bmonsuez