Programmation C++

Master M2 Informatique --- Feuille n° 5


Résumé:

Ce TD est une liste d'exercices extraits de précédents examens.

Exercice n° 1

Dans un rapport de projet, on trouve le diagramme de classe ci-contre. Par ailleurs, dans le code, on peut lire
A* p= new C();
//...
C& c = dynamic_cast<C&>(*p);
Le diagramme de classe est correct, la classe A contient des méthodes non redéfinies et appelées dans la classe C et le programme compile. Expliquer à quel(s) endroit(s) au minimum doit apparaître le mot clé virtual.

Exercice n° 2

La bibliothèque Boost propose une classe noncopyable. Cette classe est telle que tout objet d'une classe qui hérite de noncopyable ne peut être dupliqué, ou servir d'argument gauche d'un opérateur d'affectation. Écrire une implémentation de la classe noncopyable.

Exercice n° 3 : Pimpl

On désire écrire un module permettant de gérer des logins et mots de passe. Ce module offre une classe login_t, qui contient: L'utilisateur de la classe qui charge le fichier login.hh contenant la définition de la classe login_t ne doit voir ni les implémentations des méthodes, ni même le nom et le type sous lesquels un objet login_t stocke le login et le mot de passe. On suppose que pour chaque plateforme, on fournit aux utilisateurs le fichier login.hh et un binaire login.o correspondant à la compilation de login.cc. Écrire login.hh et login.cc.

Exercice n° 4

On souhaite utiliser des collections de manière analogue à Java. Pour cela, on crée un type Collection paramétré par le type des éléments stockés et par le conteneur (au sens de la bibliothèque standard) qui implémente la collection. La valeur par défaut de ce second paramètre est std::list<T>. On veut pouvoir par exemple écrire le morceau de code suivant:
int main(){
  Collection<int> y;
  for(int x=0;x<10;x++){
    y.add(x*5);
  }
  Collection<int>::Iterator it=y.iterator(); \\(*)
  while(it.hasNext()){
    std::cout << it.next() << std::endl;
  }
}
Pour simplifier, on supposera que la classe Collection ne contient que les méthodes add et iterator, et que les Iterator ne contiennent que les méthodes hasNext et next. Écrire les définitions de la classe Collection, de la classe correspondant au type Collection<T>::Iterator, ansi que de leurs méthodes. (On supposera que le conteneur sous-jacent dispose d'une méthode push_back.) Dans le cas d'un appel de next alors que l'itérateur est à la fin de la collection, lancer une exception (à définir) NoSuchElementException.

Discuter la possibilité d'écrire

Iterator<int> it=y.iterator();+ à la ligne (*).

Exercice n° 5

Le design pattern Strategy est illustré par la figure ci-dessus. Un client peut utiliser dans l'une ou l'autre de ses méthodes différentes versions d'un algorithme selon la Strategie avec lequel il est composé. On désire appliquer ce design pattern à la validation de documents. On suppose l'existence d'une structure ficheLogin dont les champs sont Nom, Prenom, Telephone et Login. On suppose que la classe Client est une fabrique registerLogin qui dispose d'une méthode newLogin qui demande d'écrire sur l'entrée standard les renseignements nécessaires et retourne un objet ficheLogin. Cette méthode vérifie en particulier que le format du numéro de téléphone est correct en appelant une méthode isValid dont l'implémentation dépend d'un objet de type Validator (jouant ici le rôle de Strategie). On suppose en outre que cet objet fournit une méthode correctForm qui indique quel est le format attendu.

  1. Écrire en langage objet classique en C++ la classe registerLogin (contenant la méthode newLogin), l'interface Validator ainsi qu'une classe StandardValidator qui permet de valider le numéro de téléphone si celui-ci est une chaîne de caractères de 10 chiffres sans espace. registerLogin devra aussi fournir une méthode permettant de fixer un Validator.

    On prêtera attention au fait que toutes les instances d'une même implémentation de Validator se comportent de la même manière; on mettra donc en place dans StandardValidator les mécanismes qui permettent d'assurer qu'on ne peut créer qu'une instance de StandardValidator.

  2. On suppose maintenant que le Validator utilisé est connu dès la déclaration de l'objet registerLogin et ne change pas.
  3. Modifier la classe registerLogin de sorte que le type de Validator en soit un paramètre. Mettre en place les mécanismes permettant de vérifier à la compilation que le type paramètre est bien un Validator.

    Comme le Validator est un paramètre de registerLogin, on a uniquement besoin des classes Validator, et non des objets. Indiquer les modifications que ceci implique.