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

Both sides previous revision Previous revision
Next revision
Previous revision
in204:tds:sujets:td7:part3 [2019/11/03 13:30]
bmonsuez
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 qu’un 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 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> <code cpp>
-void insertion_sort(std::vector<​int>&​ anArray)+#​include<​exception>​ 
 +... 
 + 
 +class extended_exception : public ​std::runtime_error
 { {
- for (int i = 0; i < anArray.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>​ </​code>​
  
-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.+===== Question n°1 ===== 
  
-===== Question n° 1=====+Proposer une implantation de cette classe. ​
  
-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. +<hidden Correction>​
  
-Nous souhaitons utiliser l’algorithme avec la signature suivante : 
  
 +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> <code cpp>
-void insertion_sort(std::vector<​Base*>&​ anArray)+#​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>​ </​code>​
  
-Quelles sont les méthodes virtuelles que la classe ​abstraite doit exposer ? +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=====+
  
-==== Question ​n° 2.1====+===== Question ​n°2 ===== 
  
-Ajouter à la classe ​de base ''​Base'' ​une méthode purement virtuelle ​''​print()''​ qui affiche le contenu ​de la classe ​sur la console.+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''​.
  
-==== Question n° 2.2 ====+Réaliser une implantation de la classe extended_divide_by_zero.
  
-Créer une fonction ''​print(std::​vector<Base*anArray)''​ qui prend un tableau en paramètre et affiche l’ensemble des éléments contenus dans le tableau sur la console.+<hidden Correction>
  
-===== Question n° 3 ===== 
  
-===== Question n° 3.1 ====+La nouvelle classe ''​extended_divide_by_zero''​ dérive directement de la classe ''​extended_exception''​Ce qui nous donne le code suivant :
  
-Créer une classe Entier qui dérive de la classe « abstraite » ''​Base''​ et qui contient un champ ''​m_value''​ ayant comme type le type ''​int''​.+<code cpp> 
 +class extended_divide_by_zero:​ public extended_exception 
 +
 +public:  
 +    division_by_zero():​ extended_exception("​Division by zero"​) 
 +    {} 
 +}; 
 +</​code>​
  
-==== Question n° 3.2 ====+</​hidden>​
  
-Créer une fonction qui crée un tableau de ''​theNumberOfValues''​ entiers de type Entier+===== Question n°3 ===== 
  
-<code cpp> +Nous proposons ​de modifier la fonction ​''​divide'' ​pour qu’elle lance non plus une exception ​''​divide_by_zero'' ​mais ''​extended_divide_by_zero''​.
-std::​vector<​Base*>​ create_integer_array( +
- size_t theNumberOfValues) +
-</​code>​ +
-qui crée un tableau ​de ''​theNumberOfValues'' ​valeurs commençant par la valeur ​''​0'' ​et se terminant à la valeur ​''​theNumberOfValues-1''​.+
  
-==== Question n° 3.3 ====+Nous souhaitons tester cette nouvelle fonction avec le code suivant :
  
-Créer une fonction qui crée un tableau de ''​theNumberOfValues''​ entiers de type ''​Entier''​ dont les éléments sont des nombres aléatoires compris entre ''​theMinValue''​ et ''​theMaxValue''​.+<code cpp> 
 +double successive_division(double i) nexcept(false)
  
-Cette fonction peut s’implanter comme suit.  +void test_succesive_division() noexcept
-<code cpp>  +
-std::​vector<​Base*>​ create_random_integer_array( +
- size_t theNumberOfValues,​ int theMinValue,​ int theMaxValue)+
 { {
- std::​random_device rd+ double i
- std::mt19937 gen(rd());  + std::cout << "The numerator: "
- std::uniform_int_distribution<​distr(theMinValue,​ theMaxValue)+ std::cin >> i
- std::​vector<​Entier*>​ array(theNumberOfValues); + try { 
- for (size_t i = 0; i < theNumberOfValues;​ i+++ successive_division(i); 
- array[i] = new Entier(distr(gen)); +
- return array;+ catch ​(extended_division_by_zero e{ 
 + e.catched(); 
 + std::cout << "​Division by zero occurred after "  
 + << e.getCatchNumber() 
 + << " divisions"​ << std::endl; 
 + }
 } }
-</​code>​ 
  
-===== Question n°4 ===== +double successive_division(double i)  
- + noexcept(false) 
-Modifier la fonction de tri ''​insertion_sort(std::vector<int>&​ anArray)''​ afin de ne plus travailler sur des entiers mais sur des objets dérivant de la classe « abstraite » ''​Base'' ​+
- +  double j; 
-<code cpp> +  ​std::cout << "Next divisor (-1 to stop sequence): "; 
-void insertion_sort(std::vector<​Base*>& anArray)+  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>​
  
-Tester la fonction avec le tableau dentiers que vous avez créé à la question n°3.3.+Commentez ​le résultat de lexécution.
  
-===== Question n° 5 ===== +<hidden Correction>​
-Nous souhaitons étendre le code à une classe de réel.+
  
-==== Question n° 5.1 ====+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 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.
  
-Ecrire une nouvelles classe ''​Reel''​ qui dérive de ''​Base''​ et qui contient un champ  ''​m_value''​ de type ''​double''​.+Ceci est effectivement logique, puisque quand nous effectuons la capture :
  
-==== Question n° 5.2 ====+<code cpp> 
 +  try { 
 +    successive_division(j);​ 
 +    return divide(i,​j);​ 
 +  } 
 +  catch(extended_divide_by_zero e) { 
 +    e.catched() ;  
 +    throw e;  
 +  } 
 +  ... 
 +</​code>​
  
-Créer une fonction qui crée un tableau ​de ''​theNumberOfValues'' ​objets de type ''​Reel'' ​dont les éléments sont des nombres aléatoires compris entre ''​theMinValue'' ​et ''​theMaxValue'​'.+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 :
  
-Cette fonction peut s’implanter comme suit.  
-  
 <code cpp> <code cpp>
-std::​vector<​Base*>​ create_random_double_array( +  try 
- size_t theNumberOfValues,​ double theMinValue,​ double theMaxValue) +    ​successive_division(j); 
-+    ​return divide(i,j); 
- std::​random_device rd; +  } 
- std::​mt19937 gen(rd()); +  catch(extended_divide_by_zero&​ e{ 
- std::​uniform_real_distribution<>​ distr(theMinValuetheMaxValue); +    ​e.catched() ;  
- std::​vector<​Base*>​ array(theNumberOfValues);​ +    throw e;  
- for (size_t i = 0; i < theNumberOfValues;​ i+++  } 
- array[i] = new Real(distr(gen)); +  ...
- return array+
-}+
 </​code>​ </​code>​
  
-Vérifier que l’algorithme de tri fonctionne aussi pour cette nouvelle nouvelle classe.+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.1572787835.txt.gz · Last modified: 2019/11/03 13:30 by bmonsuez