TD 11 C++: Fonctions abstraites, exceptions

Rappels


Exercice 1: Fonctions abstraites

  1. Téléchargez 1.1.h (copié ci-dessous) et complétez-le, et implémentez les classes dans un fichier 1.1.cc.
    class Sequence {
     public:
      // The value of the sequence at the current step.
      double Value();
    
      // Advances to the next step.
      void Next();
    };
    
    // 1, 1, 2, 3, 5, 8, ...
    class FibonacciSequence : public Sequence {
    };
    
    // 1, 1, 2, 6, 24, 120, 720, ... modulo x: if x = 10, that's
    // 1, 1, 2, 6, 4, 0, 0, ...
    class FactorialModXSequence : public Sequence {
     public:
      explicit FactorialModXSequence(int x);
    };
    Veillez à rendre les fonctions de la classe de base Sequence abstraites.

    Testez votre code avec 1.tar.gz:
    rm 1.tar.gz; wget --no-cache http://fabien.viger.free.fr/cpp/td11/1.tar.gz
    tar xf 1.tar.gz
    make 1.1
    RENDU: 1.1.h et 1.1.cc

  2. Copiez 1.1.h et 1.1.cc dans 1.2.h et 1.2.cc.
    Ensuite, Créez une classe ShiftSequence, sous-classe de Sequence, dont le constructeur prendra en argument une Sequence* arbitraire seq et un décalage (entier positif) shift, telle que:
    ShiftSequence(seq, shift)n = seqseq0 + n + shift, où seq0 est l'étape initiale de seq quand on a construit l'objet ShiftSequence.

    Le passage de seq se fera par pointeur, et la classe ShiftSequence prendra possession de l'objet seq donné: c'est lui qui devra se charger de sa suppression.

    Subtilité supplémentaire: contrairement au reste des Sequence donnés jusqu'à présent, vos objets ShiftSequence ne peuvent pas être copiés "naturellement" sans créer des problèmes. Empêchez la copie d'un ShiftSequence vers un autre! Ma solution préférée est la 3ème méthode citée ici.

    Testez votre code avec
    make 1.2
    RENDU: 1.2.h et 1.2.cc

  3. Copiez 1.2.h et 1.2.cc dans 1.3.h et 1.3.cc.
    Ensuite, ajoutez une fonction int Step() qui renvoie l'étape courante d'une Sequence (elle renverra 0 au début). Pour ne pas avoir à la redéfinir pour chaque sous-classe de Sequence, on va utiliser une astuce:
    Testez votre code avec
    make 1.3
    RENDU: 1.3.h et 1.3.cc

Exercice 2: Exceptions

  1. Dans un fichier 2.1.cc, implémentez la fonction ParseInt() décrite dans 2.1.h (également copié ci-dessous), et faites-lui renvoyer les exceptions dédiées, afin que cela fonctionne (avec l'archive 2.tar.gz):
    rm 2.tar.gz; wget --no-cache http://fabien.viger.free.fr/cpp/td11/2.tar.gz
    tar xf 2.tar.gz
    make 2.1
    Ne changez pas 2.1.h!
    #include <exception>
    
    // Converts a string to an integer, with strict checking: throws an exception
    // if 'str' doesn't represent an integer in the range [-2^31...2^31-1].
    //
    // Exceptions thrown:
    // - NullPtrException: if str == nullptr.
    // - EmptyStrException: if str is empty.
    // - BadFormatException: if the string doesn't follow the regexp 0|(-?[1-9][0-9]*)
    // - OverflowException: if the string follows the regexp above, but the integer
    //   is outside p[-2^31...2^31-1].
    //
    // The last two exceptions take an argument at construction: a string that helps
    // to know what failed. Typically it would be the input that's being parsed.
    // The first two don't need it, because the context is pretty clear (nullptr
    // or empty string).
    int ParseInt(const char* str);
    
    using std::exception;
    class NullPtrException : public exception {};
    class EmptyStrException : public exception {};
    class BadFormatException : public exception {
     public:
      explicit BadFormatException(const char* data) : data_(data) {}
      // See http://www.cplusplus.com/reference/exception/exception/what/
      const char* what() const throw() override { return data_; }
     private:
      const char* data_;
    };
    class OverflowException : public exception {
     public:
      explicit OverflowException(const char* data) : data_(data) {}
      const char* what() const throw() override { return data_; }
     private:
      const char* data_;
    };
    RENDU: 2.1.cc