M2103-TP3-Exo-1

Créez le projet CException.

Dans les fichiers CException.h et CException.cpp, ajouter dans l’espace de noms nsUtil la classe CException, dérivée de la classe standard exception, possédant deux attributs (données membres) :

  • myLibelle : un texte de type string contenant un diagnostic d’erreur,
  • myCodErr : un entier non signé,

et les méthodes suivantes :

  • un constructeur à deux paramètres (le libellé de l’exception et le code de l’erreur), avec d’éventuelles valeurs par défaut,
  • un destructeur virtuel (vide), nécessaire car la classe mère (exception) est elle-même virtuelle,
  • deux accesseurs permettant de récupérer les valeurs des données membres,
  • une récriture de la fonction virtuelle what(), héritée de la classe mère exception, de profil suivant :
    virtual const char* what() const noexcept;
    

    qui, au moyen de la méthode c_str() de la classe string, renvoie le libellé de l’exception sous la forme d’une NTCTS (dont le type est const char*).

  • la fonction d’affichage (provisoire) diplay(), qui affiche à l’écran le contenu de l’exception, par exemple dans le format suivant :
    Exception : xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Code      : yyyyy
    

Dans la fonction testException() de l’espace de noms anonyme du fichier testCException.cpp, écrire une boucle terminée par la fin de fichier cin, constituée :

  • de la saisie d’une chaîne de caractères (le libellé de l’exception),
  • de la saisie d’un entier (le code d’erreur associé),
  • de la construction d’une CException,
  • de son affichage.

Compiler et tester.

M2103-TP3-Exo-1-Corrigé

CException.h

/**
 *
 * \file    CException.h
 *
 * \authors M. Laporte
 *
 * \date    02/04/2018
 *
 * \version V2.0
 *
 * \brief  déclarations de la classe Exception
 *
 **/
#ifndef __CEXCEPTION_H__
#define __CEXCEPTION_H__

#include <string>
#include <exception>

namespace nsUtil
{
	class CException : public std::exception
	{
		std::string myLibelle;
		unsigned    myCodErr;
	  public :
	    CException (const std::string & libelle = string (), 
                        unsigned codErr = 0);
				   
            virtual ~CException (void) {}
            virtual const char * what (void) const noexcept;
		
            std::string getLibelle    (void) const;
            unsigned    getCodErr     (void) const;
		
            void        display       (void) const;
		
	}; // CException
} // nsUtil

#endif /* __CEXCEPTION_H__ */

Exception.cpp

/**
 *
 * \file    CException.cpp
 *
 * \authors M. Laporte
 *
 * \date    02/04/2018
 *
 * \version V2.0
 *
 * \brief  définitions de la classe Exception
 *
 **/
#include <string>
#include <iostream>

#include "CException.h"

#define EXC nsUtil::CException

using namespace std;
using namespace nsUtil;

EXC::CException (const string & libelle /* = string () */, 
		        unsigned       codErr  /* = 0 */ )
				: myLibelle (libelle), myCodErr (codErr) {}
				
const char * EXC::what (void) const noexcept
{ 
	return myLibelle.c_str (); 
	
} // what()
				
string   EXC::getLibelle (void) const { return myLibelle; }
unsigned EXC::getCodErr  (void) const { return myCodErr;  }

void  EXC::display    (void) const
{
	cout << "Exception : " << myLibelle << endl;
	     << "Code      : " << myCodErr  << endl;
		 
} // display()
		
#undef EXC

testException.cpp

/**
 *
 * \file    testException.cpp
 *
 * \authors M. Laporte
 *
 * \date    02/04/2018
 *
 * \version V2.0
 *
 * \brief  tests de la classe Exception
 *
 **/
#include <string>
#include <iostream>

#include "CException.h"

namespace
{
	void testException (void)
	{
		string line;
		for (getline (cin, line); ! cin.eof (); getline (cin, line))
		{
			unsigned codeErr;
			cin >> codErr;
			getline (cin, ligne); // pour vider cin d u retour charriot
			CException except (line, codErr);
			except.display ();
		}
		
	} // testException()
	
} // namespace

int main (void) 
{
	testException ();
	
} // main()

M2103-TP3-Exo-2

La classe standard string est une classe très riche et indispensable et il est heureux qu’elle existe !

Cependant, on peut lui reprocher l’absence de certaines fonctionnalités, que l’on aimerait bien y trouver.

On se souvient, par exemple, de la mise en majuscules ou en minuscules.

Une première solution est d’écrire des “moulinettes”, fonctions prenant comme paramètre donnée (ou donnée-résultat) la string et la rendant transformée.

C’est ce que nous avons fait précédemment (au premier semestre).

La seconde solution consiste à dériver la classe standard string en une classe CString à laquelle ne sont ajoutées aucun attribut (aucune donnée membre), mais seulement des méthodes (fonctions-membres).

Les seules fonctions qui ne sont pas héritées de la classe mère sont ses constructeurs, son destructeur, ainsi que l’affectation.

En revanche, un constructeur par recopie, un constructeur par défaut, un destructeur et une affectation sont données à la nouvelle classe (comme à chaque nouvelle classe), par le compilateur.

En ce qui concerne le constructeur par recopie, l’affectation et le destructeur, ils ne sont pas notre problème pour le moment.

Leur récriture sera abordée en temps utile.

La classe string possède de nombreux constructeurs ayant chacun leur utilité.

Ne posséder qu’un seul constructeur CString() qui se contente d’appeler le constructeur de sa classe mère, string(), qui lui-même crée une chaîne vide, est un peu frustrant.

C’est pourquoi on dotera la classe CString des mêmes constructeurs que sa classe mère.

Créez le projet CString.

Copier / coller le code suivant :

/**
 *
 * \file     TestCString.cpp
 *
 * \authors  M. Laporte, D. Mathieu
 *
 * \date     05/11/2007
 *
 * \version  V1.0
 *
 * \brief    Test de la classe String, extension de String
 *
 **/

#include <iostream>

#include "CString.h"

using namespace std;
using namespace nsUtil;

namespace
{
    void testString (void)
    {
        cout << "Test des constructeurs\n\n";

        CString s1;
        cout << '"' << s1 << "\"\n";
        cout << s1.append ("s1") << '\n';
        CString s2 ("Coucou");
        cout << (s2 + ' ' + s1) << '\n';
        CString s3 ("Coucou", 4);
        cout << s3 << '\n';
        CString s4 (10, '#');
        cout << s4 << '\n';

        CString s5 ("AbCdEf1234");
        cout << s5 << '\n';
        cout << s5.toupper() << '\n';
        cout << s5 << '\n';
        cout << s5.tolower() << '\n';
        cout << s5 << '\n';

        cout << "\nTest des fonctions\n\n";
        CString STR ("MAJUSCULE");
        CString str ("minuscule");
        CString space ("  \t\t\n\n");

        cout << boolalpha;

        cout << str   << " alpha ? "  << str.isalpha   () << '\n';
        cout << str   << " alnum ? "  << str.isalnum   () << '\n';
        cout << str   << " digit ?  " << str.isdigit   () << '\n';
        cout << str   << " xdigit ? " << str.isxdigit  () << '\n';
        cout << str   << " lower ? "  << str.islower   () << '\n';
        cout << str   << " upper ? "  << str.isupper   () << '\n';
        cout << str   << " space ? "  << str.isspace   () << '\n';
        cout << STR   << " upper ? "  << STR.isupper   () << '\n';
        cout << str   << " lower ? "  << str.islower   () << '\n';
        cout << space << " space ? "  << space.isspace () << '\n';

        cout << noboolalpha;

    } // testString ()

} // namespace

int main (void)
{
    testString();

    return 0;

} // main()

Dans l’espace de noms nsUtil des fichiers CString.h et CString.cpp, dériver publiquement la classe string (afin de garder et de transmettre la visibilité sur les fonctions membres de la classe mère).

Lui ajouter les constructeurs ayant les mêmes profils que les constructeurs suivants de la classe string, et qui se contentent d’appeler ces derniers en leur passant les mêmes paramètres :

string (const char * NTCTS); 
string (const char * NTCTS, size_type size);
string (const string & S, size_type pos = 0, size_type size = npos);
string (size_type size, char c);

Ajouter les fonctions membres tolower() et toupper(), de même identificateurs que les fonctions standard tolower() et toupper() qui s’appliquent aux caractères.

Le paramètre désignant la chaîne à traiter n’a plus lieu d’être puisque les fonctions deviennent des méthodes de la classe CString (fonctions-membres), donc appelées sur un objet donné.

Rappel : l’objet lui-même est désigné par (*this).

Ajoutez les prédicats isalpha(), isdigit(), isalnum(), isxdigit(), islower(), isupper(), isspace(), extensions des mêmes fonctions standard existant pour les caractères.

Si vous les avez faites, ajoutez aussi les fonctions complémentaires qui vous avaient été proposées : leftAlign(), compact(), rightAlign(), expandTab(), justify().

M2103-TP3-Exo-2-Corrigé

CString.h

/**
 *
 * \file    CString.h
 *
 * \authors M. Laporte, D. Mathieu
 *
 * \date    05/11/2007
 *
 * \version V1.0
 *
 * \brief   Extension de la classe standard string
 *
 **/
#if ! defined __CSTRING_H__
#define       __CSTRING_H__

#include <string>

namespace nsUtil
{
    class CString : public std::string
    {
      public :
        CString (void);
        CString (const char * NTCTS);
        CString (const char * NTCTS, size_type size);
        CString (const std::string & s, size_type pos = 0, 
                size_type size = npos);
        CString (size_type size, char c);

        CString & toupper (void);    
        CString & tolower (void);

        bool isalpha  (void) const;
        bool isdigit  (void) const;
        bool isalnum  (void) const;
        bool isxdigit (void) const;
        bool islower  (void) const;
        bool isupper  (void) const;
        bool isspace  (void) const;

    }; // CString
    
} // namespace nsUtil

#endif /* __CSTRING_H__ */


CString.cpp

/**
 *
 * \file    CString.cpp
 *
 * \authors M. Laporte, D. Mathieu
 *
 * \date    04/02/2011
 *
 * \version V1.0
 *
 * \brief   Definition des methodes de la classe CString
 *
 **/
#include <string>
#include <cctype>   // tolower(), toupper(), isalnum(), isdigit(), ...

#include "CString.h"

using namespace std;

#define CSTR nsUtil::CString

// =========================
// Classe nsUtil::String
// =========================

CSTR::CString (void) : string () {}

CSTR::CString (const char * NTCTS) : string (NTCTS) {}

CSTR::CString (const char * NTCTS, size_type size)
    : string (NTCTS, size) {}

CSTR::CString (const string & s, size_type pos  /* = 0    */,
              size_type size /* = npos */)
    : string (s, pos, size) {}

CSTR::CString (size_type size, char c)
    : string (size, c) {}

CSTR & CSTR::toupper (void) noexcept
{
    for (size_type i (size()); i-- > 0; )
        (*this) [i] =std::toupper ((*this) [i]);
    
    return *this;

} // toupper()

CSTR & CSTR::tolower (void) noexcept
{
    for (size_type i (size()); i-- > 0; )
        (*this) [i] =std::tolower ((*this) [i]);

    return *this;

} // tolower()

bool CSTR::isalpha  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isalpha ((*this)[i])) return false;

    return true;

} // isalpha()

bool CSTR::isdigit  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isdigit ((*this)[i])) return false;

    return true;

} // isdigit()

bool CSTR::isalnum  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isalnum ((*this)[i])) return false;

    return true;

} // isalnum()

bool CSTR::isxdigit (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isxdigit ((*this)[i])) return false;

    return true;

} // isxdigit()

bool CSTR::islower  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::islower ((*this)[i])) return false;

    return true;

} // islower()

bool CSTR::isupper  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isupper ((*this)[i])) return false;

    return true;

} // isupper()

bool CSTR::isspace  (void) const   noexcept
{
    for (size_type i (size()); i-- > 0; )
        if (! std::isspace ((*this)[i])) return false;

    return true;

} // isspace()

#undef CSTR