Exercices sur la programmation en C++ - correction., Exercices de Application informatique
Christophe
Christophe3 March 2014

Exercices sur la programmation en C++ - correction., Exercices de Application informatique

PDF (314.3 KB)
8 pages
167Numéro de visites
Description
Exercices d’informatique sur la programmation en C++ - correction. Les principaux thèmes abordés sont les suivants: exercices.
20points
Points de téléchargement necessaire pour télécharger
ce document
Télécharger le document
Aperçu3 pages / 8
Ceci c'est un aperçu avant impression
Chercher dans l'extrait du document
Ceci c'est un aperçu avant impression
Chercher dans l'extrait du document
Aperçu avant impression terminé
Chercher dans l'extrait du document
Ceci c'est un aperçu avant impression
Chercher dans l'extrait du document
Ceci c'est un aperçu avant impression
Chercher dans l'extrait du document
Aperçu avant impression terminé
Chercher dans l'extrait du document

Année 2010-2011 1ère session

Programmation C++ PG212

Georges Eyrolles

Filière : Informatique Année : Deuxième Semestre : Premier

Date de l’examen : 12 janvier 2011 Durée de l’examen : 2h

Documents autorisés  sans document  Calculatrice autorisée  non autorisée 

Autre : Les réponses aux questions doivent se faire sur le sujet d’examen. N’oubliez pas pour cela de remplir l’entête au verso

de chacune des feuilles. lors d’écritures de codes sources, écrivez

uniquement les parties modifiées de telle sorte que cela soit

compréhensible pour le correcteur. Le barème n’est pas définitif.

Bon courage !

CORRIGÉ

de Cédric Lachat

xExercice 1. Les collections (ou conteneurs) : /9 Les différents fichiers présents compilent sans erreur. Ci-dessous les classes Container contenant une implémentation basique d’une collection et Queue correspondant à l’implémentation d’une file d’attente, sous- classe de Container :

Container.hpp

1 #include <iostream> 2

3 c l a s s Container { 4 protected : 5 int next ; 6 int s i z e ; 7 f l o a t ∗ tab ; 8

9 public : 10 Container ( ) ; 11 Container ( int ) ; 12 Container ( const Container &); 13 ˜Container ( ) ; 14

15 // Test i f not empty 16 bool operator ! ( ) ; 17

18 // Push 19 Container& operator+=( f l o a t ) ; 20

21 // Access l a s t element 22 f l o a t& operator ∗ ( ) ; 23

24 // Pop ( i n t −> p o s t f i x ) 25 Container& operator−−( int ) ; 26

27 f r iend std : : ostream &operator<< ( 28 std : : ostream &stream , const Container &c ) ;

29 } ;

Queue.hpp

1 #include <iostream> 2 #include " Container.hpp" 3

4 c l a s s Queue : public Container { 5 int f i r s t ; 6 bool atLeastOne ; 7

8 public : 9 Queue ( ) ;

10 Queue ( int ) ; 11 exp l i c i t Queue ( const Queue&); 12 ˜Queue ( ) ; 13

14 bool operator ! ( ) ; 15

16 Queue& operator+=( f l o a t ) ; 17

18 f l o a t& operator ∗ ( ) ; 19

20 Queue& operator−−( int ) ; 21

22 operator std : : s t r i n g ( ) const ; 23

24 f r iend std : : ostream &operator<< ( 25 std : : ostream &stream , const Queue &q ) ; 26 } ;

1

Container.cpp

1 #include " Container.hpp" 2 #include <iostream> 3

4 using namespace std ; 5

6 Container : : Container ( ) : 7 next ( 0 ) , 8 s i z e (0 ) { 9 cout << " Container () : " << ∗ th i s << endl ;

10 } 11

12

13 Container : : Container ( int s i z e ) : 14 next ( 0 ) , 15 s i z e ( s i z e ) , 16 tab (new f l oa t [ s i z e ] ) { 17 cout<< " Container(int) : " << ∗ th i s << endl ; 18 } 19

20

21 Container : : Container ( const Container& c ) : 22 next ( c . next ) , 23 s i z e ( c . s i z e ) , 24 tab (new f l oa t [ s i z e ] ) { 25 int i ; 26 for ( i = 0 ; i < next ; i++) 27 tab [ i ] = c . tab [ i ] ; 28 cout << " Container( Container &) : " << 29 ∗ th i s << endl ; 30 } 31

32

33 Container : : ˜ Container ( ) { 34 delete [ ] tab ; 35 cout << "~Container ()" << endl ; 36 } 37

38

39 bool Container : : operator ! ( ) { 40 return ( next != 0 ) ; 41 } 42

43

44 Container& Container : : operator+=( f l o a t f ) { 45 tab [ next++] = f ; 46 return ∗ th i s ; 47 } 48

49 f l o a t& Container : : operator ∗ ( ) { 50 return tab [ next ] ; 51 } 52

53 Container& Container : : operator−−( int ) { 54 next−−; 55 return ∗ th i s ; 56 } 57

58 ostream &operator<< ( ostream &stream , 59 const Container &c ) { 60 stream << "size : " << c . s i z e 61 << ", next : " << c . next ; 62 return stream ; 63 }

Queue.cpp

1 #include "Queue.hpp"

2 #include <iostream> 3

4 using namespace std ; 5

6 Queue : : Queue ( ) : 7 Container ( ) , 8 f i r s t ( 0 ) , atLeastOne ( f a l s e ) { 9 cout << "Queue () : " << ∗ th i s << endl ;

10 } 11

12 Queue : : Queue ( int s i z e ) : 13 Container ( s i z e ) , 14 f i r s t ( 0 ) , 15 atLeastOne ( f a l s e ) { 16 cout << "Queue(int) : " << ∗ th i s << endl ; 17 } 18

19 Queue : : Queue ( const Queue& q ) : 20 f i r s t ( q . f i r s t ) , 21 atLeastOne (q . atLeastOne ) { 22 int i ; 23 for ( i = 0 ; i < s i z e ; i++) 24 tab [ i ] = q . tab [ i ] ; 25 cout << "Queue(Queue &) : " << ∗ th i s << endl ; 26 } 27

28

29 Queue : : ˜ Queue ( ) { 30 cout << "~Queue ()" << endl ; 31 } 32

33 bool Queue : : operator ! ( ) { 34 return ( atLeastOne ) ; 35 } 36

37 Queue& Queue : : operator+=( f l o a t f ) { 38 i f ( ! atLeastOne ) 39 atLeastOne = true ; 40 tab [ next ] = f ; 41 next = ( next + 1) % s i z e ; 42 return ∗ th i s ; 43 } 44

45 f l o a t& Queue : : operator ∗ ( ) { 46 return tab [ f i r s t ] ; 47 } 48

49 Queue& Queue : : operator−−( int ) { 50 f i r s t = ( f i r s t + 1) % s i z e ; 51 i f ( f i r s t == next ) 52 atLeastOne = f a l s e ; 53 return ∗ th i s ; 54 } 55

56 Queue : : operator std : : s t r i n g ( ) const { 57 return "42" ; 58 } 59

60 ostream &operator<< ( ostream &stream , 61 const Queue &q) { 62 // stream << ”Queue : ” << ∗( dynamic cast<const Container∗>(&q )) 63 // stream << ”Queue : ” << ∗(( const Container ∗) &q ) 64 stream << "Queue : " << ( ( Container ) q ) 65 << ", first : " << q . f i r s t << 66 ", atLeastOne : " << q . atLeastOne 67 << endl ; 68 return stream ; 69 }

2

Nom: Prénom: Groupe:

Soit le fichier Main1.cpp suivant :

1 #include <c s t d l i b> 2 #include <iostream> 3 #include "Queue.hpp" 4

5 int main ( ) { 6 Queue q1 ( 1 0 ) ; 7 Container ∗ c1 = new Queue ( 5 ) ; 8 Container &c2 = q1 ; 9

10 delete c1 ; 11 return EXIT SUCCESS ; 12 }

1. Que pensez-vous de la pertinence de l’utilisation des opérateurs dans ces classes par rapport à l’utilisation standard de ceux-ci ? Justifiez votre réponse./1

Les opérateurs !, += et – ne sont pas utilisés de la sorte dans la STL et peuvent être ambigus. L’opérateur * peut servir à déférencer une valeur comme pour les itérateurs.

2. Il manque deux opérateurs dans ces deux classes, l’un étant lié aux collections (plus exactement l’accès aux éléments) et l’autre résultant de l’implémentation en C++. Donnez les noms de ces deux opérateurs et justifiez la nécessité du deuxième./1

Il s’agit de l’opérateur [] pour accéder à n’importe quel élément de la collection. Quant à l’autre opérateur, il s’agit de l’opérateur d’affectation vu que nous avons un attribut alloué dynamiquement.

3. Complétez le tableau en indiquant le nombre d’allocations dynamiques et automatiques (sans les cumuler) pour les lignes spécifiées du fichier Main1.cpp. Vous devez prendre en compte les allocations des attributs pour les objets, en précisant également la taille pour les tableaux./3

ligne allocation auto. allocation dyn. instanciation 6 6 ou 7 1 (taille 10) 2 ou 3

q1, next, size, *tab, first, tab = new q1, tab, atLeastOne ((Container) q) ((Container) q)

7 1 ou 2 2 ou 7 (taille 5) 2 ou 3 c1 ((Container) q) c1 = new, tab = new q1, tab

(next, size, *tab, first, atLeastOne) ((Container) q)

8 1 ou 0 0 0 c2

3

4. Écrivez la sortie standard issue lors de l’exécution du programme en indiquant la correspondance entre la ligne de la sortie avec la ligne du programme à l’origine de l’affichage./2

Les parties entre crochets n’ont pas été prises en compte pour la correction.

1 // Ligne 6 de Main1 . cpp : 2 Container ( int ) : s i z e : 10 , next : 0 // l i g n e s 17 Cont , [60 Cont ] 3 Queue ( int ) : [ Container ( Container&) : s i z e : 10 , next : 0 ] // l i g n e s 16 Queu , [28 Cont , 60 Cont ] 4 [ Queue : s i z e : 10 , next : 0 , f i r s t : 0 , atLeastOne : 0 ] // [ l i g n e s 58 Queu , 60 Cont ] 5 ˜Container ( ) // l i g n e 35 Cont 6

7 // Ligne 7 de Main1 . cpp : 8 Container ( int ) : s i z e : 5 , next : 0 // l i g n e s 17 Cont , [60 Cont ] 9 Queue ( int ) : [ Container ( Container&) : s i z e : 5 , next : 0 ] // l i g n e s 16 Queu , [28 Cont , 60 Cont ]

10 [ Queue : s i z e : 5 , next : 0 , f i r s t : 0 , atLeastOne : 0 ] // [ l i g n e s 58 Queu , 60 Cont ] 11 ˜Container ( ) // l i g n e 35 Cont 12

13 // Ligne 10 de Main1 . cpp : 14 ˜Container ( ) // l i g n e 35 Cont 15

16 // Ligne 12 de Main1 . cpp : 17 ˜Queue ( ) // l i g n e 30 Queu 18 ˜Container ( ) // l i g n e 35 Cont

5. Implémentez une pile (classe Stack sous-type de Container) en écrivant uniquement le code strictement nécessaire et conforme à une collection./2

La classe Container implémente par défaut une pile.

Stack.cpp

1#include <c s t d l i b> 2#include "Container.hpp" 3#include "Stack.hpp" 4#include <stdexcept> 5

6 using namespace std ; 7

8

9 Stack : : Stack ( int s i z e ) : Container ( s i z e ){} 10

11 ostream &operator<< ( ostream &stream , 12 const Stack &s ) 13 { 14 stream << "Stack , size : " << s . s i z e

15 << ", next : " << s . next ; 16 return stream ; 17 }

Stack.hpp

1#include <iostream> 2

3 class Stack : public Container { 4

5 public : 6 Stack ( int ) ; 7 friend std : : ostream &operator<< ( 8 std : : ostream &stream , const Stack &q ) ; 9 } ;

4

Nom: Prénom: Groupe:

xExercice 2. Héritage et polymorphismes : /5 1. Modifiez les classes pour que nous puissions faire du polymorphisme et ainsi exécuter correctement le

fichier suivant Main2.cpp :/1

1 #include <c s t d l i b> 2 #include <iostream> 3 #include "Queue.hpp" 4

5 int main ( ) { 6 int i ; 7 Queue q ( 5 ) ; 8 Container &c = q ; 9

10 c+= 1 ; 11 c−−; 12 for ( i =0; i <5; i++) 13 c += 1.5∗ i ; 14

15 while ( ! c ) { 16 std : : cout << ∗c << std : : endl ; 17 c−−; 18 } 19

20 return EXIT SUCCESS ; 21 }

Container.hpp

1 virtual ˜Container ( ) ; 2 virtual bool operator ! ( ) ; 3 virtual Container& operator+=(f loat ) ; 4 virtual f loat& operator ∗ ( ) ; 5 virtual Container& operator−−(int ) ;

2. Justifiez pourquoi vous avez modifié telle ou telle partie dans la question précédente./2

Il suffit de modifier uniquement le fichier hpp, le mot-clé virtual ne fait pas partie de la signature. Les méthodes redéfinies dans les sous-classes de Container seront par défaut virtuelles. Par soucis de clarté, nous pourrons remettre le mot-clé virtual lors de la redéfinition des méthodes.

5

3. Décrivez comment le compilateur trouve la méthode qui va être exécutée à la ligne 11 du fichier Main2.cpp./1

La réponse ci-dessous explique la partie compilation, mais aussi la partie exécution, sachant que cette dernière n’était pas demandée.

Existe-t-il un opérateur - - dans la classe Container ?

• Oui

• Est-il virtuel ?

– L’appel est effectué par rapport à l’attribut caché vtable de l’objet c.

– La ligne c−− est remplacée par c.vtable[”operator −−”](0)

À la compilation, la méthode appelée à la ligne 11 n’est pas connue. À l’exécution, l’appel de la méthode - - sur l’objet c, revient à exécuter :

c.vtable[”operator −−”](0)

Dès la première méthode virtuelle de la classe Container, une table des méthodes virtuelles est créée. Il s’agit d’une table de pointeurs de fonctions. Le compilateur ajoute une instruction au sein des constructeurs de cette classe pour initialiser l’attribut caché vtable. Ainsi, à l’instanciation de q, l’attribut caché vtable pointera sur la table des méthodes virtuelles de Queue. Par conséquent, lors de l’initialisation de c, l’attribut caché vtable de c n’est autre que celui de q vu que c pointe sur q. D’où l’appel de la méthode - - de Queue.

4. Représentez la pile et le tas après avoir exécuté la ligne 11 du fichier Main2.cpp en supposant que les classes intègrent correctement le polymorphisme. Un exemple de représentation est donné après avoir exécuté la ligne 6. Vous devrez respecter les conventions suivantes :/1

• le nom d’une variable sera écrit à côté de la case représentant sa zone réservée en mémoire, et sa valeur sera écrite à l’intérieur de cette case ;

• un point d’interrogation sera mis dans une case dont la valeur est indéfinie ; • pour une variable pointeur, une flèche désignera la case pointée.

Le schéma de la ligne 7 était donné en tant qu’exemple et n’était pas à modifier.

ligne 12

?

Code et staticPile

atLeastOne

vtable

q first

tab

size

next

i

5

false

1

?

?

?

?

1

1

6

Nom: Prénom: Groupe:

xExercice 3. Visibilité et exceptions : /3 1. Modifiez les classes afin de gérer les erreurs dans les cas suivants :/2

• L’accès à un élément d’une collection vide doit lever une exception de type out of range ; • L’ajout d’un élément à une collection pleine doit lever une exception de type overflow error ; • La suppression d’un élément d’une collection vide doit lever une exception de type underflow error ; • L’accès à une méthode qui n’a pas de sens pour telle ou telle collection doit lever une exception de

type logic error.

Ces exceptions ont un constructeur prenant comme argument une châıne de caractères, mais ne possèdent pas de constructeur par défaut.

Container.hpp

1 public : 2 virtual Container& operator+=(f loat ) 3 throw ( std : : o v e r f l ow e r r o r ) ; 4 virtual f loat& operator ∗ ( ) 5 throw ( std : : ou t o f r ang e ) ; 6 virtual Container& operator−−(int ) 7 throw ( std : : unde r f l ow e r r o r ) ;

Container.cpp

1 Container& Container : : operator+=(f loat f ) 2 throw ( o v e r f l ow e r r o r ) 3 { 4 i f ( next == s i z e ) 5 throw ov e r f l ow e r r o r ( "error" ) ; 6

7 tab [ next++] = f ; 8 return ∗ this ; 9 }

10

11

12 f loat& Container : : operator ∗ ( ) 13 throw ( ou t o f r ange ) 14 { 15 i f ( ! ( ! ∗ this ) ) 16 throw ou t o f r ange ( "error" ) ; 17 return tab [ next ] ; 18 } 19

20

21 Container& Container : : operator−−(int ) 22 throw ( unde r f l ow e r r o r ) 23 { 24 i f ( ! ( ! ∗ this ) ) 25 throw unde r f l ow e r r o r ( "error" ) ; 26

27 next−−; 28 return ∗ this ; 29 }

2. Écrivez un des opérateurs manquants (l’accès à un élément de la collection) en prenant soin de donner l’accès le plus juste, et de lever une exception si nécessaire./1

Container.hpp

1 public : 2 virtual f loat operator [ ] ( int ) 3 throw ( std : : ou t o f range , 4 std : : l o g i c e r r o r ) ;

Container.cpp

1 f loat Container : : operator [ ] ( int index ) 2 throw ( out o f range , l o g i c e r r o r ) 3 { 4 i f ( ( ! ( ! ∗ this ) ) | | ( index >= next ) ) 5 throw ou t o f r ang e ( "error" ) ; 6 return tab [ index ] ;

7 }

Queue.hpp

1 private : 2 virtual f loat operator [ ] ( int ) 3 throw ( std : : ou t o f range , std : : l o g i c e r r o r ) ;

Queue.cpp

1 f loat Queue : : operator [ ] ( int ) 2 throw ( out o f range , l o g i c e r r o r ) { 3 throw l o g i c e r r o r ( "error" ) ; 4 }

7

xExercice 4. Templates : /3 1. Le problème des classes Container et Queue est qu’elles ne sont utilisables que pour des réels. Modifiez

la classe Container pour utiliser n’importe quel type d’élément. Voici un exemple d’utilisation avec le fichier Main4.cpp :/2

Il faut tout mettre dans un seul et même fichier, Container.hpp, pour que le compilateur puisse créer autant de classes nécessaires à partir de la classe générique.

1#include <iostream> 2 using namespace std ; 3

4 template <class T=f loat> 5 class Container { 6 protected : 7 int next , s i z e ; 8 T ∗ tab ; 9

10 public : 11 Container ( ){} 12 Container ( int s i z e ) : next ( 0 ) , s i z e ( s i z e ) , tab (new T[ s i z e ] ){} 13 Container ( const Container&c ) : next ( c . next ) , s i z e ( c . s i z e ) , tab (new T[ s i z e ] ) { 14 int i ; 15 for ( i = 0 ; i < next ; i++) 16 tab [ i ] = c . tab [ i ] ; 17 cout << "Container(Container &) : " << 18 ∗ this << endl ; 19 } 20

21 ˜Container ( ) { 22 delete [ ] tab ; 23 } 24

25 bool operator ! ( ) { 26 return ( next != 0 ) ; 27 } 28

29 Container<T>& operator+=(T &f ) { 30 tab [ next++] = f ; 31 return ∗ this ; 32 } 33

34 T& operator ∗ ( ) { 35 return tab [ next ] ; 36 } 37

38 Container<T>& operator−−(int ) { 39 next−−; return ∗ this ; 40 } 41

42 friend std : : ostream &operator<< ( 43 std : : ostream &stream , const Container<T> &c ) { 44 stream << "Queue , size : " << c . s i z e 45 << ", next : " << c . next ; 46 return stream ; 47 } 48

49 } ;

2. Après avoir donné le nom de votre (vos) fichier(s), écrivez la ou les lignes de commandes pour compiler et exécuter le programme Main4.cpp./1

Le fichier s’appelle Container template.hpp. Les lignes de compilation sont :

• g++ -c -o Main4.o Main4.cpp

• g++ Main4.o Container template.hpp -o Main4

Quant à l’exécution, il faut écrire :

• ./Main4

8

commentaires (0)
Aucun commentaire n'a été pas fait
Écrire ton premier commentaire
Ceci c'est un aperçu avant impression
Chercher dans l'extrait du document
Docsity n'est pas optimisée pour le navigateur que vous utilisez. Passez à Google Chrome, Firefox, Internet Explorer ou Safari 9+! Téléchargez Google Chrome