personne qui aborde le C+ + : elle connaît déjà le langage C sur lequel s'appuie
effectivement C+ + ; ... Naturellem ent, tous les exercices sont "corrigés".
Exercices en langage C++
C. Delannoy
A VANT-PRO PO S
La m aî trise d'un langage de program m ation pas s e obligatoire m e nt par la pratiq ue , c'e s t-à -dire la re ch e rch e pe rsonne lle d'une solution à un problèm e donné. Cette affirm ation re s te vraie pour le program m e ur ch e vronné q ui é tudie un nouve au langage . C'e s t dans ce tte s ituation q ue s e trouve gé né ralem e nt une pe rsonne q ui aborde le C+ + : e lle connaî t déjà le langage C sur leq ue ls'appuie e ffe ctive m e nt C+ + ; toute fois, ce dernie r langage introduit suffisam m e nt de possibilité s s upplém e ntaire s e t surtout de nouve aux conce pts (e n particulie r, ce ux de la Program m ation O rie nté e O b je t) pour q ue s on appre ntissage s 'appare nte à ce lui d'un nouve au langage . Ce livre vous propose d'accom pagne r votre é tude du C+ + e t de la prolonge r, ce ci à l'aide d'exercices approprié s , varié s e t de difficulté croissante . Les diffé re nts ch apitre s , à l'e xce ption du de rnie r, corre s ponde nt à une progre s s ion classique d'un "cours de C+ + " : incom patiblité s e ntre C e t C+ + ;les s pé cificités de C+ + ;notions de clas s e , constructe ur e t destructe ur ;proprié tés des fonctions m e m bre ;construction, de s truction e t initialisation de s obje ts ;les fonctions am ie s ;la surdéfinition d'opé rate urs ;les conve rsions de type définie s par l'utilisate ur ;la te ch niq ue de l'h é ritage ;les fonctions virtue lles ;les flots d'entré e e t de sortie , les patrons de fonctions e t les patrons de clas s e s . Le dernie r ch apitre , e nfin, propose des "e xe rcices de synth è s e ". Ch aq ue ch apitre débute par un "rappe ldétaillé"1 des connaissance s né ce s s aire s pour aborde r les e xe rcice s corre s pondants (nature llem e nt, un e xe rcice d'un ch apitre donné peut faire inte rve nir de s points ré s um és dans les ch apitre s pré cédents). Au sein de ch aq ue ch apitre , les e xe rcice s propos é s vont d'une application im m édiate du cours à des ré alisations de clas s e s re lative m e nt com plète s . Au filde votre progre s s ion dans l'ouvrage , vous ré aliserez des classes de plus e n plus "ré aliste s e t opé rationne lles " e t ayant un inté rê t gé né ral;citons, par e xe m ple : - les e ns e m bles , - les ve cte urs dynam iq ue s , - les tableaux dynam iq ue s à plusieurs dim e nsions, - les liste s ch aî né e s , - les tableaux de bits, - les (vraie s ) ch aî nes de caractè re s , - les piles , - les com plexe s , - e tc. Nature llem e nt, tous les e xe rcice s s ont "corrigé s ". Pour la plupart, la solution propos é e ne s e lim ite pas à une sim ple liste d'un program m e (laq ue lle ne re pré s e nte finalem e nt q u'une rédaction possible parm i d'autre s ). Vous y trouve re z une analyse détaillée du problèm e e t, si besoin, les justifications de ce rtains ch oix. D e s com m e ntaire s vie nne nt, le cas é ch é ant, é claire r les partie s q ue lque pe u dé licate s . Fré q ue m m e nt, vous trouve re z des suggestions de prolonge m e nt ou de gé né ralisation du problèm e abordé .
1 Le cours com pl et corre s pondant à ces résum é s peut ê tre trouvé dans "Program m er en langage C+ + " ou dans "Program m er en
Turbo C+ + ", du m ê m e auteur, aux Editions Eyrolles.
O utre la m aî trise du langage C+ + propre m e nt dit, les e xe rcice s propos é s vous perm e ttront de vous forge r une "m é th odologie de conce ption de vos propre s clas s e s ". Notam m e nt, vous saure z : - décide r du bie n-fondé de la surdéfinition de l'opé rate ur d'affe ctation ou du constructe ur par re copie , - e xploite r, lors q ue vous juge re z q ue ce la e s t opportun, les possibilités de "conve rsions autom atiq ue s " q ue le com pilate ur pe ut m e ttre e n place , - com m e nt tire r parti de l'h é ritage (sim ple ou m ultiple) e t q ue ls avantage s pré s e nte la cré ation d'une "biblioth è q ue de clas s e s ", notam m e nt par le biais du "typage dynam iq ue des obje ts" q ui dé coule de l'e m ploi de s fonctions virtue lles . D e s urcroî t, vous aure z re ncontré un ce rtain nom bre de te ch niq ue s fondam e ntales te lles q ue : la ré alisation d'un "ité rate ur" ou les "clas s e s conte ne urs" e t l'utilisation de s possibilités de "fonctions génériques" (patrons de fonctions) e t de "clas s e s gé né riq ue s " (patrons de clas s e s ).
N.B. En atte ndant la norm alisation de C+ + , ce s ont des publications de AT& T q ui s e rve nt de "ré fé re nce s " : ve rsion 1.1 e n 86, 1.2 e n 87, 2.0 e n 89 , 3.0 e n 9 1 (ce tte derniè re s e rvant de bas e au travaildu com ité ANSI). Le s rares diffé re nce s e xistant e ntre les ve rsions sont claire m e nt m e ntionnées dans les ré s um és des diffé re nts ch apitre s . Le s e xe m ples de program m e s fournis e n solution ont é té te s té s ave c le com pilate ur du logicie lTurbo C+ + pour W indow s, ve rsion 3.0.
TA BLE D ES M A TIERES
Avant-propos ......................................................................................... V I. Incom patibil ités entre C et C+ + ..............................................................1 II. Les spécificités de C+ + ........................................................................7 III. Notions de cl asse, constructeur et destructeur ......................................... 23 IV. Proprié tés des fonctions m em bre .......................................................... 45 V. Construction, destruction et initial isation des objets................................... 59 VI. Les fonctions am ies ........................................................................... 81 VII. La surdéfinition d'opérateurs ............................................................. 9 1 VIII. Les conversions de type définies par l 'util isateur ..................................121 IX. La tech nique de l 'h éritage .................................................................133 X. L'h éritage m ul tipl e ...........................................................................153 XI. Les fonctions virtuel l es .....................................................................167 XII. Les fl ots d'entrée et de sortie.............................................................179 XIII. Les patrons de fonctions .................................................................19 5 XIV. Les patrons de cl asses .....................................................................205 XV. Exercices de synth è se.......................................................................225
CH A PITRE I : INCO M PA TIBILITES ENTRE C ET C+ +
RAPPELS C+ + e s t "pre s q ue " un sur-e ns e m ble du C, te lq u'ile s t défini par la norm e ANSI. Se ules e xiste nt q ue lque s "incom patibilité s " dont nous vous rappe lons ici les principales .
D é cl arations d e fonctions En C+ + , toute fonction utilisée dans un fich ie r source doit obligatoire m e nt avoir fait l'obje t : - soit d'une déclaration sous form e d'un prototype (ilpré cis e à la fois le nom de la fonction, le type de s e s argum e nts é ve ntue ls e t le type de sa valeur de re tour), com m e dans ce t e xe m ple : float fexp (int, double, char *) ;
- soit d'une définition pré alable au s e in du m ê m e fich ie r source (ce dernie r cas é tant d'ailleurs peu cons e illé, dans la m e s ure où de s problèm e s ris q ue nt d'apparaî tre dè s lors q u'on s é pare ladite fonction du fich ie r source e n q ue s tion). En C, une fonction pouvait ne pas ê tre déclaré e (auq ue lcas, on considérait, par dé faut, q ue s a valeur de re tour é tait de type int), ou e ncore déclaré e partie llem e nt (sans fournir le type de ses argum e nts), com m e dans : float fexp () ;
Fonctions s ans argum e nts En C+ + , une fonction sans argum e nt se définit (au nive au de l'e n-tê te ) e t se déclare (au nive au du prototype ) e n fournissant une "liste d'argum e nts vide" com m e dans : float fct () ;
En C, on pouvait indiffé re m m e nt utiliser cette notation ou faire appe lau m ot clé void com m e dans : float fct (void)
2
Exe rcice s e n langage C+ +
Fonctions s ans val e ur de re tour En C+ + , une fonction sans valeur de re tour se définit (e n-tê te ) e t se déclare (prototype ) obligatoire m e nt à l'aide du m ot clé void com m e dans : void fct (int, double) ;
En C, l'e m ploi du m ot clé void é tait, dans ce cas, facultatif.
Le q ual ificatif cons t En C+ + , un sym bole globaldéclaré ave c le q ualificatif const : - a une porté e lim ité e au fich ie r source conce rné , tandis q u'e n C ilpouvait é ve ntue llem e nt ê tre utilisé dans un autre fich ie r source (e n utilisant le m ot clé e xte rn), - pe ut ê tre utilisé dans une "expression constante " (e xpre s s ion calculable au m om e nt de la com pilation), alors q u'ilne pouvait pas l'ê tre e n C ;ce dernie r point pe rm e t notam m e nt d'utiliser de te ls sym boles pour dé finir la taille d'un tableau (e n C, ilfallait obligatoire m e nt avoir re cours à une "définition" de sym boles par la dire ctive #de fine ).
Le type void * En C+ + , un pointe ur de type void *ne pe ut pas ê tre conve rti "im plicite m e nt" lors d'une affe ctation e n un pointe ur d'un autre type ;la ch os e é tait pe rm ise en C. Bie n e nte ndu, e n C+ + , ilre s te possible de faire appe là l'opé rate ur de "cast".
Exe rcice I.1 ___________________________________________________________________________
Enoncé Quelles e rre urs s e ront déte cté e s par un com pilate ur C+ + com pilate ur C?
dans ce fich ie r source q ui e s t acce pté par un
main() { int a=10, b=20, c ; c = g(a, b) ; printf ("valeur de g(%d,%d) = %d", a, b, c) ; } g(int x, int y) { return (x*x + 2*x*y + y*y) ; }
___________________________________________________________________________
Sol ution 1) La fonction g doit obligatoire m e nt faire l'obje t d'une déclaration (sous form e d'un prototype ) dans la fonction m ain. Par e xe m ple, on pourrait introduire (n'im porte où avant l'appe lde g) :
I. Incom patibilité s e ntre C e t C+ +
3
int g (int, int) ;
ou e ncore : int g (int x, int y) ;
R appe lons q ue , dans ce dernie r cas, les nom s x e t y sont fictifs : ils n'ont aucun rôle dans la suite e t ils n'inte rfè re nt nullem e nt ave c d'autre s variables de m ê m e nom q ui pourraie nt ê tre déclarées dans la m ê m e fonction (ici m ain). 2) La fonction printf doit, e lle aussi, com m e toute s les fonctions C+ + (le com pilate ur n'é tant pas e n m e s ure de distingue r les fonctions de la biblioth è q ue des "fonctions définie s par l'utilisate ur"), faire l'obje t d'un prototype . Nature llem e nt, iln'e s t pas néce s s aire de l'é crire e xplicite m e nt : ile s t obte nu par incorporation du fich ie r e n-tê te corre s pondant : #include
Note z q ue ce rtains com pilate urs C refus e nt déjà l'abs e nce de prototype pour une fonction de la biblioth è q ue s tandard te lle q ue printf (m ais la norm e ANSI n'im posait rie n à ce s uje t!).
Exe rcice I.2 ___________________________________________________________________________ Ecrire corre cte m e nt e n C ce program m e q ui e s t corre ct e n C+ + : #include const int nb = 10 ; const int exclus = 5 ; main() { int valeurs [nb] ; int i, nbval = 0 ; printf ("donnez %d valeurs :\n", nb) ; for (i=0 ; i taille ; for (nbloc=1 ; ; nbloc++) { adr = new int [taille] ; if (adr) cout " ;
Voici un pe tit program m e d'essai de la clas s e ve cte ur3d, accom pagné des ré s ultats produit par son e xé cution : /* programme d'essai de la classe vecteur3d */ main() { vecteur3d v1 (1,2,3), v2 (3,0, 2), w ; cout valeur = adsource->valeur ; // copie valeur adbut->suivant = debut ; // insertion nouveau noeud debut = adbut ; // dans nouvelle liste adsource = adsource->suivant ; // noeud suivant ancienne liste } } set_int::~set_int () { noeud * adn ; noeud * courant = debut ; while (courant) { adn = courant ; courant = courant->suivant ; delete adn ; } } void set_int::ajoute (int nb) { if (!appartient (nb) ) { noeud * adn = new noeud ; adn->valeur = nb ; adn->suivant = debut ; debut = adn ; nelem++ ; } }
// libération de tous // les noeuds // de la liste
// si nb n'appartient pas à la liste // on l'ajoute en début de liste
int set_int::appartient (int nb) { noeud * courant = debut ; // attention à l'ordre des deux conditions
V. Construction, de s truction e t initialisation de s obje ts
71
while (courant && (courant->valeur != nb) ) courant = courant->suivant ; return (courant != NULL) ; } int set_int::cardinal () { return nelem ; }
Note z q ue le program m e d'utilisation proposé dans l'e xe rcice V.4 re s te valable ici, puis q ue nous n'avons pré cis é m e nt pas m odifié l'inte rface de notre clas s e . Par ailleurs, le problèm e é voq ué à propos de l'ajout d'un é lém e nt à un e ns e m ble "plein" ne s e pos e plus ici, com pte te nu de la nouve lle im plém e ntation de notre clas s e .
Exe rcice V.6 ___________________________________________________________________________
Enoncé M odifie r la clas s e s e t_int pré cédente (im plém e nté e s ous form e d'une liste ch aî né e - ave c ou sans son constructe ur par re copie ) pour q u'e lle dispose de ce q ue l'on nom m e un "ité rate ur" sur les diffé re nts é lém e nts de l'e ns e m ble. R appe lons q u'on nom m e ainsi un m é canism e pe rm e ttant d'accéder s é q ue ntie llem e nt aux diffé re nts é lém e nts de l'e ns e m ble. O n pré voira trois nouve lles fonctions m e m bre : init, pour intialiser le proce s s us d'ité ration ;proch ain , pour fournir l'é lém e nt suivant lors q u'ile xiste e t e xiste , pour te s te r s'il e xiste e ncore un é lém e nt non e xploré . O n com pléte ra alors le program m e d'utilisation pré cédent (e n fait, ce lui de l'e xe rcice V.4), de m aniè re à ce q u'ilaffich e les diffé re nts e ntie rs conte nus dans les valeurs fournie s e n donné e . N.B. Ce t e xe rcice s e ra plus profitable s 'il e s t traité aprè s l'e xe rcice du ch apitre III q ui proposait l'introduction d'un te l ité rate ur dans une clas s e re pré s e ntant des ens e m bles de caractè re s (m ais dont l'im plém e ntation é tait diffé re nte de l'actue lle clas s e ). ___________________________________________________________________________
Sol ution Ici, la ge s tion du m é canism e d'ité ration né ce s s ite l'e m ploi d'un pointe ur (q ue nous nom m e rons courant) sur un noe ud de notre liste . Nous convie ndrons q u'ilpointe s ur le pre m ie r é lém e nt non e ncore traité dans l'ité ration, c'e s t-à -dire dont la valeur corre s pondante n'a pas e ncore é té re nvoyé e par la fonction proch ain. Il n'e s t pas utile, ici, de pré voir un m e m bre donnée pour indiq ue r si la fin de liste a é té atte inte ;e n e ffe t, ave c la conve ntion adopté e , ilnous suffit de te s te r la valeur de courant (q ui s e ra é gale à NULL, lors q ue l'on s e ra e n fin de liste ). Le rôle de la fonction init s e lim ite à l'initialisation de courant à la valeur du pointe ur sur le début de la liste (de but). La fonction suivant fournira e n re tour la valeur e ntiè re associé e au noe ud pointé par courant lors q u'ile xiste (courant diffé re nt de NULL) ou la valeur 0 dans le cas contraire (ils'agit, là e ncore , d'une conve ntion destiné e à proté ge r l'utilisate ur ayant appe lé ce tte fonction, alors q ue la fin de liste é tait déjà atte inte e t, donc, q u'aucun é lém e nt de l'e ns e m ble n'é tait disponible). De plus, dans le pre m ie r cas (usuel), la fonction suivant actualisera la valeur de courant, de m aniè re à ce q u'ilpointe s ur le noe ud suivant.
72
Exe rcice s e n langage C+ +
Enfin, la fonction e xiste e xam ine ra sim plem e nt la valeur de de but pour savoir s'ile xiste e ncore un é lém e nt à traite r. Voici la déclaration com plète de notre nouve lle clas s e : /* fichier SETINT4.H */ /* déclaration de la classe set_int */ struct noeud { int valeur ; // valeur d'un élément de l'ensemble noeud * suivant ; // pointeur sur le noeud suivant de la liste } ; class set_int { noeud * debut ; int nelem ; noeud * courant ; public : set_int (int = 20) ; set_int (set_int &) ; ~set_int () ; void ajoute (int) ; int appartient (int) ; int cardinal () ; void init () ; int prochain () ; int existe () ; } ;
// pointeur sur le début de la liste // nombre courant d'éléments // pointeur sur noeud courant // // // // // // // // //
constructeur constructeur par recopie destructeur ajout d'un élément appartenance d'un élément cardinal de l'ensemble initialisation itération entier suivant test fin liste
Voici la définition de s trois nouve lles fonctions m e m bre init, suivant e t e xiste : void set_int::init () { courant = debut ; }
int set_int::prochain () { if (courant) { int val = courant->valeur ; courant = courant->suivant ; return val ; } else return 0 ; // par convention } int set_int::existe () { return (courant != NULL) ; }
Voici le nouve au program m e d'utilisation de m andé : /* utilisation de la classe set_int */ #include #include "setint1.h" main()
V. Construction, de s truction e t initialisation de s obje ts
{
}
void fct (set_int) ; set_int ens ; cout n ; ens.ajoute (n) ; } cout , ne w e t de lete doive nt obligatoire m e nt ê tre définis com m e fonctions m e m bre . Le s opé rate urs = (affe ctation) e t & (pointe ur sur) possè dent une s ignification prédéfinie pour les obje ts de n'im porte q ue ltype clas s e . Ce la ne les e m pê ch e nullem e nt d'ê tre s urdé finis. La surdéfinition de ne w , pour un type classe donné, se fait par une fonction de prototype : void * new (size_t)
Elle re çoit, e n uniq ue argum e nt, la taille de l'obje t à alloue r (ce t argum e nt s e ra gé né ré autom atiq ue m e nt par le com pilate ur, lors d'un appe lde ne w ), e t e lle doit fournir e n re tour l'adresse de l'obje t alloué . La surdéfinition de de lete , pour un type donné , s e fait par une fonction de prototype : void delete (type *)
Elle re çoit, e n uniq ue argum e nt, l'adresse de l'obje t à libérer.
Tabl e au ré capitul atif ____________________________________________________________________________________ PLURALITE OPERATEURS ASSOCIATIVITE _____________________________________________________________________________________ (3)
Binaire
()
Unaire
+ - ++ new
(3)
[]
(4)
(5)
(2)(3)
->
(5)
--
(4)
delete
-> (1)
! ~ * &
Binaire
+ -
->
Binaire
>
->
Binaire
<
->
Binaire
== !=
->
Binaire
&
->
Binaire
^
->
Binaire
||
->
Binaire
&&
->
Binaire
|
->
Binaire
= += -= *= &= ^= |= =
(1)(3)
/= %=
_____________________________________________________________________________________
Le s opé rate urs surdé finissables e n C+ + (clas s é s par priorité décroissante ) (1) S'iln'e s t pas s urdéfini, ilpos s è de une signification par dé faut. (2) D e puis l a ve rsion 2.0 seul e m e nt.
VII. La surdéfinition d'opé rateurs
93
(3) D oit ê tre défini com m e fonction m e m bre. (4) A un "nive au gl obal " avant l a ve rsion 2.0. Depuis l a ve rsion 2.0, ilpe ut, en outre, ê tre s urdéfini pour une cl as s e ;dans ce cas, ildoit l 'ê tre com m e fonction m e m bre. (5) Jus q u'à l a ve rsion 3.0, on ne pe ut pas distingue r e ntre l e s notations "pré " e t "pos t". D e puis l a ve rsion 3.0, ce s opé rate urs (l ors q u'il s s ont définis de façon unaire ) corre s ponde nt à l a notation "pré " ;m ais ile n e xis te une définition binaire (ave c de uxiè m e opé rande fictif de type int) q ui corre s pond à l a notation "pos t".
R e m arque: M ê m e lors q ue l'on a surdéfini les opé rate urs ne w e t de lete pour une clas s e , ilre s te possible de faire appe l aux opé rate urs ne w e t de lete usuels, e n utilisant l'opé rate ur de ré s olution de porté e (::).
Exe rcice VII.1 ___________________________________________________________________________
Enoncé Soit une clas s e ve cte ur3d définie com m e s uit : class vecteur3d { float x, y, z ; public : vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0) { x = c1 ; y = c2 ; z = c3 ; } } ;
D é finir les opé rate urs == e t !=, de m aniè re à ce q u'ils perm e tte nt de te s te r la coïncide nce ou la noncoïncide nce de deux points : - e n utilisant des fonctions m e m bre , - e n utilisant des fonctions am ie s . ___________________________________________________________________________
Sol ution a) Avec des fonctions m em bre Ilsuffit donc de pré voir, dans la clas s e ve cte ur3d, deux fonctions m e m bre de nom ope rator == e t ope rator !=, re ce vant un argum e nt de type ve cte ur3d corre s pondant au s e cond argum e nt des opérate urs (le pre m ie r opé rande é tant fourni par l'argum e nt im plicte - th is - des fonctions m e m bre ). Voici la déclaration com plète de notre clas s e , accom pagnée des définitions des opérate urs : class vecteur3d { float x, y, z ; public : vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0) { x = c1 ; y = c2 ; z = c3 ; } int operator == (vecteur3d) ; int operator != (vecteur3d) ;
94
Exercices en langage C+ +
} ; int vecteur3d::operator == (vecteur3d v) { if ( (v.x == x) && (v.y == y) && (v.z ==z) ) return 1 ; else return 0 ; } int vecteur3d::operator != (vecteur3d v) { return ! ( (*this) == v ) ; }
Note z q ue , dans la définition de !=, nous nous som m e s s e rvi de l'opé rate ur ==. En pratiq ue , on s e ra souve nt am e né à ré é crire e ntiè re m e nt la définition d'un te lopé rate ur, pour de s im ples raisons d'efficacité (d'ailleurs, pour les m ê m e s raisons, on place ra "e n ligne " les fonctions ope rator == e t ope rator !=).
b) Avec des fonctions am ies Ilfaut donc pré voir de déclare r com m e am ie s , dans la clas s e ve cte ur3d, deux fonctions (ope rator == e t ope rator !=), re ce vant deux argum e nts de type ve cte ur3d corre s pondant aux de ux opé randes des opé rate urs Voici la nouve lle déclaration de notre clas s e , accom pagnée des définitions des opérate urs : class vecteur3d { float x, y, z ; public : vecteur3d (float c1=0.0, float c2=0.0, float c3=0.0) { x = c1 ; y = c2 ; z = c3 ; } friend int operator == (vecteur3d, vecteur3d) ; friend int operator != (vecteur3d, vecteur3d) ; } ; int operator == (vecteur3d v, vecteur3d w) { if ( (v.x == w.x) && (v.y == w.y) && (v.z == w.z) ) return 1 ; else return 0 ; } int operator != (vecteur3d v, vecteur3d w) { return ! ( v == w ) ; }
R e m arque: Voici, à titre indicatif, un e xe m ple de program m e utilisant n'im porte laq ue lle des deux clas s e s ve cte ur3d q ue nous ve nons de définir. #include "vecteur3d.h" #include main() { vecteur3d v1 (3,4,5), v2 (4,5,6), v3 (3,4,5) ; cout > , te lq ue p> > n place dans n la valeur du h aut de la pile, e n la supprim ant de la pile (si la pile e s t vide, la valeur de n ne s e ra pas m odifié e ), + + , te lq ue p+ + vale 1 si la pile e s t pleine e t 0 dans le cas contraire , --, te lq ue p-- vale 1 si la pile e s t vide et 0 dans le cas contraire . O n pré voira q ue les opé rate urs < < e t > > pourront ê tre utilisés sous les form e s s uivante s (n1, n2 e t n3 é tant des entie rs) : p > n2 < < n3 ;
108
Exercices en langage C+ +
O n fe ra e n sorte q u'ilsoit possible de transm e ttre une pile par valeur. En re vanch e , l'affe ctation e ntre piles ne s e ra pas perm ise, et on s'arrange ra pour q ue ce tte s ituation aboutisse à un arrê t de l'e xé cution. ___________________________________________________________________________
Sol ution La clas s e stack _int contie ndra com m e m e m bres donnée : la taille de l'e m place m e nt ré s e rvé pour la pile (nm ax), le nom bre d'élém e nts placé s à un m om e nt donné s ur la pile (ne le m ) e t un pointe ur sur l'e m place m e nt q ui s e ra alloué par le constructe ur pour y range r les é lém e nts de la pile (adv). Note z q u'il n'e s t pas néce s s aire de pré voir une donnée supplém e ntaire pour un é ve ntue l"pointe ur" de pile, dans la m e s ure où c'e s t le nom bre d'élém e nts ne le m q ui joue ce rôle ici. Le s opé rate urs re q uis peuve nt indifé re m m e nt ê tre définis com m e fonctions m e m bre ou com m e fonctions am ie s . Nous ch oisirons ici la pre m iè re s olution. Pour q ue les opé rate urs < < e t > > puis s e nt ê tre utilisés à plusieurs reprises dans une m ê m e e xpre s s ion, ile s t né ce s s aire q ue , par e xe m ple : p double (analogue à ce lles q ui sont m ises en place e n langage C). A titre indicatif, voici ce q ue fournit pré cis é m e nt l'e xé cution du program m e : *** appel int() pour le point 1 5 n1 = 4
124
Exercices en langage C+ +
*** appel *** appel n2 = 3 *** appel z1 = 4 *** appel *** appel z2 = 3
int() pour le point 1 5 int() pour le point 2 8 int() pour le point 1 5 int() pour le point 1 5 int() pour le point 2 8
Exe rcice VIII.3 ___________________________________________________________________________
Enoncé Quels ré s ultats fournira le program m e s uivant : #include class point { int x, y ; public : point (int abs, int ord) // constructeur 2 arguments { x = abs ; y = ord ; } operator int() // "cast" point --> int { cout com plexe obte nue s par une conve rsion int --> double suivie d'une conve rsion double --> com plexe .
Exe rcice VIII.6 ___________________________________________________________________________
Enoncé Quels ré s ultats fournira le program m e s uivant : #include class point { int x, y ; public : point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments { x = abs ; y = ord ; cout > sous form e d'une fonction m e m bre : istream & operator >> (& type_de_base)
180
Exercices en langage C+ +
Le type _de _base pe ut ê tre q ue lconq ue , pour pe u q u'ilne s 'agis s e pas d'un pointe ur (ch ar *e s t ce pe ndant acce pté - ilcorre s pond à l'e ntrée d'une ch aî ne de caractè re s , e t non d'une adre s s e ). Le s "e s pace s _blancs" (e s pace , tabulation h orizontale \t ou ve rticale \v , fin de ligne \n, re tour ch ariot \r e t ch ange m e nt de page \f) s e rve nt de "délim ite urs" (com m e dans scanf), y com pris pour les ch aî nes de caractè re s . Principal es fonctions m em bres : istream & get (ch ar & c) : e xtrait un caractè re du flot d'entré e e t le range dans c. int get () : e xtrait un caractè re du flot d'entré e e t e n re nvoie la valeur (sous form e d'un entie r) ;fournit EOF e n cas de fin de fich ie r. istream & read (void *adr, int tail l e) lit taille caractè re s s ur le flot e t les range à partir de l'adre s s e adr.
La cl as s e ios tre am Elle e s t dérivé e d e istre am e t ostre am . Elle pe rm e t de ré aliser des entré e s s ortie s "conve rsationne lles ".
Le s tatut d'e rre ur d'un fl ot A ch aq ue flot e s t associé un e ns e m ble de bits d'un entie r form ant le "statut d'erreur du flot". Les bits d'erreur : La clas s e ios (dont dérive nt istre am e t ostre am ) définit les constante s s uivante s : e ofbit : fin de fich ie r (le flot n'a plus de caractè res disponibles ), failbit : la proch aine opé ration sur le flot ne pourra pas aboutir, badbit : le flot e s t dans un état irré cupé rable, goodbit (valant, e n fait 0) : aucune d e s e rrre urs précédente s . Une opé ration sur le flot a ré ussi lors q ue l'un des bits goodbit ou e ofbit e s t activé . La proch aine opé ration sur le flot ne pourra ré ussir que si goodbit e s t activé (m ais iln'e s t pas ce rtain q u'e lle ré ussisse !). Lors q u'un flot e s t dans un état d'erreur, aucune opé ration ne pe ut aboutir tant q ue la condition d'e rre ur n'a pas é té corrigé e e t q ue le bit d'erreur corre s pondant n'a pas é té re m is à zé ro (à l'aide de la fonction clear).
Accè s aux bits d'erreur : ios contie nt 5 fonctions m e m bre : eof() : valeur de e ofbit, bad() : valeur de badbit, fail() : valeur de failbit, good () : 1 si aucun bit du statut d'erreur n'est activé , rdstate () : valeur du statut d'erreur (entie r).
M odification du statut d'erreur :
XII. Les flots d'entré e e tde sortie
181
void cl ear (int i=0) donne la valeur i au statut d'erreur. Pour active r un s e ulbit (par e xe m ple badbit), on procédera ainsi (flé tant un flot) : fl.clear (ios::badbit | fl rdstate() ) ;
Surdéfinition de () et de ! Si fle s t un flot, (fl ) e s t vrai si aucun des bits d'erreur n'est activé (c'e s t-à -dire s i good e s t vrai) ;de m ê m e , !fle s t vrai si un des bits d'erreur précédents e s t activé (c'e s t-à -dire s i good e s t faux).
Surdé finition de > pour de s type s cl as s e O n surdéfinira < < e t > > pour une clas s e q ue lconq ue , sous form e de fonctions am ie s , e n utilisant ce s "cane vas" : ostream & operator > ..... ; return entree ; }
Le m ot d'é tat du s tatut de form atage A ch aq ue flot, e s t associé un "statut de form atage " constitué d'un m ot d'état e t de 3 valeurs num é riq ue s (gabarit, pré cision et caractè re de re m plissage ). Voici (page ci-conre ) les principaux bits du m ot d'état :
_____________________________________________________________________________________ NOM DE CHAMP NOM DU BIT SIGNIFICATION (s'il existe) (quand activé) _____________________________________________________________________________________ ios::basefield ios::dec conversion décimale ios::oct
conversion octale
ios::hex
conversion hexadécimale
1 Ici, l a trans m ission peut s e faire par val e ur ou par ré fé re nce.
182
Exercices en langage C+ +
_____________________________________________________________________________________ ios::showbase affichage indicateur de base (en sortie) ios::showpoint
affichage point décimal (en sortie)
_____________________________________________________________________________________ ios::floatfield ios::scientific notation "scientifique" ios::fixed notation "point fixe" _____________________________________________________________________________________
Le m ot d'état du statut de form atage (partie l)
A ction sur l e s tatut de form atage O n pe ut utiliser, soit des "m anipulate urs" q ui pe uve nt ê tre "sim ples " ou "param é triq ue s ", soit des fonctions m e m bre .
a) Les m anipul ateurs non param é triques Ils s'e m ploie nt sous la form e : flot > manipulateur
Le s principaux m anipulate urs non param é triq ue s s ont pré s e nté s e n page s uivante :
_____________________________________________________________________________________ MANIPULATEUR UTILISATION ACTION ____________________________________________________________________________________ dec
Entrée/Sortie
Active le bit de conversion décimale
hex
Entrée/Sortie
Active le bit de conversion hexadécimale
oct
Entrée/Sortie
Active le bit de conversion octale
endl
Sortie
Insère un saut de ligne et vide le tampon
ends Sortie Insère un caractère de fin de chaîne (\0) _____________________________________________________________________________________
Le s principaux m anipulate urs non param é triq ue s b) Les m anipul ateurs param é triques Ils s'utilisent sous la form e : istream & manipulateur (argument)
XII. Les flots d'entré e e tde sortie
183
ostream & manipulateur (argument)
Voici les principaux : _____________________________________________________________________________________ MANIPULATEUR UTILISATION ROLE _____________________________________________________________________________________ setbase (int)
Entrée/Sortie
Définit la base de conversion
setprecision (int)
Entrée/Sortie
Définit la précision des nombres flottants
setw (int)
Entrée/Sortie
Définit le gabarit. Il retombe à 0 après chaque opération _____________________________________________________________________________________
Le s principaux m anipulate urs param é triq ue s
A s s ociation d'un fl ot à un fich ie r La clas s e ofstre am , dérivant de ostre am pe rm e t de cré e r un flot de sortie associé à un fich ie r : ofstream flot (char * nomfich, mode_d_ouverture)
La fonction m e m bre s e e k p (déplace m e nt, origine ) pe rm e t d'agir sur le pointe ur de fich ie r. D e m ê m e , la clas s e ifstre am , dérivant de istre am , pe rm e t de cré e r un flot d'entré e associé à un fich ie r : ifstream flot (char * nomfich, mode_d_ouverture)
La fonction m e m bre s e e k g (dé place m e nt, origine ) pe rm e t d'agir sur le pointe ur de fich ie r D ans tous les cas, la fonction clos e pe rm e t de fe rm e r le fich ie r. L'utilisation de s clas s e s ofstre am e t ifstre am dem ande l'inclusion du fich ie r fstre am .h . M odes d'ouverture d'un fich ier _____________________________________________________________________________________ BIT DE MODE ACTION D'OUVERTURE _____________________________________________________________________________________ ios::in
Ouverture en lecture (obligatoire pour la classe ifstream)
ios::out
Ouverture en écriture (obligatoire pour la classe ofstream)
ios::app
Ouverture en ajout de données (écriture en fin de fichier)
ios::ate
Se place en fin de fichier après ouverture
ios::trunc
Si le fichier existe, son contenu est perdu (obligatoire si ios::out est activé sans ios::ate ni ios::app
ios::nocreate
Le fichier doit exister
ios::noreplace
Le fichier ne doit pas exister (sauf si ios::ate ou ios::app est activé) _____________________________________________________________________________________
184
Exercices en langage C+ +
Les diffé re nts m odes d'ouve rture d'un fich ie r
Exe rcice X I.1 ___________________________________________________________________________
Enoncé Ecrire un program m e q ui lit un nom bre ré e le t q ui e n affich e le carré s ur un "gabarit" m inim alde 12 caractè re s , de 22 façons diffé re nte s : - e n "point fixe ", ave c un nom bre de décim ales variant de 0 à 10, - e n notation scie ntifiq ue , ave c un nom bre de décim ales variant de 0 à 10. D ans tous les cas, on affich e ra les ré s ulats ave c ce tte pré s e ntation : précision de xx chiffres : cccccccccccc
___________________________________________________________________________
Sol ution Ilfaut donc active r, d'abord le bit fixe d, e nsuite le bit scie ntific du ch am p floatfie ld. Nous utiliserons la fonction s e tf, m e m bre de la clas s e ios. Note z bie n q u'ilfaut é vite r d'é crire , par e xe m ple : setf (ios::fixed) ;
ce q ui aurait pour e ffe t d'active r le bit fixe d, sans m odifie r les autres donc, e n particulie r, sans m odifie r les autres bits du ch am p floatfie ld. Le gabarit d'affich age e s t déte rm iné par le m anipulate ur s e tw . Note z q u'ilfaut transm e ttre ce m anipulate ur au flot conce rné , juste avant d'affich e r l'inform ation voulue .
#include #include //pour les "manipulateurs paramétriques" main() { float val, carre ; cout > val ; carre = val*val ; cout x >> c ; if (c != ',') ok = 0 ; else { entree >> y >> c ; if (c != '>') ok = 0 ; } } if (ok) { p.x = x ; p.y = y ; } // on n'affecte à p que si tout est OK else entree.clear (ios::badbit | entree.rdstate () ) ; return entree ; }
A titre indicatif, voici un pe tit program m e d'essai, accom pagné d'un exem ple d'exécution :
main() { char ligne [121] ; point a(2,3), b ; cout setw (LGMAX) >> nomfich ; ofstream sortie (nomfich, ios::out) ; if (!sortie) { cout n ; if (n) sortie.write ((char *)&n, sizeof(int) ) ; }
188
Exercices en langage C+ +
while (n && sortie) ; sortie.close () ; }
Note z q ue if (!sortie ) e s t é q uivalent à if (!sortie .good()) e t q ue w h ile (n & & sortie ) e s t é q uivalent à w h ile (n & & sortie .good()).
Exe rcice X II.4 ___________________________________________________________________________
Enoncé Ecrire un program m e pe rm e ttant de liste r (sur la sortie s tandard) les e ntie rs conte nus dans un fich ie r te lq ue ce lui cré é par l'e xe rcice pré cédent. ___________________________________________________________________________
Sol ution const int LGMAX = 20 ; #include // pour exit #include #include #include main() { char nomfich [LGMAX+1] ; int n ; cout > setw (LGMAX) >> nomfich ; ifstream entree (nomfich, ios::in) ; if (!entree) { cout setw (LGMAX_NOM_FICH) >> nomfich ; ifstream entree (nomfich, ios::in) ; if (!entree) { cout num ; if (num) { entree.seekg (sizeof(int) * (num-1) , ios::beg ) ; entree.read ( (char *) &n, sizeof(int) ) ; if (entree) cout A : class B : public A
// B dérive de la classe patron A
O n obtie nt une s e ule clas s e nom m é e B - Patron de cl asses dérivé d 'une cl asse "ordinaire", par e xe m ple (A étant une clas s e ordinaire ) : template class B : public A
O n obtie nt une fam ille de clas s e s (de param è tre de type T). - Patron de cl asses dérivé d 'un patron de cl asses. Par e xe m ple, si A est une clas s e patron dé finie par te m plate < class T> A, on pe ut : *définir une nouve lle fam ille de fonctions dérivé e s par : template class B : public A
D ans ce cas, ile xiste autant de classes dérivé e s possibles q ue de classes de bas e possibles . *définir une nouve lle fam ille de fonctions dérivé e s par : template class B : public A
D ans ce cas, on pe ut dire q ue ch aq ue classe de bas e possible pe ut e nge ndre r une fam ille de clas s e s dérivé e s (de param è tre de type U).
Exe rcice X IV.1 ___________________________________________________________________________
Enoncé Soit la définition suivante d'un patron de clas s e s : template class essai { T tab [n] ;
206
public : essai (T) ; } ;
Exercices en C+ +
// constructeur
a) D onne z la définition du constructe ur e s s ai, e n supposant : - q u'e lle e s t fournie "à l'e xté rie ur" de la définition pré cédente , - q ue le constructe ur re copie la valeur re çue e n argum e nt dans ch acun de s é lém e nts du tableau tab . b) D isposant ainsi de la définition pré cédente du patron e s s ai, de son constructe ur e t de ces déclarations : const int n = 3 ; int p = 5 ;
Quelles s ont les instructions corre cte s e t les clas s e s instancié e s : on e n fournira (dans ch aq ue cas) une définition é q uivalente s ous form e d'une "clas s e ordinaire ", c'e s t-à -dire dans laq ue lle la notion de param è tre a disparu. essai ei (3) ; essai ef (0.0) ; essai ed (2.5) ;
// I // II // III
___________________________________________________________________________
Sol ution a) La définition du constructe ur e s t analogue à ce lle q ue l'on aurait é crite "e n ligne " ;ilfaut sim plem e nt "pré fixe r" son en-tê te d'une liste de param è tre s introduite par te m plate . De plus, ilfaut pré fixe r l'e n-tê te de la fonction m e m bre du nom du patron accom pagné de ses param è tre s (bie n q ue ce la soit redondant) :
template essai::essai(T a) { int i ; for (i=0 ; i