Vous êtes sur la page 1sur 459

Programmer en langage C++

C. Delannoy
A VANT-PRO PO S

La Program m ation O rie nté e O b je t (e n abré gé P.O .O .) a pour am bition de facilite r l'activité de
program m ation, notam m e nt e n pe rm e ttant de déve loppe r de s "com posants logicie ls" ré utilisables . Elle fait
appe là des notions fondam e ntales (clas s e s , obje ts, h é ritage , ligature dynam iq ue ou polym orph ism e ...)
inconnues de la plupart des langages de program m ation traditionne ls te ls q ue C ou Pascal.

Un ce rtain nom bre de langage s ont é té définis de toute s piè ce s pour appliq ue r les conce pts de P.O .O . ;
citons Sm alltalk, Sim ula, Eiffe l... (on parle alors de "Langage s O rie nté s O b je t" ou L.O .O .). Le langage
C+ + , q uant à lui, a é té conçu suivant une dém arch e q ue lque pe u diffé re nte par B. Stroustrup (AT& T), à
partir de s anné e s 19 80 ;son obje ctif a é té , e n e ffe t, d'adjoindre au langage C un ce rtain nom bre de
spécificité s lui pe rm e ttant d'appliq ue r les conce pts de P.O .O . Ainsi, C+ + pré s e nte -t-il sur un "vrai
L.O .O ." l'originalité d'ê tre fondé s ur un langage ré pandu. Ce ci lais s e au program m e ur toute liberté
d'adopte r un "style plus ou m oins orie nté obje t", e n s e s ituant e ntre les deux e xtrê m e s q ue constitue nt la
poursuite d'une program m ation classique d'une part, une pure P.O .O . d'autre part. Si une te lle liberté
pré s e nte le ris q ue de céder, dans un pre m ie r te m ps, à la facilité e n "m é lange ant les ge nre s " (la P.O .O . ne
re nie pas la program m ation classique - e lle l'e nrich it), e lle pe rm e t é galem e nt une "transition e n douce ur"
ve rs la P.O .O pure , ave c tout le béné fice q u'on pe ut e n e s com pte r à te rm e .

D e s a conce ption jus q u'à sa norm alisation, le langage C+ + a q ue lque pe u é volué . Plus précisém e nt, un
ce rtain nom bre de publications de AT& T ont s e rvi de réfé re nce au cours des derniè re s anné e s . Elles s ont
connue s s ous la te rm inologie s uivante : ve rsion 1.1 e n 19 86, ve rsion 1.2 e n 19 87, ve rsion 2.0 e n 19 89 ,
ve rsions 2.1 e t 3 e n 19 9 1 ;ce tte derniè re a s e rvi de bas e au travaildu com ité ANSI q ui, sans la re m e ttre e n
caus e , l'a e nrich ie d e q ue lque s e xte nsions et surtout de com posants standard originaux s e pré s e ntant sous
form e de fonctions e t de clas s e s gé né riq ue s .

Ce t ouvrage e s t destiné à tous ce ux q ui souh aite nt m aî tris e r le langage C+ + , q ue ce s oit dans un but
didactiq ue ou e n vue de déve loppe r de vé ritables applications. Conçu sous form e d'un cours, ilsuppose que
vous possédez déjà q ue lque s rudim e nts de C1. En e ffe t, ré aliser un livre de taille raisonnable ne né ce s s itant
aucune connaissance pré alable nous aurait im m anq uablem e nt conduit à ê tre s uccinct e t, partant, à é lude r les
points q ui s e ré vè lent e n ré alité les plus fondam e ntaux lors du déve loppe m e nt de logicie ls e n vraie grande ur.

Bie n q ue nous adre s s ant à un public "ave rti", nous avons ch e rch é à re s te r pédagogiq ue . Les diffé re nte s
notions, e n particulie r ce lles re lative s aux conce pts de P.O .O , sont introduite s progre s s ive m e nt. Le s
"ré fé re nce s avant" ont toujours é té é vité e s , de façon à pe rm e ttre , le cas é ch é ant, une é tude s é q ue ntie lle de

1 - Le cas é ch é ant, on pourra trouve r un cours com pl


e t de l
angage C dans Program m e r e n langage C du m ê m e aute ur, ch e z l
e mê me
édite ur.
VI Program m e r e n langage C+ +
l'ouvrage . Ch aq ue notion e s t illustré e par un program m e com plet, assorti d'un e xe m ple d'exécution
m ontrant com m e nt la m e ttre e n œuvre dans un conte xte ré e l. Ce lui-ci pe ut é galem e nt s e rvir :

• à une prise de connaissance intuitive ou à une ré vision rapide de la notion e n q ue s tion,


• à une e xpé rim e ntation dire cte dans votre propre e nvironne m e nt de travail,
• de point de départ à une e xpé rim e ntation pe rsonne lle.
Nous avons ch e rch é à ê tre com plet non s e ulem e nt e n couvrant l'e ns e m ble des possibilités du C+ + , m ais
é galem e nt e n approfondissant suffisam m e nt ce rtains aspects fondam e ntaux, de m aniè re à re ndre le lecte ur
parfaite m e nt opé rationne ldans la conce ption e t le déve loppe m e nt de ses propre s clas s e s . C'e s t ainsi que
nous avons large m e nt insisté s ur le rôle du constructe ur de re copie , ainsi que sur la redéfinition de
l'opé rate ur d'affe ctation, é lém e nts q ui conduis e nt à la notion de "clas s e canoniq ue ". Toujours dans le m ê m e
e s prit, nous avons pris soin de bien déve loppe r les notions avancé e s m ais indispensables q ue s ont la ligature
dynam iq ue e t les clas s e s abstraite s , les q ue lles débouch e nt sur la notion la plus puissante du langage q u'e s t le
polym orph ism e . De m ê m e , nous avons large m e nt insisté s ur les notions de conte ne ur, d'ité rate ur e t
d'algorith m e q ui inte rvie nne nt dans l'utisation de bon nom bre de com posants de la biblioth è q ue s tandard.

Note z q ue ce s ouci de com plétude nous a am e né à pré s e nte r de s é lém e nts d'inté rê t lim ité (voire dange re ux !)
q ui pe uve nt ê tre ignorés dans un pre m ie r te m ps (notam m e nt dans un cours de C+ + ). Ils sont alors re pé ré s
par le pictogram m e $ .

Le s ch apitre s les plus im portants ont é té dotés d'exercices 2 com portant :

• des suggestions de m anipulations destiné e s à m ie ux vous fam iliaris e r ave c votre e nvironne m e nt ;par
e ffe t d'entraî
ne m e nt, e lles vous fe ront probablem e nt im agine r d'autre s e xpé rim e ntations de votre cru ;
• des program m e s à rédiger ;dans ce cas, un e xe m ple de corre ction e s t fourni e n fin de volum e .

Re m arq ue conce rnant ce tte nouve l


le é dition
Les derniè res éditions se basaie nt plutôt sur la ve rsion 3 e t sur le proje t de norm e . Dorénavant, nous nous
basons sur la norm e e lle-m ê m e , laq ue lle e s t re connue de la plupart des com pilate urs du m arch é , à q ue lque s
détails prè s (q ue nous signalons dans le te xte ). Toute fois, pour vous perm e ttre d'utiliser d'anciens
e nvironne m e nts de program m ation, nous m e ntionnons les apports de la norm e par rapport à la ve rsion 3
ainsi que les q ue lques diffé re nce s ave c les ve rsions anté rie ure s . Ces derniè re s ont surtout un caractè re
h istoriq ue ;e n particulie r, e lles m e tte nt e n avant les points délicats du langage pour les q ue ls la ge nè s e a é té
q ue lque pe u difficile.

Par ailleurs, ce tte nouve lle édition a é té e nrich ie d e q uatre ch apitre s s upplém e ntaire s (XVII à XXI) e t d'une
anne xe (F) décrivant les nouve aux com posants standard, notam m e nt les conte ne urs e t les algorith m e s .

2 - D e nom breux autre s e xe rcice s pe uve nt ê tre trouvés dans Exe rcice s e n langage C+ + du m ê m e aute ur, ch e z l
e m ê m e édite ur.
I. PRÉSENTA TIO N GÉNÉRA LE
D E C+ +

Le langage C+ + a é té conçu (à partir de 19 82) par Bjarne Stroustrup (AT& T Be llLaboratorie s ) ave c un
obje ctif pré cis : ajoute r au langage C des "clas s e s " analogue s à ce lles du langage Sim ula. Ils'agissait donc
de "gre ffe r" sur un langage classique des possibilités de "Program m ation O rie nté e O b je t". Avant de vous
décrire le ré s ultat auq ue la abouti B. Stroustrup, nous com m e nce rons par e xam ine r succincte m e nt ce q u'e s t
la Program m ation O rie nté e O b je t d'une m aniè re gé né rale.

1. LA PRO GRA M M A TIO N O RIENTÉE O BJET

1.1 La probl
é m atiq ue de l
a program m ation

Jus q u'à m ainte nant, l'activité de program m ation a toujours suscité des ré actions dive rs e s allant jus q u'à la
contradiction totale. Pour ce rtains, e n e ffe t, ilne s 'agit q ue d'un je u de construction e nfantin, dans leq ue lil
suffit d'ench aî ne r de s instructions é lém e ntaire s (e n nom bre re s tre int) pour parve nir à ré s oudre (pre s q ue )
n'im porte q ue lproblèm e . Pour d'autre s au contraire , ils'agit de produire (au s e ns industrie ldu te rm e ) des
logicie ls ave c des exige nce s d e q ualité q u'on te nte de m e s ure r suivant ce rtains critè re s ;citons :

• l'e xactitude : aptitude d'un logicie l à fournir les ré s ultats voulus, dans des conditions norm ales
d'utilisation (par e xe m ple, donné e s corre s pondant aux "spécifications"),
• la robuste s s e : aptitude à bien réagir lors q ue l'on s'é carte des conditions norm ales d'utilisation,
• l'e xte nsibilité : facilité ave c laq ue lle un program m e pourra ê tre adapté pour satisfaire à une é volution de s
spécifications,
• la réutilisabilité : possibilité d'utiliser certaine s partie s ("m odules ") du logicie lpour ré s oudre un autre
problèm e ,
• la portabilité : facilité ave c laq ue lle on pe ut e xploite r un m ê m e logicie l dans diffé re nte s
im plém e ntations,
• l'e fficie nce : te m ps d'exécution, taille m é m oire ...
2 Pré s e ntation générale de C+ +
La contradiction n'e s t souve nt q u'appare nte e t e s s e ntie llem e nt lié e à l'im portance des proje ts conce rné s . Par
e xe m ple, ile s t facile d'écrire un program m e e xact e t robuste lors q u'ilcom porte une ce ntaine d'instructions ;
il e n va tout autre m e nt lors q u'il s'agit d'un proje t de dix h om m e s -anné e s ! D e m ê m e , les aspects
e xte nsibilité e t ré utilisabilité n'auront guè re d'im portance dans le pre m ie r cas, alors q u'ils s e ront
probablem e nt cruciaux dans le s e cond, ne s e rait-ce q ue pour de s raisons économ iq ue s .

1.2 La program m ation s tructuré e

La program m ation structuré e a m anife s te m e nt fait progre s s e r la q ualité de la production de s logicie ls. M ais,
ave c le re cul, ilfaut bien reconnaî
tre q ue s e s propre s fonde m e nts lui im posaie nt des lim itations "nature lles ".
En e ffe t, la program m ation structuré e re posait sur ce q ue l'on nom m e s ouve nt "l'é q uation de W irth ", à
savoir :

Algorith m e s + Structures de données = Program m e s

Bie n sûr, e lle a pe rm is de structure r les program m e s , e t, partant, d'e n am é liore r l'e xactitude e t la
robuste s s e . O n avait e s pé ré q u'e lle pe rm e ttrait é galem e nt d'en am é liore r l'e xte nsibilité e t la ré utilisabilité .
O r, e n pratiq ue , on s'e s t ape rçu q ue l'adaptation ou la ré utilisation d'un logicie lconduisait souve nt à
"cas s e r" le "m odule" inté re s s ant, e t ce ci parce q u'ilé tait né ce s s aire de re m e ttre e n caus e une s tructure de
donné e s . Pré cis é m e nt, ce type de difficulté s e s t l'é m anation m ê m e de l'é q uation de W irth q ui dé couple
totalem e nt les données des procédures agissant sur ces données.

1.3 La Program m ation O rie nté e O bje t

a)O bje t
C'e s t là q u'inte rvie nt la P.O .O . (abré viation de Program m ation O rie nté e O b je t), fondé e juste m e nt sur le
conce pt d'objet, à savoir une association des données et des procédures (qu'on appelle alors m é th ode s )
agissant sur ces données. Par analogie ave c l'é q uation de W irth , on pourrait dire q ue l'é q uation de la P.O .O .
e s t:

M é th ode s + D onné e s = O bje t

b)Encaps ul
ation
M ais ce tte association e s t plus q u'une s im ple juxtaposition. En e ffe t, dans ce q ue l'on pourrait q ualifie r de
P.O .O . "pure "1, on ré alise ce q ue l'on nom m e une encapsul ation des données. Ce la signifie q u'iln'e s t pas
possible d'agir dire cte m e nt sur les données d'un obje t ;ile s t né ce s s aire de pas s e r par l'inte rm édiaire de ses
m é th ode s q ui joue nt ainsi le rôle d'inte rface obligatoire . O n traduit parfois ce la e n disant q ue l'appe ld'une
m é th ode e s t e n fait l'e nvoi d'un "m e s s age " à l'obje t.

Le grand m é rite de l'e ncapsulation e s t q ue , vu de l'e xté rie ur, un obje t s e caracté ris e uniq ue m e nt par les
spécifications 2 de ses m é th ode s , la m aniè re dont sont ré e llem e nt im planté e s les données étant sans
im portance . O n dé crit souve nt une te lle s ituation e n disant q u'e lle ré alise une "abstraction des données" (ce
q ui e xprim e bien que les détails concre ts d'im plém e ntation sont cach é s ). A ce propos, on pe ut re m arq ue r

1 - Nous ve rrons, en effe t, q ue l


e s conce pts de l
a P.O .O . pe uve nt ê tre appl
iq ués d'une m aniè re pl
us ou m oins rigoure use. En particul
ie r,
e n C+ + , l'encapsul ation ne s e ra pas obl
igatoire, ce qui ne ve ut pas dire qu'el
le ne s oit pas s ouh aitabl
e.
2 - Nom s, argum e nts e t rôl
es.
Pré s e ntation générale de C+ + 3
q u'e n program m ation structuré e , une procédure pouvait é galem e nt ê tre caracté ris é e (de l'e xté rie ur) par s e s
spécifications, m ais q ue , faute d'encapsulation, l'abstraction des données n'était pas ré alisée.

L'e ncapsulation des données présente un inté rê t m anife s te e n m atiè re d e q ualité de logicie l. Elle facilite
considérablem e nt la m ainte nance : une m odification é ve ntue lle de la structure de données d'un obje t n'a
d'incide nce q ue s ur l'obje t lui-m ê m e ;les utilisate urs de l'obje t ne s e ront pas conce rné s par la te ne ur de
ce tte m odification (ce q ui n'é tait, bie n sûr, pas le cas ave c la program m ation structuré e ). De la m ê m e
m aniè re , l'e ncapsulation des données facilite grande m e nt la ré utilisation d'un obje t.

c)Cl
as s e

En P.O .O . apparaî t gé né ralem e nt le conce pt de clas s e 3. Ce dernie r corre s pond sim plem e nt à la
gé né ralisation de la notion de type q ue l'on re ncontre dans les langage s classiques. Une clas s e , e n e ffe t,
n'e s t rie n d'autre q ue la description d'un e ns e m ble d'obje ts ayant une s tructure de données com m une 4 e t
disposant des m ê m e s m é th ode s . Le s obje ts apparais s e nt alors com m e des variables d'un te ltype clas s e (e n
P.O .O ., on dit aussi qu'un obje t e s t une "instance " de sa clas s e ).

d)H é ritage
Un autre conce pt im portant e n P.O .O . e s t ce lui d'h é ritage . Ilpe rm e t de définir une nouve lle clas s e à partir
d'une clas s e e xistante (q u'on ré utilise en bloc !), à laq ue lle on ajoute de nouve lles données et de nouve lles
m é th ode s . La conce ption de la nouve lle clas s e , q ui "h é rite " des propriété s e t des aptitudes de l'ancie nne ,
pe ut ainsi s'appuye r sur des réalisations anté rie ure s parfaite m e nt au point e t les "spécialiser" à volonté .
Com m e on pe ut s'e n doute r, l'h é ritage facilite large m e nt la ré utilisation de produits e xistants, e t ce ci
d'autant plus q u'ilpe ut ê tre ré ité ré autant de fois q ue né ce s s aire (la clas s e C pe ut h é rite r de B, q ui e lle-
m ê m e h é rite de A)5.

1.4 P.O .O . e t l
angage s

Nous ve nons d'énoncer les grands principes de la P.O .O ., d'une m aniè re gé né rale, sans nous attach e r à un
langage particulie r.

O r, m anife s te m e nt, ce rtains langage s pe uve nt ê tre conçus (de toute s piè ce s ) pour appliq ue r à la lettre ce s
principe s e t ré aliser ce que nous nom m ons de la P.O .O . "pure ". C'e s t, par e xe m ple, le cas de Sim ula,
Sm alltalk ou, plus ré ce m m e nt Eiffe l. Le m ê m e ph é nom è ne a e u lie u, e n son te m ps, pour la program m ation
structuré e ave c Pascal.

A l'oppos é , on pe ut toujours te nte r d'appliq ue r, ave c plus ou m oins de bonh e ur, ce q ue nous aurions
te ndance à nom m e r "une ph ilosoph ie P.O .O ." à un langage classique (Pascal, C...). O n re trouve là une idée
com parable à ce lle q ui consistait à appliq ue r les principes de la program m ation structuré e à des langage s
com m e Fortran ou Basic.

Le langage C+ + s e s itue à m i-ch e m in e ntre ces deux points de vue . Ila, e n e ffe t, é té obte nu e n ajoutant à
un langage classique (C) les outils perm e ttant de m e ttre e n œuvre tous les principes de la P.O .O .
Program m e r e n C+ + va donc plus loin q u'adopte r une ph ilosoph ie P.O .O . e n C, m ais m oins loin q ue de
faire de la P.O .O . pure ave c Eiffe l!

3 - D ans ce rtains langages (Turbo Pas cal , par e xe m ple ), l


e m ot cl
as s e e s t re m pl
acé par obje t e t l
e m ot obje t par variabl
e.
4 - Bie n e nte ndu, seul
e l
a s tructure e s t com m une, l es données étant propre s à ch aq ue obje t. Le s m é th odes, par contre, sont e ffe ctive m e nt
com m une s à l
'ensem bl e des obje ts d'une m ê m e classe.
5 - En C+ + , l e s te ch niq ues de m é th odes virtue l
les él
argis s e nt e ncore pl
us l
a portée de l
'h é ritage ;m ais iln'e s t pas possibl
e, pour
l
'instant, d'en faire pe rce voir l
'inté rê t.
4 Pré s e ntation générale de C+ +
La solution adopté e par B. Stroustrup a le m é rite de pré s e rve r l'e xistant (com patibilité ave c C+ + de
program m es déjà é crits e n C) ;e lle pe rm e t é galem e nt une "transition e n douce ur" de la program m ation
structuré e ve rs la P.O .O . En re vanch e , e lle n'im pos e nullem e nt l'application stricte des principes de P.O .O .
Com m e vous le ve rre z, e n C+ + , rie n ne vous e m pê ch e ra (sauf votre bon sens !) de faire coh abite r de s
obje ts (dignes de ce nom , parce q ue ré alisant une parfaite e ncapsulation de leurs données), ave c des
fonctions classiques réalisant des effe ts de bord sur des variables globales ...

2. C+ + , C ANSI ET P.O .O .

Pré cédem m e nt, nous avons dit, d'une façon q ue lque pe u sim pliste , q ue C+ + s e pré s e ntait com m e un "sur-
e ns e m ble" du langage C, offrant des possibilités de P.O .O . Il nous faut m ainte nant nuance r ce tte
affirm ation.

D 'une part, lors q ue l'on parle de sur-e ns e m ble du C, nous nous réfé rons au langage C te lq u'ile s t défini par
la norm e ANSI6. O r, e n fait, ile xiste q ue lque s incom patibilité s e ntre le C ANSI e t le C+ + . Ce lles -ci,
com m e nous le ve rrons, sont né anm oins re lative m e nt m ine ure s ;e lles s ont, pour la plupart, due s à la
diffé re nce "d'esprit" des deux langage s , ainsi qu'à la tolérance dont a fait pre uve la norm e ANSI e n
ch e rch ant à "pré s e rve r l'e xistant" (ce rtaine s tolérance s ont disparu e n C+ + ).

D 'autre part, les e xte nsions du C+ + par rapport au C ANSI ne s ont pas toute s vé ritablem e nt lié e s à la
P.O .O . Ce rtaines de ce s e xte nsions, en effe t, pourraie nt ê tre ajouté e s ave c profit au langage C, sans q u'il
devie nne pour autant "orie nté obje t"7.

En fait, nous pourrions caracté ris e r C+ + par ce tte form ule :

C+ + = C + E + S + P

dans laq ue lle :

C désigne le C norm e ANSI,


E re pré s e nte les "é carts à la norm e " de C+ + ,
S re pré s e nte les s pé cificités de C+ + q ui ne s ont pas vé ritablem e nt axé e s s ur la P.O .O .,
P re pré s e nte les possibilités de P.O .O .

3. LES INCO M PA TIBILITÉS D E C+ + A VEC LE C ANSI

Le s principaux "é carts à la norm e " sont décrits dans le ch apitre II ;ils sont accom pagnés de rappe ls
conce rnant la norm e C ANSI. Ils conce rne nt e s s e ntie llem e nt :

• les définitions de fonctions : e n-tê te s , prototype s , argum e nts e t valeur de re tour,


• la portée du q ualificatif cons t,
• les com patibilité s e ntre pointe urs.

6 - Laq ue lle a s e nsibl


e m e nt é vol
ué, par rapport à l
a dé finition initial
e du l angage C, ré alisée en 1978, par Kernigh an e t R itch ie.
7 - D'aille urs, certaine s e xte nsions de C+ + , par rapport à l a pre m iè re définition du C, ont é té introduites dans l
e C ANSI (prototypes,
fonctions à argum e nts variabl
es...).
Pré s e ntation générale de C+ + 5
Ilfaut note r q ue ce s incom patibilité s s ont re s té e s les m ê m e s au fildes diffé re nte s ve rsions de C+ + .

4. LES SPÉCIFICITÉS D E C+ +

Com m e nous l'avons dit, C+ + pré s e nte , par rapport au C ANSI, de s e xte nsions q ui ne s ont pas
vé ritablem e nt orie nté e s P.O .O . Elles s e ront décrites dans le ch apitre IV. En voici un bref résum é :

• nouve lle form e de com m e ntaire (e n fin de ligne ),


• plus grande liberté dans l'e m place m e nt des déclarations,
• notion de ré fé re nce facilitant la m ise en œuvre de la transm ission d'argum e nts par adre s s e ,
• surdéfinition de s fonctions : attribution d'un m ê m e nom à diffé re nte s fonctions, la re connaissance de la
fonction ré e llem e nt appe lée s e faisant d'aprè s le type e t le nom bre des argum e nts figurant dans l'appe l
(on parle parfois de signature ),
• nouve aux opé rate urs de gestion dynam iq ue de la m é m oire : ne w e t de lete ,
• possibilité de définir de s fonctions "e n ligne " (inline ), ce q ui accroî
t la vitesse d'e xé cution, sans perdre
pour autant le form alism e des fonctions.

5. C+ + ET LA PRO GRA M M A TIO N O RIENTÉE O BJET

Le s possibilités de P.O .O . re pré s e nte nt, bie n sûr, l'e s s e ntie lde l'apport de C+ + .

C+ + dispose de la notion de clas s e (gé né ralisation de la notion de type défini par l'utilisate ur). Une clas s e
com porte ra :

• la description d'une s tructure de données,


• des m é th ode s .
Sur le plan du vocabulaire , C+ + utilise des te rm e s q ui lui sont propre s . O n parle, e n e ffe t :

• de "m e m bres donnée" pour dé s igne r les diffé re nts m e m bres de la structure de données associé e à une
clas s e ,
• de "fonctions m e m bre " pour dé s igne r les m é th ode s .
A partir d'une clas s e , on pourra "instancie r" de s obje ts (nous dirons généralem e nt cré e r de s obje ts) :

• soit par des déclarations usuelles (de type clas s e ),


• soit par allocation dynam iq ue , e n faisant appe lau nouve lopé rate ur ne w .
C+ + pe rm e t l'e ncapsulation des données, m ais ilne l'im pos e pas. O n pe ut le re gre tte r m ais ilne faut pas
pe rdre de vue q ue , de par sa conce ption m ê m e (e xte nsion de C), le C+ + ne pe ut pas, de toute façon, ê tre
un langage de P.O .O . pure . Bie n e nte ndu, ilre s te toujours possible au conce pte ur de faire pre uve de
rigue ur, e n s'astre ignant à ce rtaine s rè gles te lles q ue l'e ncapsulation absolue .

C+ + pe rm e t de définir ce q ue l'on nom m e des "constructe urs" de clas s e . Un constructe ur e s t une fonction
m e m bre particuliè re q ui e s t e xé cuté e au m om e nt de la cré ation d'un obje t de la clas s e . Le constructe ur pe ut
notam m e nt pre ndre e n ch arge "l'initialisation d'un obje t", au s e ns le plus large du te rm e , c'e s t-à -dire s a
m ise dans un état initialpe rm e ttant son bon fonctionne m e nt ulté rie ur ;ilpe ut s'agir de banales initialisations
de m e m bres donnée, m ais é galem e nt d'une pré paration plus é laboré e corre s pondant au dé roulem e nt
d'instructions, voire d'une allocation dynam iq ue d'em place m e nts néce s s aire s à l'utilisation de l'obje t.
6 Pré s e ntation générale de C+ +
L'e xiste nce d'un constructe ur garantit q ue l'obje t s e ra toujours initialisé, ce qui constitue m anife s te m e nt une
s é curité .

D 'une m aniè re s im ilaire , une clas s e pe ut disposer d'un "destructe ur", fonction m e m bre e xé cuté e au m om e nt
de la destruction d'un obje t. Ce lle-ci pré s e nte ra surtout un inté rê t dans le cas d'obje ts e ffe ctuant des
allocations dynam iq ues d'em place m e nts ;ces dernie rs pourront ê tre libérés par le destructe ur.

Une des originalités de C+ + , par rapport à d'autre s langages de P.O .O ., ré s ide dans la possibilité de définir
des "fonctions am ies d'une clas s e ". Ils'agit de fonctions "usuelles " (q ui ne s ont donc pas des fonctions
m e m bre d'une clas s e ) q ui sont autoris é e s (par une clas s e ) à accéder aux donné e s (e ncapsulée s ) de la clas s e .
Ce rte s , le principe d'encapsulation e s t violé, m ais uniq ue m e nt par de s fonctions dûm e nt autoris é e s à le faire .

La clas s e e s t un type défini par l'utilisate ur. La notion de "surdéfinition d'opé rate urs" va pe rm e ttre de dote r
ce tte classe d'opérations analogue s à ce lles q ue l'on re ncontre pour les type s prédéfinis. Par e xe m ple, on
pourra dé finir une clas s e com plexe (destiné e à re pré s e nte r de s nom bre s com plexe s ) e t la m unir de s
opé rations d'addition, de s oustraction, de m ultiplication e t de division. Qui plus e s t, ce s opé rations pourront
utiliser les sym boles e xistants : + , -, *, /.

C dispose de possibilités de conve rsions (explicite s ou im plicite s ). C+ + pe rm e t d'élargir ce s conve rsions


aux types définis par l'utilisate ur q ue s ont les clas s e s . Par e xe m ple, on pourra donne r un s e ns à la conve rsion
int -> com plexe ou à la conve rsion com plexe -> float (com plexe é tant une clas s e ).

Nature llem e nt, C+ + dispose de l'h é ritage e t m ê m e (depuis la ve rsion 2.0) de possibilités dite s "d'h é ritage
m ultiple" pe rm e ttant à une classe d'h é rite r sim ultané m e nt de plusieurs autre s .

En m atiè re d'entré e s -sortie s , C+ + com porte de nouve lles possibilités bas é e s s ur la notion de "flot". Le urs
avantage s s ur les e ntré e s -sorties de C sont, e n particulie r :

• sim plicité d'utilisation,


• taille m é m oire réduite (on n'introduit q ue ce q ui e s t utile),
• possibilité de leur donne r un s e ns pour les types définis par l'utilisate ur q ue s ont les clas s e s (grâ ce au
m é canism e de surdé finition d'opé rate ur).
Bie n q u'e lles s oie nt lié e s à l'aspect P.O .O ., nous fe rons une prem iè re pré s e ntation de ce s nouve lles
possibilités d'entré e s -sorties dè s le ch apitre III. Ce ci nous perm e ttra de ré aliser rapidem e nt des program m e s
dans l'e s prit du C+ + .

D ans ses derniè re s ve rsions, le C+ + a é té doté de la notion de patron. Elle pe rm e t de définir de s m odè les
utilisables pour gé né re r diffé re nte s clas s e s ou diffé re nte s fonctions q ualifié e s parfois de génériques, m ê m e s i
ce tte gé né ricité n'e s t pas totalem e nt inté grée dans le langage lui-m ê m e com m e c'e s t par e xe m ple le cas ave c
ADA.

Enfin, la norm e ANSI a notablem e nt accru le conte nu de la biblioth è q ue s tandard de C+ + q ui vie nt


com pléte r ce lle du C, toujours disponible. En particulie r, on y trouve des nom bre ux patrons de clas s e s e t de
fonctions perm e ttant de m e ttre e n œuvre les s tructures de données et les algorith m e s les plus usuels, é vitant
ainsi d'avoir à ré inve nte r la roue à la m oindre occasion.
II. LES INCO M PA TIBILITÉS
D E C+ + A VEC LE C ANSI

A priori, le langage C+ + pe ut ê tre considéré com m e une e xte nsion du langage C, te lq u'ile s t défini par la
norm e ANSI. Tout program m e é crit e n C de vrait donc pouvoir ê tre traduit corre cte m e nt par un com pilate ur
C+ + e t son exécution de vrait alors fournir les m ê m e s ré s ultats q ue ce ux obte nus e n utilisant un com pilate ur
C.

Ce point de vue corre s pond e ffe ctive m e nt au souh ait du conce pte ur du langage C+ + . Né anm oins, e n
pratiq ue , un ce rtain nom bre "d'incom patibilité s " ave c le C ANSI ont subsisté , Elles s ont e s s e ntie llem e nt
inh é re nte s à l'e s prit m ê m e dans leq ue lles deux langage s ont é té conçus.

Nous allons décrire ici les incom patibilité s les plus im portante s e n pratiq ue , e n particulie r ce lles q ui s e
ré vé leraie nt q uasim e nt à coup sûr dans la m ise au point de vos prem ie rs program m e s C+ + . A ce propos,
note z q ue nous aurions pu nous conte nte r de "cite r" ce s incom patibilité s . Né anm oins, ce lles -ci sont définie s
par rapport au C ANSI ;e lles conce rne nt, pour la plupart, des possibilité s q ui n'e xistaie nt pas dans la
pre m iè re définition de K e rningh an e t R itch ie e t q ui ne s ont donc pas (e ncore ) re connues de toute s les
im plém e ntations du C. Aussi, en profitons-nous pour vous e xpos e r (ou rappe ler) ce q ue s ont ce s possibilité s
du C ANSI, e n m ê m e te m ps q ue nous vous m ontrons ce q u'e lles s ont deve nue s e n C+ + .

Par ailleurs, q ue lque s autre s incom patibilité s m ine ure s s e ront abordé e s au fildes proch ains ch apitre s ;e lles
s e ront toute s ré capitulées dans l'anne xe B.

1. LES D ÉFINITIO NS D E FO NCTIO NS EN C+ +

Suivant la norm e ANSI, ile xiste e n C de ux façons de définir1 une fonction. Suppos e z, par e xe m ple, q ue
nous ayons à définir une fonction nom m é e fe xple, fournissant une valeur de re tour2 de type double e t
re ce vant deux argum e nts, l'un de type int, l'autre de type double. Nous pouvons, pour ce la, procéder de
l'une des deux façons suivante s :

double fexple (u, v) double fexple (int u, double v)


int u ; {
double v ; ...

1 - Ne confondez pas l
a "dé finition" d'une fonction q ui corre s pond à l
a de s cription, à l
'aide d'instructions C, de "ce q ue fait" une fonction
ave c s a "dé cl
aration" q ui corre s pond à une s im pl
e inform ation (nom de l
a fonction e t, éve ntue l
le m e nt, type des argum e nts e t de l
a val
e ur
de retour) fournie au com pil ate ur.
2 - O n parle é gal
e m e nt de "ré s ul
tat fourni par l
a fonction", de "val
e ur re tourné e "...
8 Program m e r e n langage C+ +
{ ... /* corps de la fonction */
... /* corps de la fonction */ }
}

La pre m iè re form e é tait la s e ule pré vue par la définition initiale de Kernigh an e t R itch ie . La s e conde a é té
introduite par la norm e ANSI q ui n'a, toute fois, pas e xclu l'ancie nne 3.

Le langage C+ + n'acce pte , q uant à lui, q ue la s e conde form e :

double fexple (int u, double v)


{
... /* corps de la fonction */
}

R e m arque :

Com m e e n C ANSI, lors q u'une fonction fournit une valeur de type int, le m ot int pe ut ê tre om is dans
l'e n-tê te . Nous ne vous cons e illons guè re , toute fois, d'e m ploye r ce tte possibilité q ui nuit à la lisibilité des
program m e s .

2. LES PRO TO TYPES EN C+ +

Nous ve nons de voir q ue le C+ + é tait plus re s trictif q ue le C ANSI e n m atiè re de définition de fonctions. Il
e n va de m ê m e pour les déclarations de fonctions. En C ANSI, lors q ue vous utilisiez une fonction q ui
n'avait pas é té définie auparavant dans le m ê m e fich ie r source , vous pouvie z :

• ne pas la déclare r (on considérait alors q ue s a valeur de re tour é tait de type int),
• la déclare r e n ne pré cisant q ue le type de la valeur de re tour, par e xe m ple :
double fexple ;

• la déclare r à l'aide de ce q ue l'on nom m e un "prototype ", par e xe m ple :


double fexple (int, double) :

En C+ + , un appe lde fonction ne s e ra acce pté q ue s i le com pilate ur connaî t le type des argum e nts e t ce lui
de sa valeur de re tour. Ce q ui signifie q ue la fonction e n q ue s tion doit avoir fait l'objet d'une décl aration
sous form e d'un prototype (ou, à la rigue ur, avoir é té pré alablem e nt définie dans le m ê m e fich ie r source 4).

N'oublie z pas q ue , à ch aq ue fois q ue le com pilate ur re ncontre un appe lde fonction, ilcom pare les types des
"argum e nts e ffe ctifs" ave c ce ux de s argum e nts m ue ts corre s pondants 5. En cas de diffé re nce , ilm e t e n place
les conve rsions nécessaires pour que la fonction re çoive des argum e nts du bon type . Le s conve rsions
possibles ne s e lim ite nt pas aux "conve rsions non dégradante s " (te lles q ue , par e xe m ple, ch ar -> double,
int -> long). En e ffe t, e lles com porte nt toute s les conve rsions autoris é e s lors d'une affe ctation. O n pe ut
donc y re ncontre r de s "conve rsions dégradante s " te lles q ue , par e xe m ple, int -> ch ar, double -> float,
double -> int, ...

Voici un e xe m ple illustrant ce point :

3 - D ans le s e ulbut de rendre com patibl e ave c l


a norm e, des ancie ns program m e s ou des anciens com pil ate urs.
4 - Toute fois, m ê m e dans ce cas, l
e prototype reste cons e ill
é, notam m e nt pour é vite r tout problè m e e n cas d'écl ate m e nt du fich ie r s ource.
5 - Nous supposons que l e com pil
ate ur connaî tle type des argum e nts de l
a fonction, ce q ui e s t toujours l e cas e n C+ + .
II. Le s incom patibilité s d e C+ + ave c le C ANSI 9
_______________________________________________________________________________
______

double fexple (int, double) ; /* déclaration de fexple */


.....
main()
{
int n ;
char c ;
double z, res1, res2, res3 ;
.....

res1 = fexple (n, z) ; /* appel "normal" - aucune conversion */


res2 = fexple (c, z) ; /* conversion, avant appel, de c en int */
res3 = fexple (z, n) ; /* conversion, avant appel, de z en int */
/* et de n en double */
.....
}
_______________________________________________________________________________
______

Exe m ple de conve rsions de type s lors d e l'appe ld'une fonction

R e m arques

1) Lors q ue la définition de la fonction e t sa déclaration (sous form e d'un prototype ) figure nt dans le
m ê m e fich ie r source , le com pilate ur e s t e n m e s ure de vé rifie r la coh é re nce e ntre l'e n-tê te de la
fonction e t le prototype . S'iln'y a pas corre s pondance (e xacte ce tte fois) de type , on obtie nt une
e rre ur de com pilation. Voici un e xe m ple corre ct :
double fexple (int, double) ; /* déclaration de fexple */
main()
{ .....
}
/* définition de fexple */
double fexple (int u, double v)
{ /* corps de la fonction */
}

En re vanch e , ce lui-ci conduit à une e rre ur de com pilation :


double fexple (int, float) ; /* déclaration de fexple */
main()
{ .....
}
/* définition de fexple */
double fexple (int u, double v)
{ /* corps de la fonction */
}

Bie n e nte ndu, si la définition de la fonction e t sa déclaration (donc son utilisation6) ne figure nt pas
dans le m ê m e fich ie r source , aucun contrôle ne pe ut plus ê tre e ffe ctué par le com pilate ur. En gé né ral,

6 - A m oins q u'on ne l
'ait décl
arée, sans l
'util
iser, ce qui arrive fré q ue m m e nt l
ors q ue l
'on fait appe là des fich ie rs e n-tê te.
10 Program m e r e n langage C+ +
à partir du m om e nt où l'on doit utiliser une fonction e n de h ors du fich ie r où e lle e s t définie (ou, à
partir de plusieurs fich ie rs source diffé re nts), on place s on prototype dans un fich ie r e n-tê te ;ce
dernie r e s t incorporé , e n cas de besoin, par la dire ctive #include , ce q ui é vite tout ris q ue de faute
d'écriture du prototype .

2) Com m e e n C, la "porté e " du prototype e s t lim ité e à :


- la partie du fich ie r source s itué e à la suite de sa déclaration, si elle figure à un nive au global,
c'e s t-à -dire e n de h ors de toute définition de fonction7 ;c'é tait le cas du prototype de fe xple dans
nos précédents e xe m ples ,
- la fonction dans laq ue lle ilfigure , dans le cas contraire .

3) D e m aniè re analogue à ce q ui s e produit pour l'e n-tê te d'une fonction, lors q u'un prototype ne pré cis e
pas le type de la valeur de re tour, com m e dans :
bizarre (int, float, char) ;

C+ + considérera qu'ils'agit, par dé faut, du type int. Ainsi, le prototype pré cédent e s t-ilé q uivalent
à :
int bizarre (int, float, char) ;

Nous vous cons e illons d'évite r ce tte possibilité q ui nuit à la lisibilité des program m e s .

4) Le prototype pe ut pre ndre une form e plus é toffé e 8, dans laq ue lle figure nt é galem e nt des nom s
d'argum e nts. Ainsi, le prototype de notre fonction fe xple du début du paragraph e 2 pourrait
é galem e nt s'é crire :
double fexple (int a, double x) ;

ou e ncore :
double fexple (int u, double v) ;

D ans ce cas, les nom s d'argum e nts (a e t x dans le pre m ie r e xe m ple, u e t v dans le s e cond) ne joue nt
aucun rôle. Ils sont pure m e nt e t sim plem e nt ignorés du com pilate ur, de s orte q ue ce s prototype s
re s te nt parfaite m e nt é q uivalents aux pré cédents. O n pe ut trouve r un inté rê t à ce tte possibilité lors q ue
l'on souh aite accom pagne r ce prototype de com m e ntaires décrivant le rôle des diffé re nts argum e nts
(ce la pe ut s'avé re r pratiq ue dans le cas où l'on place ce prototype dans un fich ie r e n-tê te ).

5) Ce rtains com pilate urs s e m blent ne pas im pos e r l'e m ploi de prototype s . En ré alité , ils fabriq ue nt
autom atiq ue m e nt un prototype à la re ncontre du prem ie r appe ld'une fonction e n te nant com pte de ses
argum e nts e ffe ctifs. Une te lle dém arch e q ui s e m ble partir d'un bon se ntim e nt (allége r la tâ ch e de
l'utilisate ur) pe ut s e ré vé ler dé s astre us e . Actue llem e nt, toute fois, la te ndance e s t de n'effe ctue r ce
"prototypage autom atiq ue " q ue s ur de m ande e xplicite de l'utilisate ur ou dans le cas de com pilation de
program m e s é crits e n C (pour é vite r leur m odification systé m atiq ue ).

7 - Y com pris la fonction m ain.


8 - Nom m é e parfois prototype com pl
e t ;l
'autre é tant nom m é e prototype réduit.
II. Le s incom patibilité s d e C+ + ave c le C ANSI 11
3. ARGUM ENTS ET VA LEUR D E RETO UR D 'UNE FO NCTIO N

3.1 Points com m uns à C e t C+ +

En C+ + , com m e e n C ANSI, les argum e nts d'une fonction ainsi que la valeur de re tour pe uve nt :

• ne pas e xiste r,
• ê tre une valeur "scalaire ", d'un de s types de bas e (caractè re s , e ntie rs, flottants, pointe urs),
• ê tre une valeur d'un type s tructure .
La derniè re possibilité a é té introduite par la norm e ANSI. Nous ve rrons q u'e n C+ + , e lle s e gé né ralise aux
obje ts d'un type clas s e . Pour l'instant, notons sim plem e nt q u'ilsubsiste e n C+ + , com m e e n C ANSI, une
disparité e ntre les tableaux e t les s tructure s puis q ue :

• ile s t possible de transm e ttre la valeur d'une s tructure , aussi bien en argum e nt q u'e n valeur de re tour,
• iln'e s t pas possible de faire de m ê m e ave c les tableaux.
Note z q u'ils'agit là d'une disparité difficile à ré s orbe r, com pte te nu de la volonté de re ndre é q uivalents le
nom d'un tableau e t son adre s s e .

Bie n e nte ndu, ile s t toujours possible de transm e ttre l'adresse d'un tableau, m ais ce tte re m arq ue vaut
é galem e nt pour une s tructure .

3.2 D iffé re nce s e ntre C e t C+ +

En fait, les diffé re nce s ne porte nt q ue s ur la syntaxe d e s e n-tê te s e t des prototypes des fonctions, e t ce ci
uniq ue m e nt dans deux cas précis :

• fonctions sans argum e nts,


• fonctions sans valeur de re tour.

a)Fonctions s ans argum e nts


Alors q u'e n C ANSI on pe ut e m ploye r le m ot void pour dé finir (e n-tê te ) ou dé clare r (prototype ) une fonction
sans argum e nt, e n C+ + , on fournit une "liste vide". Ainsi, là où e n C, on dé clarait :

float fct (void) ;

on dé clare ra, e n C+ + :

float fct ( ) ;

b)Fonctions s ans val


e ur de re tour
En C ANSI, on peut utiliser le m ot void pour dé finir (e n-tê te ) ou dé clare r (prototype ) une fonction sans
valeur de re tour. En C+ + , on doit absolum e nt le faire , com m e dans ce t e xe m ple :

void fct (int, double) ;

La déclaration :

fct (int, double) ;


12 Program m e r e n langage C+ +

conduirait C+ + à considérer que fct fournit une valeur de re tour de type int (voir la re m arq ue du
paragraph e 1).

4. LE QUALIFICA TIF CO NST

La norm e C ANSI a introduit le q ualificatif cons t. Ilpe rm e t de spécifie r q u'un sym bole corre s pond à
"q ue lque ch os e " dont la valeur ne doit pas ch ange r, ce q ui pe ut pe rm e ttre au com pilate ur de s ignaler les
te ntatives de m odification (lors q ue ce la lui e s t possible !).

Ce ci re s te vrai e n C+ + . Ce pe ndant, un ce rtain nom bre de diffé re nce s im portante s apparais s e nt, au nive au
de la portée du sym bole conce rné e t de son utilisation dans une expression.

4.1 Porté e

Lors q ue cons t s'appliq ue à des variables locales autom atiq ue s , aucune diffé re nce n'e xiste e ntre C e t C+ + ,
la porté e é tant lim ité e au bloc ou à la fonction conce rné e par la déclaration.

En re vanch e , lors q ue cons t s'appliq ue à une variable globale, C+ + lim ite la portée du sym bole au fich ie r
source conte nant la déclaration (com m e s 'ilavait re çu l'attribut s tatic) ;C ne faisait aucune lim itation.

Pourq uoi ce tte diffé re nce ?La principale raison ré s ide dans l'idé e q u'ave c la rè gle adopté e par C+ + il
devie nt plus facile de re m place r ce rtaine s instructions #de fine par des déclarations de constante s ;Ainsi, là
où e n C vous procédiez de ce tte façon :

#define N 8 #define N 3
..... .....

fichier 1 fichier 2

vous pouve z, e n C+ + , procéder ainsi :

const int N = 8 ; const int N = 3 ;


..... .....

fichier 1 fichier 2

En C, vous aurie z obte nu une e rre ur au m om e nt de l'édition de lie ns. Vous aurie z pu l'é vite r :

• soit e n dé clarant N s tatic, dans au m oins un des deux fich ie rs (ou, m ie ux, dans les deux) :
static const int N = 8 ; static const int N = 3
;

Ce ci aurait alors é té parfaite m e nt é q uivalent à ce q ue fait C+ + ave c les pre m iè res déclarations ;
• soit, si N avait e u la m ê m e valeur dans les deux fich ie rs, e n plaçant, dans le s e cond fich ie r :
extern const int N ;

m ais, dans ce cas, ilne s e s e rait plus agi d'un re m place m e nt de #de fine .
II. Le s incom patibilité s d e C+ + ave c le C ANSI 13
4.2 Util
is ation dans une e xpre s s ion

R appe lons q ue l'on nom m e "e xpre s s ion constante " une e xpre s s ion dont la valeur e s t calculée lors de la
com pilation. Ainsi, ave c :

const int p = 3 ;

l'e xpre s s ion :

2 * p * 5

n'est pas une expression constante en C al


ors qu'el
le est une expression constante en C+ + .

Ce point e s t particuliè re m e nt s e nsible dans les déclarations de tableaux (statiq ue s ou autom atiq ue s ) dont les
dim e nsions doive nt obligatoire m e nt ê tre d e s e xpre s s ions constante s (m ê m e pour les tableaux autom atiq ue s ,
le com pilate ur doit connaî tre la taille à ré s e rve r sur la pile !). Ainsi, les instructions :

const int nel = 15 ;


.....
double t1 [nel + 1], t2[2 * nel] [nel] ;

s e ront acce pté e s e n C+ + , alors q u'e lles é taie nt re fus é e s e n C.

R e m arques :

1) En toute rigue ur, la possibilité q ue nous ve nons de décrire ne constitue pas une incom patibilité e ntre C e t
C+ + puis q u'ils'agit d'une facilité s upplém e ntaire .

2) D 'une m aniè re gé né rale, C+ + a é té conçu pour lim ite r au m axim um l'e m ploi des directives du
pré proce s s e ur (on de vrait pouvoir s e conte nte r de #include e t des directives d'inclusion conditionne lle).
Le s m odifications apporté e s au q ualificatif cons t vont e ffe ctive m e nt dans ce s e ns 9 .

5. CO M PA TIBILITÉ ENTRE LE TYPE VO ID *


ET LES AUTRES PO INTEURS

En C ANSI, le "type gé né riq ue " void *e s t com patible ave c les autre s type s pointe urs, e t ce ci dans les deux
s e ns. Ainsi, ave c ces déclarations :

void * gen ;
int * adi ;

Ces deux affe ctations sont légales e n C ANSI :

gen = adi ;
adi = gen ;

Elles font inte rve nir de s "conve rsions im plicite s ", à savoir :

9 - Encore faut-ilq ue l
e program m e ur C+ + acce pte de ch ange r l
e s h abitudes qu'ilavait dû prendre en C (faute de pouvoir faire
autre m e nt) !
14 Program m e r e n langage C+ +
int *-> void * pour la pre m iè re ,
void *-> int * pour la s e conde .
En C+ + , s e ule la conve rsion d'un pointe ur q ue lconq ue e n void * pe ut ê tre im plicite . Ainsi, ave c les
déclarations précédente s , s e ule l'affe ctation

gen = adi ;

e s t acce pté e . Bie n e nte ndu, ilre s te toujours possible de faire appe le xplicite m e nt à la conve rsion void *->
int *e n utilisant l'opé rate ur de "cast" :

adi = (int *) gen ;

R e m arque :

O n pe ut dire q ue la conve rsion d'un pointe ur de type q ue lconq ue e n void *re vie nt à ne s 'inté re s s e r q u'à
l'adre s s e corre s pondant au pointe ur, e n ignorant son type . La conve rsion inve rs e , e n re vanch e , de void *
e n un pointe ur de type donné, revie nt à associe r (pe ut-ê tre arbitraire m e nt !) un type à une adre s s e .
M anife s te m e nt, ce tte deuxiè m e possibilité e s t plus dange re us e q ue la pre m iè re ;e lle pe ut m ê m e oblige r
le com pilate ur à introduire des m odifications de l'adresse de départ, dans le s e ul but de re s pe cte r
ce rtaine s contraintes d'aligne m e nt (lié e s au type d'arrivé e ). C'e s t la raison pour laq ue lle ce tte conve rsion
ne fait plus partie des conve rsions im plicite s e n C+ + .
III. LES NO UVELLES PO SSIBILITÉS
D 'ENTRÉES-SO RTIES
CO NVERSA TIO NNELLES
D E C+ +

C+ + dispose de toute s les routine s offe rte s par la "biblioth è q ue s tandard" du C ANSI. M ais ilcom porte
é galem e nt de nouve lles possibilités d'entré e s -sortie s . Ce lles -ci re pos e nt sur les notions de "flots" e t de
"surdéfinition d'opé rate ur" q ue nous n'aborde rons q u'ulté rie ure m e nt. Toute fois, ilne s e rait pas judicie ux
d'atte ndre q ue vous ayez étudié ces diffé re nts points pour com m e nce r à é crire des program m e s com plets,
rédigés dans l'e s prit de C+ + . C'e s t pourq uoi nous allons dans ce ch apitre vous présente r, de m aniè re as s e z
inform e lle, ce s nouve lles possibilités d'entré e s -sortie s e n nous lim itant ce pe ndant à ce q ue nous nom m ons
l'aspect "conve rsationne l" (lecture s ur "l'e ntré e s tandard", é criture s ur la "sortie s tandard").

1. LES NO UVELLES ENTRÉES-SO RTIES EN C+ +

Le s "routine s " (fonctions e t m acros) de la "biblioth è q ue s tandard" du C ANSI1, donc, e n particulie r, ce lles
re lative s aux e ntré e s -sortie s , sont utilisables e n C+ + ;pour ce faire , ilvous suffit d'inclure les fich ie rs e n-
tê te h abitue ls, pour obte nir les prototype s e t autres déclarations néce s s aire s à leur bonne utilisation.

M ais C+ + dispose en plus de possibilités d'entré e s -sortie s ayant les caracté ristiq ue s s uivante s :

• sim plicité d'utilisation : e n particulie r, on pourra souve nt s'y affranch ir de la notion de "form at", si ch è re
aux fonctions de la fam ille printf ou s canf,
• dim inution de la taille du "m odule obje t2" corre s pondant : alors q ue , par e xe m ple, un s e ulappe lde printf
introduit obligatoire m e nt, dans le m odule obje t, un e ns e m ble d'instructions e n couvrant toute s les
é ve ntualité s , l'e m ploi de s nouve lles possibilité s offe rte s par C+ + n'am è ne ra q ue les s e ules instructions
né ce s s aire s ,
• possibilité s e xte nsibles aux type s q ue vous définire z vous-m ê m e s ous form e de clas s e s .
Voyons donc, dè s m ainte nant, com m e nt utiliser ces possibilités dans le cas de l'e ntré e s tandard ou de la
sortie s tandard.

1 - L'un des grands m é rites de ce tte norm e e s t de définir, outre l


e l
angage C l
ui-m ê m e, l
e s caracté ris tiq ues d'un certain nom bre de
routine s form ant ce q ue l
'on nom m e l
a "bibl
ioth è q ue s tandard".
2 - Ensem bl e d'instructions, en l
angage m ach ine, résul tant de l
a traduction d'un fich ie r s ource.
16 Program m e r e n langage C+ +
2. ÉCRITURE SUR LA SO RTIE STANDARD

2.1 Q u e l
q ue s e xe m pl
es

Avant d'étudie r les diffé re nte s possibilité s offe rte s par C+ + , e xam inons q ue lque s e xe m ples .

a)Exe m pl
e 1
Voye z ce pre m ie r cas, trè s sim ple, accom pagné de son e xe m ple d'exécution :

_______________________________________________________________________________
______

#include <iostream.h> /* indispensable pour utiliser cout


*/
/* suivant l'implémentation : on peut utiliser
<iostream> */
/* ou <iostream.hpp> <iostream.hxx> ...
*/
main()
{
cout << "bonjour" ;
}
_______________________
bonjour
_______________________________________________________________________________
______

Ecriture e n C+ + (1)

Note z, tout d'abord, q ue nous avons inclus un fich ie r e n-tê te nom m é iostre am .h ;son im plém e ntation pe ut
varie r ave c les im plém e ntations de C+ + ;dans l'ave nir, on de vrait plutôt re ncontre r iostre am , sans
e xte nsion. Ce fich ie r contie nt toute s les déclarations néce s s aire s à l'utilisation de s e ntré e s -sortie s s pé cifiq ue s
au C+ + .

L'inte rpré tation dé taillée d e l'instruction :

cout << "bonjour" ;

né ce s s ite rait des connaissance s q ui ne s e ront introduite s q u'ulté rie ure m e nt. Pour l'instant, ilvous suffit
d'adm e ttre les points suivants :

• cout désigne un "flot de sortie " prédéfini, associé à l'e ntré e s tandard du C (s tdout),
• < < e s t un "opé rate ur" dont l'opé rande de gauch e (ici cout) e s t un flot e t l'opé rande de droite une
e xpre s s ion de type q ue lconq ue . L'instruction pré cédente pe ut ê tre inte rpré té e com m e ce ci : le flot cout
re çoit la valeur "bonjour".

b)Exe m pl
e 2
_______________________________________________________________________________
______
III. Le s nouve lles possibilités d'entré e s -s ortie s conve rs ationne lles d e C+ + 17
#include <iostream.h>
main()
{
int n = 25 ;
cout << "valeur : " ;
cout << n ;
}
_______________________
valeur : 25
_______________________________________________________________________________
______

Ecriture e n C+ + (2)

Ilre s s e m ble au pré cédent, m ais, ce tte fois, vous constate z q ue nous avons utilisé le m ê m e opé rate ur < <
pour e nvoye r sur le flot cout, d'abord une inform ation de type ch aî ne , e nsuite une inform ation de type
e ntie r. Le rôle de l'opé rate ur < < e s t m anife s te m e nt diffé re nt dans les deux cas : dans le pre m ie r, on a
transm is les caractè res de la ch aî ne , dans le s e cond, on a procédé à un "form atage 3" pour "conve rtir" une
valeur binaire e ntiè re e n une s uite de caractè re s . Ce tte possibilité d'attribue r plusieurs significations à un
m ê m e opé rate ur corre s pond à ce q ue l'on nom m e e n C+ + , la "surdéfinition d'opé rate ur" (q ue nous
aborde rons e n dé taildans le ch apitre IX).

c)Exe m pl
e 3
Jus q u'ici, nous avons é crit une instruction diffé re nte pour ch aq ue inform ation transm ise au flot cout. En fait,
les deux instructions :

cout << "valeur :" ;


cout << n ;

pe uve nt s e conde ns e r e n une s e ule :

cout << "valeur :" << n ;

Là e ncore , l'inte rpré tation e xacte de ce tte possibilité s e ra fournie ulté rie ure m e nt m ais, d'ore s e t déjà , nous
pouvons dire qu'elle ré s ide dans deux points :

• l'opé rate ur < < e s t (com m e l'opé rate ur "original") associatif de gauch e à droite ,
• le ré s ultat fourni par l'opé rate ur < < , q uand ilre çoit un flot e n pre m ie r opé rande e s t ce m ê m e flot,
aprè s q u'ilait re çu l'inform ation conce rné e .
Ainsi, l'instruction pré cédente e s t-e lle é q uivalente à :

(cout << "valeur :") << n ;

Ce lle-ci pe ut s'inte rpré te r com m e ce ci :

• dans un pre m ie r te m ps, le flot cout re çoit la ch aî


ne "bonjour",
• dans un deuxiè m e te m ps, le flot (cout < < "bonjour"), c'e s t-à -dire le flot cout augm e nté de "bonjour",
re çoit la valeur de n.

3 - Ici, ce form atage e s t im pl


icite ;dans l
e cas de printf, on l
'aurait e xpl
icité (%d).
18 Program m e r e n langage C+ +
Note z bie n q ue , si ce tte inte rpré tation ne vous paraî
t pas é vidente , ilvous suffit d'adm e ttre pour l'instant
q u'une instruction te lle q ue :

cout << ----- << ----- << ----- << ----- ;

pe rm e t d'envoye r sur le flot cout les inform ations sym bolisées par de s traits, dans l'ordre où e lles
apparais s e nt.

2.2 Le s pos s ibil


ité s d'é criture s ur cout

Nous ve nons de voir de s e xe m ples d'écriture de ch aî ne s e t d'entie rs. D'une m aniè re gé né rale, vous pouve z
utiliser l'opé rate ur < < pour e nvoye r sur cout la valeur d'une e xpre s s ion de l'un de s type s s uivants :

• type de bas e q ue lconq ue (caractè re , e ntie r signé ou non, flottant),


ne de caractè re s (ch ar *)4 : on obtie nt l'affich age des caractè re s constituant la ch aî
• ch aî ne ,
• pointe ur, autre q ue ch ar *5 : on obtie nt l'adre s s e corre s pondante (e n h e xadé cim al) ;si on ve ut obte nir
l'adresse d'une ch aî ne de caractè re s e t non les caractè re s q u'e lle contie nt, on pe ut toujours conve rtir ce tte
ch aî
ne (de type ch ar *) e n void *.
Voici un e xe m ple de program m e illustrant ce s possibilités d'écriture s ur cout ;ile st accom pagné d'un
e xe m ple d'exécution dans un environne m e nt C+ + Builder.

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
int n = 25 ; long p = 250000; unsigned q = 63000 ;
char c = 'a' ;
float x = 12.3456789 ; double y = 12.3456789e16 ;
char * ch = "bonjour" ;
int * ad = & n ;

cout << "valeur de n : " << n << "\n" ;


cout << "valeur de p : " << p << "\n" ;
cout << "caractère c : " << c << "\n" ;
cout << "valeur de q : " << q << "\n" ;
cout << "valeur de x : " << x << "\n" ;
cout << "valeur de y : " << y << "\n" ;
cout << "chaîne ch : " << ch << "\n" ;
cout << "adresse de n : " << ad << "\n" ;
cout << "adresse de ch : " << (void *) ch << "\n" ;
}
_______________________
valeur de n : 25
valeur de p : 250000
caractère c : a
valeur de q : 63000
valeur de x : 12.345679

4 - Le s ve rsions de C+ + anté rie ure s à l a 2.0 traitaie nt un caractè re com m e un e ntie r e t, par s uite, en affich aie nt l
e code.
5 - Ce tte possibilité n'e xis tait pas dans l
e s ve rs ions de C+ + anté rie ure s à l
a 2.0.
III. Le s nouve lles possibilités d'entré e s -s ortie s conve rs ationne lles d e C+ + 19
valeur de y : 1.234567e+17
chaîne ch : bonjour
adresse de n : 0x19c7fff4
adresse de ch : 0x19c700b4
_______________________________________________________________________________
______

Le s possibilités d'écriture s u r cout

R e m arque :

Note z q ue C+ + a décidé d'affich e r la ch aî ne s itué e à l'adre s s e indiq ué e par un pointe ur de type ch ar *


e t non l'adre s s e e lle-m ê m e . Si te ln'avait pas é té le cas, le com porte m e nt d'une instruction aussi banale
q ue :
cout << "bonjour" ;

aurait é té bien déroutant.

3. LECTURE SUR L'ENTRÉE STANDARD

3.1 Introduction

D e m ê m e q u'ile xiste un flot de sortie prédéfini cout, associé à la sortie s tandard du C (s tdout), ile xiste un
flot d'entré e prédéfini, nom m é cin, associé à l'e ntré e s tandard du C (s tdin). De m ê m e q ue l'opé rate ur < <
pe rm e t d'envoye r de s inform ations sur un flot de sortie (donc, e n particulie r, sur cout), l'opé rate ur > >
pe rm e t de re ce voir6 de l'inform ation e n prove nance d'un flot d'entré e (donc, e n particulie r, de cin).

Par e xe m ple, l'instruction (n é tant de type int) :

cin >> n ;

dem ande ra de lire "des caractè re s " sur le flot cin e t de les "conve rtir" e n une valeur de type int.

D 'une m aniè re gé né rale :

cin >> n >> p ;

s e ra é q uivalent à :

(cin >> n) >> p ;

Pour donne r une inte rpré tation im agé e (e t pe u form e lle) analogue à ce lle fournie pour cout, nous pouvons
dire q ue la valeur de n e s t d'abord e xtraite du flot cin ;e nsuite , la valeur de p e s t e xtraite du flot cin > > n
(com m e pour < < , le ré s ultat de l'opé rate ur > > e s t un flot), c'e s t-à -dire de ce q u'e s t deve nu le flot cin,
aprè s q u'on e n a e xtrait la valeur de n.

6 - O n dit aussi extraire.


20 Program m e r e n langage C+ +
3.2 Le s pos s ibil
ité s de l
e cture s ur cin

D 'une m aniè re gé né rale, dans toute s les ve rsions de C+ + , vous pouve z utiliser l'opé rate ur > > pour
accéder à des inform ations de type de bas e q ue lconq ue (signé ou non pour les type s e ntie rs) ou à des ch aî
ne s
de caractè re s 7 (ch ar *).

Par ailleurs, une bonne part des conve ntions d'analyse des caractè re s lus sont les m ê m e s q ue ce lles
e m ployé e s par s canf. Ainsi :

• les diffé re nte s inform ations sont s é paré e s par un ou plusieurs caractè re s parm i ce ux-ci8 : e s pace ,
tabulation h orizontale (\t) ou ve rticale (\v), fin de ligne (\n), re tour ch ariot (\r) ou ch ange m e nt de page
(\f)9 .
• un caractè re "invalide" pour l'usage q u'on doit e n faire (un point pour un e ntie r, une lettre pour un
nom bre ...) arrê te l'e xploration du flot, com m e s i l'on avait re ncontré un s é parate ur ;m ais ce caractè re
invalide sera à nouve au pris e n com pte lors d'une proch aine lecture .
En re vanch e , contraire m e nt à ce q ui s e produisait pour s canf, la lecture d'un caractè re s ur cin com m e nce par
"saute r les s é parate urs" ;aussi n'est-il pas possible de lire directe m e nt ce s caractè re s . Nous ve rrons
com m e nt y parve nir dans le ch apitre consacré aux flots.

3.3 Exe m pl
es

Nous vous proposons diffé re nts program m e s , accom pagnés d'exem ples d'exécution (ré alisés ave c le clavie r
e t l'é cran com m e e ntré e s -sortie s s tandard) illustrant les possibilités de lecture s ur cin.

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
int n ; float x ;
char t[81] ;
do
{ cout << "donnez un entier, une chaîne et un flottant : " ;
cin >> n >> t >> x ;
cout << "merci pour " << n << ", " << t << " et " << x << "\n" ;
}
while (n) ;
} _______________________

donnez un entier, une chaîne et un flottant : 15 bonjour 8.25


merci pour 15, bonjour et 8.25
donnez un entier, une chaîne et un flottant : 15

bonjour

8.25

7. Iln'e s t pas pré vu de l


ire l
a val e ur d'un pointe ur ;e n pratiq ue, cel a n'aurait guè re d'inté rê t e t, de pl
us, com porte rait de grand risques.
8 - On le s appe lle parfois des "e s paces-bl ancs " (de l'anglais, "w h ite s pace s ").
9 - En pratiq ue, on expl
oite e s s e ntie l
le m e nt l
'espace et l
a fin de l
igne (dans l
e s e nvironne m e nts D O S, toute fois, l
e re tour ch ariot pe ut
apparaî
tre e n pl
us de l
a fin de l
igne, m ais on ne s'en aperçoit q ue l
ors q u'on l
it des caractè re s ).
III. Le s nouve lles possibilités d'entré e s -s ortie s conve rs ationne lles d e C+ + 21
merci pour 15, bonjour et 8.25
donnez un entier, une chaîne et un flottant : 0 bye 0
merci pour 0, bye et 0
_______________________________________________________________________________
______

Usage classique des séparate urs

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
char tc[81] ; // pour conserver les caractères lus sur cin
int i = 0 ; // position courante dans le tableau c

cout << "donnez une suite de caractères terminée par un point \n" ;
do
cin >> tc[i] ; // attention, pas de test de débordement dans tc
while (tc[i++] != '.') ;
cout << "\n\nVoici les caractères effectivement lus : \n" ;

i=0 ;
do
cout << tc[i] ;
while (tc[i++] != '.') ;
}
_______________________

donnez une suite de caractères terminée par un point


Voyez comme

C++
pose quelques problèmes
lors de la lecture d'une

"suite de caractères"
.

Voici les caractères effectivement lus :


VoyezcommeC++posequelquesproblèmeslorsdelalectured'une"suitedecaractères".
_______________________________________________________________________________
______

Quand on ch e rch e à lire une suite de caractè re s

_______________________________________________________________________________
______

#include <iostream.h>
main()
{ int n ;
do
22 Program m e r e n langage C+ +
{ cout << "donnez un nombre entier : " ;
cin >> n ;
cout << "voici son carré : " << n*n << "\n" ;
}
while (n) ;
} _______________________

donnez un nombre entier : 3


voici son carré : 9
donnez un nombre entier : à
voici son carré : 9
donnez un nombre entier : voici son carré : 9
donnez un nombre entier : voici son carré : 9
^C
_______________________________________________________________________________
______

Boucle infinie s u r un caractè re invalide

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
int n, p ;
cout << "donnez une valeur pour n : " ;
cin >> n ;
cout << "merci pour " << n << "\n" ;
cout << "donnez une valeur pour p : " ;
cin >> p ;
cout << "merci pour " << p << "\n" ;
} _______________________
donnez une valeur pour n : 12 25
merci pour 12
donnez une valeur pour p : merci pour 25
_______________________________________________________________________________
______

Quand le clavie r e t l'écran se m blent m alsynch ronis é s


IV. LES SPÉCIFICITÉS D U C+ +

Com m e nous l'avons dit dans le pre m ie r ch apitre , C+ + dispose d'un certain nom bre de spé cificité s q ui ne
sont pas vé ritablem e nt axé e s s ur la P.O .O . Ils'agit e s s e ntie llem e nt des suivante s :

• nouve lle form e de com m e ntaire (e n fin de ligne ),


• e m place m e nt libre des déclarations,
• notion de ré fé re nce ,
• argum e nts par dé faut dans les déclarations des fonctions,
• surdéfinition de fonctions,
• opé rate urs ne w e t de lete ,
• fonctions "e n ligne " (inline ).
D 'une m aniè re gé né rale, ce s possibilité s s e ront, pour la plupart, souve nt utilisées conjointe m e nt ave c ce lles
de P.O .O . C'e s t ce q ui justifie q ue nous vous les e xposions dè s m ainte nant.

Note z q ue le C+ + introduit é galem e nt de nouve aux opé rate urs de cas t ;m ais com m e ce rtains aspects
inte rfè re nt ave c la notion d'obje t e t d'identification dynam iq ue de type lors de l'e xé cution, ils fe ront l'obje t
d'une pré s e ntation s é parée dans l'anne xe C.

1. LE CO M M ENTA IRE D E FIN D E LIGNE

En C ANSI, un com m e ntaire pe ut ê tre introduit e n n'im porte q ue le ndroit où un e s pace e s t autoris é 1 e n le
faisant pré céder de /*e t suivre de */. Ilpe ut alors é ve ntue llem e nt s'é te ndre s ur plusieurs ligne s .

En C+ + , vous pouve z, en outre, utiliser des "com m e ntaires de fin de ligne " e n introduisant les deux
caractè re s : //. Dans ce cas, tout ce q ui e s t situé e ntre // e t la fin de la ligne e s t un com m e ntaire . Note z q ue
ce tte nouve lle possibilité n'apporte q u'un surcroî t de confort e t de sécurité ;e n e ffe t, une ligne te lle q ue :

cout << "bonjour\n" ; // formule de politesse

pe ut toujours ê tre é crite ainsi :

1 - D onc, e n pratiq ue, n'im porte où, pourvu q u'on ne "coupe pas e n deux" un identificate ur q ue l
conq ue ou une ch aî
ne cons tante.
24 Program m e r e n langage C+ +
cout << "bonjour\n" ; /*formule de politesse*/

Vous pouve z m ê ler (volontaire m e nt ou non !) les deux form ules . Dans ce cas, note z q ue , dans :

/* partie // partie */ partie


1 2 3

le com m e ntaire "ouve rt" par /* ne s e te rm ine q u'au proch ain */ ;donc partie 1 e t partie 2 sont des
com m e ntaire s , tandis q ue partie 3 e s t considérée com m e apparte nant aux instructions.

D e m ê m e , dans :

partie // partie /* partie */ partie


1 2 3 4

le com m e ntaire introduit par // s'é te nd jus q u'à la fin de la ligne . Il"couvre " donc partie 2, partie 3 e t partie 4.

R e m arques :

1) Le com m e ntaire de fin de ligne constitue le s e ulcas où la fin de ligne joue un rôle s ignificatif autre q ue
ce lui d'un sim ple s é parate ur.
2) Si l'on utilise systé m atiq ue m e nt le com m e ntaire de fin de ligne , on pe ut alors faire appe là /*e t * pour
inh iber un ensem ble d'instructions (conte nant é ve ntue llem e nt des com m e ntaire s ) e n ph ase de m ise au
point.

2. D ÉCLARATIO NS ET INITIA LISATIO NS

2.1 Rè gl
e s gé né ral
es

C+ + s'avè re plus souple q ue le C ANSI e n m atiè re de déclarations. Plus précisém e nt, e n C+ + , iln'e s t
plus obligatoire de re groupe r au début les déclarations e ffe ctué e s au s e in d'une fonction ou au s e in d'un
bloc. Ce lles -ci pe uve nt ê tre e ffe ctué e s où bon vous s e m ble, pour pe u q u'e lles apparais s e nt avant q ue l'on e n
ait besoin : leur porté e re s te lim ité e à la partie du bloc ou de la fonction suivant leur dé claration.

Par ailleurs, les e xpre s s ions utilisées pour initialiser une variable s calaire pe uve nt ê tre q ue lconq ue s , alors
q u'e n C e lles ne pe uve nt faire inte rve nir q ue des variables dont la valeur e s t connue dè s l'e ntrée dans la
fonction conce rné e .

Voici un e xe m ple incorre ct e n C ANSI e t acce pté e n C+ + :

main()
{
int n ;
.....
n = ...
.....
int q = 2*n - 1 ;
.....
}
IV. Le s s pécificités du C+ + 25
La déclaration "tardive " d e q pe rm e t de l'initialiser 2 ave c une e xpre s s ion dont la valeur n'é tait pas connue
lors de l'e ntrée dans la fonction (ici m ain).

2.2 Cas d e s ins tructions s tructuré e s

L'instruction suivante e s t acce pté e e n C+ + :

for (int i=0 ; ... ; ...)


{
.....
}

Là e ncore , la variable i a é té déclaré e s e ulem e nt au m om e nt où l'on e n avait besoin. Sa porté e e s t, d'aprè s la


norm e , lim ité e au bloc ré git par l'instruction for. O n note ra q u'il n'e xiste aucune façon d'é crire des
instructions é q uivalente s e n C.

Ce tte possibilité s 'appliq ue à toute s les instructions structuré e s , c’


e s t-à -dire aux instructions for, s w itch ,
w h ile e t do...w h ile.

R e m arque im portante :

Le rôle de ces déclarations à l'inté rie ur d'instructions structuré e s n'a é té fixé q ue tardive m e nt par la
norm e ANSI. D ans les ve rsions anté rie ure s , ce ge nre de déclaration é tait, ce rte s , autoris é m ais, tout s e
passait com m e s i e lle figurait à l'e xté rie ur du bloc ;ainsi, l'e xe m ple pré cédent é tait inte rpré té com m e si
l'on avait é crit :
int i ;
for (i=0 ; ... ; ... )
{
.....
}

3. LA NOTIO N D E RÉFÉRENCE

En C, les argum e nts e t la valeur de re tour d'une fonction sont transm is par valeur. Pour sim uler e n q ue lque
sorte ce q ui s e nom m e "transm ission par adre s s e " dans d'autre s langage s , ile s t alors néce s s aire de "jongler"
ave c les pointe urs pour y parve nir (la transm ission se faisant toujours par valeur, m ais, dans ce cas, ils'agit
de la valeur d'un pointe ur). En C+ + , le principalinté rê t de la notion de ré fé re nce e s t q u'e lle pe rm e t de
lais s e r le com pilate ur m e ttre e n œuvre les "bonne s instructions" pe rm e ttant d'assure r e ffe ctive m e nt un
transfe rt par adre s s e . Pour m ie ux vous e n faire s aisir l'inté rê t, nous vous proposons de faire d'abord un
rappe lm ontrant com m e nt ilfallait procéder e n C.

3.1 Trans m is s ion de s argum e nts e n C

Considérons l'e xe m ple classique suivant :

2 - N'oubl
iez pas qu'en C (com m e e n C+ + ) ile s t possibl
e d'initial
iser une variabl
e autom atiq ue s cal
aire à l
'aide d'une expression
q ue l
conq ue.
26 Program m e r e n langage C+ +
_______________________________________________________________________________
______

#include <iostream.h>
main()
{
void echange (int, int) ;
int n=10, p=20 ;
cout << "avant appel : " << n << " " << p << "\n" ;
echange (n, p) ;
cout << "après appel : " << n << " " << p << "\n" ;
}
void echange (int a, int b)
{
int c ;
cout << "début echange : " << a << " " << b << "\n" ;
c = a ; a = b ; b = c ;
cout << "fin echange : " << a << " " << b << "\n" ;
}
_______________________
avant appel : 10 20
début echange : 10 20
fin echange : 20 10
après appel : 10 20
_______________________________________________________________________________
______

Le s argum e nts s ont trans m is par valeur

Lors de l'appe lde e ch ange , ily a transm ission des valeurs de n et de p ;on pe ut considérer que la fonction
les a re copiées dans des em place m e nts locaux, corre s pondant à s e s argum e nts form e ls a e t b et q u'e lle a
e ffe ctive m e nt "travaillé" sur ce s copie s .

Bie n e nte ndu, ile s t toujours possible de program m e r une fonction e ch ange pour q u'e lle opè re e ffe ctive m e nt
sur des variables de la fonction q ui l'appe lle ;ilsuffit tout sim plem e nt de lui fournir, e n argum e nt, l'adre s s e
de ce s variables , com m e dans l'e xe m ple s uivant :

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
void echange (int *, int *) ;
int n=10, p=20 ;
cout << "avant appel : " << n << " " << p << "\n" ;
echange (&n, &p) ;
cout << "après appel : " << n << " " << p << "\n" ;
}
void echange (int * a, int * b)
{
int c ;
cout << "début echange : " << * a << " " << * b << "\n" ;
c = * a ; * a = * b ; * b = c ;
cout << "fin echange : " << * a << " " << * b << "\n" ;
IV. Le s s pécificités du C+ + 27
}
_______________________
avant appel : 10 20
début echange : 10 20
fin echange : 20 10
après appel : 20 10
_______________________________________________________________________________
______

M i s e e n œuvre , par le program m e ur, d'une trans m ission par adre s s e

Note z bie n les diffé re nce s e ntre les deux e xe m ples , à la fois dans l'é criture de la fonction e ch ange , m ais
aussi dans son appe l. Ce dernie r point signifie q ue l'utilisate ur de la fonction (q ui n'e s t pas toujours ce lui q ui
l'a é crite ) doit savoir s'ilfaut lui transm e ttre une variable ou son adre s s e 3.

3.2 Trans m is s ion par ré fé re nce e n C+ +

C+ + pe rm e t de dem ande r au com pilate ur de pre ndre lui-m ê m e e n ch arge la transm ission des argum e nts par
adre s s e : on parle alors e n gé né ral, dans ce cas, de transm ission d'argum e nt par ré fé re nce . Le m ê m e
m é canism e pourra é galem e nt s'appliq ue r à une valeur de re tour d'une fonction. Exam inons ces deux
possibilité s .

a)Trans m is s ion d'argum e nts par ré fé re nce


Le program m e ci-de s s ous m ontre com m e nt appliq ue r un te lm é canism e à notre fonction e ch ange .

_______________________________________________________________________________
______

#include <iostream.h>
main()
{ void echange (int &, int &) ;
int n=10, p=20 ;
cout << "avant appel : " << n << " " << p << "\n" ;
echange (n, p) ; // attention, ici pas de &n, &p
cout << "après appel : " << n << " " << p << "\n" ;
}
void echange (int & a, int & b)
{ int c ;
cout << "début echange : " << a << " " << b << "\n" ;
c = a ; a = b ; b = c ;
cout << "fin echange : " << a << " " << b << "\n" ;
} _______________________

avant appel : 10 20
début echange : 10 20
fin echange : 20 10
après appel : 20 10

3 - Ce rtes, ici, si l
'on ve ut q ue l
a fonction e ch ange puis s e "faire corre cte m e nt s on travail
", l
e ch oix s'im pos e . M ais, iln'e n va pas toujours
ainsi.
28 Program m e r e n langage C+ +
_______________________________________________________________________________
______

U tilisation de la trans m ission d'argum e nts par ré fé re nce e n C+ +

D ans l'instruction :

void echange (int & a, int & b) ;

La notation int & a signifie q ue a e s t une inform ation e ntiè re transm ise par réfé re nce . Note z bie n q ue , dans
la fonction e ch ange , on utilise sim plem e nt le sym bole a pour dé s igne r ce tte variable dont la fonction aura
re çu e ffe ctive m e nt l'adre s s e (e t non la valeur) : iln'e s t plus utile (e t ce s e rait une e rre ur !) de faire appe là
l'opé rate ur d'indire ction *.

Autre m e nt dit, ilnous suffit d'avoir fait ce ch oix de transm ission par ré férence au niveau de l
'en-tê te de
l
a fonction pour que l e processus soit entiè rem ent pris en ch arge par le com pilateur 4.

Le m ê m e ph é nom è ne s 'appliq ue au nive au de l'utilisation de la fonction. Ilsuffit, e n e ffe t, d'avoir spécifié ,


dans le prototype , les argum e nts (ici, les deux) q ue l'on souh aite voir transm is par ré fé re nce . Au nive au de
l'appe l:

echange (n, p) ;

nous n'avons plus à nous préoccuper du m ode de transm ission effe ctive m e nt utilisé.

R e m arques :

1) La transm ission d'argum e nts par ré fé re nce s im plifie l'é criture de la fonction corre s pondante .
2) Le ch oix du m ode de transm ission par ré fé re nce e s t fait au m om e nt de l'é criture de la fonction
conce rné e . L'utilisate ur de la fonction n'a plus à s'e n soucie r e nsuite , si ce n'e s t au nive au de la
déclaration du prototype de la fonction (e n gé né ral, d'ailleurs, ce prototype vie ndra d'un fich ie r e n-
tê te ).
3) En contre partie des avantage s pré cédents, l'e m ploi de la transm ission par ré fé re nce accroî t les ris q ue s
"d'effe ts de bord" non dé s iré s . En e ffe t, lors q u'ilappe lle une fonction, l'utilisate ur ne s ait plus s'il
transm e t, au bout du com pte , la valeur ou l'adresse d'un argum e nt (la m ê m e notation pouvant
désigner l'une ou l'autre des deux possibilité s ) ;ilris q ue donc de m odifie r une variable dont ilpe nsait
n'avoir transm is qu'une copie de la valeur !

R e m arque :

Lors q u'on doit transm e ttre e n argum e nt la ré fé re nce à un pointe ur, on e s t am e né à utiliser ce genre
d'écriture :
int * & adr // adr est une référence à un pointeur sur un int

b)Trans m is s ion par ré fé re nce de l


a val
e ur de re tour d'une fonction
Le m é canism e q ue nous ve nons d'exposer pour la transm ission des argum e nts s'appliq ue é galem e nt à la
valeur de re tour d'une fonction. Son vé ritable inté rê t n'apparaî
tra toute fois q ue lors q ue nous é tudie rons la

4 - Ce tte possibil
ité e s t anal
ogue à l
'util
isation du m ot cl
é var dans l
'en-tê te d'une procédure en Pas cal
.
IV. Le s s pécificités du C+ + 29
surdéfinition d'opé rate urs ;e n e ffe t, dans ce rtains cas, ils e ra indispensable q u'un opé rate ur (c'e s t-à -dire , e n
fait, une fonction) transm e tte s a valeur de re tour par ré fé re nce 5.

$ 3.3 La ré fé re nce d'une m aniè re gé né ral


e

L'e s s e ntie lconce rnant la notion de ré fé re nce a é té pré s e nté dans le paragraph e pré cédent. Ce pe ndant, e n
toute rigue ur, la notion de ré fé re nce pe ut inte rve nir e n de h ors de la notion d'argum e nt ou de valeur de
re tour. C'e s t ce q ue nous vous présentons dans le pré s e nt paragraph e (q ui pe ut ê tre ignoré s ans problèm e s
dans une prem iè re lecture ).

a)La notion de ré fé re nce e s t pl


us gé né ral
e q ue ce l
le d'argum e nt
D 'une m aniè re gé né rale, ile s t possible de déclare r un ide ntificate ur com m e ré fé re nce d'une autre variable.
Considérez, par exem ple, ce s instructions :

int n ;
int & p = n ;

La s e conde s ignifie q ue p e s t une ré fé re nce à la variable n. Ainsi, dans la suite , n e t p dé s igne ront le m ê m e
e m place m e nt m é m oire . Par e xe m ple, ave c :

n = 3 ;
cout << p ;

nous obtie ndrons la valeur 3.

b)Initial
is ation de ré fé re nce
La déclaration :

int & p=n ;

e s t e n fait une déclaration de ré fé re nce (ici p) accom pagnée d'une initialisation (à la ré fé re nce de n). D'une
façon gé né rale, iln'e s t pas possible de déclare r une ré fé re nce s ans l'initialiser, com m e dans :

int & p ; // incorrect, car pas d'initialisation

Note z bie n q u'une fois déclaré e (e t initialisée), une ré fé re nce ne pe ut plus ê tre m odifié e . D'ailleurs aucun
m é canism e n'e s t pré vu à ce t e ffe t : si, ayant déclaré int & p=n ;vous é crive z p=q , ils'agit obligatoire m e nt
de l'affe ctation de la valeur de q à l'e m place m e nt de ré fé re nce p, e t non de la m odification de la ré fé re nce
q.

Une déclaration te lle q ue :

int & n = 3 ; // incorrecte depuis la version 3

e s t incorre cte depuis la ve rsion 3. Ce ci s e justifie par le fait q ue s i e lle é tait acce pté e , e lle re vie ndrait à
initialiser n ave c une ré fé re nce à la valeur 3. D ans ce s conditions, q ue fe rait l'instruction :

5 - Ce s e ra notam m e nt l
e cas de l
'opé rate ur [ ] l
ors q ue l
'on souh aite ra pouvoir l
'em pl
oyer dans des affe ctations de l
a form e t[i] = x.
30 Program m e r e n langage C+ +
n = 5 ;

En re vanch e , une déclaration te lle q ue ce lle-ci e s t corre cte :

const int & n = 3 ;

Elle gé nè re une variable te m poraire (ayant une durée de vie im pos é e par l'e m place m e nt de la déclaration)
conte nant la valeur 3 e t place s a ré fé re nce dans n. O n pe ut dire q ue tout s e pas s e com m e s i vous avie z :

int temps = 3 ;
int & n = temps ;

ave c ce tte diffé re nce q ue , dans le pre m ie r cas, vous n'ave z pas e xplicite m e nt accè s à la variable te m poraire .

c)La trans m is s ion d'un argum e nt ou d'une val


e ur de re tour
e s t une initial
is ation
Ce tte re m arq ue pre nd tout son sens dans le cas où l'on a affaire à des ré fé re nce s . En e ffe t, supposons q u'une
fonction fct ait pour prototype :

void fct (int &) ;

Alors, le com pilate ur re fus e ra un appe lde la form e s uivante (n é tant de type int) :

fct (3) ; // incorrect

Ile n ira de m ê m e pour :

const int c = 15 ;
...
fct (c) ; // incorrect

En e ffe t, de te ls appe ls sont assim ilés à des initialisations de ré fé re nce s (à q ue lque ch ose de non constant)
ave c une ré fé re nce à une constante . Ce re fus s e justifie parfaite m e nt si l'on pe ns e q ue l'on doit transm e ttre à
fct l'adresse d'une constante (3 ou c), sach ant q ue ce tte fonction ris q ue de m odifie r ce q ui s e trouve à ce tte
adre s s e .

Pour les m ê m e s raisons, l'appe lsuivant s e ra re je té :

fct (&n) ;

En re vanch e , ave c une fonction de prototype :

fct1 (const int &) ;

ce s appe ls s e ront corre cts :

fct1 (3) ; // correct ici


fct1 (c) ; // correct ici

Qui plus e s t, dans ce cas, un appe lte lfct1 (x) s e ra acce pté q ue lq ue s oit le type de x. En e ffe t, dans ce cas,
ily a cré ation d'une variable te m poraire (de type int) q ui re ce vra le ré s ultat de la conve rsion de x e n int.

Ce tte fois, l'acce ptation de ce s instructions s e justifie par le fait q ue fct a pré vu de re ce voir une ré fé re nce à
q ue lque ch ose de constant ;le ris q ue de m odification é voq ué pré cédem m e nt n'e xiste donc plus.
IV. Le s s pécificités du C+ + 31

4. LES ARGUM ENTS PAR D ÉFAUT

4.1 Exe m pl
es

En C ANSI, ile s t indispensable q ue l'appe ld'une fonction contie nne autant d'argum e nts q ue la fonction e n
atte nd e ffe ctive m e nt. C+ + pe rm e t de s'affranch ir e n partie de ce tte rè gle, grâ ce à un m é canism e
d'attribution de valeurs par dé faut à des argum e nts. Considérez l'e xe m ple s uivant :

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
int n=10, p=20 ;
void fct (int, int=12) ; // proto avec une valeur par défaut
fct (n, p) ; // appel "normal"
fct (n) ; // appel avec un seul argument
// fct() serait, ici, rejeté */
}
void fct (int a, int b) // en-tête "habituelle"
{
cout << "premier argument : " << a << "\n" ;
cout << "second argument : " << b << "\n" ;
}
_______________________
premier argument : 10
second argument : 20
premier argument : 10
second argument : 12
_______________________________________________________________________________
______

Exe m ple de définition de valeur par défaut pour un argum e nt

La déclaration de fct, ici dans la fonction m ain, e s t ré alisée par le prototype :

void fct (int, int = 12) ;

Vous y note z la déclaration du se cond argum e nt sous la form e :

int = 12

Ce lle-ci pré cis e au com pilate ur q ue , e n cas d'absence de ce s e cond argum e nt dans un éve ntue lappe lde fct,
illui faudra "faire com m e s i" l'appe lavait é té e ffe ctué ave c ce tte valeur.

Les deux appe ls de fct illustre nt le ph é nom è ne . Note z q u'un appe lte lq ue :

fct ( )

s e rait re je té à la com pilation puis q u'ici iln'é tait pas prévu de valeur par dé faut pour le pre m ie r argum e nt de
fct.
32 Program m e r e n langage C+ +
Voici un s e cond e xe m ple, dans leq ue lnous avons prévu de s valeurs par dé faut pour tous les argum e nts de
fct.

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
int n=10, p=20 ;
void fct (int=0, int=12) ; // proto avec deux valeurs par défaut
fct (n, p) ; // appel "normal"
fct (n) ; // appel avec un seul argument
fct () ; // appel sans argument
}

void fct (int a, int b) // en-tête "habituelle"


{
cout << "premier argument : " << a << "\n" ;
cout << "second argument : " << b << "\n" ;
}
_______________________
premier argument : 10
second argument : 20
premier argument : 10
second argument : 12
premier argument : 0
second argument : 12
_______________________________________________________________________________
______

Exe m ple de définition de valeurs par défaut pour plusie urs argum e nts

4.2 D 'une m aniè re gé né ral


e

Lorsqu'une décl aration pré voit des val eurs par défaut, l es argum ents concernés doivent
obl
igatoirem ent ê tre l
es derniers de l
aliste. Par e xe m ple, une déclaration te lle q ue :

float fexple (int = 5, long, int = 3) ;

e s t inte rdite . En fait, une te lle inte rdiction re lève du pur bon sens : e n e ffe t, si ce tte déclaration é tait
acce pté e , l'appe lsuivant :

fexple (10, 20) ;

pourrait ê tre inte rpré té aussi bien com m e :

fexple (5, 10, 20) ;

q ue com m e :

fexple (10, 20, 3) ;

Note z bie n q ue le m é canism e propos é par C+ + re vie nt à fixer l


es val
eurs par défaut dans l a d é cl
aration
de la fonction et non dans sa définition. Autre m e nt dit, ce n'e s t pas le "conce pte ur" de la fonction q ui
IV. Le s s pécificités du C+ + 33
décide des valeurs par dé faut, m ais l'utilisate ur. Une cons é q ue nce im m édiate de ce tte particularité e s t q ue
les argum e nts soum is à ce m é canism e e t les valeurs corre s pondante s pe uve nt varie r d'une utilisation à une
autre ;e n pratiq ue , toute fois, ce point ne s e ra guè re e xploité , ne s e rait-ce q ue parce q ue les déclarations de
fonctions sont, e n gé né ral, "figé e s " une fois pour toute s , dans un fich ie r e n-tê te .

Nous ve rrons q ue les argum e nts par dé faut s e ré vé leront particuliè re m e nt pré cie ux lors q u'ils'agira de
fabriq ue r ce q ue l'on nom m e le "constructe ur d'une clas s e ".

R e m arques :

1) Th é oriq ue m e nt C+ + autoris e (au s e in d'un m ê m e fich ie r source ) une redéclaration de la fonction,


dans la m e s ure où ce tte derniè re s e conte nte d'ajoute r de nouve lles valeurs par dé faut. Pour notre
part, nous préfé rons nous en te nir aux points proposés, pour d'évidente s raisons de sim plicité .
2) Si l'on souh aite attribue r une valeur par dé faut à un argum e nt de type pointe ur, on pre ndra garde de
s é pare r par au m oins un espace les caractè re s *e t = ;dans le cas contraire , ils s e raie nt inte rpré té s
com m e l'opé rate ur d'affe ctation *=, ce q ui conduirait à une e rre ur.
3) Le s valeurs par dé faut pe uve nt ê tre constitué e s d e n'im porte q ue lle e xpre s s ion (e t non s e ulem e nt
d'une e xpre s s ion constante ), pour pe u q ue ce tte derniè re ait un s e ns au m om e nt où e lle e s t com pilée .
En voici un e xe m ple d'école (ilné ce s s ite s im plem e nt q ue les déclarations de x e t de n figure nt avant
ce lle de fct) :
float x ;
int n ;
void fct (float = n*x + 1.5) ; /* la valeur par défaut dépend des
variables
n et x */

$ 4.3 Lors q ue l 'on conjugue argum e nt par dé faut


e t trans m is s ion par ré fé re nce

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps. Sach e z sim plem e nt q ue s a lecture né ce s s ite
l'é tude pré alable du paragraph e 3.3.

Voici, e n parallèle, deux exem ples de program m e s q ui ré alisent la m ê m e ch os e , l'un e n faisant appe là la
transm ission d'un argum e nt par ré fé re nce , l'autre à une dém arch e classique bas é e s ur un pointe ur.

_______________________________________________________________________________
______
main() main()
{ {
int n, p ; int n, p ;
void fct (int, int & = n) ; void fct (int, int * = &n) ;
fct(10, p) ; // idem p=10 fct(10, &p) ; // idem p=10
fct(10) ; // idem n=10 fct(10) ; // idem n=10
} }
void fct (int a, int & b) void fct (int a, int * adb)
{ {
b = a ; * adb = a ;
} }
_______________________________________________________________________________
______

Exe m ple de valeur par défaut pour un argum e nt trans m is par réfé re nce ou par adre s s e

Note z la déclaration :

void fct (int, int & = n) ;

dans laq ue lle la notation

int & = n

signifie :

• q ue l'argum e nt corre spondant, de type int, e s t transm is par ré fé re nce ,


• q ue ce tte ré fé re nce re çoit une valeur par dé faut corre s pondant à l'adresse de n (e t non à sa valeur).
Si nous avions souh aité q ue ce t argum e nt (transm is par ré fé re nce ) re çoive par dé faut la valeur 3, nous
n'aurions pas pu déclare r ainsi notre fonction fct :

void fct (int, int & = 3) ; // erreur

En re vanch e , ce la aurait é té possible s i le s e cond argum e nt de notre fonction avait re çu l'attribut cons t (e t,
bien sûr, l'e n-tê te approprié ) :

void fct (int, const & = 3) ; // correct

Ce ci aurait, com m e nous l'avons déjà indiq ué dans le paragraph e pré cédent, e ntraî né la cré ation d'une
variable te m poraire , conte nant la valeur 3, dont on aurait transm is la ré fé re nce com m e argum e nt par dé faut.

5. SURD ÉFINITIO N D E FO NCTIO NS

D 'une m aniè re gé né rale, on parle de "surdéfinition"1 lors q u'un m ê m e sym bole possè de plusieurs
significations diffé re nte s , le ch oix de l'une des significations s e faisant e n fonction du "conte xte ". C'e s t ainsi
q ue C, com m e la plupart des langage s é volué s , utilise la surdéfinition d'un ce rtain nom bre d'opérate urs. Par
e xe m ple, dans une expression te lle q ue :

a + b

la signification du + dépend du type des opé rande s a e t b ;suivant le cas, ilpourra s'agir d'une addition
d'entie rs ou d'une addition de flottants. De m ê m e , le sym bole * pe ut désigne r, suivant le conte xte , une
m ultiplication d'e ntie rs, de flottants ou une "indire ction2".

Un de s grands atouts de C+ + e s t de perm e ttre la surdéfinition de la plupart des opérate urs (lors q u'ils sont
associé s à la notion de clas s e ). Lors q ue nous é tudie rons ce t aspect, nous ve rrons alors q u'ilre pos e e n fait sur
la surdéfinition de fonctions. C'e s t ce tte derniè re possibilité q ue nous proposons d'étudie r ici pour e lle-
m ê m e.

Pour pouvoir e m ploye r plusieurs fonctions de m ê m e nom , ilfaut, bie n sûr, un critè re (autre q ue le nom )
pe rm e ttant de ch oisir la bonne fonction. En C+ + , ce ch oix e s t bas é (com m e pour les opé rate urs cité s

1 - D e "ove rl
oading", e n angl ais, parfois traduit par "s urch arge ".
2 - O n parle parfois de "dé ré fé re nce " ;ce l
a corre s pond à des situations te l
le s q ue :
int*a ;
*a = 5 ;
36 Program m e r e n langage C+ +
pré cédem m e nt e n e xe m ple) sur le type des argum e nts. Nous com m e nce rons par vous présente r un e xe m ple
com plet m ontrant com m e nt m e ttre e n œuvre la surdéfinition de fonctions. Nous e xam ine rons e nsuite
diffé re nte s s ituations d'appe ld'une fonction surdéfinie avant d'étudie r les rè gles détaillée s q ui pré s ident au
ch oix de la "bonne fonction".

5.1 M is e e n œuvre de l
a surdé finition de fonctions

Nous allons définir e t utiliser deux fonctions nom m é e s , toute s les deux, sosie . La pre m iè re possédera un
argum e nt de type int, la s e conde un argum e nt de type double, ce q ui les diffé re ncie bien l'une de l'autre .
Pour q ue l'e xé cution du program m e m ontre claire m e nt la fonction e ffe ctive m e nt appe lée , nous introduisons
dans ch acune des fonctions une instruction d'affich age approprié e . Dans le program m e "d'essai", nous nous
conte ntons d'appe ler succe s s ive m e nt la fonction surdéfinie sosie , une pre m iè re fois ave c un argum e nt de
type int, une s e conde fois ave c un argum e nt de type double.

_______________________________________________________________________________
______

#include <iostream.h>

void sosie (int) ; // les prototypes


void sosie (double) ;

main() // le programme de test


{
int n=5, p ; double x=2.5 ;
sosie (n) ;
sosie (x) ;
}

void sosie (int a) // la première fonction


{
cout << "sosie numéro I a = " << a << "\n" ;
}
void sosie (double a) // la deuxième fonction
{
cout << "sosie numéro II a = " << a << "\n" ;
}
_______________________

sosie numéro I a = 5
sosie numéro II a = 2.5
_______________________________________________________________________________
______

Exe m ple de s u rdéfinition de la fonction s os i e

Vous constate z q ue le com pilate ur a bie n m is en place l'appe lde la "bonne fonction" sosie , au vu de la liste
d'argum e nts (ici réduite à un s e ul).
IV. Le s s pécificités du C+ + 37
5.2 Exe m pl
e s de ch oix d'une fonction surdé finie

Notre pré cédent e xe m ple é tait sim ple, dans la m e s ure où nous appe lions toujours la fonction sosie ave c un
argum e nt ayant exactem ent l'un de s type s pré vus dans les prototype s (int ou double). O n pe ut se dem ande r
ce q ui s e produirait si nous l'appe lions, par e xe m ple, ave c un argum e nt de type ch ar, long ou pointe ur, ou si
l'on avait affaire à des fonctions com portant plusieurs argum e nts...

Avant d'exam ine r les rè gles de déte rm ination d'une fonction surdéfinie , e xam inons tout d'abord q ue lque s
situations as s e z intuitive s .

Exem pl
e1

Ave c nos deux précédentes déclarations :

void sosie (int) ; // sosie I


void sosie (double) ; // sosie II

e t les variables s uivante s :

char c ; float y ;

• l'instruction sosie (c) appe llera la fonction sosie I, aprè s conve rsion de la valeur de c e n int,
• l'instruction sosie (y) appe llera la fonction sosie II, aprè s conve rsion de la valeur de y en double,
• l'instruction sosie ('d') appe llera la fonction sosie I, aprè s conve rsion de la valeur de 'd' e n int.

Exem pl
e2

Ave c ces déclarations :

void affiche (char *) ; // affiche I


void affiche (void *) ; // affiche II
char * ad1 ;
double * ad2 ;

• l'instruction affich e (ad1) appe llera la fonction affich e I,


• l'instruction affich e (ad2) appe llera la fonction affich e II, aprè s conve rsion de la valeur de ad2 e n void*.

Exem pl
e3

Ave c ces déclarations :

void essai (int, double) ; // essai I


void essai (double, int) ; // essai II
int n, p ; double z ; char c ;

• l'instruction e s s ai(n,z) appe llera la fonction e s s ai I,


• l'instruction e s s ai(c,z) appe llera la fonction e s s ai I, aprè s conve rsion de la valeur de c e n int,
• l'instruction e s s ai(n,p) conduira à une e rre ur de com pilation, com pte te nu de s on am biguïté ;e n e ffe t,
deux possibilité s e xiste nt ici : conve rtir p e n double, sans m odifie r n e t appe ler e s s ai I ou, au contraire ,
conve rtir n e n double, sans m odifie r p e t appe ler e s s ai II.
38 Program m e r e n langage C+ +
Exem pl
e4

Ave c ces déclarations :

void test (int n=0, double x=0) ; // test I


void test (double y=0, int p=0) ; // test II
int n ; double z ;

• l'instruction te s t(n,z) appe llera la fonction te s t I


• l'instruction te s t(z,n) appe llera la fonction te s t II
• l'instruction te s t(n) appe llera la fonction te s t I
• l'instruction te s t(z) appe llera la fonction te s t II
• l'instruction te s t() conduira à une e rre ur de com pilation, com pte te nu de s on am biguïté .

Exem pl
e5

Ave c ces déclarations :

void truc (int) ; // truc I


void truc (const int) ; // truc II

vous obtie ndre z une e rre ur de com pilation. En e ffe t, C+ + n'a pas prévu de distingue r int de cons t int. Ce ci
s e justifie par le fait q ue , les deux fonctions truc re ce vant une copie de l'inform ation à traite r, aucun ris q ue
n'e xiste de m odifie r la valeur originale.

Exem pl
e6

En re vanch e , considérez m ainte nant ces déclarations :

void chose (int *) ; // chose I


void chose (const int *) ; // chose II
int n = 3 ;
const p = 5 ;

Ce tte fois, la distinction e ntre int *e t cons t int *e s t justifié e . En e ffe t, on pe ut trè s bien prévoir q ue ch ose I
m odifie la valeur de la lvalue 3 dont e lle re çoit l'adre s s e , tandis q ue ch ose II n'e n fait rie n. Ce tte distinction
e s t possible e n C+ , de sorte q ue :

• l'instruction ch ose (& n) appe llera la fonction ch ose I


• l'instruction ch ose (& p) appe llera la fonction ch ose II

3 - R appe l
ons q u'on nom m e l
val
ue l
a ré fé re nce à q ue l
q ue ch ose dont on pe ut m odifie r l
a val
e ur. Ce te rm e provie nt de l
a contraction de
"l
e ft val
ue " q ui désigne quel
q ue ch os e q ui pe ut apparaî
tre à gauch e d'un opé rate ur d'affe ctation.
IV. Le s s pécificités du C+ + 39
5.3 Rè gl
e s de re ch e rch e d'une fonction surdé finie

Pour l'instant, nous vous proposons sim plem e nt de vous e n donne r plutôt la ph ilosoph ie gé né rale, ce q ui s e ra
suffisant pour l'é tude des ch apitre s s uivants. Au filde l'é tude de ce t ouvrage , nous s e rons am e né à vous
apporte r de s inform ations com plém e ntaire s . De plus, l'anne xe A re pre nd l'e ns e m ble pré cis de toute s ce s
rè gles .

a)Cas de s fonctions à un argum e nt

Le com pilate ur re ch e rch e la "m e illeure corre s pondance " possible. Bie n e nte ndu, pour pouvoir dé finir ce
q u'e s t ce tte m e illeure corre s pondance , ilfaut q u'ildispose d'un critè re d'évaluation. Pour ce faire , ile s t
pré vu diffé re nts nive aux de corre s pondance :

1 - Corre s pondance e xacte : on distingue bien les uns des autre s les diffé re nts types de bas e , e n te nant
com pte de leur é ve ntue lattribut de signe 4 ;de plus, com m e on l'a vu dans nos précédents e xe m ples ,
l'attribut cons t pe ut inte rve nir dans le cas de pointe urs ou de réfé re nce s .
2 - Corrre s pondance ave c "prom otions num é riq ue s ", c'e s t-à -dire e s s e ntie llem e nt :
*ch ar e t s h ort -> int
*float -> double
3 - Conve rsions dite s "standard" : ils'agit des conve rsions légales e n C+ + , c'e st-à -dire de ce lles q ui
pe uve nt ê tre im pos é e s par une affe ctation (sans opérate ur de "cast") ;ce ttte fois, ilpe ut s'agir de
conve rsions dégradante s puis q ue , notam m e nt, toute conve rsion d'un type num é riq ue e n un autre type
num é riq ue e s t acce pté e .
D 'autre s nive aux sont pré vus ;e n particulie r on pourra faire inte rve nir ce q ue l'on nom m e des
"conve rsions définie s par l'utilisate ur" (C.D .U.) ;e lles ne s e ront é tudié e s q ue dans le ch apitre X.
La re ch e rch e s 'arrê te au pre m ie r nive au ayant pe rm is de trouve r une corre s pondance e t ce tte derniè re doit
ê tre uniq ue ;si plusieurs fonctions convie nne nt au m ê m e nive au de corre s pondance , il y a e rre ur de
com pilation due à l'am biguïté re ncontré e . Bie n e nte ndu, si aucune fonction ne convie nt à aucun nive au, ily
a é galem e nt e rre ur de com pilation.

b)Cas de s fonctions à pl
us ie urs argum e nts
L'idé e gé né rale e s t q u'ildoit se dégage r une fonction "m e illeure " q ue toute s les autre s . Pour ce faire , le
com pilate ur s é lectionne , pour ch aque argum ent, la ou les fonctions q ui ré alisent la m e illeure
corre s pondance (au s e ns de la h ié rarch ie définie ci-de s s us). Parm i l'e ns e m ble des fonctions ainsi
s é lectionné e s , ilch oisit ce lle (si elle e xiste e t si elle e s t uniq ue ) q ui ré alise, pour ch aq ue argum e nt, une
corre s pondance au m oins é gale à ce lle de toute s les autre s fonctions 5.

Si plusieurs fonctions convie nne nt, là e ncore , on aura une e rre ur de com pilation due à l'am biguïté
re ncontré e ;de m ê m e s i aucune fonction ne convie nt, ily aura e rre ur de com pilation.

Note z q ue les fonctions com portant un ou plusieurs argum e nts par dé faut sont traité e s com m e s i plusieurs
fonctions diffé re nte s avaie nt é té définie s ave c un nom bre croissant d'argum e nts.

4 - Atte ntion, e n C+ + , ch ar e s t diffé re nt de signed ch ar e t de unsigned ch ar.


5 - Ce q ui re vie nt à dire qu'ilconsidè re l 'inte rs e ction de s e ns e m bl
e s cons titués des fonctions ré al
isant l
a m e il
le ure corre s pondance pour
ch acun de s argum e nts.
40 Program m e r e n langage C+ +
5.4 Le m é canis m e de l
a surdé finition de fonctions

Jus q u'ici, nous avons e xam iné la m aniè re dont le com pilate ur faisait le ch oix de la "bonne fonction", e n
raisonnant sur un seulfich ie r source à la fois. M ais ils e rait tout à fait e nvisage able :

• de com piler d'une part un fich ie r conte nant la définition de nos deux fonctions nom m é e s sosie ,
• d'utiliser ces fonctions par ailleurs e n nous conte ntant d'en fournir les prototype s .
O r, pour q ue ce ci soit possible, l'édite ur de lie ns doit ê tre e n m e s ure d'effe ctue r le lie n e ntre le ch oix opé ré
par le com pilate ur e t la "bonne fonction" figurant dans un autre m odule obje t. Ce tte re connaissance e s t bas é e
sur la m odification, par le com pilate ur, de s nom s "e xte rne s " des fonctions ;ce lui-ci fabriq ue un nouve au
nom bas é , de m aniè re déte rm iniste , d'une part sur le nom inte rne de la fonction, d'autre part sur le nom bre
e t la nature de ses argum e nts.

Il e s t trè s im portant de note r q ue ce m é canism e s 'appliq ue à toute s les fonctions, q u'e lles s oie nt
e ffe ctive m e nt surdéfinie s ou non (ile s t im possible de savoir si une fonction com pilée dans un fich ie r source
s e ra surdéfinie dans un autre ). O n voit donc q u'un problèm e s e pos e , dè s lors q ue l'on souh aite pouvoir
utiliser, dans un program m e C+ + , une fonction é crite e t com pilée e n C (ou dans un autre langage utilisant
les m ê m e s conve ntions d'appe ls de fonction, notam m e nt l'as s e m bleur ou le Fortran) ;e n e ffe t, une te lle
fonction ne voit pas son nom m odifié s uivant le m é canism e é voq ué . Une s olution e xiste toute fois : déclare r
une te lle fonction, e n faisant pré céder son prototype de la m e ntion e xte rn "C". Par e xe m ple, si nous avons
é crit e t com pilé e n C une fonction d'e n-tê te :

double fct (int n, char c) ;

e t q ue nous souh aitons l'utiliser dans un program m e C+ + , ilnous suffira d'y fournir son prototype de la
façon suivante :

extern "C" double fct (int, char) ;

R e m arques :

1) Ile xiste une form e "collective " de la déclaration e xte rn ;e lle s e pré s e nte ainsi :
extern "C" { void exple (int) ;
double chose (int, char, float) ;
.....
} ;

2) Le problèm e é voq ué pour les fonctions C (assem bleur ou Fortran) s e pos e , a priori, pour toute s les
fonctions de la biblioth è q ue s tandard C q ue l'on ré utilise en C+ + ;e n fait, dans beaucoup
d'environne m e nts, ce t aspect e s t autom atiq ue m e nt pris e n ch arge au nive au de s fich ie rs e n-tê te
corre s pondants (ils contie nne nt des déclarations e xte rn conditionne lles ).
3) Ile s t possible d'em ploye r, au s e in d'un m ê m e program m e C+ + , une fonction C (as s e m bleur ou
Fortran) e t une ou plusieurs autre s fonctions C+ + de m ê m e nom (m ais d'argum e nts diffé re nts). Par
e xe m ple, nous pouvons utiliser dans un program m e C+ + la fonction fct pré cédente e t deux fonctions
C+ + d'en-tê te :
void fct (double x)
void fct (float y)

e n procédant ainsi :
extern "C" void fct (int) ;
void fct (double) ;
void fct (float) ;
IV. Le s s pécificités du C+ + 41

Suivant la nature de l'argum e nt d'appe lde fct, ily aura bie n appe lde l'une des trois fonctions fct.
Note z toute fois q u'iln'e s t pas possible de m e ntionne r plusieurs fonctions C de nom fct.

6. LES O PÉRA TEURS NEW ET D ELETE

En langage C, la ge s tion dynam iq ue de m é m oire fait appe là des fonctions de la biblioth è q ue s tandard te lles
q ue m alloc e t fre e . Bie n e nte ndu, ce lles -ci, com m e toute s les fonctions standard, re s te nt utilisables e n C+ + .

M ais, dans le conte xte de la Program m ation O rie nté e O b je t, C+ + a introduit deux nouve aux opé rate urs,
ne w e t de lete , particuliè re m e nt adapté s à la ge s tion dynam iq ue d'obje ts. Ce s opé rate urs peuve nt é galem e nt
ê tre utilisés pour des "variables classiques 6". D ans ce s conditions, par souci d'h om ogé né ité e t de sim plicité ,
ile s t plus raisonnable, e n C+ + , d'utiliser systé m atiq ue m e nt ce s opé rate urs, q ue l'on ait affaire à des
variables classiques ou à des obje ts. C'e s t pourq uoi nous vous les pré s e ntons dè s m ainte nant.

6.1 Exe m pl
e s d'util
is ation de ne w

a) Ave c la déclaration :

int * ad ;

l'instruction :

ad = new int ;

pe rm e t d'alloue r l'e s pace m é m oire né ce s s aire pour un é lém e nt de type int e t d'affe cte r à ad l'adre s s e
corre s pondante . En C, vous aurie z obte nu le m ê m e ré s ultat e n é crivant :

ad = (int *) malloc (sizeof (int)) ;

(l'opé rate ur de "cast", ici int *, é tant facultatif)

Com pte te nu de ce q u'e n C+ + , les déclarations ont un e m place m e nt libre , vous pouve z m ê m e déclare r la
variable ad au m om e nt où vous e n ave z besoin en écrivant, par e xe m ple :

int * ad = new int ;

b) Ave c la déclaration :

char * adc ;

l'instruction :

adc = new char[100] ;

alloue l'e m place m e nt né ce s s aire pour un tableau de 100 caractè re s e t place l'adre s s e (de début) dans adc. En
C, vous aurie z obte nu le m ê m e ré s ultat e n é crivant

adc = (char *) malloc (100) ;

6 - Un obje t é tant e n fait une variabl


e d'un type particul
ie r.
42 Program m e r e n langage C+ +
6.2 Syntaxe e t rôl
e de ne w

n e w e s t donc un opé rate ur unaire (à un s e ulopé rande ) q ui s'utilise ainsi :

new type
où type re pré s e nte un type absolum e nt q ue lconq ue . Ilfournit com m e ré s ultat :

• un pointe ur (de type type *) sur l'e m place m e nt corre s pondant, lors q ue l'allocation a ré ussi,
• un pointe ur nul(NULL= 0), dans le cas contraire .
ne w acce pte é galem e nt une syntaxe de la form e :

new type [n]


où n dé s igne une e xpre s s ion e ntiè re q ue lconq ue (non né gative ).

D ans ce cas, ne w alloue l'e m place m e nt né ce s s aire pour n é lém e nts du type indiq ué e t fournit e n ré s ultat un
pointe ur (toujours de type type *) sur le pre m ie r é lém e nt de ce tableau.

R e m arques :

1) La norm e de C+ + pré voit q u'e n cas d'éch e c, ne w peut7 déclench e r ce q ue l'on nom m e une e xce ption
de type bad_alloc. Ce m é canism e de ge s tion de s e xce ptions e s t édudié en détaildans le ch apitre XVII.
Vous y ve rre z q ue s i rie n n'e s t pré vu par le program m e ur pour traite r une e xce ption, le program m e
s'inte rrom pt. Autre m e nt dit, on ne pe ut plus com pte r (de façon ce rtaine ) sur un pointe ur nuldans les
im plém e ntations re s pe ctant la norm e à ve nir, à m oins de prendre soi-m ê m e e n com pte la ge s tion de
l'e xce ption bad_alloc. Si vous ne souh aite z pas faire ce tte dém arch e (au de m e urant re lative m e nt
lourde !), sach e z q ue le paragraph e 6.5 vous proposera une solution plus sim ple.
2) En toute rigue ur, ne w pe ut ê tre utilisé pour alloue r un e m place m e nt pour un tableau à plusieurs
dim e nsions, par e xe m ple :
new type [n] [10]
D ans ce cas, ne w fournit un pointe ur de type type *[10]. D'une m aniè re gé né rale, la pre m iè re dim e nsion
pe ut ê tre une e xpre s s ion e ntiè re q ue lconq ue ;les autres doive nt obligatoire m e nt ê tre d e s e xpre s s ions
constante s .
Ce tte possibilité e s t rare m e nt utilisée en pratiq ue .

6.3 Exe m pl
e s d'util
is ation de l
'opé rate ur de l
e te

Lors q ue l'on souh aite libérer un em place m e nt alloué pré alablem e nt par ne w , on doit absolum e nt utiliser
l'opé rate ur de lete . Ainsi, pour libérer les e m place m e nts créés dans les e xe m ples du paragraph e 6.1, nous
é crivons :

delete ad ;

pour l'e m place m e nt alloué par :

ad = new int ;

e t:

7 - A ctue l
le m e nt, l
a norm e ne l
'im pos e pas.
IV. Le s s pécificités du C+ + 43
delete adc ;

pour l'e m place m e nt alloué par :

adc = new char [100] ;

6.4 Syntaxe e t rôl


e de l
'opé rate ur de l
e te

La syntaxe usuelle de l'opé rate ur de lete e s t la suivante (adre s s e é tant une e xpre s s ion de vant avoir com m e
valeur un pointe ur sur un e m place m e nt alloué par ne w ) :

del
ete adresse
Note z bie n q ue le com porte m e nt du program m e n'e s t absolum e nt pas défini lors q ue :

• vous libérez, par ne w , un e m place m e nt déjà libéré ;nous ve rrons, à ce propos, q ue ce rtaine s pré cautions
devront ê tre pris e s lors q ue l'on dé finit des constructe urs e t des destructe urs de ce rtains obje ts,
• vous fournis s e z à ne w , une "m auvais e adre s s e " où un pointe ur obte nu autre m e nt q ue par ne w (m alloc,
par e xe m ple).

R e m arque :

Ile xiste une autre syntaxe de ne w ;de la form e de lete [] adre s s e , e lle n'inte rvie nt q ue dans le cas de
tableaux d'obje ts. Nous e n parlerons dans le paragraph e 6 du ch apitre 7.

6.5 Pour gé re r l
e s dé borde m e nts d e m é m oire : s e t_ne w _h andl
er

D ans le paragraph e 6.2, nous avons vu q u'iln'é tait pas toujours possible de déte cte r le m anq ue d'espace
m é m oire e n e xam inant la valeur de re tour de ne w .

En fait, C+ + vous perm e t de définir une fonction de votre ch oix e t de dem ande r q u'e lle s oit appe lée e n cas
de m anq ue de m é m oire . Il vous suffit, pour ce faire , d'appe ler la fonction s e t_ne w _h andler, e n lui
fournissant, e n argum e nt, l'adresse de la fonction q ue vous ave z pré vue pour traite r le cas de m anq ue de
m é m oire . Voici, par e xe m ple, un program m e q ui alloue d e s e m place m e nts pour de s tableaux d'e ntie rs dont
la taille e s t fournie e n donné e , e t ce ci jus q u'à ce q u'iln'y ait plus suffisam m e nt de place (note z q u'ici nous
utilisons toujours la m ê m e variable adr pour re ce voir les diffé re nte s adresses des tableaux, ce q ui, dans un
program m e ré e l, ne s e rait probablem e nt pas acce ptable).

_______________________________________________________________________________
______

#include <iostream.h>
main()
{
void deborde () ; // proto fonction appelée en cas manque mémoire
set_new_handler (&deborde) ;
long taille ;
int * adr ;
int nbloc ;
cout << "Taille souhaitée ? " ;
cin >> taille ;
for (nbloc=1 ; ; nbloc++)
44 Program m e r e n langage C+ +
{ adr = new int [taille] ;
cout << "Allocation bloc numéro : " << nbloc << "\n" ;
}
}
void deborde () // fonction appelée en cas de manque mémoire
{ cout << "Mémoire insuffisante - arrêt exécution \n " ;
exit (1) ;
}
_______________________
Taille souhaitée ? 5000
Allocation bloc numéro : 1
Allocation bloc numéro : 2
Allocation bloc numéro : 3
Allocation bloc numéro : 4
Allocation bloc numéro : 5
Mémoire insuffisante - arrêt exécution
_______________________________________________________________________________
______

Exe m ple de définition, par s e t_ne w _h andler, d'une fonction de ge s tion du m anque de m é m oire

R e m arque :

La te ch niq ue décrite ici e s t utilisable ave c toute s les ve rsions de C+ + , q u'e lles disposent ou non du
m é canism e de ge s tion de s e xce ptions. En e ffe t, dans ce dernie r cas, l'e xce ption de type bad_alloc e s t
lancé e , non pas directe m e nt par ne w , m ais par l'inte rm édiaire d'une fonction.

7. LA SPÉCIFICA TIO N INLINE

7.1 Rappe l
s conce rnant l
e s m acros e t l
e s fonctions

En langage C, vous save z q u'ile xiste deux notions as s e z voisines, à savoir les m acros e t les fonctions. Une
m acro e t une fonction s'utilisent appare m m e nt de la m ê m e façon e n faisant suivre leur nom d'une liste
d'argum e nts e ntre pare nth è s e s . Ce pe ndant :

• les instructions corre s pondant à une m acro sont incorporé e s à votre program m e 8, à ch aq ue fois q ue vous
l'appe lez ;

• les instructions corre s pondant à une fonction sont "gé né ré e s " une s e ule fois 9 ;à ch aq ue appe l, ily aura
s e ulem e nt m ise en place des instructions néce s s aire s à é tablir la liaison entre le program m e 10 e t la
fonction, c'e s t-à -dire : sauve garde de "l'é tat courant" (valeurs de ce rtains re gistre s , par e xe m ple),
re copie des valeurs des argum e nts, branch e m e nt ave c cons e rvation de l'adresse de re tour..., re copie de la
valeur de re tour, re s tauration de l'é tat courant e t re tour dans le program m e . Toute s ce s instructions,

8 - En toute rigue ur, l


'incorporation e s t ré al
isée au nive au du pré proce s s e ur, l
e q ue lintroduit l
e s ins tructions e n l
angage C corre s pondant à
"l'expansion" de la m acro ;ce s ins tructions pe uve nt d'aille urs varie r d'un appe là un autre.
9 - Par l
e com pilate ur, ce tte fois, sous form e d'instructions e n langage m ach ine.
10 - En toute rigue ur, ilfaudrait pl
utôt parl
e r de fonction appe l
ante.
IV. Le s s pécificités du C+ + 45
né ce s s aire s à la m ise en œuvre de l'appe lde la fonction, n'e xiste nt pas dans le cas de la m acro. O n pe ut
donc dire q ue la fonction pe rm e t de gagne r de l'e s pace m é m oire , e n contre partie d'une perte de te m ps
d'exécution. Bie n e nte ndu, la pe rte de te m ps s e ra re lative m e nt d'autant plus faible q ue la fonction s e ra de
taille im portante ;

• les m acros peuve nt, contraire m e nt aux fonctions, e ntraî ne r de s "e ffe ts de bord" indé s irables , ou pour le
m oins, pas néce s s aire m e nt pré vus. Citons deux exem ples :
- si une m acro introduit de nouve lles variables , ce lles -ci pe uve nt inte rfé re r ave c d'autre s variables de
m ê m e nom . Ce ris q ue n'e xiste pas ave c une fonction, sauf si l'on utilise, volontaire m e nt ce tte fois,
des variables globales ;
- une m acro dé finie par :
carre(x) x * x

e t appe lée par :


carre(a++)

gé né re ra les instructions :
a++ * a++

q ui incré m e nte nt deux fois la variable a.

Gé né ralem e nt, e n C, lors q ue l'on a be s oin d'une fonction courte e t q ue le te m ps d'exécution e s t prim ordial,
on fait appe là une m acro, m algré les inconvé nie nts q ue ce la im pliq ue . En C+ + , ile xiste , dans ce cas, une
solution plus satisfaisante : utiliser une fonction "e n ligne " (inline ).

7.2 Util
is ation de fonctions "e n l
igne "

Une fonction "e n ligne " se définit e t s'utilise com m e une fonction ordinaire , ave c la s e ule diffé re nce q u'on
fait pré céder son en-tê te de la spécification inline . En voici un e xe m ple.

_______________________________________________________________________________
______

#include <iostream.h>
#include <math.h>
/* définition d'une fonction "inline" */
inline double norme (double vec[3])
{ int i ; double s = 0 ;
for (i=0 ; i<3 ; i++) s+= vec[i]*vec[i] ;
return sqrt(s) ;
}

/* exemple d'utilisation */
main()
{ double v1[3], v2[3] ;
int i ;
for (i=0 ; i<3 ; i++) { v1[i] = i ; v2[i] = 2*i-1 ; }
cout << "norme de v1 : " << norme(v1) << " - norme de v2 : " << norme(v2) ;
46 Program m e r e n langage C+ +
} _______________________

norme de v1 : 2.236068 - norme de v2 : 3.316625


_______________________________________________________________________________
______

Exe m ple de définition e t d'utilisation d'une fonction "e n ligne "

La fonction norm e a pour but de calculer la norm e d'un ve cte ur à trois com posante s q u'on lui fournit e n
argum e nt.

La pré s e nce du m ot inline dem ande au com pilate ur de traite r la fonction norm e d'une m aniè re diffé re nte
d'une fonction ordinaire . Plus précisém e nt, à ch aq ue appe lde norm e , ildevra incorpore r, au s e in du
program m e , les instructions corre s pondante s (e n langage m ach ine 11). Le m é canism e h abitue lde gestion de
l'appe le t du re tour n'e xiste ra plus (iln'y a plus besoin de sauve garde s , re copie s , ...), ce q ui ré alise une
é conom ie de te m ps. Par contre , les instructions corre s pondante s s e ront gé né ré e s à ch aq ue appe l, ce q ui
consom m e ra une q uantité de m é m oire croissant ave c le nom bre d'appe ls.

Ile s t trè s im portant de note r q ue , de par sa nature m ê m e , une fonction "e n ligne " doit ê tre définie dans le
m ê m e fich ie r source q ue ce lui où on l'utilise. El le ne peut plus ê tre com pil ée séparém ent ! Ce ci e xpliq ue
q u'ilne s oit pas néce s s aire de déclare r une te lle fonction (sauf si elle e s t utilisée, au s e in d'un fich ie r source ,
avant d'ê tre définie ). Ainsi, dans notre e xe m ple, ne trouvons-nous pas de déclaration te lle q ue :

double norme (double) ;

Ce tte absence de possibilité de com pilation s é paré e constitue une contre partie notable aux avantage s offe rts
par la fonction "e n ligne ". En e ffe t, pour q u'une m ê m e fonction "e n ligne " puis s e ê tre partagé e par
diffé re nts program m e s , ilfaudra absolum e nt la place r dans un fich ie r e n-tê te 12 (com m e on le fait ave c une
m acro).

Avantage s Inconvé nie nts


M acro - É conom ie de te m ps - Pe rte d'espace m é m oire
d'exécution - R isque d'effe ts de bord non désirés
- Pas de com pilation s é paré e possible
Fonction - É conom ie d'espace - Pe rte de te m ps d'exécution
m é m oire
- Com pilation s é paré e
possible
Fonction - É conom ie de te m ps - Pe rte d'espace m é m oire
"e n ligne " d'exécution - Pas de com pilation s é paré e possible

Com parais on e ntre m acro, fonction e t fonction "e n ligne "

11 - Notez qu'ils'agit bien, ici, d'un travail e ffe ctué par l


e com pil
ate ur l
ui-m ê m e, al
ors q ue dans l
e cas d'une m acro, un travail
com parable é tait e ffe ctué par l
e pré proce s s e ur.
12 - A m oins d'en écrire pl usieurs fois l a dé finition, ce q ui ne s e rait pas "rais onnabl
e ", com pte te nu des risques d'erreurs que cel
a
com porte.
IV. Le s s pécificités du C+ + 47
R e m arque im portante :

La déclaration inline constitue une dem ande e ffe ctué e auprè s du com pilate ur. Ce dernie r pe ut
é ve ntue llem e nt (par e xe m ple, si la fonction e s t volum ine us e ) ne pas l'introduire e n ligne e t e n faire une
fonction ordinaire . De m ê m e , si vous utilisez quelque part (au s e in du fich ie r source conce rné ) l'adre s s e
d'une fonction dé claré e inline , le com pilate ur e n fe ra une fonction ordinaire (dans le cas contraire , ils e rait
incapable de lui attribue r une adre s s e e t e ncore m oins de m e ttre e n place un é ve ntue lappe ld'une fonction
situé e à ce tte adre s s e ).

8. LES ESPACES D E NO M S

Lors q ue l'on doit utiliser plusieurs biblioth è q ues d'obje ts dans un program m e , on pe ut ê tre confronté au
problèm e dit de "pollution de l'e s pace des nom s", lié à ce q u'un m ê m e identificate ur pe ut trè s bien avoir é té
utilisé par plusieurs biblioth è q ue s . Le m ê m e problèm e pe ut é galem e nt s e pos e r, à un de gré m oindre
toute fois, lors du déve loppe m e nt de gros program m e s . C'e s t la raison pour laq ue lle la norm e ANSI a
introduit le conce pt d'"e s pace de nom s". Il s'agit sim plem e nt de donner un nom à un "e s pace " de
déclarations, e n procédant ainsi :

namespace une_bibli
{ // déclarations usuelles
}

Pour s e ré fé re r à des identificate urs définis dans ce t e s pace de nom s, on utilisera une instruction using :

using namespace une_bibli


// ici, les identificateurs de une_bibli sont connus

O n pe ut leve r l'am biguïté ris q uant d'apparaî


tre lors q u'on utilise plusieurs espaces de nom s com portant des
identificate urs identiq ue s ;ilsuffit pour ce la de faire appe là l'opé rate ur de ré s olution de porté e ;par
e xe m ple :

une_bibli::point ... // on se réfère à l'identificateur point


// de l'espace de noms une_bibli

O n pe ut aussi utiliser l'instruction using pour faire un ch oix pe rm ane nt :

using une_bibli::point ; // dorénavant, l'identificateur point, employé seul


// correspondra à celui défini dans
// l'espace de noms une_bibli

En particulie r, lors q u'on fe ra appe laux com posants de la biblioth è q ue s tandard te ls q ue les conte ne urs ou les
algorith m e s , ilfaudra m e ntionne r l'instruction :

using namespace std ; /* utilisation de la bibliothèque standard */

9 . LE TYPE BO O L

Ce type e s t tout nature llem e nt form é de deux valeurs noté e s true e t false . En th é orie , les ré s ultats des
com paraisons ou des com binaisons logiq ues doive nt ê tre de ce type . Toute fois, ile xiste des conve rsions
im plicite s :

• de boole n num é riq ue , true deve nant 1 e t false deve nant 0,


48 Program m e r e n langage C+ +
• de num é riq ue (y com pris flottant) e n bool, toute valeur non nulle deve nant true e t zé ro de ve nant false .
D ans ce s conditions, tout s e pas s e com m e s i, finalem e nt, boolé tait un type é num é ré défini ainsi :

typedef enum { false=0, true } bool ;

En dé finitive , ce type bools e rt surtout à apporte r plus de clarté aux program m e s , sans re m e ttre e n caus e
q uoi q ue ce s oit.
V. CLASSES ET O BJETS

Ave c ce ch apitre , nous abordons vé ritablem e nt les possibilités de P.O .O . de C+ + . Com m e nous l'avons dit
dans le pre m ie r ch apitre , ce lles -ci re pos e nt e ntiè re m e nt sur le conce pt de clas s e . Une clas s e e s t la
gé né ralisation de la notion de type défini par l'utilisate ur1, dans leq ue ls e trouve nt associé e s à la fois des
donné e s (m e m bres donnée) e t des m é th ode s (fonctions m e m bre ). En P.O .O . "pure ", les données sont
e ncapsulée s e t leur accè s ne peut s e faire q ue par le biais des m é th ode s . C+ + vous autoris e à n'e ncapsuler
q u'une partie s e ulem e nt des données d'une clas s e (ce tte dém arch e re s te ce pe ndant forte m e nt décons e illée ).
Qui plus e s t, ile xiste m ê m e un type particulie r, corre s pondant à la gé né ralisation du type s tructure du C,
dans leq ue lsont e ffe ctive m e nt associées des données et des m é th ode s , m ais sans aucune e ncapsulation.

En pratiq ue , ce nouve au type s tructure du C+ + s e ra rare m e nt e m ployé s ous ce tte form e gé né ralisée. En
re vanch e , sur le plan conce ptue l, ilcorre s pond à un cas particulie r de la clas s e ;ils'agit, e n e ffe t, d'une
classe dans laq ue lle aucune donnée n'est e ncapsulée . C'e s t pour ce tte raison q ue nous com m e nce rons par
vous présente r le type s tructure de C+ + (m ot clé s truct) ;ce ci nous perm e ttra, dans un pre m ie r te m ps, de
nous lim ite r à la façon de m e ttre e n œuvre l'association des données et des m é th ode s . Ce n'e s t q u'e nsuite
q ue nous ve rrons com m e nt s'e xprim e l'e ncapsulation au s e in d'une clas s e (m ot clé class).

Com m e une clas s e (ou une s tructure ) n'e s t q u'un sim ple type défini par l'utilisate ur, les obje ts possè dent les
m ê m e s caracté ristiq ue s q ue les variables ordinaire s , e n particulie r e n ce q ui conce rne leurs diffé re nte s
classes d'allocation (statiq ue , autom atiq ue , dynam iq ue ). Ce pe ndant, pour re s te r sim ple dans un pre m ie r
te m ps e t nous focaliser essentie llem e nt sur le conce pt de clas s e , nous ne considérerons, dans ce ch apitre , q ue
des obje ts autom atiq ue s (déclaré s au s e in d'une fonction q ue lconq ue ), ce q ui corre s pond au cas le plus
nature l. Ce n'e s t q ue dans le ch apitre VII q ue nous aborde rons les autre s classes d'allocation de s obje ts.

Par ailleurs, nous introduirons ici les trè s im portante s notions de constructe ur e t de destructe ur (iln'y a
guè re d'obje ts inté re s s ants q ui n'y fas s e nt pas appe l). Là e ncore , com pte te nu de la rich esse de ce tte notion
e t de son inte rfé re nce ave c d'autre s (com m e les classes d'allocation), ilvous faudra atte ndre la fin du
ch apitre VII pour e n connaî tre toute s les possibilité s .

1. LES STRUCTURES EN C+ +

R appe lons d'abord trè s succincte m e nt com m e nt on m anipule les s tructure s e n C.

1 - En C, l
e s types définis par l
'util
isate ur s ont : l
e s s tructures, l
e s unions e t l
e s é num é rations.
50 Program m e r e n langage C+ +
1.1 Rappe l: l
e s s tructure s e n C

En C, une déclaration te lle q ue :

struct point
{ int x ;
int y ;
} ;

définit un "type s tructure " nom m é point (on dit aussi un m odè le de structure nom m é point ou parfois, par
abus de langage , la structure point2). Quant à x e t y, on dit q ue ce s ont des ch am ps ou de s m e m bre s 3 de la
structure point.

O n dé clare e nsuite des variables du type point par de s instructions te lles q ue :

struct point a, b ;

Ce lle-ci ré s e rve l'e m place m e nt pour de ux structure s nom m é e s a e t b, de type point. L'accè s aux m e m bre s
(ch am ps) de a ou de b se fait à l'aide de l'opé rate ur point (.) ;par e xe m ple, a.y désigne le m e m bre y de la
structure a.

En C+ + , com m e nous l'avons dit, nous allons pouvoir, dans une structure , associe r aux donné e s
constitué e s par s e s m e m bre s , des m é th ode s q u'on nom m e ra "fonctions m e m bre ". R appe lons q ue , puis q ue les
donné e s ne s ont pas e ncapsulées dans la structure , une te lle association e s t re lative m e nt artificie lle e t q ue s on
principalinté rê t e s t de préparer à la notion de clas s e .

1.2 D é cl
aration d'une s tructure com portant de s fonctions m e m bre

Suppos e z q ue nous souh aitions associe r à la structure point pré cédente trois fonctions :

• initialise pour donne r de s valeurs aux "coordonné e s " d'un point,


• de place pour m odifie r les coordonnées d'un point,
• affich e pour affich e r un point : ici, nous nous conte nte rons, par souci de s im plicité , d'affich e r les
coordonnées du point.
Voici com m e nt nous pourrions déclare r notre s tructure point.

_______________________________________________________________________________
______

/* ------------ Déclaration du type point ------------- */


struct point
{ /* déclaration "classique" des données */
int x ;
int y ;
/* déclaration des fonctions membre (méthodes) */
void initialise (int, int) ;
void deplace (int, int) ;
void affiche () ;

2 - D ans ce cas, ily a am biguïté car l


e m ê m e m ot s tructure désignera à l
a fois un type et des obje ts d'un type structure. Général
e m e nt, l
e
conte xte pe rm e ttra de tranch e r e t c'e s t s ouve nt ce te rm e q ue nous util
iserons.
3 - C'e s t pl
utôt ce dernier te rm e q ue l 'on e m pl oie ra e n C+ + .
V. Clas s e s e t obje ts 51
} ;
_______________________________________________________________________________
______

D é claration d'une s tructure com portant de s m é th ode s

Nous y trouvons ce tte fois, outre la déclaration classique des données 4, les déclarations (e n-tê te s ) de nos
trois fonctions. Note z bie n q ue la définition de ce s fonctions ne figure pas à ce nive au de s im ple
déclaration : e lle s e ra ré alisée par ailleurs com m e nous le ve rrons un pe u plus loin.

Ici, nous avons prévu q ue la fonction m e m bre initialise re ce vra, e n argum e nt, deux valeurs de type int. A ce
nive au, rie n ne dit l'usage q ui s e ra fait de ces deux valeurs. Ici, bie n e nte ndu, nous avons é crit l'e n-tê te de
initialise e n ayant à l'e s prit l'idé e q u'e lle affe cte rait aux m e m bre s x e t y les valeurs re çue s e n argum e nt. Le s
m ê m e s re m arq ue s s 'appliq ue nt aux de ux autre s fonctions m e m bre .

Vous vous atte ndie z (pe ut-ê tre !) à trouve r, pour ch aq ue fonction m e m bre , un argum e nt supplém e ntaire
pré cisant la structure (variable) sur laq ue lle e lle doit opé re r5. Nous ve rrons com m e nt ce tte inform ation s e ra
autom atiq ue m e nt fournie à la fonction m e m bre lors de son appe l.

1.3 D é finition de s fonctions m e m bre

Elle s e fait par une définition (pre s q ue ) classique de fonction. Voici ce q ue pourrait ê tre la définition de
initialise :

void point::initialise (int abs, int ord)


{ x = abs ;
y = ord ;
}

D ans l'e n-tê te , le nom de la fonction e s t :

point::initialise

Le sym bole :: corre s pond à ce q ue l'on nom m e , e n C+ + , l'opé rate ur de "ré s olution de porté e ". Ilpe ut ê tre
utilisé dans d'autre s conte xte s q ue ce lui-ci ;ils e rt à m odifie r la portée d'un ide ntificate ur. Ici, ilsignifie q ue
l'ide ntificate ur initialise dont on "parle" e s t ce lui dé fini dans point. En l'abs e nce de ce "pré fixe " (point::),
nous définirions e ffe ctive m e nt une fonction nom m é e initialise , m ais ce lle-ci ne s e rait plus associé e à point ;
ils'agirait d'une fonction "ordinaire ", nom m é e initialise e t non plus de la fonction m e m bre initialise de (la
structure ) point.

Si nous e xam inons m ainte nant le corps de la fonction initialise , nous y trouvons une affe ctation :

x = abs ;

Le sym bole abs y désigne, classiquem e nt, la valeur re çue e n pre m ie r argum e nt. M ais x, q uant à lui, n'e s t ni
un argum e nt ni une variable locale. En fait, x dé s igne le m e m bre x corre s pondant au type point (ce tte
association é tant ré alisée par le point:: de l'e n-tê te ). Que lle s e ra pré cis é m e nt la structure 6 conce rné e ?Là

4 - O n parl
e parfois de "variabl e s ", par anal
ogie ave c l
e s "fonctions m e m bre".
5 - Pour q u'une te l
le inform ation ne s oit pas utile, ilfaudrait "dupl iq ue r" l
e s fonctions m e m bre en autant d'exem pl
aire s q u'ily a de
s tructures de type point, ce q ui s e rait particuliè re m e nt ine fficace !
6 - Ici, le te rm e s tructure e s t bien synonym e de variabl e de type structure.
52 Program m e r e n langage C+ +
e ncore , nous ve rrons com m e nt ce tte inform ation s e ra transm ise autom atiq ue m e nt à la fonction initialise lors
de son appe l.

Nous n'insistons pas sur la définition des deux autre s fonctions m e m bre ;vous trouve re z ci-de s s ous
l'e ns e m ble des définitions de nos trois fonctions.

_______________________________________________________________________________
______

/* ----- Définition des fonctions membre du type point ---- */


void point::initialise (int abs, int ord)
{
x = abs ; y = ord ;
}
void point::deplace (int dx, int dy)
{
x += dx ; y += dy ;
}
void point::affiche ()
{
cout << "Je suis en " << x << " " << y << "\n" ;
}
_______________________________________________________________________________
______

D é finition de s fonctions m e m bre

1.4 Util
is ation d'une s tructure com portant de s fonctions m e m bre

D isposant du type point te lq u'ilvie nt d'ê tre déclaré dans le paragraph e 1.2, nous pouvons tout d'abord
déclare r autant de structures de ce type q ue nous le s ouh aitons. Par e xe m ple :

point a, b ;7

déclare deux structure s nom m é e s a e t b, possédant ch acune des m e m bre s x e t y et disposant ch acune des
trois m é th ode s initialise , de place e t affich e . A ce propos, nous pouvons d'ores et déjà re m arq ue r q ue , si
ch aq ue s tructure dispose en propre de ch acun de s e s m e m bre s , iln'e n va pas de m ê m e des fonctions
m e m bre : ce lles -ci ne s ont "gé né ré e s 8" q u'une s e ule fois (le contraire conduirait m anife s te m e nt à un
gaspillage de m é m oire !).

L'accè s aux m e m bre s x e t y de nos structure s a e t b pourrait se dérouler com m e e n C ;ainsi pourrions-nous
é crire :

a.x = 5 ;

Ce faisant, nous accéderions "dire cte m e nt" aux donné e s , sans passer par l'inte rm édiaire des m é th ode s .
Ce rte s , nous ne respecte rions pas le principe d'encapsulation m ais, dans ce cas précis (de structure e t pas
e ncore de clas s e ), ce s e rait parfaite m e nt acce pté e n C+ + 9 .

L'appe ld'une fonction m e m bre e s t fait d'une m aniè re s e m blable. Ainsi :

7 - O u s truct point a, b ;l
e m ot s truct e s t facul
tatif e n C+ + .
8 - Exce ption faite des fonctions "e n ligne ".
9 - Ici, jus te m e nt, l
e s fonctions m e m bre prévue s pour notre s tructure point pe rm e tte nt de respecte r l
e principe d'encapsul
ation.
V. Clas s e s e t obje ts 53
a.initialise (5,2) ;

signifie : appe ler la fonction m e m bre initialise , pour l a structure a, e n lui transm e ttant e n argum e nt les
valeurs 5 et 2. Si l'on fait abstraction du "pré fixe " a., ce t appe le s t analogue à un appe lclassique de
fonction. Bie n e nte ndu, c'e s t juste m e nt ce pré fixe q ui va pré cis e r à la fonction m e m bre q ue lle e s t la
structure s ur laq ue lle e lle doit opé re r. Ainsi, ici, l'instruction :

x = abs ;

de point::initialise place ra dans le ch am p x de la structure a, la valeur re çue pour abs (c'e s t-à -dire 5).

R e m arques :

1) Un appe lte lq ue a.initialise (5,2) ;pourrait ê tre re m placé , ici, par :


a.x = 5 ; a.y = 2 ;

Nous ve rrons précisém e nt q u'iln'e n ira plus de m ê m e dans le cas d'une (vraie ) clas s e , pour pe u q u'on y
ait conve nablem e nt e ncapsulé les données.
2) En jargon P.O .O ., on dit é galem e nt q ue a.initialise (5, 2) constitue l'envoi d'un m essage (initialise ,
accom pagné des inform ations 5 et 2) à l'obje t a.

1.5 Exe m pl
e ré capitul
atif

Voici un e xe m ple de program m e , re pre nant la déclaration du type point, la définition de s e s fonctions
m e m bre e t l'utilisant dans la fonction m ain.

_______________________________________________________________________________
______

#include <iostream.h>
/* ------------ Déclaration du type point ------------- */
struct point
{ /* déclaration "classique" des données */
int x ;
int y ;
/* déclaration des fonctions membre (méthodes) */
void initialise (int, int) ;
void deplace (int, int) ;
void affiche () ;
} ;
/* ----- Définition des fonctions membre du type point ---- */
void point::initialise (int abs, int ord)
{
x = abs ; y = ord ;
}
void point::deplace (int dx, int dy)
{
x += dx ; y += dy ;
}
void point::affiche ()
{
54 Program m e r e n langage C+ +
cout << "Je suis en " << x << " " << y << "\n" ;
}

main()
{
point a, b ;
a.initialise (5, 2) ; a.affiche () ;
a.deplace (-2, 4) ; a.affiche () ;
b.initialise (1,-1) ; b.affiche () ;
}

_______________________

Je suis en 5 2
Je suis en 3 6
Je suis en 1 -1
_______________________________________________________________________________
______

Exe m ple de définition e t d'utilisation du type point

R e m arques

1) La syntaxe m ê m e de l'appe l d'une fonction m e m bre fait q ue ce lle-ci re çoit obligatoire m e nt un


"argum e nt im plicite " du type de la structure corre s pondante . Une fonction m e m bre ne pe ut pas ê tre
appe lée com m e une "fonction ordinaire ". Par e xe m ple, ce tte instruction :
initialise (3,1) ;

s e ra re je té e à la com pilation (à m oins q u'iln'e xiste , par ailleurs, une fonction ordinaire nom m é e
initialise ).

2) D ans la déclaration d'une s tructure , ile s t pe rm is (m ais généralem e nt pe u cons e illé) d'introduire les
donné e s e t les fonctions dans un ordre q ue lconq ue (nous avons systé m atiq ue m e nt placé les données
avant les fonctions).

3) D ans notre e xe m ple de program m e com plet, nous avons introduit :


- la déclaration du type point,
- la définition de s fonctions m e m bre ,
- la fonction (m ain) utilisant le type point.
M ais, bie n e nte ndu, ils e rait possible de "com piler s é paré m e nt" le type point ;c'e s t d'ailleurs ainsi
q ue l'on pourra "ré utiliser" un "com posant logicie l". Nous y revie ndrons à la fin de ce ch apitre .

2. NO TIO N D E CLASSE

Com m e nous l'avons déjà dit, la structure e n C+ + e s t un cas particulie r de la clas s e . Plus précisém e nt, une
clas s e s e ra une s tructure dans laq ue lle s e ulem e nt ce rtains m e m bre s e t/ou fonctions m e m bre s e ront "publics",
c'e s t-à -dire acce s s ibles "de l'e xté rie ur", les autre s m e m bre s é tant dits "privé s ".

La déclaration d'une clas s e e s t voisine de ce lle d'une structure puis q u'e n e ffe t, ilsuffit :
V. Clas s e s e t obje ts 55
• de re m place r le m ot clé s truct par le m ot clé class,
• de préciser quels sont les m e m bre s publics (fonctions ou donné e s ) e t les m e m bre s privé s e n utilisant les
m ots clés public e t private .

Par e xe m ple, faisons de notre pré cédente s tructure point une classe dans laq ue lle tous les m e m bres donnée
sont privé s e t toute s les fonctions m e m bre s ont publiq ue s . Sa déclaration s e rait sim plem e nt la suivante .

_______________________________________________________________________________
______

/* ------------ Déclaration de la classe point ------------- */


class point
{ /* déclaration des membres privés */
private : /* facultatif (voir remarque 4) */
int x ;
int y ;
/* déclaration des membres publics */
public :
void initialise (int, int) ;
void deplace (int, int) ;
void affiche () ;
} ;
_______________________________________________________________________________
______

D é claration d'une clas s e

Ici, les m e m bre s nom m é s x e t y sont privé s , tandis q ue les fonctions m e m bre nom m é e s initialise , de place e t
affich e sont publiq ue s .

En ce q ui conce rne la définition de s fonctions m e m bre d'une clas s e , e lle s e fait e xacte m e nt de la m ê m e
m aniè re q ue ce lle des fonctions m e m bre d'une structure (q u'ils'agisse de fonctions publiq ue s ou privé e s ).
En particulie r, ce s fonctions m e m bre ont (e lles !) accè s à l'e ns e m ble des m e m bre s (publics ou privé s ) de la
clas s e .

L'utilisation d'une clas s e s e fait é galem e nt com m e ce lle d'une structure . A titre indicatif, voici ce q ue
devie nt notre program m e du paragraph e 1.5 lors q ue l'on y re m place la structure point par la clas s e point
te lle q ue nous ve nons de la définir.

_______________________________________________________________________________
______

#include <iostream.h>
/* ------------ Déclaration de la classe point ------------- */
class point
{ /* déclaration des membres privés */
private :
int x ;
int y ;
/* déclaration des membres publics */
public :
void initialise (int, int) ;
56 Program m e r e n langage C+ +
void deplace (int, int) ;
void affiche () ;
} ;

/* ----- Définition des fonctions membre de la classe point ---- */


void point::initialise (int abs, int ord)
{
x = abs ; y = ord ;
}
void point::deplace (int dx, int dy)
{
x = x + dx ; y = y + dy ;
}
void point::affiche ()
{
cout << "Je suis en " << x << " " << y << "\n" ;
}

/* -------- Utilisation de la classe point -------- */


main()
{
point a, b ;
a.initialise (5, 2) ; a.affiche () ;
a.deplace (-2, 4) ; a.affiche () ;
b.initialise (1,-1) ; b.affiche () ;
}
_______________________________________________________________________________
______

Exe m ple de définition e t d'utilisation d'une clas s e (point)

R e m arques

1) D ans le "jargon" de la P.O .O ., on dit q ue a e t b sont des instances de la clas s e point, ou e ncore q ue
ce s ont des objets de type point ;c'e s t gé né ralem e nt ce dernie r te rm e q ue nous utiliserons 10 ;
2) D ans notre e xe m ple, tous les m e m bres donnée de point sont privé s , ce q ui ré alise une encapsulation
com plète des données. Ainsi, une te ntative d'utilisation dire cte (ici au s e in de la fonction m ain) du
m e m bre a :
a.x = 5

conduirait à un diagnostic de com pilation (bie n e nte ndu, ce tte instruction s e rait acce pté s s i nous
avions fait de x un m e m bre public).
En gé né ral, on ch e rch e ra à re s pe cte r le principe d'encapsulation des données, quitte à pré voir de s
fonctions m e m bre approprié e s pour y accéder.
3) D ans notre e xe m ple, toute s les fonctions m e m bre é taie nt publiq ue s . Ile s t tout à fait possible d'en
re ndre ce rtaine s privé e s . Dans ce cas, de te lles fonctions ne seront plus acce s s ibles de "l'e xté rie ur" de
la clas s e . Elles ne pourront ê tre appe lée s q ue par d'autre s fonctions m e m bre .
4) Le s m ots clés public e t private pe uve nt apparaî
tre à plusieurs reprises dans la définition d'une clas s e ,
com m e dans ce t e xe m ple :

10 - Ilpourrait d'ail
le urs s'appl
iq ue r aux ins tances de structure.
V. Clas s e s e t obje ts 57
class X
{ private :
...
public :
...
private :
...
} ;

Si aucun de ces deux m ots n'apparaî t au début de la définition, tout s e pas s e com m e s i private y avait
é té placé . C'e s t pourq uoi la pré s e nce de ce m ot n'é tait pas indispensable dans la définition de notre
clas s e point.
Si aucun de ces deux m ots n'apparaî t dans la définition d'une clas s e , tous s e s m e m bre s s e ront donc
privé s , donc inacce s s ibles . Ce la s e ra rare m e nt utile.
5) Si l'on re nd publics tous les m e m bres d'une clas s e , on obtie nt l'é q uivalent d'une s tructure . Ainsi, ce s
deux déclarations définis s e nt le m ê m e type point :
struct point class point
{ int x ; { public :
int y ; int x ;
void initialise (...) ; int y ;
..... void initialise (...) ;
} ; .....
} ;

6) Par la suite , e n l'abs e nce de pré cisions supplém e ntaire s , nous utiliserons le m ot classe pour dé s igne r
indiffé re m m e nt une "vraie " clas s e (cl
ass) ou une s tructure (struct), voire é galem e nt une union ou une
é num é ration (enum ) dont nous parlerons un pe u plus loin11. De m ê m e , nous utiliserons le m ot objet
pour dé s igne r de s instances de ces diffé re nts type s .
7) En toute rigue ur, ile xiste un troisiè m e m ot, à savoir prote cte d (proté gé ) q ui s'utilise de la m ê m e
m aniè re q ue les deux autre s ;ils e rt à définir un statut inte rm édiaire e ntre public e t privé , leq ue l
n'inte rvie nt q ue dans le cas de classes dérivé e s . Nous e n re parlerons dans le ch apitre XII.

3. A FFECTA TIO N D 'O BJETS

En C, ile s t possible d'affe cte r à une s tructure la "valeur" d'une autre s tructure de m ê m e type . Ainsi, ave c
ces déclarations :

struct point
{ int x ;
int y ;
} ;
struct point a, b ;

vous pouve z tout à fait é crire :

a = b ;

Ce tte instruction re copie l'e ns e m ble des valeurs des ch am ps de b dans ce ux de a. Elle joue le m ê m e rôle
q ue :

11 - La situation l
a pl
us ré pandue é tant ce l
le du type class.
58 Program m e r e n langage C+ +
a.x = b.x ;
a.y = b.y ;

En C+ + , ce tte possibilité d'affectation gl obal e s'é te nd aux obje ts 12 de m ê m e type . Elle corre s pond à une
recopie des val eurs des m em bres donné e 13, q ue ce ux-ci soient publics ou non. Ainsi, ave c ces déclarations
(note z q u'ici nous avons prévu, artificie llem e nt, x privé e t y public) :

class point
{ int x ;
public :
int y ;
....
} ;
point a, b ;

l'instruction :

b = a ;

provoq ue ra la re copie des valeurs des m e m bre s x e t y de a dans les m e m bre s corre s pondants de b.

Ilfaut note r q u'ici, contraire m e nt à ce q ui a é té dit pour les s tructure s , iln'e s t plus possible de re m place r
ce tte instruction par :

b.x = a.x ;
b.y = a.y ;

En e ffe t, si la deuxiè m e affe ctation e s t légale, com pte te nu (ici) de ce q ue y est public, la pre m iè re ne l'e s t
pas, puis q ue x e s t privé 14.

Note z bie n q ue l'affe ctation b = a e s t toujours légale, q ue lq ue s oit le s tatut (public ou privé ) des m e m bre s
donné e . O n pe ut considérer qu'elle ne viole pas le principe d'encapsulation, dans la m e s ure où les données
privées de b (c'e s t-à -dire les copies de ce lles de a) re s te nt toujours inacce s s ibles de m aniè re directe .

R e m arque trè s im portante :


Le rôle de l'opé rate ur =, te lq ue nous ve nons de le définir (re copie des m e m bres données) pe ut, ici,
paraître nature l. En fait, ilne l'e s t q ue pour de s cas sim ples . Nous ve rrons des circonstance s où ce tte
banale re copie s 'avé re ra insuffisante ;ce s e ra notam m e nt le cas dè s q u'un obje t com porte ra de s pointe urs
sur des em place m e nts dynam iq ue s . La re copie e n q ue s tion ne conce rne ra pas ce tte partie dynam iq ue de
l'obje t (on dira q u'ils'agit d'une "re copie s upe rficie lle"). Nous re vie ndrons ulté rie ure m e nt sur ce point
fondam e ntalq ui ne trouve ra de s olution satisfaisante q ue dans la surdéfinition (pour la clas s e conce rné e )
de l'opé rate ur =.

12 - A u s e ns l
arge : de type cl ass, struct, union ou e num .
13 - Le s fonctions m e m bre n'ont aucune rais on d'ê tre conce rnées.
14 - Sauf, si l 'affe ctation b.x = a.x é tait é crite au s e in d'une fonction m e m bre de l
a cl
as s e point.
V. Clas s e s e t obje ts 59
4. NO TIO N D E CO NSTRUCTEUR ET D E D ESTRUCTEUR

4.1 Introduction

A priori, les obje ts 15 suive nt les rè gles h abitue lles conce rnant leur initialisation par dé faut, à savoir q ue s e uls
les obje ts statiq ue s voie nt leurs données initialisées à zé ro. En gé né ral, ile s t donc né ce s s aire de faire appe là
une fonction m e m bre pour attribue r de s valeurs aux données d'un obje t. C'e s t ce q ue nous avons fait pour
notre type point ave c la fonction initialise .

Une te lle dém arch e oblige toute fois à com pte r sur l'utilisate ur de l'obje t pour e ffe ctue r l'appe lvoulu au bon
m om e nt. En outre , si, dans le cas présent, le ris q ue ne porte q ue s ur de s valeurs non définie s , iln'e n va plus
de m ê m e dans le cas où, avant m ê m e d'ê tre utilisé, un obje t doit s'alloue r dynam iq ue m e nt de la m é m oire 16.
L'abs e nce de procédure d'initialisation pe ut, dans ce dernie r cas, deve nir catastroph iq ue .

C+ + offre un m é canism e trè s perform ant pour traite r ce s problèm e s , à savoir le constructeur. Ils'agit
d'une fonction m e m bre (définie com m e les autre s fonctions m e m bre ) q ui s e ra appe lée autom atiq ue m e nt à
ch aq ue "cré ation" d'un obje t. Ce ci aura lie u q ue lle q ue s oit la "classe d'allocation" de l'obje t : statiq ue ,
autom atiq ue ou dynam iq ue . Note z q ue les obje ts autom atiq ue s auxq ue ls nous nous lim itons ici sont "cré é s "
par une déclaration. Ce ux de classe dynam iq ue s e ront cré é s par ne w (nous y revie ndrons dans le ch apitre
VII).

D 'une m aniè re s im ilaire , un obje t pourra posséder un destructeur ;ils'agit é galem e nt d'une fonction
m e m bre q ui e s t appe lée autom atiq ue m e nt au m om e nt de la "destruction" de l'obje t corre s pondant. Dans le
cas des obje ts autom atiq ue s , la destruction de l'obje t a lie u lors q ue l'on q uitte le bloc ou la fonction où ila
é té déclaré .

Par conve ntion, le constructe ur s e re connaî t à ce q u'il porte le m ê m e nom q ue la clas s e . Quant au
destructe ur, ilporte le m ê m e nom q ue la clas s e , pré cédé du sym bole tilda (~ ).

4.2 Exe m pl
e de cl
as s e com portant un cons tructe ur

Considérons notre clas s e point pré cédente e t transform ons sim plem e nt notre fonction m e m bre initialise e n
un constructe ur e n la re nom m ant point (dans sa déclaration e t dans sa définition). Notre nouve lle clas s e point
s e pré s e nte alors ainsi :

_______________________________________________________________________________
______

/* ------------ Déclaration de la classe point ------------- */


class point
{ /* déclaration des membres privés */
int x ;
int y ;
/* déclaration des membres publics */
public :
point (int, int) ; // constructeur
void deplace (int, int) ;
void affiche () ;
} ;

15 - A u s e ns l
arge du te rm e.
16 - Ne confondez pas un obje t dynam iq ue ave c un obje t (par e xe m pl
e, autom atiq ue ) q ui s'al
loue dynam iq ue m e nt de l
a m é m oire. Une
situation de ce type sera étudiée dans l
e proch ain ch apitre.
60 Program m e r e n langage C+ +
_______________________________________________________________________________
______

Une clas s e (point) m unie d'un cons tructe ur

Com m e nt utiliser cette clas s e ?A priori, vous pourrie z pe ns e r q ue la déclaration suivante convie nt toujours :

point a ;

En fait, à partir du m om e nt où un constructe ur e s t défini, ildoit pouvoir ê tre appe lé (autom atiq ue m e nt) lors
de la cré ation de l'obje t a. Ici, notre constructe ur a be s oin de deux argum e nts. Ce ux-ci doive nt
obligatoire m e nt ê tre fournis dans notre déclaration, par e xe m ple :

point a(1,3) ;

Ce tte contrainte e s t e n fait un e xce llent garde -fou : à partir du m om ent où une cl asse possè de un
constructeur 17, iln'est pl us possibl e de créer un objet sans fournir l es argum ents requis par son
constructeur (sauf si ce dernie r ne possè de aucun argum e nt18 !).

A titre d'exem ple, voici com m e nt pourrait ê tre adapté le program m e du paragraph e 1.5, pour q u'ilutilise
m ainte nant notre nouve lle clas s e point.

_______________________________________________________________________________
______

#include <iostream.h>
/* ------------ Déclaration de la classe point ------------- */
class point
{ /* déclaration des membres privés */
int x ;
int y ;
/* déclaration des membres publics */
public :
point (int, int) ; // constructeur
void deplace (int, int) ;
void affiche () ;
} ;
/* ----- Définition des fonctions membre de la classe point ---- */
point::point (int abs, int ord)
{ x = abs ; y = ord ;
}
void point::deplace (int dx, int dy)
{ x = x + dx ; y = y + dy ;
}
void point::affiche ()
{ cout << "Je suis en " << x << " " << y << "\n" ;
}
/* -------- Utilisation de la classe point -------- */
main()
{ point a(5,2) ;
a.affiche () ;
a.deplace (-2, 4) ; a.affiche () ;

17 - Nous ve rrons, dans le proch ain ch apitre, que l


e cons tructe ur pe ut ê tre s urdéfini ou posséder des argum e nts par dé faut.
18. M ais, dans tous l
e s cas, ily aura appe ldu constructe ur.
V. Clas s e s e t obje ts 61
point b(1,-1) ;
b.affiche () ;
} _______________________
Je suis en 5 2
Je suis en 3 6
Je suis en 1 -1
_______________________________________________________________________________
______

Exe m ple d'utilisation d'une clas s e (point) m unie d'un cons tructe ur

4.3 Cons truction e t de s truction de s obje ts

Nous vous proposons ci-de s s ous un pe tit program m e m e ttant e n é vidence les m om e nts où sont appe lés
re s pe ctive m e nt le constructe ur e t le destructe ur d'une clas s e . Nous y définissons une clas s e nom m é e te s t
com portant e s s e ntie llem e nt ces deux fonctions m e m bre : ce lles -ci affich e nt un m e s s age , nous fournissant
ainsi une trace de leur appe l. En outre , le m e m bre donnée num initialisé par le constructe ur nous perm e t
"d'identifie r" l'obje t conce rné (dans la m e s ure où nous nous som m e s arrangé s pour q u'aucun de s obje ts
cré é s ne contie nne la m ê m e valeur). Nous cré ons des obje ts autom atiq ue s 19 de type te s t à deux "endroits"
diffé re nts : dans la fonction m ain d'une part, dans une fonction fct appe lée par m ain d'autre part.

_______________________________________________________________________________
______

#include <iostream.h>
class test
{
public :
int num ;
test (int) ; // déclaration constructeur
~test () ; // déclaration destructeur
} ;
test::test (int n) // définition constructeur
{ num = n ;
cout << "++ Appel constructeur - num = " << num << "\n" ;
}
test::~test () // définition destructeur
{
cout << "-- Appel destructeur - num = " << num << "\n" ;
}
main()
{
void fct (int) ;
test a(1) ;
for (int i=1 ; i<=2 ; i++) fct(i) ;
}
void fct (int p)
{ test x(2*p) ; // notez l'expression (non constante) : 2*p
}
_______________________

++ Appel constructeur - num = 1

19 - R appe l
ons q u'ici nous nous l
im itons à ce cas.
62 Program m e r e n langage C+ +
++ Appel constructeur - num = 2
-- Appel destructeur - num = 2
++ Appel constructeur - num = 4
-- Appel destructeur - num = 4
-- Appel destructeur - num = 1
_______________________________________________________________________________
______

Cons truction e t de s truction de s obje ts

4.4 Rôl
e s du cons tructe ur e t du de s tructe ur

D ans nos précédents e xe m ples , le rôle du constructe ur s e lim itait à une "initialisation" de l'obje t à l'aide des
valeurs q u'ilavait re çue s e n argum e nt. M ais le travailré alisé par le constructe ur pe ut ê tre beaucoup plus
é laboré . Voici un program m e e xploitant une clas s e nom m é e h asard, dans laq ue lle le constructe ur fabriq ue
dix valeurs e ntiè re s aléatoire s q u'ilrange dans le m e m bre donnée val(ce s valeurs sont com pris e s e ntre zé ro
e t la valeur q ui lui e s t fournie e n argum e nt).

_______________________________________________________________________________
______

#include <iostream.h>
#include <stdlib.h> // pour la fonction rand

class hasard
{ int val[10] ;
public :
hasard (int) ;
void affiche () ;
} ;
hasard::hasard (int max) // constructeur : il tire 10 valeurs au hasard
// rappel : rand fournit un entier entre 0 et RAND_MAX
{ int i ;
for (i=0 ; i<10 ; i++) val[i] = double (rand()) / RAND_MAX * max ;
}
void hasard::affiche () // pour afficher les 10 valeurs
{ int i ;
for (i=0 ; i<10 ; i++) cout << val[i] << " " ;
cout << "\n" ;
}

main()
{ hasard suite1 (5) ;
suite1.affiche () ;
hasard suite2 (12) ;
suite2.affiche () ;
}
_______________________
2 0 1 2 4 0 3 1 2 0
1 4 3 4 11 6 9 7 9 9
_______________________________________________________________________________
______
V. Clas s e s e t obje ts 63
Un constructe ur de valeurs aléatoire s

En pratiq ue , d'ailleurs, on pré fé re ra disposer d'une classe dans laq ue lle le nom bre de valeurs (ici fixé à dix)
pe ut ê tre fourni e n argum e nt du constructe ur. D ans ce cas, ile s t alors préfé rable q ue l'e s pace (variable) soit
alloué dynam iq ue m e nt au lie u d'ê tre s urdim e nsionné . Il e s t alors tout nature l de faire e ffe ctue r ce tte
allocation dynam iq ue par le constructe ur lui-m ê m e . Les données de la clas s e h asard s e lim ite ront alors à :

class hasard
{
int nbval // nombre de valeurs
int * val // pointeur sur un tableau de valeurs
...
} ;

Bie n sûr, ilfaudra pré voir q ue le constructe ur re çoive e n argum e nt, outre la valeur m axim ale, le nom bre de
valeurs souh aité e s .

Par ailleurs, à partir du m om e nt où un e m place m e nt a é té alloué dynam iq ue m e nt, ilfaut s e s oucie r de s a


libération lors q u'ils e ra de ve nu inutile. Là e ncore , ilparaî
t tout nature lde confie r ce travailau de s tructe ur
de la clas s e .

Voici com m e nt nous pourrions adapte r dans ce s e ns notre pré cédent e xe m ple.

_______________________________________________________________________________
______

#include <iostream.h>
#include <stdlib.h> // pour la fonction rand
class hasard
{
int nbval ; // nombre de valeurs
int * val ; // pointeur sur les valeurs
public :
hasard (int, int) ; // constructeur
~hasard () ; // destructeur
void affiche () ;
} ;
hasard::hasard (int nb, int max)
{ int i ;
val = new int [nbval = nb] ;
for (i=0 ; i<nb ; i++) val[i] = double (rand()) / RAND_MAX * max ;
}
hasard::~hasard ()
{ delete val ;
}
void hasard::affiche () // pour afficher les nbavl valeurs
{ int i ;
for (i=0 ; i<nbval ; i++) cout << val[i] << " " ;
cout << "\n" ;
}
main()
{
hasard suite1 (10, 5) ; // 10 valeurs entre 0 et 5
suite1.affiche () ;
hasard suite2 (6, 12) ; // 6 valeurs entre 0 et 12
64 Program m e r e n langage C+ +
suite2.affiche () ;
}
_______________________

2 0 1 2 4 0 3 1 2 0
1 4 3 4 11 6
_______________________________________________________________________________
______

Exe m ple de classe dont le cons tructe ur e ffe ctue une allocation dynam ique de m é m oire

D ans le constructe ur, l'instruction :

val = new [nbval = nb] ;

re m place avantage us e m e nt :

nbval = nb ;
val = new [nbval] ;

R e m arques :

1) Ne confonde z pas une allocation dynam iq ue e ffe ctué e au s e in d'une fonction m e m bre d'un obje t
(souve nt le constructe ur) ave c une allocation dynam iq ue d'un obje t, dont nous parlerons plus tard.

2) Lors q u'un constructe ur s e conte nte d'attribue r de s valeurs initiales aux données d'un obje t, le
destructe ur e s t rare m e nt indispensable. Ille devie nt, par contre , dè s q ue , com m e dans notre e xe m ple,
l'obje t e s t am e né (par le biais de son constructe ur ou d'autre s fonctions m e m bre ) à alloue r
dynam iq ue m e nt de la m é m oire .

3) Com m e nous l'avons déjà m e ntionné , dè s lors q u'une clas s e contie nt, com m e dans notre dernie r
e xe m ple, des pointe urs sur de s e m place m e nts alloués dynam iq ue m e nt, l'affe ctation e ntre obje ts de
m ê m e type ne conce rne pas ce s parties dynam iq ue s ;gé né ralem e nt, ce ci pose problèm e e t la solution
pas s e par la surdéfinition de l'opé rate ur =. Autre m e nt dit, la clas s e h asard définie dans le dernie r
e xe m ple ne pe rm e ttrait pas de traite r corre cte m e nt l'affe ctation d'obje ts de ce type .

4.5 Q u e l
q ue s rè gl
es

Un constructe ur pe ut com porte r un nom bre q ue lconq ue d'argum e nts, é ve ntue llem e nt aucun. Par définition,
un constructe ur ne re nvoie pas de valeur ;aucun type ne pe ut figure r de vant son nom (la pré s e nce de void
e s t, dans ce cas précis, une erreur).

Un de s tructe ur, par dé finition, ne pe ut pas disposer d'argum e nts e t ne re nvoie pas de valeur. Là e ncore ,
aucun type ne pe ut figure r de vant son nom (e t la pré s e nce de void e s t une e rre ur).

En th é orie , constructe urs e t destructe urs peuve nt ê tre publics ou privé s . En pratiq ue , à m oins d'avoir de
bonne s raisons de faire le contraire , ilvaut m ie ux les re ndre publics. En e ffe t, un de s tructe ur privé ne pourra
pas ê tre appe lé directe m e nt20, ce q ui n'e s t pas grave , dans la m e s ure où ce la e s t rare m e nt utile. En

20 - L'appe ldirect d'un destructe ur n'e s t possibl


e q ue dans l
a ve rsion 2.0.
V. Clas s e s e t obje ts 65
re vanch e , si le constructe ur d'une clas s e e s t privé , ilne s e ra plus possible de cré e r de s obje ts de ce tte
clas s e 21, q ue ce s oit par une déclaration ou une allocation dynam iq ue . Ce ci pe ut, à la rigue ur, s e justifie r,
dans le cas où la clas s e conce rné e e s t destiné e à donne r naissance , par h é ritage , à des classes dérivé e s .

5. LES M EM BRES D O NNÉE STA TIQUES

5.1 Le q ual
ificatif s tatic pour un m e m bre donné e

A priori, lors q ue dans un m ê m e program m e on crée diffé re nts obje ts d'une m ê m e clas s e , ch aq ue obje t
possè de ses propre s m e m bres donnée. Par e xe m ple, si nous avons défini une clas s e e xple1 par :

class exple1
{ int n ;
float x ;
...
} ;

Une déclaration te lle q ue :

exple1 a, b ;

conduit à une s ituation q ue l'on pe ut sch é m atiser ainsi :

_______ _______
a.n --->| | b.n --->| |
|_ _____| |_______|
| | | |
a.x --->|_______| b.x --->|_______|

Objet a Objet b

Une façon (parm i d'autre s ) de perm e ttre à plusieurs obje ts de "partage r" des données consiste à déclare r
ave c le q ualificatif s tatic les m e m bres donnée qu'on souh aite voir e xiste r e n un s e ule xe m plaire pour tous les
obje ts de la clas s e . Par e xe m ple, si nous définissons une clas s e e xple2 par :

class exple2
{ static int n ;
float x ;
...
} ;

la déclaration :

exple2 a, b ;

conduit à une s ituation q ue l'on pe ut sch é m atiser ainsi :

_______
a.n ------->| |<------- b.n
___|_______|___

21 - En util
isant l
e cons tructe ur e n q ue s tion ;e n e ffe t, nous ve rrons dans l
e proch ain ch apitre, qu'une cl
as s e pe ut posséder pl
usieurs
cons tructe urs (surdéfinis ).
66 Program m e r e n langage C+ +
| | |
a.x --->|_______|_______|<--- b.x

Objet a Objet b

O n pe ut dire q ue les m e m bres donnée statiq ue s s ont des sortes de variables globales dont la porté e e s t lim ité e
à la clas s e .

5.2 Initial
is ation de s m e m bre s donné e s tatiq ue s

D e par leur nature m ê m e , les m e m bres donnée statiq ue s n'e xiste nt q u'e n un s e ul e xe m plaire ,
indé pe ndam m e nt des obje ts de la clas s e (m ê m e , d'ailleurs, si aucun obje t de la clas s e n'a e ncore é té cré é ).
D ans ce s conditions, leur initialisation ne pe ut plus ê tre faite par le constructe ur de la clas s e .

O n pourrait pe ns e r q u'ile s t possible d'initialiser un m e m bre s tatiq ue lors de sa déclaration, com m e dans :

class exple2
{ static int n = 2 ; // erreur
.....
} ;

En fait, ce ci n'e s t pas perm is car, com pte te nu de s possibilités de com pilation s é paré e , le m e m bre s tatiq ue
ris q ue rait de se voir ré s e rve r diffé re nts e m place m e nts 22 dans diffé re nts m odules obje t.

Un m e m bre s tatiq ue doit donc ê tre initialisé explicite m e nt (à l'e xté rie ur de la déclaration de la clas s e ) par
une instruction te lle q ue :

int exple2::n = 5 ;

Par ailleurs, contraire m e nt à ce q ui s e produit pour une variable ordinaire , un m e m bre s tatiq ue n'e s t pas
initialisé par défaut à zé ro.

R e m arque :

La norm e ANSI pré voit q u'on puis s e initialiser les m e m bre s s tatiq ue s constants (q ualificatif cons t), lors
de leur dé claration.

5.3 Exe m pl
e

Voici un e xe m ple de program m e e xploitant ce tte possibilité , dans une clas s e nom m é e cpte _obj, afin de
connaî tre , à tout m om e nt, le nom bre d'obje ts e xistant. Pour ce faire , nous avons déclaré ave c l'attribut
statiq ue le m e m bre ctr. Sa valeur e s t incré m e nté e d e 1 à ch aq ue appe ldu constructe ur e t décré m e nté e d e 1 à
ch aq ue appe ldu destructe ur.

_______________________________________________________________________________
______

#include <iostream.h>

22 - O n re trouve l
e m ê m e ph é nom è ne pour l
e s variabl
e s gl
obal
es en l
angage C : el
le s pe uve nt ê tre décl
aré e s pl
usieurs fois, m ais e l
le s ne
doive nt ê tre définie s q u'une s e ul
e fois.
V. Clas s e s e t obje ts 67
class cpte_obj
{ static int ctr ; // compteur du nombre d'objets créés
public :
cpte_obj () ;
~cpte_obj () ;
} ;
int cpte_obj::ctr = 0 ; // initialisation du membre statique ctr
cpte_obj::cpte_obj () // constructeur
{ cout << "++ construction : il y a maintenant " << ++ctr << " objets\n" ;
}
cpte_obj::~cpte_obj () // destructeur
{ cout << "-- destruction : il reste maintenant " << --ctr << " objets\n" ;
}
main()
{ void fct () ;
cpte_obj a ;
fct () ;
cpte_obj b ;
}
void fct ()
{ cpte_obj u, v ;
}
_______________________
++ construction : il y a maintenant 1 objets
++ construction : il y a maintenant 2 objets
++ construction : il y a maintenant 3 objets
-- destruction : il reste maintenant 2 objets
-- destruction : il reste maintenant 1 objets
++ construction : il y a maintenant 2 objets
-- destruction : il reste maintenant 1 objets
-- destruction : il reste maintenant 0 objets
_______________________________________________________________________________
______

Exe m ple d'utilisation de m e m bre s tatique

R e m arques :

1) L'initialisation d'un m e m bre donnée statiq ue e s t toujours possible s uivant la m é th ode indiq ué e , q u'il
soit public ou privé . En de h ors de ce la, son accè s re s te ré gi com m e ce lui de n'im porte q ue lautre
m e m bre de la clas s e , e n fonction de s on statut public ou privé .
2) En C, le te rm e s tatiq ue avait déjà deux significations : "de clas s e s tatiq ue " ou "de porté e lim ité e au
fich ie r source 23". En C+ + , lors q u'ils'appliq ue aux m e m bres d'une clas s e , ile n possè de donc une
troisiè m e : "indé pe ndant d'une q ue lconq ue instance de la clas s e ". Nous ve rrons, dans le proch ain
ch apitre , q u'ilpourra é galem e nt s'appliq ue r aux fonctions m e m bre , ave c la m ê m e s ignification.

23 - D u m oins q uand on l
'em pl
oyait pour dé s igne r ce q ui é tait q ual
ifié par l
e m ot cl
é s tatic.
68 Program m e r e n langage C+ +
6. EXPLO ITA TIO N D 'UNE CLASSE

6.1 La cl
as s e , com m e "com pos ant l
ogicie l
"

Jus q u'ici, nous avions re groupé , au s e in d'un m ê m e program m e , la définition de la clas s e e t son utilisation.
D ans la pratiq ue , ile n ira gé né ralem e nt autre m e nt. En e ffe t, dans un souci de ré utilisabilité , la clas s e s e ra
fournie com m e un com posant s é paré com m e pouvait l'ê tre d'ailleurs une fonction C de s tiné e à ê tre
e m ployé e par plusieurs program m e s (l'e xe m ple le plus flagrant é tant ce lui de s fonctions de la biblioth è q ue
standard). Ce la signifie q u'un utilisate ur pote ntie lde ce tte classe disposera :

• d'un m odule obje t ré s ultant de la com pilation de la définition de la clas s e ,


• d'un fich ie r e n-tê te conte nant la déclaration (uniq ue m e nt) de la clas s e .
En gé né ral, le conce pte ur de la clas s e la com pilera e n utilisant, lui aussi, le fich ie r e n-tê te q u'ils e ra am e né à
fournir à l'utilisate ur. Ce n'e s t, bie n sûr, pas une nécessité , m ais ce la sim plifie d'éve ntue lles m odifications
ulté rie ures de la clas s e .

Par e xe m ple, le conce pte ur de la clas s e point du paragraph e 4.2 pourra cré e r le fich ie r e n-tê te s uivant :

_______________________________________________________________________________
______

/* ------------ Déclaration de la classe point ------------- */


class point
{ /* déclaration des membres privés */
int x ;
int y ;
/* déclaration des membres publics */
public :
point (int, int) ; // constructeur
void deplace (int, int) ;
void affiche () ;
} ;
_______________________________________________________________________________
______

Fich ie r e n-tê te pour la clas s e point

Si ce fich ie r s e nom m e point.h 24, le conce pte ur fabriq ue ra alors un m odule obje t, e n com pilant la définition
de la clas s e point.

_______________________________________________________________________________
______

#include <iostream.h>
#include "point.h"
/* ----- Définition des fonctions membre de la classe point ---- */
point::point (int abs, int ord)
{
x = abs ; y = ord ;
}

24 - Le nom du fich ie r pe ut, bien sûr, ê tre ch oisi com m e vous l


e voul
ez. L'exte nsion, par contre, est im pos é e par l
'im pl
é m e ntation. Ilpe ut
s'agir de h , de h xx, h pp, ...
V. Clas s e s e t obje ts 69
void point::deplace (int dx, int dy)
{ x = x + dx ; y = y + dy ;
}
void point::affiche ()
{
cout << "Je suis en " << x << " " << y << "\n" ;
}
_______________________________________________________________________________
______

Fich ie r à com piler pour obte nir le m odule obje t de la clas s e point25

Pour faire appe là la clas s e point au s e in d'un program m e , l'utilisate ur procédera alors ainsi :

• il"inclura" la déclaration de la clas s e point dans le fich ie r source conte nant son program m e par une
dire ctive te lle q ue :
#include "point.h"

• ilincorpore ra le m odule obje t corre s pondant, au m om e nt de l'édition de lie ns de son propre program m e .
En principe , à ce nive au, la plupart des édite urs de lie ns n'introduise nt q ue les fonctions ré e llem e nt
utilisées, de sorte q u'ilne faut pas craindre de pré voir trop de m é th ode s pour une clas s e .
Parfois, on trouve ra plusieurs classes diffé re nte s au s e in d'un m ê m e m odule obje t e t d'un m ê m e fich ie r e n-
tê te , de façon com parable à ce q ui s e pas s e pour les fonctions de la biblioth è q ue s tandard26. Là e ncore , e n
gé né ral, s e ules les fonctions ré e llem e nt utilisées seront incorporé e s à l'édition de lie ns, de sorte q u'ile s t
toujours possible d'effe ctue r de s re groupe m e nts de clas s e s possédant q ue lque s affinité s .

6.2 Prote ction contre l


e s incl
us ions m ul
tipl
es

Plus tard, nous ve rrons q u'ile xiste diffé re nte s circonstance s pouvant am e ne r l'utilisate ur d'une clas s e à
inclure plusieurs fois un m ê m e fich ie r e n-tê te , lors de la com pilation d'un m ê m e fich ie r source (sans m ê m e
q u'iln'e n ait conscie nce !). Ce s e ra notam m e nt le cas dans les s ituations d'obje ts m e m bre e t de clas s e s
dérivé e s .

D ans ce s conditions, on ris q ue d'aboutir à des erre urs de com pilation, lié e s tout sim plem e nt à la redéfinition
de la clas s e conce rné e .

En gé né ral, on ré glera ce problèm e e n proté ge ant systé m atiq ue m e nt tout fich ie r e n-tê te des inclusions
m ultiples par une te ch niq ue de com pilation conditionne lle, com m e dans :

#ifndef POINT_H
#define POINT_H
// déclaration de la classe point
#endif

Le sym bole défini pour ch aq ue fich ie r e n-tê te s e ra ch oisi de façon à é vite r tout ris q ue de doublons. Ici, nous
avons ch oisi le nom de la clas s e (e n m ajuscules ), suffixé par _H .

25 - R appe l
ons q ue l
a dire ctive #include pos s è de deux syntaxes diffé re ntes, l
'une (<...> ) e ffe ctuant l
a re ch e rch e dans un répertoire
s pé cifiq ue (où se trouve nt l
e s fich ie rs e n-tê te s tandard), l
'autre ("...") e ffe ctuant l
a re ch e rch e dans l
e ré pe rtoire courant ;é ve ntue l
le m e nt,
on pe ut é gal
e m e nt y spécifie r un ré pe rtoire particul
ie r.
26 - A ve c ce tte diffé re nce, toute fois, que, dans ce cas, on n'a pas à s pé cifie r l
e s m odul
e s obje ts conce rnés, au m om e nt de l
'édition de
l
ie ns.
70 Program m e r e n langage C+ +

6.3 Cas d e s m e m bre s donné e s tatiq ue s

Nous avons vu (paragraph e 5.2) q u'un m e m bre donnée statiq ue doit toujours ê tre initialisé explicite m e nt.
D è s lors q u'on e s t am e né à considérer une clas s e com m e un com posant s é paré , le problèm e s e pos e alors de
savoir dans q ue lfich ie r source place r une te lle initialisation : fich ie r e n-tê te , fich ie r dé finition de la clas s e ,
fich ie r utilisate ur (dans notre e xe m ple du paragraph e 5.3, ce problèm e ne s e posait pas car nous n'avions
q u'un s e ulfich ie r source ).

O n pourrait pe ns e r q ue le fich ie r e n-tê te e s t un e xce llent candidat pour ce tte initialisation, dè s lors q u'ile s t
proté gé contre les inclusions m ultiples . En fait, iln'e n e s t rie n ;e n e ffe t, si l'utilisate ur com pile s é paré m e nt
plusieurs fich ie rs source utilisant la m ê m e clas s e , plusieurs em place m e nts s e ront gé né ré s pour le m ê m e
m e m bre s tatiq ue e t, e n principe , l'édition de lie ns déte cte ra ce tte e rre ur.

Com m e par ailleurs iln'e s t guè re raisonnable de lais s e r l'utilisate ur initialiser lui-m ê m e un m e m bre s tatiq ue
(sauf situations , on voit q ue :

ilest conseil lé d e prévoir l


'initial
isation des m em bres donnée statiques dans l
e fich ier contenant l
a
d é finition de la classe.

6.4 En cas d e m odification d'une cl


as s e

A priori, lors q u'une clas s e e s t considérée com m e un "com posant logicie l", c'e s t q u'e lle e s t "au point" e t
q ue , par cons é q ue nt, e lle ne devrait plus ê tre m odifié e . Si, m algré tout, une te lle m odification s'avè re
né ce s s aire , ilfaut e nvisage r de ux situations as s e z diffé re nte s .

a)La dé cl
aration de s m e m bre s publ
ics n'a pas ch angé
C'e s t ce q ui s e produit lors q u'on s e lim ite à des m odifications inte rne s , n'ayant aucune ré pe rcussion sur la
m aniè re d'utiliser la clas s e (son "inte rface " ave c l'e xté rie ur re s te la m ê m e ). Ilpe ut s'agir de transform ation
de structures de données encapsulée s (privé e s ), de m odification d'algorith m es de traite m e nt...

D ans ce cas, les program m es util isant l a classe n'ont pas à ê tre m odifié s . Né anm oins, ils doivent ê tre
recom pil és avec l e nouveau fich ier en-tê te correspondant27. O n procédera e nsuite à une édition de lie ns
e n incorporant le nouve au m odule obje t.

O n voit donc q ue C+ + pe rm e t une m ainte nance facile d'une clas s e à laq ue lle on souh aite apporte r de s
m odifications inte rne s (corre ctions d'erreurs, am é lioration de s pe rform ance s ...) n'atte ignant pas la
spécification de s on inte rface .

b)La dé cl
aration de s m e m bre s publ
ics a ch angé
Ici, ile s t clair q ue les program m e s utilisant la clas s e ris q ue nt de néce s s ite r de s m odifications. Ce tte s ituation
devra, bie n sûr, ê tre é vitée dans la m e s ure du possible. Elle doit ê tre considérée com m e une faute de
conce ption de la clas s e . Nous ve rrons d'ailleurs q ue ce s problèm e s pourront souve nt ê tre ré s olus par
l'e m ploi du m é canism e d'h é ritage q ui pe rm e t d'adapte r une clas s e s ans la re m e ttre e n caus e .

27 - Une te l
le l
im itation n'e xis te pas dans tous l
es l
angages de P.O .O . En C+ + , el
le s e jus tifie par l
e besoin qu'a l
e com pil
ate ur de
connaî
tre l
a tail
le des obje ts pour l
e ur al
loue r un e m pl
ace m e nt.
V. Clas s e s e t obje ts 71
7. LES CLASSES EN GÉNÉRA L

7.1 Le s autre s s orte s de cl


as s e s e n C+ +

Nous avons déjà e u l'occasion de dire que C+ + q ualifiait de "clas s e " les types définis par s truct e t class. La
caracté ristiq ue d'une clas s e , au s e ns large q ue lui donne C+ + 28, e s t d'associe r, au s e in d'un m ê m e type ,
des m e m bres donnée et des fonctions m e m bre .

Pour C+ + , les unions e t les énum érations sont aussi des cl asses. Ces deux type s pe uve nt donc dispose r de
fonctions m e m bre . Note z bie n q ue , com m e pour le type s truct, les données corre s pondante s ne pe uve nt pas
s e voir attribue r un "statut" particulie r : e lles s ont, de fait, publiq ue s .

7.2 Ce q u'on pe ut trouve r dans l


a dé cl
aration d'une cl
as s e

En de h ors des déclarations de fonctions m e m bre , la plupart des instructions figurant dans une déclaration de
clas s e s e ront des déclarations de m e m bres donnée d'un type q ue lconq ue . Né anm oins, on pe ut y re ncontre r
é galem e nt des déclarations de type , y com pris d'autre s type s clas s e s ;dans ce cas, leur porté e e s t lim ité e à la
clas s e . En pratiq ue , ce tte s ituation s e re ncontre pe u souve nt.

Par ailleurs, iln'est pas possibl iser un m em bre donné e d'une clas s e , lors de sa déclaration29 .
e d'initial
Ce tte inte rdiction e s t justifié e pour au m oins deux raisons :

• une te lle initialisation ris q ue rait de faire double e m ploi ave c le constructe ur,
• une te lle initialisation constitue rait une définition du m e m bre corre s pondant (e t non plus une sim ple
déclaration) ;or, ce tte définition ris q ue rait d'apparaî
tre plusieurs fois e n cas de com pilation s é paré e , ce
q ui e s t illégal30.

En re vanch e , la déclaration de m e m bres donnée constants 31 e s t autoris é e , com m e dans :

class exple
{ int n ; // membre donnée usuel
const int p ; // membre donnée constant
.....
} ;

D ans ce cas, ce pe ndant, iln'e s t pas perm is d'initialiser le m e m bre constant au m om e nt de sa déclaration.
Pour y parve nir, la s e ule s olution consiste ra à utiliser une "syntaxe " particuliè re du constructe ur, te lle
q u'e lle s e ra pré s e nté e au ch apitre s uivant, dans le paragraph e re latif aux "obje ts m e m bre ".

28 - Et non l a P.O .O . d'une m aniè re gé né ral


e q ui as s ocie l
'encapsul ation des données à l a notion de cl asse.
29 - M ais, com m e nous l 'avons dit dans l e paragraph e 5.2, l a norm e ANSI fait une e xce ption pour l e s m e m bres statiq ue s cons tants.
30 - O n re trouve le m ê m e ph é nom è ne pour le s m e m bres données statiq ue s e t pour l
e s variable s global es en l angage C : il s pe uve nt ê tre
déclaré s pl
usieurs fois, m ais il
s ne doive nt ê tre définis q u'une s e ul
e fois.
31 - Ne confondez pas l a notion de m e m bre donnée constant (ch aq ue obje t e n pos s è de un ;s a val
e ur ne pe ut pas ê tre m odifié e ) e t l
a notion
de m e m bre donnée statiq ue (tous l
e s obje ts d'une m ê m e cl
as s e partage nt l
e m ê m e ;s a val
e ur pe ut ch ange r).
72 Program m e r e n langage C+ +
7.3 D é cl
aration d'une cl
as s e
La plupart du te m ps, les clas s e s s e ront déclaré e s à un nive au global. Né anm oins, ile s t pe rm is de déclare r
des clas s e s locales à une fonction. D ans ce cas, leur porté e e s t nature llem e nt lim ité e à ce tte fonction (c'e s t
bien ce qui en lim ite l'inté rê t).

EXERCICES

N.B : les e xe rcice s m arqués (C) sont corrigé s e n fin de volum e .

1- Expé rim e nte z (é ve ntue llem e nt sur un e xe m ple de ce ch apitre ) la com pilation s é parée d'une clas s e
(cré ation d'un m odule obje t e t d'un fich ie r e n-tê te ) e t son utilisation au s e in d'un program m e .
2 - (C)Ecrive z une clas s e ve cte ur (de type class e t non s truct) com portant :
- e n m e m bres donnée privé s : trois com posantes de type double,
- e n fonctions m e m bre publiq ue s :
*initialise pour attribue r de s valeurs aux com posante s ,
*h om oth e tie pour m ultiplie r les com posante s par une valeur fournie e n argum e nt,
*affich e pour affich e r les com posantes du ve cte ur.
3 - (C)Ecrive z une clas s e ve cte ur, analogue à la pré cédente , dans laq ue lle la fonction initialise e s t re m placé e
par un constructe ur.
4- Expé rim e nte z la cré ation d'un fich ie r e n-tê te e t d'un m odule obje t ras s e m blant deux clas s e s
diffé re nte s .
5- Vé rifie z q ue , lors q u'une clas s e com porte un m e m bre donnée statiq ue , ce dernie r pe ut ê tre utilisé,
m ê m e lors q u'aucun obje t de ce type n'a é té déclaré .
6- M e tte z e n é vidence les problèm e s pos é s par l'affe ctation e ntre obje ts com portant une partie
dynam iq ue . Pour ce faire , utilisez la clas s e h asard du second e xe m ple du paragraph e 4.4, e n ajoutant
sim plem e nt des instructions affich ant l'adre s s e conte nue dans val, dans le constructe ur d'une part,
dans le destructe ur d'autre part. Vous constate re z q u'ave c ces déclarations :
hasard h1(10, 3) ;
hasard h2(20, 5) ;

une instruction te lle q ue :


h2 = h1 ;

n'e ntraî
ne pas toute s les re copie s e s com pté e s e t q ue , de surcroî
t, e lle conduit à libérer (en fin de
fonction) deux fois le m ê m e e m place m e nt.
VI. LES PRO PRIÉTÉS
D ES FO NCTIO NS M EM BRE

Le ch apitre pré cédent vous a pré s e nté les conce pts fondam e ntaux de clas s e , d'obje t, de constructe ur e t de
destructe ur. Ici, nous allons é tudie r un pe u plus e n dé taill'application aux fonctions m e m bre des possibilité s
offe rte s par C+ + pour les fonctions ordinaire s : surdéfinition, argum e nts par dé faut, fonction "e n ligne ",
transm ission par ré fé re nce .

Nous ve rrons é galem e nt com m e nt une fonction m e m bre pe ut re ce voir e n argum e nt, outre l'obje t l'ayant
appe lé (transm is im plicite m e nt) un ou plusieurs obje ts de type clas s e . Ici, nous nous lim ite rons au cas
d'obje ts de m ê m e type q ue la classe dont la fonction e s t m e m bre ;les autre s s ituations, corre s pondant à une
violation du principe d'encapsulation, ne s e ront e xam iné e s q ue plus tard, dans le cadre des "fonctions
am ie s ".

Nous ve rrons e nsuite com m e nt, au s e in d'une fonction m e m bre , accéder à l'adresse de l'obje t l'ayant
appe lé, e n utilisant le m ot clé th is.

Enfin, nous e xam ine rons les cas particulie rs des fonctions m e m bre s tatiq ue s e t des fonctions m e m bre
constante s , ainsi que l'e m ploi de pointe urs sur de s fonctions m e m bre .

1. SURD ÉFINITIO N D ES FO NCTIO NS M EM BRE

Nous avons déjà vu com m e nt C+ + nous autoris e à "surdéfinir" les fonctions "ordinaire s ". Ce tte possibilité
s'appliq ue é galem e nt aux fonctions m e m bre d'une clas s e , y com pris au constructe ur lui-m ê m e (m ais pas au
destructe ur puis q u'ilne possè de pas d'argum e nts). En voici un e xe m ple, dans leq ue lnous surdé finissons :

• le constructe ur point ;le ch oix du bon constructe ur s e faisant (ici) suivant le nom bre d'argum e nts :
- 0 argum e nt : les deux coordonné e s attribué e s au point construit sont toutes deux nulles ,
- 1 argum e nt : ils e rt de valeur com m une aux de ux coordonné e s ,
- 2 argum e nts : c'e s t le cas "usuel" q ue nous avions déjà re ncontré .
• la fonction affich e de m aniè re q u'on puis s e l'appe ler :
- sans argum e nt com m e auparavant,
74 Program m e r e n langage C+ +
- ave c un argum e nt de type ch aî
ne : dans ce cas, e lle affich e le te xte corre s pondant avant les
coordonnées du point.
_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point () ; // constructeur 1 (sans arguments)
point (int) ; // constructeur 2 (un argument)
point (int, int) ; // constructeur 3 (deux arguments)
void affiche () ; // fonction affiche 1 (sans arguments)
void affiche (char *) ; // fonction affiche 2 (un argument chaîne)
} ;
point::point () // constructeur 1
{ x = 0 ; y = 0 ;
}
point::point (int abs) // constructeur 2
{ x = y = abs ;
}
point::point (int abs, int ord) // constructeur 3
{ x = abs ; y = ord ;
}
void point::affiche () // fonction affiche 1
{ cout << "Je suis en : " << x << " " << y << "\n" ;
}
void point::affiche (char * message) // fonction affiche 2
{ cout << message ; affiche () ;
}
main()
{
point a ; // appel constructeur 1
a.affiche () ; // appel fonction affiche 1
point b (5) ; // appel constructeur 2
b.affiche ("Point b - ") ; // appel fonction affiche 2
point c (3, 12) ; // appel constructeur 3
c.affiche ("Hello ---- ") ; // appel fonction affiche 2
}
_______________________

Je suis en : 0 0
Point b - Je suis en : 5 5
Hello ---- Je suis en : 3 12
_______________________________________________________________________________
______

Exe m ple de s u rdéfinition de fonctions m e m bre (point e t affich e )

R e m arques :

1) Souve nt, e n utilisant les possibilités d'argum e nts par dé faut, ile s t possible de dim inue r le nom bre de
fonctions surdé finie s . C'e s t le cas ici pour la fonction affich e , com m e nous le ve rrons d'ailleurs dans
le paragraph e s uivant.
VI. Le s propriété s d e s fonctions m e m bre 75
2) Ici, dans la fonction affich e (ch ar *), nous faisons appelà l'autre fonction m e m bre affich e (). En e ffe t,
une fonction m e m bre pe ut toujours e n appe ler une autre (q u'e lle s oit publiq ue ou non). Une fonction
m e m bre pe ut m ê m e s 'appe ler e lle-m ê m e , dans la m e s ure où l'on a pré vu le m oye n de re ndre fini le
proce s s us de ré cursivité q ui e n dé coule.

2. ARGUM ENTS PAR DÉFAUT

Le s fonctions m e m bre , com m e les fonctions "ordinaire s " pe uve nt disposer d'argum e nts par dé faut. Voici
com m e nt nous pourrions m odifie r l'e xe m ple pré cédent pour q ue notre clas s e point ne possè de plus q u'une
s e ule fonction affich e à un s e ulargum e nt de type ch aî ne : le m e s s age à affich e r avant les valeurs des
coordonné e s , sa valeur par dé faut é tant alors la ch aî
ne vide.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point () ; // constructeur 1 (sans argument)
point (int) ; // constructeur 2 (un argument)
point (int, int) ; // constructeur 3 (deux arguments)
void affiche (char * = "") ; // fonction affiche (un argument par défaut)
} ;
point::point () // constructeur 1
{ x = 0 ; y = 0 ;
}
point::point (int abs) // constructeur 2
{ x = y = abs ;
}
point::point (int abs, int ord) // constructeur 3
{ x = abs ; y = ord ;
}
void point::affiche (char * message) // fonction affiche
{ cout << message << "Je suis en : " << x << " " << y << "\n" ;
}
main()
{ point a ; // appel constructeur 1
a.affiche () ;
point b (5) ; // appel constructeur 2
b.affiche ("Point b - ") ;
point c (3, 12) ; // appel constructeur 3
c.affiche ("Hello ---- ") ;
}
_______________________
Je suis en : 0 0
Point b - Je suis en : 5 5
Hello ---- Je suis en : 3 12
_______________________________________________________________________________
______

Exe m ple d'utilisation d'argum e nts par défaut dans une fonction m e m bre
76 Program m e r e n langage C+ +
R e m arque :

Ici, nous avons re m placé deux fonctions surdé finie s par une s e ule fonction ayant un argum e nt par dé faut.
Bie n e nte ndu, ce tte s im plification n'e s t pas toujours possible. Par e xe m ple, ici, nous ne pouvons pas
l'appliq ue r à notre constructe ur point. Si, par contre , nous avions prévu q ue , dans le constructe ur point à
un s e ulargum e nt, ce dernie r re pré s e nte s im plem e nt l'abscisse du point auq ue lon aurait alors attribué une
ordonné e nulle, nous aurions pu alors définir un s e ulconstructe ur :
point::point (int abs = 0, int ord = 0)
{x = abs ; y = ord ;}

3. LES FO NCTIO NS M EM BRE "EN LIGNE"

Nous avons vu q ue C+ + pe rm e t de définir de s fonctions "e n ligne ". Ce ci accroî t l'e fficie nce d'un
program m e , dans le cas de fonctions courte s . Là e ncore , ce tte possibilité s 'appliq ue aux fonctions m e m bre ,
m oye nnant ce pe ndant une pe tite nuance conce rnant sa m ise en œuvre . En e ffe t, pour re ndre "e n ligne " une
fonction m e m bre , on pe ut :

• soit fournir dire cte m e nt la définition de la fonction dans la déclaration m ê m e de la clas s e ;dans ce cas le
q ualificatif inline n'a pas à ê tre utilisé,
• soit procéder com m e pour une fonction "ordinaire " e n fournissant une définition e n de h ors de la
déclaration de la clas s e ;dans ce cas, le q ualificatif inline doit apparaî
tre , à la fois devant la déclaration
e t devant l'e n-tê te .
Voici com m e nt nous pourrions re ndre "e n ligne " les trois constructe urs de notre pré cédent e xe m ple e n
adoptant ici la pre m iè re m aniè re .

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point () { x = 0 ; y = 0 ; } // constructeur 1 "en
ligne"
point (int abs) { x = y = abs ; } // constructeur 2 "en
ligne"
point (int abs, int ord) { x = abs ; y = ord ; } // constructeur 3 "en
ligne"
void affiche (char * = "") ;
} ;

void point::affiche (char * message) // fonction affiche


{ cout << message << "Je suis en : " << x << " " << y << "\n" ;
}

main()
{
point a ; // "appel" constructeur 1
a.affiche () ;
point b (5) ; // "appel" constructeur 2
VI. Le s propriété s d e s fonctions m e m bre 77
b.affiche ("Point b - ") ;
point c (3, 12) ; // "appel" constructeur 3
c.affiche ("Hello ---- ") ;
}
_______________________
Je suis en : 0 0
Point b - Je suis en : 5 5
Hello ---- Je suis en : 3 12
_______________________________________________________________________________
______

Exe m ple de fonctions m e m bre "e n ligne "

R e m arques

1) Voici com m e nt s e s e rait pré s e nté e la déclaration de notre clas s e s i nous avions déclaré nos fonctions
m e m bre e n ligne à la m aniè re des fonctions ordinaire s (ici, nous n'avons m e ntionné q u'un
constructe ur) :
class point
{ .....
public :
inline point () ;
.....
} ;
inline point::point() { x = 0 ; y = 0 ; }
.....

2) Si nous n'avions e u be s oin q ue d'un seulconstructe ur ave c argum e nts par dé faut (com m e dans la
re m arq ue du précédent paragraph e ), nous aurions pu tout aussi bien le re ndre "e n ligne " ;ave c la
pre m iè re dém arch e (définition de fonction inté grée dans la déclaration de la clas s e ), nous aurions
alors spé cifié les valeurs par dé faut dire cte m e nt dans l'e n-tê te :
class point
{ ...
point (int abs = 0, int ord = 0)
{x = abs ; y = ord ;}

Nous utiliserons d'ailleurs un te lconstructe ur dans l'e xe m ple du paragraph e s uivant.

3) D e par sa nature m ê m e , la définition d'une fonction "e n ligne " doit obligatoire m e nt ê tre connue du
com pilate ur lors q u'iltraduit le program m e q ui l'utilise. Cette condition e s t obligatoire m e nt ré alisée
lors q ue l'on utilise la pre m iè re dém arch e . En re vanch e , ce n'e s t plus vrai ave c la deuxiè m e
dém arch e ;e n gé né ral, dans ce cas, on place ra les définitions des fonctions e n ligne , à la suite de la
déclaration de la clas s e , dans le m ê m e fich ie r e n-tê te .
D ans tous les cas, on voit toute fois q ue l'utilisate ur d'une clas s e (q ui disposera obligatoire m e nt du
fich ie r e n-tê te re latif à une clas s e ) pourra toujours connaî
tre la définition de s fonctions e n ligne ;le
fournis s e ur d'une clas s e ne pourra jam ais avoir la ce rtitude q u'un utilisate ur de ce tte clas s e ne te nte ra
pas de les m odifie r. Ce ris q ue n'e xiste pas pour les autre s fonctions m e m bre (dè s lors q ue l'utilisate ur
ne dispose que du m odule obje t re latif à la clas s e ).
78 Program m e r e n langage C+ +
4. CAS DES OBJETS TRANSM IS EN ARGUM ENT D 'UNE FO NCTIO N M EM BRE

D ans nos précédents e xe m ples , les fonctions m e m bre re ce vaie nt :

• un argum e nt im plicite du type de leur clas s e , à savoir l'adresse de l'obje t l'ayant appe lé,
• un ce rtain nom bre d'argum e nts q ui é taie nt d'un type "ordinaire " (c'e s t-à -dire autre q ue clas s e ).
M ais une fonction m e m bre pe ut, outre l'argum e nt im plicite , re ce voir un ou plusieurs argum e nts du type de
sa clas s e . Par e xe m ple, supposez q ue nous souh aitions, au s e in d'une clas s e point, introduire une fonction
m e m bre nom m é e coincide , ch argée de déte cte r la coïncide nce é ve ntue lle de deux points. Son appe l, au s e in
d'un program m e , s e pré s e nte ra obligatoire m e nt, com m e pour toute fonction m e m bre , sous la form e :

a.coincide (...)

a é tant un obje t de type point.

Ilfaudra donc im pé rative m e nt transm e ttre le s e cond point e n argum e nt ;e n supposant q u'ils e nom m e b,
ce ci nous conduira à un appe lde la form e :

a.coincide (b)

ou, ici, com pte te nu de la "sym é trie " du problèm e :

b.coincide (a)

Voyons m ainte nant plus précisém e nt com m e nt é crire la fonction coincide . Voici ce q ue pe ut ê tre s on e n-tê te ,
e n supposant q u'e lle fournit une valeur de re tour e ntiè re (1 e n cas de coïncide nce , 0 dans le cas contraire ) :

int point::coincide (point pt)

D ans coincide , nous devons donc com pare r les coordonné e s d e l'obje t fourni im plicite m e nt lors de son appe l
(s e s m e m bre s s ont désignés, com m e d'h abitude , par x e t y) ave c les coordonné e s d e l'obje t fourni e n
argum e nt, dont les m e m bre s s ont désignés par pt.x e t pt.y. Le corps de coincide s e pré s e nte ra donc ainsi :

if ((pt.x == x) && (pt.y == y)) return 1 ;


else return 0 ;

Voici un e xe m ple com plet de program m e , dans leq ue lnous avons lim ité les fonctions m e m bre de la clas s e
point à un constructe ur e t à coincide .

_______________________________________________________________________________
______

#include <iostream.h>
class point // Une classe point contenant seulement :
{
int x, y ;
public :
point (int abs=0, int ord=0) // un constructeur ("en ligne")
{ x=abs; y=ord ; }
int coincide (point) ; // une fonction membre : coincide
} ;

int point::coincide (point pt)


{ if ( (pt.x == x) && (pt.y == y) ) return 1 ;
else return 0 ;
VI. Le s propriété s d e s fonctions m e m bre 79
// remarquez la "dissymétrie" des notations : pt.x et x
}

main() // Un petit programme d'essai


{
point a, b(1), c(1,0) ;
cout << "a et b : " << a.coincide(b) << " ou " << b.coincide(a) << "\n" ;
cout << "b et c : " << b.coincide(c) << " ou " << c.coincide(b) << "\n" ;
}
_______________________

a et b : 0 ou 0
b et c : 1 ou 1
_______________________________________________________________________________
______

Exe m ple d'obje t trans m is en argum e nt à une fonction m e m bre

R e m arques

1) Nous aurions pu é crire coincide de la m aniè re s uivante


return ((pt.x == x) && (pt.y == y)) ;

2) En th é orie , on pe ut dire q ue la coïncide nce de deux points e s t "sym é triq ue ", e n ce s e ns q ue l'ordre
dans leq ue lon considè re les deux points e s t indiffé re nt. O r, ce tte sym é trie ne s e re trouve pas dans la
définition de la fonction coincide , pas plus q ue dans son appe l. Ce ci provie nt de la transm ission, en
argum e nt im plicite , de l'obje t appe lant la fonction.
3) O n pourrait pe ns e r q u'on viole le principe d'encapsulation dans la m e s ure où, lors q ue l'on appe lle la
fonction coincide pour l'obje t a (dans a.coincide (b)), e lle e s t autoris é e à accéder aux données de b.
En fait, e n C+ + , n'im porte q ue lle fonction m e m bre d'une clas s e pe ut accéder à n'im porte q ue l
m e m bre (public ou privé ) de n'im porte q ue lobje t de ce tte clas s e . O n traduit souve nt ce la e n disant
q u'en C+ + , l 'unité d e protection est l a classe, e t non l'obje t.
En re vanch e , si A et B sont deux classes diffé re nte s , une fonction m e m bre de A ne pe ut pas (pas plus
q u'une fonction ordinaire , m ain par e xe m ple) accéder aux m e m bre s privés d'un obje t de clas s e B ;
bien ente ndu, e lle pe ut toujours accéder aux m e m bre s publics. Nous ve rrons plus tard q u'ile s t
possible à une fonction (ordinaire ou m e m bre ) de s'affranch ir de ce tte inte rdiction (e t donc, ce tte fois,
de violer vé ritablem e nt le principe d'encapsulation) par des déclarations d'am itié approprié e s .

5. M O D E D E TRANSM ISSIO N D ES O BJETS EN ARGUM ENT

D ans notre pré cédent e xe m ple, l'obje t pt é tait transm is classiquem e nt à coincide , à savoir par valeur.
Pré cis é m e nt, ce la signifie donc q ue , lors de l'appe l:

a.coincide (b)

les valeurs des données de b sont re copiées dans un em place m e nt (de type point) localà coincide (nom m é ,
e n q ue lque s orte , pt).

Com m e pour n'im porte q ue largum e nt ordinaire , ile s t possible de pré voir d'e n transm e ttre l'adre s s e plutôt
q ue la valeur ou de m e ttre e n place une transm ission par ré fé re nce . Exam inons ces deux possibilité s .
80 Program m e r e n langage C+ +

5.1 Trans m is s ion de l


'adre s s e d'un obje t

Ile s t possible de transm e ttre e xplicite m e nt e n argum e nt l'adresse d'un obje t. R appe lons q ue , dans un te lcas,
on ne ch ange pas le m ode de transm ission de l'argum e nt (contraire m e nt à ce q ui s e produit ave c la
transm ission par ré fé re nce ) ;on s e conte nte de transm e ttre une valeur q ui s e trouve ê tre une adre s s e e t q u'il
faut donc inte rpré te r e n cons é q ue nce dans la fonction (notam m e nt e n e m ployant l'opé rate ur d'indire ction *).
A titre d'exem ple, voici com m e nt nous pourrions m odifie r la fonction coincide du paragraph e pré cédent :

int point::coincide (point * adpt)


{ if (( adpt -> x == x) && (adpt -> y == y)) return 1 ;
else return 0 ;
}

Com pte te nu de la dissym é trie nature lle de notre fonction m e m bre , ce tte é criture n'e s t guè re ch oq uante . Par
contre , l'appe lde coincide (au s e in de m ain) le devie nt davantage :

a.coincide (&b)

ou

b.coincide (&a)

Voici le program m e com plet ainsi m odifié .

_______________________________________________________________________________
______

#include <iostream.h>
class point // Une classe point contenant seulement :
{ int x, y ;
public :
point (int abs=0, int ord=0) // un constructeur ("en ligne")
{ x=abs; y=ord ; }
int coincide (point *) ; // une fonction membre : coincide
} ;
int point::coincide (point * adpt)
{ if ( (adpt->x == x) && (adpt->y == y) ) return 1 ;
else return 0 ;
}

main() // Un petit programme d'essai


{ point a, b(1), c(1,0) ;
cout << "a et b : " << a.coincide(&b) << " ou " << b.coincide(&a) << "\n" ;
cout << "b et c : " << b.coincide(&c) << " ou " << c.coincide(&b) << "\n" ;
}
_______________________
a et b : 0 ou 0
b et c : 1 ou 1
_______________________________________________________________________________
______

Exe m ple de trans m ission de l'adre s s e d 'un obje t à une fonction m e m bre
VI. Le s propriété s d e s fonctions m e m bre 81

R e m arque

N'oublie z pas q u'à partir du m om e nt où vous fournis s e z l'adresse d'un obje t à une fonction m e m bre ,
ce lle-ci pe ut e n m odifie r les valeurs (e lle a accè s à tous les m e m bre s s 'ils'agit d'un obje t de type de sa
clas s e , aux s e uls m e m bre s publics dans le cas contraire ). Si vous craigne z de te ls e ffe ts de bord au s e in
de la fonction m e m bre conce rné e , vous pouve z toujours e m ploye r le q ualificatif cons t. Ainsi, ici, l'e n-
tê te de coincide aurait pu ê tre :
int point::coincide (const point * adpt)

e n m odifiant parallèlem e nt son prototype :


int coincide (const point *) ;

Note z toute fois q u'une te lle pré caution ne pe ut pas ê tre pris e ave c l'argum e nt im plicite q u'e s t l'obje t
ayant appe lé la fonction. Ainsi, dans coincide m uni de l'e n-tê te ci-de s s us, vous ne pourrie z plus m odifie r
adpt -> x m ais vous pourrie z toujours m odifie r x.

5.2 Trans m is s ion par ré fé re nce

Com m e nous l'avons vu, l'e m ploi de s ré fé re nce s pe rm e t de m e ttre e n place une transm ission par adre s s e ,
sans avoir à e n pre ndre e n ch arge s oi-m ê m e la ge s tion. Elle s im plifie d'autant l'é criture de la fonction
conce rné e e t ses diffé re nts appe ls. Voici une adaptation de coincide dans laq ue lle s on argum e nt e s t transm is
par ré fé re nce .

_______________________________________________________________________________
______

#include <iostream.h>
class point // Une classe point contenant seulement :
{ int x, y ;
public :
point (int abs=0, int ord=0) // un constructeur ("en ligne")
{ x=abs; y=ord ; }
int coincide (point &) ; // une fonction membre : coincide
} ;
int point::coincide (point & pt)
{ if ( (pt.x == x) && (pt.y == y) ) return 1 ;
else return 0 ;
}

main() // Un petit programme d'essai


{
point a, b(1), c(1,0) ;
cout << "a et b : " << a.coincide(b) << " ou " << b.coincide(a) << "\n" ;
cout << "b et c : " << b.coincide(c) << " ou " << c.coincide(b) << "\n" ;
}
_______________________

a et b : 0 ou 0
b et c : 1 ou 1
_______________________________________________________________________________
______
82 Program m e r e n langage C+ +
Exe m ple de trans m ission par réfé re nce d'un obje t à une fonction m e m bre

R e m arque

La re m arq ue faite pré cédem m e nt (e n fin de paragraph e 5.1) à propos des ris q ues d'effe ts de bord
s'appliq ue é galem e nt ici. Le q ualificatif cons t pourrait y inte rve nir de m aniè re analogue :
int point::coincide (const point & pt)

5.3 Le s probl
è m e s pos é s par l
a trans m is s ion par val
e ur

Nous avons déjà vu q ue l'affe ctation d'obje ts pouvait pos e r de s problèm es dans le cas où ce s obje ts
possédaie nt des pointe urs sur de s e m place m e nts alloués dynam iq ue m e nt. Ce s pointe urs é taie nt e ffe ctive m e nt
re copié s , m ais iln'e n allait pas de m ê m e d e s e m place m e nts pointé s . Le transfe rt d'argum e nts par valeur
pré s e nte les m ê m e s ris q ue s , dans la m e s ure où ils'agit é galem e nt d'une s im ple re copie .

D e m ê m e q ue le problèm e pos é par l'affe ctation pe ut ê tre ré s olu par la surdéfinition de ce t opé rate ur, ce lui
pos é par le transfe rt par valeur pe ut ê tre ré glé par l'e m ploi d'un constructe ur particulie r ;nous vous
m ontre rons com m e nt dè s le proch ain ch apitre .

D 'une m aniè re gé né rale, d'ailleurs, nous ve rrons q ue les problèm e s pos é s par les obje ts conte nant des
pointe urs s e ram è ne nt e ffe ctive m e nt à l
'affectation e t à l isation1, dont la re copie e n cas de
'initial
transm ission par valeur constitue un cas particulie r.

6. LO RSQUE LA VA LEUR D E RETO UR D 'UNE FO NCTIO N


EST ELLE-M ÊM E UN O BJET

Ce q ue nous avons dit à propos des argum e nts d'une fonction m e m bre s 'appliq ue é galem e nt à sa valeur de
re tour. Ilpe ut s'agit d'un obje t e t on pe ut ch oisir entre :

• transm ission par valeur,


• transm ission de son adresse,
• transm ission par ré fé re nce .
Ce t obje t pourra ê tre :

• du m ê m e type q ue la clas s e , auq ue lcas la fonction aura accè s à s e s m e m bre s privé s ,


• d'un type diffé re nt de la clas s e , auq ue lcas la fonction n'aura accè s q u'à s e s m e m bre s publics.
La transm ission par valeur attire la m ê m e re m arq ue q ue pré cédem m e nt, à savoir q ue , par dé faut, e lle s e fait
par sim ple re copie de l'obje t. Pour les obje ts com portant des pointe urs sur de s e m place m e nts dynam iq ue s , il
faudra pré voir un constructe ur particulie r (d'initialisation).

En re vanch e , la transm ission d'une adresse ou la transm ission par ré fé re nce ris q ue nt de poser un problèm e
q ui n'e xistait pas pour les argum e nts. Si une fonction transm e t l'adre s s e ou la ré fé re nce d'un obje t, ilvaut
m ie ux é vite r q u'ils'agisse d'un obje t localà la fonction, c'e s t-à -dire de clas s e autom atiq ue . En e ffe t, dans
ce cas, l'e m place m e nt de ce t obje t s e ra libéré 2 dè s la sortie de la fonction ;la fonction appe lante ré cupé re ra

1 - Bie n q ue ce l
a n'apparais s e pas toujours cl
aire m e nt e n C, ile s t trè s im portant, en C+ + , de note r q u'affe ctation e t initial
isation s ont
deux ch oses diffé re ntes.
2 - Com m e nous l e ve rrons e n détaildans l
e ch apitre s uivant, ily aura appe ldu destructe ur, s'ile xis te.
VI. Le s propriété s d e s fonctions m e m bre 83
l'adre s s e d e q ue lque ch os e n'e xistant plus vraim e nt3. Nous re vie ndrons plus e n dé tailsur ce point dans le
ch apitre consacré à la surdéfinition d'opé rate urs.

A titre d'exem ple, voici une fonction m e m bre nom m é e sym e trique q ui pourrait ê tre introduite dans une
clas s e point pour fournir e n re tour un point sym é triq ue de ce lui l'ayant appe lé :

point point::symetrique ( )
{ point res ;
res.x = -x ; res.y = -y ;
return res ;
}

Vous constate z q u'ila é té né ce s s aire de cré e r un obje t autom atiq ue re s , au s e in de la fonction. Com m e nous
l'avons e xpliq ué ci-de s s us, ilne s e rait pas cons e illé d'en prévoir ici une transm ission par ré fé re nce , e n
utilisant ce t e n-tê te :

point & point::symetrique ( )

7. AUTO RÉFÉRENCE : LE M O T CLÉ TH IS

Nous avons déjà e u souve nt l'occasion de dire qu'une fonction m e m bre d'une clas s e re çoit une inform ation
lui pe rm e ttant d'accéder à l'obje t l'ayant appe lé. Ce te rm e "inform ation", bie n q u'ilsoit re lative m e nt flou,
nous avait suffi pour e xpliq ue r tous les e xe m ples re ncontré s jus q u'ici. M ais, nous n'avions pas besoin d'y
m anipuler e xplicite m e nt l'adresse de l'obje t e n q ue s tion. O r, ile xiste des circonstance s où ce la devie nt
indispensable. Songe z, par e xe m ple, à la ge s tion d'une liste ch aî née d'obje ts de m ê m e nature : pour é crire
une fonction m e m bre ins é rant un nouve lobje t (supposé transm is en argum e nt im plicite ), ilfaudra bie n
place r son adresse dans l'obje t pré cédent de la liste .

Pour ré s oudre de te ls problèm e s , C+ + a pré vu le m ot clé : th is.

Ce lui-ci, utilisable uniq ue m e nt au s e in d'une fonction m e m bre , désigne un pointe ur sur l'obje t l'ayant
appe lé.

Ici, ils e rait pré m aturé de déve loppe r l'e xe m ple de liste ch aî
née dont nous ve nons de parler ;nous vous
proposons un exem ple d'école : dans la clas s e point, la fonction affich e fournit l'adresse de l'obje t l'ayant
appe lé.

_______________________________________________________________________________
____

#include <iostream.h>
class point // Une classe point contenant seulement :
{
int x, y ;
public :
point (int abs=0, int ord=0) // Un constructeur ("inline")
{ x=abs; y=ord ; }
void affiche () ; // Une fonction affiche
} ;
void point::affiche ()

3 - D ans ce rtaine s im pl
é m e ntations, un em pl
ace m e nt l
ibéré n'est pas re m is à zéro. Ainsi, on peut avoir l
'il
lusion que "cel
a m arch e " si l
'on
s e conte nte d'expl
oite r l
'obje t im m édiate m e nt aprè s l
'appe lde l
a fonction.
84 Program m e r e n langage C+ +
{ cout << "Adresse : " << this << " - Coordonnées " << x << " " << y << "\n" ;
}

main() // Un petit programme d'essai


{
point a(5), b(3,15) ;
a.affiche ();
b.affiche ();
} ________________________________

Adresse : 0x40d80ffc - Coordonnées 5 0


Adresse : 0x40d80ff8 - Coordonnées 3 15
_______________________________________________________________________________
____

Exe m ple d'utilisation de th is 4

R e m arque :

A titre pure m e nt indicatif, la fonction coincide du paragraph e 5.1 pourrait s'é crire :
int point::coincide (point * adpt)
{ if ((this -> x == adpt -> x) && (this -> y == adpt -> y)) return 1 ;
else return 0 ;
}

La sym é trie du problèm e y apparaî t plus claire m e nt. Ce s e rait m oins le cas si l'on é crivait ainsi la
fonction coincide du paragraph e 4 :
int point::coincide (point pt)
{ if ((this -> x == pt.x)) && (this -> y == pt.y)) return 1 ;
else return 0 ;
}

8. LES FO NCTIO NS M EM BRE STA TIQUES

Nous avons déjà vu (ch apitre V, paragraph e 5) com m e nt C+ + pe rm e t de définir de s m e m bres donnée
statiq ue s . Ce ux-ci e xiste nt e n un s e ule xe m plaire (pour une classe donnée), indé pe ndam m e nt des obje ts de
leur clas s e .

D 'une m aniè re analogue , on pe ut im agine r q ue ce rtaine s fonctions m e m bre d'une clas s e aie nt un rôle
totalem e nt indé pe ndant d'un q ue lconq ue obje t ;ce s e rait notam m e nt le cas d'une fonction q ui s e conte nte rait
d'agir sur des m e m bres donnée statiq ue s .

O n pe ut ce rte s toujours appe ler une te lle fonction e n la faisant porte r artificie llem e nt sur un obje t de la
clas s e , e t ce ci, bie n q ue l'adresse de ce t obje t ne s oit absolum e nt pas utile à la fonction. En fait, ile s t
possible de re ndre les ch os e s plus lisibles e t plus e fficace s , e n dé clarant statiq ue (m ot clé s tatic) la fonction
m e m bre conce rné e . Dans ce cas, en effe t, son appe lne né ce s s ite plus q ue le nom de la clas s e corre s pondante
(accom pagné , nature llem e nt, de l'opé rate ur de ré s olution de porté e ). Com m e pour les m e m bre s s tatiq ue s ,
une te lle fonction m e m bre s tatiq ue pe ut m ê m e ê tre appe lée lors q u'iln'e xiste aucun obje t de sa clas s e .

4 - R é al
isé dans un environne m e nt dans l
e q ue ll
e s pointe urs (ne ar) s'exprim e nt s ur s e ize bits.
VI. Le s propriété s d e s fonctions m e m bre 85
Voici un e xe m ple de program m e illustrant l'e m ploi d'une fonction m e m bre s tatiq ue : ils'agit de l'e xe m ple
du paragraph e 5.3 du ch apitre V, dans leq ue lnous avons introduit une fonction m e m bre s tatiq ue nom m é e
com pte , affich ant sim plem e nt le nom bre d'obje ts de sa clas s e .

_______________________________________________________________________________
______

#include <iostream.h>
class cpte_obj
{ static int ctr ; // compteur (statique) du nombre d'objets créés
public :
cpte_obj () ;
~cpte_obj() ;
static void compte () ; // pour afficher le nombre d'objets créés
} ;
int cpte_obj::ctr = 0 ; // initialisation du membre statique ctr
cpte_obj::cpte_obj () // constructeur
{
cout << "++ construction : il y a maintenant " << ++ctr << " objets\n" ;
}
cpte_obj::~cpte_obj () // destructeur
{
cout << "-- destruction : il reste maintenant " << --ctr << " objets\n" ;
}
void cpte_obj::compte ()
{ cout << " appel compte : il y a " << ctr << " objets\n" ;
}
main()
{
void fct () ;
cpte_obj::compte () ; // appel de la fonction membre statique compte
// alors qu'aucun objet de sa classe n'existe
cpte_obj a ;
cpte_obj::compte () ;
fct () ;
cpte_obj::compte () ;
cpte_obj b ;
cpte_obj::compte () ;
}
void fct()
{
cpte_obj u, v ;
} _______________________

appel compte : il y a 0 objets


++ construction : il y a maintenant 1 objets
appel compte : il y a 1 objets
++ construction : il y a maintenant 2 objets
++ construction : il y a maintenant 3 objets
-- destruction : il reste maintenant 2 objets
-- destruction : il reste maintenant 1 objets
appel compte : il y a 1 objets
++ construction : il y a maintenant 2 objets
86 Program m e r e n langage C+ +
appel compte : il y a 2 objets
-- destruction : il reste maintenant 1 objets
-- destruction : il reste maintenant 0 objets
_______________________________________________________________________________
______

D é finition e t utilisation d'une fonction m e m bre s tatique

9 . LES FO NCTIO NS M EM BRE CO NSTANTES

En langage C, le q ualificatif cons t pe ut s e rvir à désigner une variable dont on souh aite q ue la valeur
n'é volue pas. Le com pilate ur e s t ainsi en m e s ure de re je te r d'é ve ntue lles te ntatives de m odification de ce tte
variable. Par e xe m ple, ave c ce tte déclaration :

const int n=20 ;

l'instruction suivante s e ra incorre cte :

n = 12 ; // incorrecte

C+ + gé né ralise ce conce pt aux clas s e s , ce q ui signifie q u'on pe ut définir de s "obje ts constants". Encore
faut-il com pre ndre ce q ue l'on e nte nd par là. En e ffe t, dans le cas d'une variable ordinaire , il e s t
re lative m e nt facile au com pilate ur d'ide ntifie r les opé rations inte rdite s (ce lles q ui pe uve nt e n m odifie r la
valeur). D ans le cas d'un obje t, par contre , les ch os e s s ont m oins faciles , dans la m e s ure où les opé rations
sont gé né ralem e nt ré alisées par les fonctions m e m bre . Ce la signifie donc q ue l'utilisate ur doit pré cis e r,
parm i ce s fonctions m e m bre , les q ue lles s ont autoris é e s à opé re r sur des obje ts constants. Ille fe ra e n
utilisant le m ot cons t dans leur dé claration, com m e dans ce t e xe m ple de définition d'une clas s e point :

class point
{ int x, y ;
public :
point (...) ;
void affiche () const ;
void deplace (...) ;
...
} ;

Ici, nous avons spé cifié q ue la fonction affich e é tait utilisable pour un "point constant" ;e n re vanch e , la
fonction de place , q ui n'a pas fait l'obje t d'une déclaration cons t ne le s e ra pas. Ainsi, ave c ces déclarations :

point a ;
const point c ;

les instructions suivante s s e ront corre cte s :

a.affiche () ;
c.affiche () ;
a.deplace (...) ;

Ce lle-ci, e n re vanch e , s e ra re je té e par le com pilate ur :

c.deplace (...) ; // incorrecte


VI. Le s propriété s d e s fonctions m e m bre 87
R e m arques :

1) Le m é canism e q ue nous ve nons d'exposer s'appliq ue aux fonctions m e m bre volatiles e t aux obje ts
volatiles (m ot clé volatile). Ilsuffit de transposer tout ce q ui vie nt d'ê tre dit e n re m plaçant le m ot clé
cons t par le m ot clé volatile.
2) Ile s t possible de surdé finir une fonction m e m bre e n se basant sur la pré s e nce ou l'abs e nce du
q ualificatif cons t. Ainsi, dans notre clas s e point pré cédente , nous pouvons définir ces deux fonctions :
void affiche () const ; // affiche I
void affiche () ; // affiche II

Ave c ces déclarations :


point a ;
const point c ;

l'instruction a.affich e () appe llera la fonction II tandis q ue c.affich e () appe llera la fonction I.
O n note ra bie n q ue s i seule la fonction void affich e () e s t définie , e lle ne pourra e n aucun cas ê tre
appliq ué e à un obje t constant ;une instruction te lle q ue c.affich e () s e rait alors re je té e e n com pilation.
En re vanch e , si seule la fonction cons t void affich e () e s t définie , e lle pourra ê tre appliq ué e
indifé re m m e nt à des obje ts constants ou non constants. Une te lle dém arch e e s t m anife s te m e nt
logiq ue ;e n e ffe t, e lle pe ut s e ré s um e r ainsi :
- on ne court aucun ris q ue e n traitant un obje t non constant com m e s 'ilé tait constant,
- e n re vanch e , ils e rait dange re ux de faire à un obje t constant ce q u'on a pré vu de faire à un obje t
non constant.

$ 10. LES PO INTEURS SUR D ES FO NCTIO NS M EM BRE

N.B. Ce paragraph e traite d'aspects re lative m e nt s e condaire s e t pe ut, é ve ntue llem e nt, ê tre ignoré dans un
pre m ie r te m ps.

Le langage C pe rm e t de définir de s pointe urs sur de s fonctions. Le ur e m ploi pe rm e t alors, e n particulie r, de


program m e r ce q ue l'on pourrait nom m e r de s "appe ls variables " de fonctions. A titre de rappe l, considérez
ces déclarations :

int f1 (char, double) ;


int f2 (char, double) ;
...
int (* adf) (char, double) ;

La derniè re s ignifie q ue adf e s t un pointe ur sur une fonction re ce vant deux argum e nts, l'un de type ch ar,
l'autre de type double e t fournissant un ré s ultat de type int. Le s affe ctations suivante s s ont alors possibles :

adf = f1 ; // affecte à adf l'adresse de la fonction f1


// on peut aussi écrire : adf = & f1 ;
adf = f2 ; // affecte à adf l'adresse de la fonction f2

L'instruction :

(* adf) ('c', 5.25) ;


88 Program m e r e n langage C+ +
ré alise l'appe lde la fonction dont l'adre s s e figure dans adf, e n lui fournissant e n argum e nt les valeurs 'c' e t
5.25.

O n note ra q ue , com m e les autre s pointe urs du C, les pointe urs sur les fonctions sont "forte m e nt typé s ", e n
ce s e ns q ue leur type pré cis e à la fois la nature de la valeur de re tour de la fonction e t la nature de ch acun de
s e s argum e nts.

Bie n e nte ndu, C+ + vous offre toute s ce s possibilité s . M ais, de surcroî t, ilpe rm e t de les é te ndre au cas des
fonctions m e m bre . Ce tte e xte nsion passe néanm oins par une gé né ralisation de la syntaxe pré cédente . En
e ffe t, ilfaut pouvoir te nir com pte de ce q u'une fonction m e m bre s e d é finit :

• d'une part, com m e une fonction ordinaire , c'e s t-à -dire d'aprè s le type de ses argum e nts e t de sa valeur de
re tour,
• d'autre part, d'aprè s le type de la clas s e auq ue lle e lle s 'appliq ue ;le type de l'obje t l'ayant appe lé
constituant, e n q ue lque s orte , le type d'un argum e nt supplém e ntaire .
Ainsi, si une clas s e point com porte deux fonctions m e m bre de prototype s :

void dep_hor (int) ;


void dep_vert (int) ;

la déclaration :

void (point::* adf) (int) ;

pré cis e ra q ue adf e s t un pointe ur sur une fonction m e m bre de la clas s e point re ce vant un argum e nt de type
int e t ne re nvoyant aucune valeur. Le s affe ctations suivante s s e ront alors possibles :

adf = point::dep_hor ; // ou adf = & point::dep_hor ;


adf = point::dep_vert ;

Enfin, si a e s t un obje t de type point, une instruction te lle q ue :

(a.*adf) (3) ;

provoq ue ra, pour le point a, l'appe lde la fonction m e m bre dont l'adre s s e e s t conte nue dans adf, e n lui
transm e ttant e n argum e nt la valeur 3.

EXERCICES

N.B. Le s e xe rcice s m arqués (C) sont corrigé s e n fin de volum e .

1 - (C)Ecrive z une clas s e ve cte ur com portant :


- trois com posantes de type double (privé e s ),
- une fonction affich e ,
- deux constructe urs :
*l'un, sans argum e nts, initialisant ch aq ue com posante à 0,
*l'autre , ave c 3 argum e nts, re pré s e ntant les com posante s ,
a) ave c des fonctions m e m bre indé pe ndante s ,
VI. Le s propriété s d e s fonctions m e m bre 89
b) ave c des fonctions m e m bre "e n ligne ".
2 - (C)Ajoute z, à la pre m iè re clas s e ve cte ur pré cédente , une fonction m e m bre nom m é e prod_scal
fournissant e n ré s ultat le produit scalaire de deux ve cte urs.
3 - (C)Ajoute z, à la clas s e ve cte ur pré cédente (e xe rcice 2), une fonction m e m bre nom m é e som m e pe rm e ttant
de calculer la som m e de deux ve cte urs.
4 - (C)M odifie z la clas s e ve cte ur pré cédente (e xe rcice 3), de m aniè re q ue toute s les transm issions de valeurs
de type ve cte ur aie nt lie u :
a) par adre s s e ,
b) par ré fé re nce .
VII. CO NSTRUCTIO N, D ESTRUCTIO N,
RECO PIE ET INITIA LISATIO N D ES
O BJETS

En langage C, une variable pe ut ê tre créée de deux façons :

• par une déclaration : e lle e s t alors de clas s e autom atique ou statique ;sa duré e d e vie e s t parfaite m e nt
définie par la nature e t l'e m place m e nt de sa déclaration,
• e n faisant appe là des fonctions de gestion dynam iq ue de la m é m oire (m alloc, calloc, fre e ...) ;e lle e s t
alors dite dynam ique ;sa duré e d e vie e s t contrôlée par le program m e .
En langage C+ + , on re trouve ra ce s trois clas s e s à la fois pour les variables ordinaire s e t pour les obje ts
ave c ce tte diffé re nce q ue la ge s tion dynam iq ue fe ra appe laux opé rate urs ne w e t de lete .

Ce s ont ces diffé re nte s possibilités de cré ation (donc aussi de destruction) des obje ts q ue nous allons é tudie r
dans ce ch apitre . Nous com m e nce rons par e xam ine r la cré ation e t la destruction de s obje ts autom atiq ue s e t
statiq ues définis par une déclaration. Ce ci nous am è ne ra à pré cis e r ce rtains é lém e nts déjà introduits dans les
ch apitre s pré cédents (pour les obje ts autom atiq ue s ). Puis nous m ontre rons com m e nt cré e r e t utiliser des
obje ts dynam iq ues d'une m aniè re com parable à ce lle e m ployé e pour cré e r de s variables dynam iq ue s
ordinaire s , m ais e n faisant appe là une syntaxe é largie de l'opé rate ur ne w .

Nous aborde rons e nsuite la notion de constructe ur de re copie , leq ue linte rvie nt dans les s ituations dite s
d'"initialisation d'un obje t", c'e s t-à -dire lors q u'ile s t né ce s s aire de ré aliser une copie d'un obje t e xistant.
Nous ve rrons q u'ile xiste trois situations de ce type : transm ission de la valeur d'un obje t e n argum e nt d'une
fonction, transm ision de la valeur d'un obje t e n ré s ultat d'une fonction, initialisation d'un obje t lors de sa
déclaration par un obje t de m ê m e type ;la derniè re possibilité n'é tant q u'un cas particulie r d'initialisation
d'un obje t au m om e nt de sa déclaration.

Puis nous exam ine rons le cas des "obje ts m e m bre ", c'e s t-à -dire le cas où un type clas s e possè de des
m e m bres donnée qui sont e ux-m ê m e d'un type clas s e . Nous aborde rons rapide m e nt le cas des tableaux
d'obje ts, notion d'autant m oins im portante q u'un te ltableau n'e s t pas lui-m ê m e un obje t.

Enfin, nous fournirons q ue lque s indications conce rnant les obje ts dits te m poraire s , c'e s t-à -dire des obje ts q ui
pe uve nt ê tre cré é s au fildu déroulem e nt du program m e 1, sans q ue le program m e ur l'ait e xplicite m e nt
dem andé .

1 - En C, ile xis te déjà des variabl


e s te m poraires, m ais l
e ur e xis te nce a m oins d'im portance q ue ce l
le, en C+ + , des obje ts te m poraires.
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 91

1. LES O BJETS AUTO M A TIQUES ET STA TIQUES

Exam inons s é paré m e nt :

• leur duré e d e vie , c'e s t-à -dire le m om e nt où ils sont cré é s e t ce lui où ils sont détruits,
• les é ve ntue ls appe ls des constructe urs e t des destructe urs.

1.1 Le ur duré e de vie

Le s rè gles s 'appliq uant aux variables ordinaire s s e transposent tout nature llem e nt aux obje ts.

Le s objets autom atiques sont ce ux cré é s par une déclaration :

• dans une fonction : c'é tait le cas dans nos exem ples des pré cédents ch apitre s . L'obje t e s t cré é lors de la
re ncontre de sa déclaration, laq ue lle pe ut trè s bien, en C+ + , ê tre s itué e aprè s d'autre s instructions
e xé cutables 2. Ile s t détruit à la fin de l'e xé cution de la fonction.
• dans un bl oc : de m aniè re analogue au cas précédent, l'obje t e s t cré é lors de la re ncontre de sa
déclaration (là e ncore , ce lle-ci pe ut ê tre pré cé d é e , au s e in de ce bloc, d'autre s instructions e xé cutables ) ;
ile s t détruit lors de la sortie du bloc.
Le s objets statiques sont ce ux cré é s par une déclaration situé e :

• e n de h ors de toute fonction,


• dans une fonction, m ais assortie du qualificatif s tatic.
Le s obje ts statiq ue s s ont cré é s avant le début de l'e xé cution de la fonction m ain e t ils sont détruits aprè s la
fin de s on e xé cution.

1.2 Appe lde s cons tructe urs e t de s de s tructe urs

R appe lons q ue , si un obje t possè de un constructe ur, sa déclaration (lors q ue , com m e nous le s upposons pour
l'instant, e lle ne contie nt pas d'initialiseur) doit obligatoire m e nt com porte r les argum e nts corre s pondants.
Par e xe m ple, si une clas s e point com porte le constructe ur de prototype :

point (int, int)

les déclarations suivante s s e ront incorre cte s :

point a ; // incorrect : le constructeur attend deux arguments


point b (3) ; // incorrect (même raison)

Ce lle-ci, e n re vanch e , convie ndra :

point a(1, 7) ; // correct car le constructeur possède deux arguments

S'ile xiste plusieurs constructe urs, ilsuffit q ue la déclaration com porte les argum e nts re q uis par l'un d'e ntre
e ux. Ainsi, si une clas s e point com porte les constructe urs suivants :

2 - La distinction e ntre ins truction e xé cutabl


e e t ins truction de décl
aration n'é tant pas toujours possibl
e dans un l
angage com m e C+ + q ui
acce pte, par exem pl
e, une instruction te l
le q ue :
doubl
e *adr = ne w doubl
e [nel
e m = 2 *n+ 1] ;
92 Program m e r e n langage C+ +
point ( ) ; // constructeur 1
point (int, int) ; // constructeur 2

la déclaration suivante s e ra re je té e :

point a(5) ; // incorrect : aucun constructeur à un argument

M ais ce lles -ci convie ndront :

point a ; // correct : appel du constructeur 1


point b(1, 7) ; // correct : appel du constructeur 2

En ce q ui conce rne la "ch ronologie ", on pe ut dire q ue :

• le constructeur e s t appe lé aprè s l


a création de l'obje t,
• le destructeur e s t appe lé avant l
a destruction de l'obje t.

R e m arque :

Une déclaration te lle q ue :


point a ; // attention, point a () est rejeté

e s t acce ptable dans deux situations fort diffé re nte s :


• iln'e xiste pas de constructe ur de point,
• ile xiste un constructe ur de point sans argum e nt.

1.3 Exe m pl
e

Voici un e xe m ple de program m e m e ttant e n é vidence la cré ation e t la destruction d'obje ts statiq ue s e t
autom atiq ue s . Pour ce faire , nous y avons défini une clas s e nom m é e point, dans laq ue lle le constructe ur e t le
destructe ur affich e nt un m e s s age pe rm e ttant de re pé re r :

• le m om e nt de leur appe l,
• l'obje t conce rné (nous avons fait e n sorte q ue ch aq ue obje t de type point possè de des valeurs diffé re nte s ).

_______________________________________________________________________________
_____

#include <iostream.h>
class point
{
int x, y ;
public :
point (int abs, int ord) // constructeur ("inline")
{ x = abs ; y = ord ;
cout << "++ Construction d'un point : " << x << " " << y << "\n" ;
}

~point () // destructeur ("inline")


{ cout << "-- Destruction du point : " << x << " " << y << "\n" ;
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 93
}
} ;

point a(1,1) ; // un objet statique de classe point


main()
{
cout << "****** Début main *****\n" ;
point b(10,10) ; // un objet automatique de classe point
int i ;
for (i=1 ; i<=3 ; i++)
{ cout << "** Boucle tour numéro " << i << "\n" ;
point b(i,2*i) ; // objets créés dans un bloc
}
cout << "****** Fin main ******\n" ;
} _______________________

++ Construction d'un point : 1 1


****** Début main *****
++ Construction d'un point : 10 10
** Boucle tour numéro 1
++ Construction d'un point : 1 2
-- Destruction du point : 1 2
** Boucle tour numéro 2
++ Construction d'un point : 2 4
-- Destruction du point : 2 4
** Boucle tour numéro 3
++ Construction d'un point : 3 6
-- Destruction du point : 3 6
****** Fin main ******
-- Destruction du point : 10 10
-- Destruction du point : 1 1
_______________________________________________________________________________
______

Cons truction e t de s truction d'obje ts s tatique s e t autom atique s

R e m arque :

L'e xiste nce de constructe urs e t de destructe urs conduit à des traite m e nts q ui n'apparais s e nt pas
e xplicite m e nt dans les instructions du program m e . Par e xe m ple, ici, une banale déclaration te lle q ue :
point b(10, 10) ;

e ntraî
ne l'affich age d'un m e s s age .
Qui plus e s t, un "ce rtain nom bre de ch os e s " se déroulent avant le début ou aprè s l'e xé cution de la
fonction m ain3. O n pourrait, à la lim ite , conce voir une fonction m ain ne com portant q ue des déclarations
(ce q ui s e rait le cas de notre e xe m ple, si nous supprim ions l'instruction d'affich age du "tour de boucle"),
e t ré alisant, m algré tout, un ce rtain traite m e nt.

3 - En toute rigue ur, ile n va dé jà de m ê m e dans l


e cas d'un program m e C (ouve rture ou fe rm e ture de fich ie rs par e xe m pl
e ) m ais ilne
s'agit pas al
ors de tâ ch e s program m é e s e xpl
icite m e nt par l
'aute ur du program m e ;dans l
e cas de C+ + , ils'agit de tâ ch e s program m é e s
par l
e conce pte ur de l
a cl
as s e conce rnée.
94 Program m e r e n langage C+ +
2. LES O BJETS D Y NA M IQUES

Nous avons déjà vu com m e nt cré e r, utiliser et détruire e n C+ + des variables dynam iq ue s s calaire s (ou de s
tableaux de te lles variables ). Bie n e nte ndu, ce s possibilité s vont s e gé né raliser aux structure s e t aux obje ts.
Nous com m e nce rons par le cas des structure s , ce q ui nous am è ne ra e n fait à e ffe ctue r un ce rtain nom bre de
rappe ls sur l'utilisation de s s tructures dynam iq ue s e n C.

2.1 Le s s tructure s dynam iq ue s

Suppos e z q ue nous ayons défini la structure s uivante :

struct chose
{ int x ;
double y ;
int t [5] ;
}

e t q ue adr soit un pointe ur sur des élém e nts de ce type , c'e s t-à -dire déclaré , e n C, par :

struct chose * adr ;

ou plus sim plem e nt, e n C+ + , par :

chose * adr ;

L'instruction :

adr = new chose ;

ré alise une allocation dynam iq ue d'espace m é m oire pour un é lém e nt de type ch ose e t affe cte s on adre s s e au
pointe ur adr.

L'accè s aux diffé re nts ch am ps de ce tte s tructure s e fait à l'aide de l'opé rate ur -> . Ainsi, adr -> y e n
désignera le s e cond ch am p. R appe lons q ue ce tte notation e s t e n fait é q uivalente à (*adr). y.

L'e s pace m é m oire ainsi alloué pourra ê tre libéré par :

delete adr ;

2.2 Le s obje ts dynam iq ue s

Voyons tout d'abord ce q u'ily a de com m un e ntre la cré ation dynam iq ue d'obje ts e t ce lle de structure s avant
d'étudie r les nouve lles possibilités de l'opé rate ur ne w .

a)Points com m uns ave c l


e s s tructure s dynam iq ue s
Le m é canism e q ue nous ve nons d'évoq ue r s'appliq ue aux obje ts (au s e ns large ), lors q u'ils ne possè dent pas
de constructe ur. Ainsi, si nous définissons le type point suivant :

class point
{ int x, y ;
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 95
public :
void initialise (int, int) ;
void deplace (int, int) ;
void affiche ( ) ;
} ;

e t si nous déclarons :

point * adr ;

nous pourrons cré e r dynam iq ue m e nt un e m place m e nt de type point (q ui contie ndra donc ici la place pour
deux entie rs) e t affe cte r son adre s s e à adr par :

adr = new point ;

L'accè s aux fonctions m e m bre de l'obje t pointé par adr s e fe ra par de s appe ls de la form e :

adr -> initialise (1, 3) ;


adr -> affiche ( ) ;

ou, é ve ntue llem e nt, sans utiliser l'opé rate ur -> , par :

(* adr).initialise (1, 3) ;
(* adr).affiche ( ) ;

Si l'obje t conte nait des m e m bres donnée publics, on y accéderait de façon com parable.

Quant à la suppre s s ion de l'obje t e n q ue s tion, e lle s e fe ra, ici e ncore , par :

delete adr ;

b)Le s nouve l
le s pos s ibil
ité s de s opé rate urs ne w e t de l
e te
Nous avons déjà vu q ue la ph ilosoph ie de C+ + consiste à faire du constructe ur (dè s lors q u'ile xiste ) un
passage obligé lors de la cré ation d'un obje t. Ile n va de m ê m e pour le destructe ur lors de la destruction d'un
obje t.

Ce tte ph ilosoph ie s 'appliq ue é galem e nt aux obje ts dynam iq ue s . Plus précisém e nt :

• aprè s l'allocation dynam iq ue de l'e m place m e nt m é m oire re q uis, l 'opérateur n e w , appel lera un
constructeur de l 'objet ;ce constructe ur s e ra dé te rm iné par la nature des argum e nts q ui figure nt à la
suite de son appe lcom m e dans :
new point (2, 5) ;

O n pe ut dire q ue le constructe ur appe lé e s t le m ê m e q ue ce lui q ui aurait é té appe lé par une déclaration


te lle q ue :
a = point (2, 5) ;

Bie n e nte ndu, s'iln'e xiste pas de constructe ur, ou s'ile xiste un constructe ur sans argum e nt, la syntaxe :
new point // ou new point ()

s e ra acce pté e . En re vanch e , si tous les constructe urs possè dent au m oins un argum e nt, ce tte syntaxe s e ra
re je té e (e lle ne s e ra acce pté e q ue dans le cas où aucun constructe ur n'e xiste ).
O n re trouve là, e n dé finitive , les m ê m e s rè gles q ue ce lles s 'appliq uant à la déclaration d'un obje t.
96 Program m e r e n langage C+ +
• Avant la libération de l'e m place m e nt m é m oire corre s pondant, l
'opérateur delete appel
lera l
e
destructeur.

c)Exe m pl
e
Voici un e xe m ple de program m e q ui crée dynam iq ue m e nt un obje t de type point dans la fonction m ain e t q ui
le détruit dans une fonction fct (appe lée par m ain). Le s m e s s age s affich é s pe rm e tte nt de m e ttre e n é vidence
les m om e nts auxq ue ls sont appe lés le constructe ur e t le destructe ur.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point (int abs, int ord) // constructeur
{ x=abs ; y=ord ;
cout << "++ Appel Constructeur \n" ;
}
~point () // destructeur (en fait, inutile ici)
{ cout << "-- Appel Destructeur \n" ;
}
} ;
main()
{ void fct (point *) ; // prototype fonction fct
point * adr ;
cout << "** Début main \n" ;
adr = new point (3,7) ; // création dynamique d'un objet
fct (adr) ;
cout << "** Fin main \n" ;
}
void fct (point * adp)
{ cout << "** Début fct \n" ;
delete adp ; // destruction de cet objet
cout << "** Fin fct \n" ;
}
_______________________
** Début main
++ Appel Constructeur
** Début fct
-- Appel Destructeur
** Fin fct
** Fin main
_______________________________________________________________________________
______

Exe m ple de création dynam ique d'obje ts


VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 97
3. LE CO NSTRUCTEUR D E RECO PIE

3.1 Pré s e ntation du cons tructe ur de re copie

Nous avons vu com m e nt C+ + garantit l'appe ld'un constructe ur pour un obje t cré é par une déclaration ou
par ne w . Ce point e s t fondam e ntalpuis q u'ildonne la ce rtitude q u'un obje t ne pourra ê tre cré é , sans avoir é té
placé dans un "é tat initialconve nable" (du m oins jugé com m e te lpar le conce pte ur de l'obje t).

M ais il e xiste des circonstances dans les q ue lles il e s t né ce s s aire de construire un obje t, m ê m e s i le
program m e ur n'a pas prévu de constructe ur pour ce la. La situation la plus fré q ue nte e s t ce lle où la valeur
d'un obje t doit ê tre transm ise en argum e nt à une fonction. D ans ce cas, ile s t né ce s s aire de cré e r, dans un
e m place m e nt localà la fonction, un obje t q ui soit une copie de l'argum e nt e ffe ctif. Le m ê m e problèm e s e
pose dans le cas d'un obje t re nvoyé par valeur com m e ré s ultat d'une fonction ;ilfaut alors cré e r, dans un
e m place m e nt localà la fonction appe lante , un obje t q ui soit une copie du résultat. Nous ve rrons q u'ile xiste
une troisiè m e s ituation de ce type , à savoir le cas où un obje t e s t initialisé, lors de sa déclaration, ave c un
autre obje t de m ê m e type .

D 'une m aniè re gé né rale, on re groupe ce s trois situations sous le nom d'initial isation par recopie4. Une
initialisation par re copie d'un obje t é tant donc la cré ation d'un obje t par re copie d'un obje t e xistant de m ê m e
type .

Pour ré aliser une te lle initialisation par re copie , C+ + a pré vu d'utiliser un constructe ur particulie r dit
constructeur de recopie 5 (nous ve rrons plus loin la form e e xacte q u'ildoit posséder). M ais, si un te l
constructe ur n'e xiste pas, un traite m e nt par dé faut e s t pré vu ;on pe ut dire q u'on utilise un constructe ur de
re copie par dé faut.

En dé finitive , on pe ut dire q ue dans toute s ituation d'initialisation par re copie ily toujours appe ld'un
constructe ur de re copie , m ais ilfaut distingue r de ux cas.

a)Iln'e xis te pas de cons tructe ur approprié


Ily appe ld'un constructeur de recopie par défaut, gé né ré autom atiq ue m e nt par le com pilate ur. Ce
constructe ur s e conte nte d'effe ctue r une copie de ch acun de s m e m bre s , laq ue lle e s t analogue , e n dé finitive , à
ce lle q ui e s t m ise en place (par dé faut) lors d'une affe ctation e ntre obje ts de m ê m e type . Nature llem e nt ce la
pos e ra les m ê m e s problèm es dans le cas d'obje ts conte nant des pointe urs sur de s e m place m e nts alloué s
dynam iq ue m e nt : on aura sim plem e nt affaire à une "copie s upe rficie lle", c'e s t-à -dire q ue s e ules les valeurs
des pointe urs s e ront re copié e s , les e m place m e nts pointé s ne le s e ront pas ;ils ris q ue nt alors, par e xe m ple,
d'ê tre détruits deux fois.

b)Ile xis te un cons tructe ur approprié


Ile xiste donc un constructeur de recopie q ue vous aure z fourni expl icitem ent dans votre clas s e . Ildoit
s'agir d'un constructe ur ayant un s e ulargum e nt6 du type de ce tte clas s e ;de plus, ile s t indispensable q ue ce t
argum e nt soit transm is par ré fé re nce , ce q ui signifie q ue l'e n-tê te du constructe ur de re copie doit ê tre
obligatoire m e nt de l'une de ces deux form e s (si la clas s e conce rné e s e nom m e point) :

point (point & ) point (const point & )

4 - Nous aurions pu nous l


im ite r au te rm e "initial
isation" s'iln'e xis tait pas des situations où l
'on pe ut initial
iser un obje t ave c une val
e ur ou
un obje t d'un type diffé re nt...
5 - En angl ais "copy cons tructor".
6 - En toute rigue ur, l
a norm e ANSI acce pte é gal
e m e nt un cons tructe ur disposant d'argum e nts s uppl
é m e ntaires, pourvu q ue ces derniers
pos s è dent des val
e urs par dé faut.
98 Program m e r e n langage C+ +
D ans ce cas, ce constructe ur e s t appe lé de m aniè re h abitue lle, aprè s la cré ation de l'obje t. Bie n e nte ndu,
aucune re copie n'e s t faite de façon autom atiq ue , pas m ê m e une re copie s upe rficie lle, contraire m e nt à la
situation pré cédente : c'e s t à ce constructe ur de pre ndre e n ch arge l'inté gralité du travail(copie s upe rficie lle
e t copie profonde ).

R e m arques :

1) Note z bie n q ue C+ + im pos e au constructe ur e n q ue s tion q ue s on uniq ue argum e nt soit transm is par
ré fé re nce (ce q ui e s t logiq ue puis q ue , sinon, l'appe l du constructe ur de re copie im pliq ue rait une
initialisation par re copie de l'argum e nt, donc, e n dé finitive , un appe ldu constructe ur de re copie q ui, lui-
m ê m e , e tc.)
Quoi q u'ile n soit, la form e s uivante s e rait re je té e e n com pilation :
point (point) ; // incorrect

2) Les deux form e s pré cédente s (point (point & ) e t point (cons t point & ) ) pourraie nt e xiste r au s e in
d'une m ê m e clas s e . Dans ce cas, la pre m iè re s e rait utilisée en cas d'initialisation d'un obje t par un obje t
q ue lconq ue , tandis q ue la s e conde s e rait utilisée en cas d'initialisation par un obje t constant. En gé né ral,
com pte te nu de ce q ue , logiq ue m e nt, un te lconstructe ur de re copie n'a aucune raison de vouloir m odifie r
l'obje t re çu e n argum e nt, ile s t cons e illé de ne définir q ue la s e conde form e ;dans ce cas, e n e ffe t, e lle
re s te ra applicable aux de ux situations é voq ué e s (une fonction pré vue pour un obje t constant pe ut toujours
s'appliq ue r à un obje t variable –la ré ciproq ue é tant nature llem e nt faus s e ).
3) Nous avons déjà re ncontré des situations de re copie dans le cas de l'affe ctation. M ais, alors, les deux
obje ts conce rné s e xistaie nt déjà ;l'affe ctation n'e s t donc pas une situation d'initialisation par re copie ,
te lle q ue nous ve nons de la définir. Bie n q ue les deux opé rations possè dent un traite m e nt par dé faut
s e m blable (copie s upe rficie lle), la pris e e n com pte d'une copie profonde pas s e par de s m é canism e s
diffé re nts : définition d'un constructe ur de re copie pour l'initialisation, surdéfinition de l'opé rate ur =
pour l'affe ctation (ce q ue nous appre ndrons à faire dans le ch apitre consacré à la surdéfinition de s
opé rate urs).

3.2 Pre m ie r e xe m pl
e d'util
is ation du cons tructe ur de re copie :
obje t trans m is par vale ur

Nous vous proposons de com pare r les deux situations q ue nous ve nons d'évoq ue r : constructe ur de re copie
par dé faut, constructe ur de re copie défini dans la clas s e . Pour ce faire , nous allons utiliser une clas s e ve ct
pe rm e ttant de gérer des tableaux d'e ntie rs de taille "variable" (on de vrait plutôt dire de taille définissable
lors de l'e xé cution car, une fois définie , ce tte taille ne ch ange ra plus). Nous souh aitons q ue l'utilisate ur de
ce tte classe déclare un tableau sous la form e :

vect t (dim) ;

où dim e s t une e xpre s s ion e ntiè re re pré s e ntant sa taille.

Ilparaî
t alors nature lde prévoir pour ve ct :

• e n m e m bres donnée, la taille du tableau e t un pointe ur sur ses élém e nts, les q ue ls ve rront leurs
e m place m e nts alloués dynam iq ue m e nt,
• un constructe ur re ce vant un argum e nt e ntie r ch argé de ce tte allocation dynam iq ue ,
• un de s tructe ur libérant l'e m place m e nt alloué par le constructe ur.
Ce la nous conduit à une "pre m iè re ébauch e " :
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 99
class vect
{ int nelem ;
double * adr ;
public :
vect (int n) ;
~vect ( ) ;
} ;

a)Em pl
oi du cons tructe ur de re copie par dé faut
Voici un e xe m ple d'utilisation d'une te lle clas s e (nous avons ajouté des affich ages de m e s s age s pour suivre à
la trace les constructions e t destructions d'obje ts). Ici, nous nous conte ntons de transm e ttre par valeur un
obje t de type ve ct à une fonction ordinaire nom m é e fct, laq ue lle ne fait rie n d'autre q ue d'affich e r un
m e s s age indiq uant son appe l.

_______________________________________________________________________________
______

#include <iostream.h>
class vect
{
int nelem ; // nombre d'éléments
double * adr ; // pointeur sur ces éléments
public :
vect (int n) // constructeur "usuel"
{ adr = new double [nelem = n] ;
cout << "+ const. usuel - adr objet : " << this
<< " - adr vecteur : " << adr << "\n" ;
}
~vect () // destructeur
{ cout << "- Destr. objet - adr objet : "
<< this << " - adr vecteur : " << adr << "\n" ;
delete adr ;
}
} ;
void fct (vect b)
{ cout << "*** appel de fct ***\n" ;
}
main()
{ vect a(5) ;
fct (a) ;
} ________________________________

+ const. usuel - adr objet : 0x40e20ffa - adr vecteur : 0x42940004


*** appel de fct ***
- Destr. objet - adr objet : 0x40e20ff4 - adr vecteur : 0x42940004
- Destr. objet - adr objet : 0x40e20ffa - adr vecteur : 0x42940004
_______________________________________________________________________________
______

Lorsqu'aucun constructe ur de re copie n'a été défini


100 Program m e r e n langage C+ +
Com m e vous pouve z le constate r, l'appe l:

fct (a) ;

a cré é un nouve lobje t, dans leq ue lon a re copié les valeurs des m e m bre s ne le m e t adr de a. La situation pe ut
ê tre s ch é m atisée ainsi (nous désignons par b le nouve lobje t ainsi cré é ) :

A la fin de l'e xé cution de la fonction m ain, ily a appe ldu destructe ur ~ point, d'abord pour a, ce q ui libè re
l'e m place m e nt pointé par adr, puis pour b, ce q ui libè re ... le m ê m e e m place m e nt. Ce tte te ntative constitue
une e rre ur (d'e xé cution) dont les cons é q ue nce s varie nt ave c l'im plém e ntation.

b)D é finition d'un cons tructe ur de re copie


Nous pouvons é vite r le problèm e é voq ué e n faisant e n sorte q ue l'appe l:

fct (a) ;

conduis e à cré e r "inté gralem e nt" un nouve lobje t de type ve ct, ave c non s e ulem e nt s e s m e m bres donnée
ne le m e t adr, m ais é galem e nt son propre e m place m e nt de stock age des valeurs du tableau. Autre m e nt dit,
nous souh aitons aboutir à ce tte s ituation :

Pour ce faire , nous définissons, au s e in de la clas s e ve ct, un constructe ur par re copie , de la form e :

vect (const vect &) ; // ou, a la rigueur vect (vect &)

dont nous savons q u'ils e ra appe lé dans toute s ituation d'initialisation donc, e n particulie r, lors de l'appe lde
fct.
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 101
Ce constructe ur (appe lé aprè s la cré ation d'un nouve lobje t7) doit :

• cré e r dynam iq ue m e nt un nouve le m place m e nt dans leq ue lilre copie les valeurs corre s pondant à l'obje t
re çu e n argum e nt,
• re ns e igne r conve nablem e nt les m e m bres donnée du nouve lobje t (ne le m = valeur du m e m bre ne le m de
l'obje t re çu e n argum e nt, adr = adresse du nouve le m place m e nt).
Introduisons ce constructe ur de re copie dans notre pré cédent e xe m ple :

_______________________________________________________________________________
______

#include <iostream.h>
class vect
{
int nelem ; // nombre d'éléments
double * adr ; // pointeur sur ces éléments
public :
vect (int n) // constructeur "usuel"
{ adr = new double [nelem = n] ;
cout << "+ const. usuel - adr objet : " << this
<< " - adr vecteur : " << adr << "\n" ;
}
vect (const vect & v) // constructeur de recopie
{ adr = new double [nelem = v.nelem] ; // création nouvel
objet
int i ; for (i=0 ; i<nelem ; i++) adr[i]=v.adr[i] ; // recopie de l'ancien
cout << "+ const. recopie - adr objet : " << this
<< " - adr vecteur : " << adr << "\n" ;
}
~vect () // destructeur
{ cout << "- Destr. objet - adr objet : "
<< this << " - adr vecteur : " << adr << "\n" ;
delete adr ;
}
} ;
void fct (vect b)
{ cout << "*** appel de fct ***\n" ; }
main()
{ vect a(5) ; fct (a) ;
}
_______________________

+ const. usuel - adr objet : 0x44ec0ffa - adr vecteur : 0x469e0004


+ const. recopie - adr objet : 0x44ec0ff4 - adr vecteur : 0x46a10004
*** appel de fct ***
- Destr. objet - adr objet : 0x44ec0ff4 - adr vecteur : 0x46a10004
- Destr. objet - adr objet : 0x44ec0ffa - adr vecteur : 0x469e0004

_______________________________________________________________________________
______

7 - Notez bien que l


e cons tructe ur n'a pas à cré e r l
'obje t l
ui-m ê m e, c'est-à -dire ici l
e s m e m bres int e t adr, m ais sim pl
e m e nt l
e s partie s
s oum ises à l
a ge s tion dynam iq ue.
102 Program m e r e n langage C+ +
D é finition e t utilisation d'un cons tructe ur de re copie

Vous constate z q ue , ce tte fois, ch aq ue obje t possédant son propre e m place m e nt m é m oire , les destructions
succe s s ives se déroulent sans problèm e .

R e m arque

Si nous avons ré glé le problèm e de l'initialisation d'un obje t de type ve ct par un autre obje t du m ê m e
type , nous n'avons pas pour autant ré glé ce lui q ui s e pos e rait e n cas d'affe ctation e ntre obje ts de type
ve ct. Com m e nous l'avons déjà signalé à plusieurs reprises, ce dernier point ne pe ut s e ré s oudre q ue par
la surdéfinition de l'opé rate ur =.

3.3 D e uxiè m e e xe m ple d'utilis ation du cons tructe ur de re copie :


obje t trans m is e n vale ur de re tour d'une fonction

Lors q ue la transm ission d'un argum e nt ou d'une valeur de re tour d'une fonction a lie u par valeur, e lle m e t
e n œuvre une re copie . Lors q ue ce lle-ci conce rne un obje t, ce tte re copie e s t, com m e nous l'avons dit,
ré alisée soit par le constructe ur de re copie par dé faut, soit, le cas é ch é ant, par le constructe ur de re copie
pré vu pour l'obje t.

D ans le cas où un obje t com porte une partie dynam iq ue , l'e m ploi de la re copie par dé faut conduit, com m e
nous l'avons déjà vu, à une "copie s upe rficie lle" ne re copiant q ue les m e m bres de l'obje t. Le s ris q ues de
double libération d'un e m place m e nt m é m oire s ont alors les m ê m e s q ue ce ux é voq ués dans le paragraph e
3.2. M ais, de surcroî t, pour la partie dynam iq ue de l'obje t, on pe rd ici le béné fice de la prote ction contre
des m odifications q u'offre la transm ission par valeur. En e ffe t, dans ce cas, la fonction conce rné e re çoit bien
une copie de l'adresse de l'e m place m e nt m ais, par le biais de ce pointe ur, e lle pe ut tout à fait m odifie r le
conte nu de l'e m place m e nt lui-m ê m e (re voye z, par e xe m ple, le s ch é m a du paragraph e 3.2a, dans leq ue la
jouait le rôle d'un argum e nt e t b ce lui de s a re copie ).

Voici un e xe m ple de program m e faisant appe là une clas s e point, dotée d'une fonction m e m bre nom m é e
sym e trique , fournissant e n re tour un point sym é triq ue de ce lui l'ayant appe lé. Note z bie n q u'ici,
contraire m e nt à l'e xe m ple pré cédent, le constructe ur de re copie n'e s t pas indispensable au bon
fonctionne m e nt de notre clas s e (q ui ne com porte aucune partie dynam iq ue ) : ilne s e rt q u'à illustre r le
m é canism e de son appe l.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur "usuel"
{ x=abs ; y=ord ;
cout << "++ Appel Const. usuel " << this << " " << x << " " << y <<
"\n" ;
}
point (point & p) // constructeur de recopie
{ x=p.x ; y=p.y ;
cout << "++ Appel Const. recopie " << this << " " << x << " " << y <<
"\n" ;
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 103
}
~point ()
{ cout << "-- Appel Destr. " << this << " " << x << " " << y <<
"\n" ;
}
point symetrique () ;
} ;
point point::symetrique ()
{ point res ; res.x = -x ; res.y = -y ; return res ;
}

main()
{ point a(1,3), b ;
cout << "** avant appel de symetrique\n" ;
b = a.symetrique () ;
cout << "** après appel de symetrique\n" ;
} _______________________

++ Appel Const. usuel 0x41000ffc 1 3


++ Appel Const. usuel 0x41000ff8 0 0
** avant appel de symetrique
++ Appel Const. usuel 0x41000fe2 0 0
++ Appel Const. recopie 0x41000ff4 -1 -3
-- Appel Destr. 0x41000fe2 -1 -3
** après appel de symetrique
-- Appel Destr. 0x41000ff4 -1 -3
-- Appel Destr. 0x41000ff8 -1 -3
-- Appel Destr. 0x41000ffc 1 3
_______________________________________________________________________________
______

Appe ldu constructe ur de re copie e n cas d e trans m ission par valeur

$ 4. INITIA LISATIO N D 'UN O BJET LO RS D E SA D ÉCLARATIO N

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

En langage C, on pe ut initialiser une variable au m om e nt de sa déclaration com m e dans :

int n = 12 ;

En th é orie , C+ + pe rm e t de faire de m ê m e ave c les obje ts, e n ajoutant un initialiseur lors de leur
déclaration. M ais si le rôle d'un te linitialiseur va de soi dans le cas de variables classiques (ilne s 'agit q ue
d'en fournir la ou les valeurs), iln'e n va plus de m ê m e dans le cas d'un obje t ;e n e ffe t, ilne s 'agit plus de
s e conte nte r d'initialiser sim plem e nt s e s m e m bre s m ais plutôt de fournir, sous une form e pe u nature lle, des
argum e nts pour un constructe ur. D e plus, C+ + n'im pos e aucune re s triction sur le type de l'initialiseur qui
pourra donc, é ve ntue llem e nt, ê tre du m ê m e type q ue l'obje t initialisé : le constructe ur utilisé sera alors le
constructe ur de re copie pré s e nté pré cédem m e nt.

Voyons ce la plus e n dé tail. Considérons d'abord cette clas s e (m unie d'un constructe ur usuel) :

class point
{ int x, y ;
public :
104 Program m e r e n langage C+ +
point (int abs) { x = abs ; y = 0 ; }
.....
} ;

Nous avons déjà vu q ue ls e rait le rôle d'une déclaration te lle q ue :

point a(3) ;

C+ + nous autoris e é galem e nt à é crire :

point a = 3 ;

Ce tte déclaration e ntraî


ne :

• la cré ation d'un obje t nom m é a,


• l'appe ldu constructe ur auq ue lon transm e t e n argum e nt la valeur de l'initialiseur, ici 3.
En dé finitive , les deux dé clarations :

point a(3) ;
point a = 3 ;

sont é q uivalente s .

D 'une m aniè re gé né rale, lors q ue l'on dé clare un obje t ave c un initial iseur, ce dernie r pe ut ê tre une
expression d'un type quel conque, à condition q u'ile xiste un constructe ur à un s e ulargum e nt de ce type .

Ce la s'appliq ue donc égalem e nt à une s ituation te lle q ue :

point a ;
point b = a ; // on initialise b avec l'objet a de même type

M anife s te m e nt, on aurait obte nu le m ê m e ré s ultat e n dé clarant :

point b(a) ; // on crée l'objet b, en utilisant le constructeur par


recopie
// de la classe point, auquel on transmet l'objet a

Quoi q u'ile n soit, ces deux dé clarations (point b=a e t point b(a)) e ntraî ne nt e ffe ctive m e nt la cré ation d'un
obje t de type point, suivie de l'appe ldu constructe ur par re copie de point (ce lui par dé faut ou, le cas
é ch é ant, ce lui q u'on y a dé fini) auq ue lon transm e t e n argum e nt l'obje t a.

R e m arques :

1) Ilne faut pas confondre l'initialiseur d'une clas s e ave c ce lui e m ployé e n C pour donne r de s valeurs
initiales à un tableau :
int t[5] = {3, 5, 11, 2, 0} ;

ou à une s tructure . Ce lui-ci e s t toujours utilisable e n C+ + , y com pris pour les s tructure s com portant des
fonctions m e m bre . Il e s t m ê m e applicable à des clas s e s ne disposant pas de constructe ur e t dans
les q ue lles tous les m e m bre s s ont publics ;e n pratiq ue , ce tte possibilité ne pré s e nte guè re d'inté rê t.
2) Supposons qu'une clas s e point soit m unie d'un constructe ur à deux argum e nts e ntie rs e t considérons la
déclaration :
point a = point (1, 5) ;
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 105

Ils'agit bien d'une déclaration com portant un initialiseur constitué d'une expression de type point. O n
pourrait logiq ue m e nt pe ns e r q u'e lle e ntraî
ne l'appe ld'un constructe ur de re copie (par dé faut ou e ffe ctif)
e n vue d'initialiser l'obje t a nouve llem e nt cré é ave c l'obje t te m poraire point (1,5).
En fait, dans ce cas précis d'initialisation d'un obje t par appe le xplicite du constructe ur, C+ + a pré vu
de traite r ce tte déclaration com m e :
point a(1, 5) ;

Autre m e nt dit, ily a cré ation d'un se ulobje t a e t appe ldu constructe ur ("usuel") pour ce t obje t. Aucun
constructe ur de re copie n'e s t appe lé.
Ce tte dém arch e e s t, au de m e urant, as s e z nature lle e t sim plificatrice . Elle n'e n de m e ure pas m oins une
e xce ption par opposition à ce lle q ui e s t m ise en œuvre dans :
point a = b ;

ou dans :
point a = b + point (1, 5)

lors q ue nous aurons appris à donne r un s e ns à une e xpre s s ion te lle q ue b + point (1, 5) (e lle s uppos e la
"surdéfinition" de l'opé rate ur + pour la clas s e point).

5. O BJETS M EM BRE

5.1 Introduction

Ile s t tout à fait possible q u'une clas s e possè de un m e m bre donnée qui soit lui-m ê m e de type clas s e . Par
e xe m ple, ayant défini :

class point
{ int x, y ;
public :
int init (int, int) ;
void affiche ( ) ;
} ;

nous pouvons définir :

class cercle
{ point centre ;
int rayon ;
public :
void affrayon ( ) ;
...
} ;

Si nous déclarons alors :

cercle c ;

l'obje t c possè de un m e m bre donnée privé ce ntre , de type point. L'obje t c pe ut accéder classiquem e nt à la
m é th ode affrayon par c.affrayon. En re vanch e , ilne poura pas accéder à la m é th ode init du m e m bre ce ntre
106 Program m e r e n langage C+ +
car ce ntre e s t privé . Si ce ntre é tait public, on pourrait accéder aux m é th odes de ce ntre par c.ce ntre .init () ou
c.ce ntre .affich e ().

D 'une m aniè re gé né rale, la situation d'obje ts m e m bre corre s pond à une re lation e ntre classe du type re lation
de possession (on dit aussi "re lation a" –du ve rbe avoir). Effe ctive m e nt, ici, on pe ut bien dire q u'un ce rcle
possè de (a) un ce ntre (de type point). Ce type de re lation s'oppos e au type de re lation q ui s e ra induite par
l'h é ritage , dont on dira q u'ils'agit de "re lation e s t" (du ve rbe ê tre ).

Voyons m ainte nant com m e nt sont m is en œuvre les constructe urs des diffé re nts obje ts lors q u'ils e xiste nt.

5.2 M is e e n œuvre de s cons tructe urs e t de s de s tructe urs

Supposons, cette fois, q ue notre clas s e point ait é té définie ave c un constructe ur :

class point
{ int x, y ;
public :
point (int, int) ;
} ;

Nous ne pouvons plus définir la clas s e ce rcle pré cédente s ans constructe ur. En e ffe t, si nous le faisions, son
m e m bre ce ntre s e ve rrait ce rte s attribue r un e m place m e nt (lors d'une création d'un obje t de type ce rcle)
m ais son constructe ur ne pourrait ê tre appe lé (q ue lles valeurs pourrait-on lui transm e ttre ?).

Ilfaut donc :

• d'une part, définir un constructe ur pour ce rcle,


• d'autre part, spécifie r les argum e nts à fournir au constructe ur de point : ce ux-ci doive nt ê tre ch oisis
obligatoire m e nt parm i ce ux fournis à ce rcle.

Voici ce q ue pourrait ê tre la définition de ce rcle e t de son constructe ur :

class cercle
{ point centre ;
int rayon ;
public :
cercle (int, int, int) ;
} ;
cercle::cercle (int abs, int ord, int ray) : centre (abs, ord)
{ ...
}

Vous voye z q ue l'e n-tê te de ce rcle spécifie , aprè s les deux-points, la liste des argum e nts q ui s e ront transm is
à point.

Le s constructe urs s e ront appe lés dans l'ordre s uivant : point, ce rcle. S'ile xiste des destructe urs, ils s e ront
appe lés dans l'ordre inve rs e .

Voici un e xe m ple com plet :

_______________________________________________________________________________
______
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 107

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0)
{ x=abs ; y=ord ;
cout << "Constr. point " << x << " " << y << "\n" ;
}
} ;

class cercle
{ point centre ;
int rayon ;
public :
cercle (int , int , int) ;
} ;

cercle::cercle (int abs, int ord, int ray) : centre(abs, ord)


{ rayon = ray ;
cout << "Constr. cercle " << rayon << "\n" ;
}

main()
{ cercle a (1,3,9) ;
}
_______________________

Constr. point 1 3
Constr. cercle 9
_______________________________________________________________________________
______

Appe ldes diffé re nts cons tructe urs dans le cas d'obje ts m e m bre

R e m arques :

1) Si point dispose d'un constructe ur sans argum e nt, le constructe ur de ce rcle pe ut ne pas spé cifie r
d'argum e nt à destination du constructe ur de ce ntre q ui s e ra appe lé autom atiq ue m e nt.
2) D ans le cas d'obje ts com portant plusieurs obje ts m e m bre , la s é lection de s argum e nts destiné s aux
diffé re nts constructe urs s e fait e n s é parant ch aq ue liste par une virgule. En voici un e xe m ple :
class A class B
{ ... { ...
A (int) ; B (double, int) ;
... ...
} ; } ;

class C
{ A a1 ;
B b ;
A a2 ;
...
C (int n, int p, double x, int q, int r) : a1(p), b(x,q), a2(r)
108 Program m e r e n langage C+ +
{ ..... }
...
} ;

Ici, nous avons, par souci de s im plification de l'é criture , supposé que le constructe ur de C é tait "e n
ligne ". Parm i les argum e nts n, p, x, q e t r q u'ilre çoit, p s e ra transm is au constructe ur A de a1, x e t q
au constructe ur B de b puis r au constructe ur A de a2. Note z bie n q ue l'ordre dans leq ue lce s trois
constructe urs sont e xé cuté s n'e s t pas im pos é par le langage (atte ntion aux é ve ntue ls e ffe ts de bord !).
Toute fois, le constructe ur C, q uant à lui, ne s e ra bie n e xé cuté q u'aprè s les trois autre s (l'ordre des
im brications e s t toujours re s pe cté ).

3) La syntaxe q ue nous ve nons de décrire pour transm e ttre des argum e nts à un constructe ur d'un obje t
m e m bre pe ut e n fait s'appliq ue r à n'im porte q ue lm e m bre m ê m e s 'ilne s 'agit pas d'un obje t. Par
e xe m ple :
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) : x(abs), y(ord) {}
.....
} ;

L'appe ldu constructe ur point provoq ue ra l'initialisation de s m e m bre s x e t y ave c re s pe ctive m e nt les
valeurs abs e t ord. Son corps e s t vide ici puisq u'iln'y a rie n de plus à faire pour re m place r notre
constructe ur classique :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }

Ce tte possibilité pe ut deve nir indispe nsable dans les cas suivants :
- initialisation d'un m e m bre donnée constant,
- initialisation d'un m e m bre donnée qui est une ré fé re nce : e n e ffe t, e n ne pe ut q u'initialiser une
te lle ré fé re nce , jam ais lui affe cte r une nouve lle valeur (re voye z é ve ntue llem e nt le paragraph e
corre s pondant dans le ch apitre IV).

5.3 Cas du cons tructe ur de re copie

Nous avons vu q ue , pour toute clas s e , ile s t pré vu un constructe ur de re copie par dé faut, leq ue le s t appe lé e n
l'abs e nce de constructe ur de re copie e ffe ctif. Son rôle e s t sim ple dans le cas d'obje ts ne com portant pas
d'obje ts m e m bre , puis q u'ils'agit alors de re copie r les valeurs des diffé re nts m e m bres donnée.

Lors q ue l'obje t com porte des obje ts m e m bre , la re copie (par dé faut) s e fait m e m bre par m e m bre 8 ;
autre m e nt dit, si l'un de s m e m bre s e s t lui-m ê m e un obje t, on le re copie ra e n appe lant son propre
constructeur de recopie (q ui pourra ê tre s oit un constructe ur par dé faut, soit un constructe ur dé fini dans la
clas s e corre s pondante ).

Ce la signifie q ue la construction par re copie (par dé faut) d'un obje t s e ra satisfaisante dè s lors q u'ilne
contie nt pas de pointe urs sur de s parties dynam iq ue s , m ê m e s i ce rtains de ses obje ts m e m bre e n com porte nt
(à condition q u'ils soie nt, q uant à e ux, conve nablem e nt m unis des constructe urs par re copie approprié s ).

Si, e n re vanch e , l'obje t contie nt des pointe urs, ilfaudra le m unir d'un constructe ur de re copie approprié . Ce
dernie r de vra alors prendre en ch arge l'inté gralité de la re copie de l'obje t. Ce pe ndant, on pourra pour ce la,

8 - En angl
ais, on parl
e de "m e m berw ise copy". Avant l
a ve rsion 2.0 de C+ + , l
a copie s e fais ait bit à bit ("bitw ise copy"), ce q ui n'é tait
pas toujours s atisfais ant.
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 109
le cas é ch é ant, transm e ttre les inform ations néce s s aire aux constructe urs par re copie (par dé faut ou non) de
ce rtains de ses m e m bre s e n utilisant la te ch niq ue décrite dans le paragraph e 5.2.

$ 6. LES TA BLEAUX D 'O BJETS

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

En C+ + , un tableau pe ut posséder de s é lém e nts de n'im porte q ue ltype , y com pris de type clas s e , ce q ui
conduit alors à des tableaux d'obje ts. Ce conce pt ne pré s e nte pas de difficulté s particuliè re s au nive au de s
notations q ue nous allons nous conte nte r de rappe ler sur un e xe m ple. En re vanch e , ilnous faudra pré cis e r
ce rtains points re latifs à l'appe ldes constructe urs e t aux initialiseurs.

6.1 Notations

Soit une clas s e point, sans constructe ur, dé finie par :

class point
{ int x, y ;
public :
void init (int, int) ;
void affiche ( ) ;
} ;

Nous pouvons déclare r un tableau courbe de vingt obje ts de type point par :

point courbe [20] ;

Si i e s t un e ntie r, la notation courbe [i] désignera un obje t de type point. L'instruction :

courbe[i].affiche () ;

appe llera le m e m bre init pour le point courbe [i] (les priorité s re latives des opé rate urs . e t [] pe rm e tte nt de
s'affranch ir de pare nth è s e s ). De m ê m e , on pourra "affich e r" tous les points par :

for (i = 0 ; i < 20 ; i++) courbe[i].affiche() ;

R e m arque :

Un tabl eau d'objets n'est pas un objet. Dans l'e s prit de la P.O .O . pure , ce conce pt n'e xiste pas,
puis q u'on ne m anipule q ue des obje ts. En re vanch e , ilre s te toujours possible de définir une classe dont
un de s m e m bre s e s t un tableau d'obje ts. Ainsi, dans notre cas, nous pourrions dé finir un type courbe
par :
class courbe
{ point p[20] ;
...
} ;
110 Program m e r e n langage C+ +
6.2 Cons tructe urs e t initial
is e urs
Nous ve nons de voir la signification de la déclaration :

point courbe[20] ;

dans le cas où point e s t une clas s e s ans constructe ur.

Si la clas s e com porte un constructe ur sans argum e nt, ce lui-ci s e ra appe lé s ucce s s ive m e nt pour ch acun de s
é lém e nts (de type point) du tableau courbe . En re vanch e , si aucun de s constructe urs de point n'e s t un
constructe ur sans argum e nt, la déclaration pré cédente conduira à une e rre ur de com pilation. Ce ci s'e xpliq ue
par le fait q ue , dans ce cas, C+ + n'e s t plus e n m e s ure de garantir le passage par un constructe ur, dè s lors
q ue la clas s e conce rné e (point) e n com porte au m oins un.

Ile s t ce pe ndant possible de com pléte r une te lle déclaration par un initialiseur com portant une liste de
valeurs ;ch aq ue valeur s e ra transm ise à un constructe ur approprié (les valeurs peuve nt donc ê tre de type s
q ue lconq ue s , é ve ntue llem e nt diffé re nts les uns des autre s , dans la m e s ure où il e xiste le constructe ur
corre s pondant). Pour les tableaux de clas s e autom atiq ue , les valeurs de l'initialiseur peuve nt ê tre une
e xpre s s ion q ue lconq ue (pour pe u q u'e lle s oit calculable au m om e nt où l'on e n a be s oin). En outre ,
l'initialiseur peut com porte r m oins de valeurs q ue le tableau n'a d'é lém e nts 9 . Dans ce cas, ily a appe ldu
constructe ur sans argum e nt (q ui doit donc e xiste r) pour les é lém e nts auxq ue ls ne corre s pond aucune valeur.

Voici un e xe m ple illustrant ce s possibilité s (ici, nous avons ch oisi un constructe ur disposant d'argum e nts par
défaut : ilre m place trois constructe urs à zé ro, un e t deux argum e nts).

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur (0, 1 ou 2 arguments)
{ x=abs ; y =ord ;
cout << "++ Constr. point : " << x << " " << y << "\n" ;
}
} ;
main()
{ int n = 3 ;
point courbe[5] = { 7, n, 2*n+5 } ;
} _______________________

++ Constr. point : 7 0
++ Constr. point : 3 0
++ Constr. point : 11 0
++ Constr. point : 0 0
++ Constr. point : 0 0
-- Destr. point : 0 0
-- Destr. point : 0 0
-- Destr. point : 11 0
-- Destr. point : 3 0
-- Destr. point : 7 0
_______________________________________________________________________________
______

9 - M ais, pour l
'instant, l
es él
é m e nts m anq uants doive nt obl
igatoire m e nt ê tre l
es derniers.
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 111

Cons truction e t initialisation d'un tableau d'obje ts (ve rsion 2.0)

6.3 Cas d e s tabl


e aux dynam iq ue s d'obje ts

Si l'on dispose d'une clas s e point, on pe ut cré e r dynam iq ue m e nt un tableau de points e n faisant appe là
l'opé rate ur ne w . Par e xe m ple :

point * adcourbe = new point[20] ;

alloue l'e m place m e nt m é m oire né ce s s aire à vingt obje ts (cons é cutifs) de type point e t place l'adresse du
pre m ie r de ce s obje ts dans adcourbe .

Là e ncore , si la clas s e point com porte un constructe ur sans argum e nt, ce dernie r s e ra appe lé pour ch acun de s
vingt obje ts. Si, e n re vanch e , aucun de s constructe urs de point n'e s t un constructe ur sans argum e nt,
l'instruction pré cédente conduira à une e rre ur de com pilation. Bie n e nte ndu, aucun problèm e particulie r ne
s e pos e ra si la clas s e point ne com porte aucun constructe ur.

Par contre , iln'e xiste ici aucune possibilité de fournir un initialiseur, alors q ue , com m e nous l'avons vu dans
le paragraph e 6.2, ce ci e s t possible dans le cas de tableaux autom atiq ue s ou statiq ue s .

Pour dé truire notre tableau d'obje ts, ilsuffira de l'instruction (note z la pré s e nce de [] q ui pré cis e q ue l'on a
affaire à un tableau d'obje ts) :

delete [] adcourbe

Ce lle-ci provoq ue ra l'appe ldu destructe ur de point e t la libération de l'e s pace corre s pondant pour ch acun
des él é m ents du tabl eau.

$ 7. LES O BJETS TEM PO RA IRES

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

Lors q u'une classe dispose d'un constructe ur, ce dernie r pe ut ê tre appe lé e xplicite m e nt (ave c la liste
d'argum e nts néce s s aire s ). Dans ce cas, ily a alors cré ation d'un obje t te m poraire . Par e xe m ple, si nous
supposons q u'une clas s e point possè de le constructe ur :

point (int, int) ;

nous pouvons, si a e s t un obje t de type point, é crire une affe ctation te lle q ue :

a = point (1, 2) ;

D ans une te lle instruction, l'é valuation de l'e xpre s s ion :

point (1, 2)

conduit à :
112 Program m e r e n langage C+ +
• la cré ation d'un obje t te m poraire de type point (ila une adre s s e pré cis e , m ais iln'e s t pas acce s s ible au
program m e )10,
• l'appe ldu constructe ur point, pour ce t obje t te m poraire , ave c transm ission des argum e nts spé cifié s (ici 1
e t 2),
• la re copie de ce t obje t te m poraire dans a (affe ctation d'un obje t à un autre de m ê m e type ).
Quant à l'obje t te m poraire ainsi cré é , iln'a plus d'inté rê t dè s q ue l'instruction d'affe ctation e s t e xé cuté e . Il
pourra donc ê tre détruit à tout m om e nt. Né anm oins, la définition du langage C+ + ne s pé cifie pas à q ue l
m om e nt ! Ce ci pe ut avoir une im portance dans le cas où l'on tie nt com pte du nom bre d'obje ts d'une m ê m e
clas s e e xistant à un m om e nt donné , ou e ncore lors q ue l'on e m ploie des "com pte urs de ré fé re nce s " dont nous
parlons e n anne xe .

Voici un e xe m ple de program m e m ontrant l'e m ploi d'obje ts te m poraire s . R e m arq ue z q u'ici, nous avons
pré vu, dans le constructe ur e t le destructe ur de notre clas s e point, d'affich e r non s e ulem e nt les valeurs de
l'obje t m ais é galem e nt son adre s s e .

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point (int abs, int ord) // constructeur ("inline")
{ x = abs ; y = ord ;
cout << "++ Constr. point " << x << " " << y
<< " à l'adresse : " << this << "\n" ;
}
~point () // destructeur ("inline")
{ cout << "-- Destr. point " << x << " " << y
<< " à l'adresse : " << this << "\n" ;
}
} ;

main()
{
point a(0,0) ; // un objet automatique de classe point
a = point (1, 2) ; // un objet temporaire
a = point (3, 5) ; // un autre objet temporaire
cout << "****** Fin main ******\n" ;
}
________________________________

++ Constr. point 0 0 à l'adresse : 0x40eb0ffc


++ Constr. point 1 2 à l'adresse : 0x40eb0ff8
++ Constr. point 3 5 à l'adresse : 0x40eb0ff4
****** Fin main ******
-- Destr. point 3 5 à l'adresse : 0x40eb0ff4

10 - En fait, ile n va de m ê m e l
ors q ue l
'on ré al
ise une affe ctation te l
le q ue y = a *x + b. Ily a bien création d'un e m pl
ace m e nt
te m poraire destiné à re cue il
lir l
e ré s ul
tat de l
'éval
uation de l
'expression a *x + b.
VII. Cons truction, de s truction, re copie e t initialisation de s obje ts 113
-- Destr. point 1 2 à l'adresse : 0x40eb0ff8
-- Destr. point 3 5 à l'adresse : 0x40eb0ffc

_______________________________________________________________________________
______

Exe m ple de création d'obje ts te m poraire s

O n y voit claire m e nt q ue les deux affe ctations de la fonction m ain e ntraî ne nt la cré ation d'un obje t
te m poraire , distinct de a. Ici, le com pilate ur utilisé n'a prévu de détruire les obje ts te m poraire s q u'à la fin de
l'e xé cution de la fonction conce rné e (m ain), de sorte q ue les m e s s ages de destruction n'apparais s e nt q u'aprè s
ce lui de fin ;bien ente ndu, ilpourrait e n aller autre m e nt ave c d'autre s com pilate urs.

R e m arques
1) R é pé tons q ue , dans une affe ctation te lle q ue :
a = point (1, 2) ;

l'obje t a e xiste déjà . Iln'a donc pas à ê tre cré é e t iln'y a pas d'appe lde constructe ur à ce nive au
pour a.
2) Le s re m arq ue s faite s à propos des ris q ue s q ue com porte une affe ctation e ntre obje ts, notam m e nt dans
le cas où ils com porte nt des parties dynam iq ue s 11 re s te nt valables ici. La m ê m e s olution pourra y ê tre
apporté e , à savoir la surdéfinition de l'opé rate ur d'affe ctation.
3) Ile xiste d'autre s circonstances dans les q ue lles s ont créés des obje ts te m poraire s , à savoir :
- transm ission de la valeur d'un obje t e n argum e nt d'une fonction ;dans ce cas, ily a cré ation d'un
obje t te m poraire au s e in de la fonction conce rné e ;
- transm ission d'un obje t e n valeur de re tour d'une fonction ;dans ce cas, ily a cré ation d'un obje t
te m poraire au s e in de la fonction appe lante .
D ans les deux cas, l'obje t te m poraire e s t initialisé par appeldu constructe ur de re copie .
4) La pré s e nce d'obje ts te m poraire s (dont le m om e nt de destruction n'e s t pas parfaite m e nt im pos é par la
norm e ) pe ut re ndre difficile le dénom bre m e nt e xact d'obje ts d'une classe donnée.
5) La norm e ANSI autoris e les com pilate urs à supprim e r ce rtaine s cré ations d'obje ts te m poraire s ,
notam m e nt dans des situations te lles q ue :
f (point (1,2)) ; // appel d'une fonction attendant un point
// avec un argument qui est un objet temporaire
// on peut ne pas créer point(1,2) dans la fonction
appelante

return (point (3, 5)) ; // renvoi de la valeur d'un point


// on peut ne pas créer point(3,5) dans la
fonction

EXERCICES

N.B. Le s e xe rcice s m arqués (C) sont corrigé s e n fin de volum e .

11 - Nous incl
uons dans ce cas l
e s obje ts dont un m e m bre (l
ui-m ê m e obje t) com porte une partie dynam iq ue.
114 Program m e r e n langage C+ +
1- Com m e le s uggè re la re m arq ue du paragraph e 1.3, é crive z une fonction m ain q ui, bie n q ue ne
conte nant q ue des déclarations (voire une s e ule déclaration), n'e n e ffe ctue pas m oins un ce rtain
traite m e nt (par e xe m ple affich age s ).
2- Expé rim e nte z le program m e du paragraph e 2 pour voir com m e nt sont traité s les obje ts te m poraire s
dans votre im plém e ntation.
3- Ch e rch e z à m e ttre e n é vidence les problèm e s pos é s par l'affe ctation d'obje ts du type ve ct, te lq u'ile s t
défini dans l'e xe m ple du paragraph e 3.2.b.
4- Ecrive z un program m e pe rm e ttant de m e ttre e n é vidence l'ordre d'appe ldes constructe urs e t des
destructe urs dans la situation du paragraph e 5.2 (obje ts m e m bre ), ainsi que dans ce lle de la s e conde
re m arq ue (obje t com portant plusieurs obje ts m e m bre ). Expé rim e nte z é galem e nt la situation d'obje ts
m e m bre d'obje ts m e m bre .
5 - (C) Ecrive z une clas s e nom m é e pile_e ntie r pe rm e ttant de gérer une pile d'entie rs. Ces dernie rs s e ront
cons e rvés dans un tableau d'e ntie rs alloués dynam iq ue m e nt. La clas s e com porte ra les fonctions
m e m bre s uivante s :
pile_e ntie r (int n)
constructe ur allouant dynam iq ue m e nt un e m place m e nt de n entie rs,
pile_e ntie r ( )
constructe ur sans argum e nt allouant par dé faut un e m place m e nt de vingt e ntie rs,
~ pile_e ntie r ( )
destructe ur
void e m pile (int p)
ajoute l'e ntie r p sur la pile,
int de pile ( )
fournit la valeur de l'e ntie r situé e n h aut de la pile, e n le s upprim ant de la pile,
int pleine ( )
fournit 1 si la pile e s t pleine , 0 sinon,
int vide ( )
fournit 1 si la pile e s t vide, 0 sinon.
6 - (C) Ecrive z une fonction m ain, utilisant des obje ts autom atiques e t dynam iques du type pile_e ntie r
défini pré cédem m e nt.
7- M e tte z e n é vidence les problèm e s pos é s par des déclarations de la form e :
pile_entier a(10) ;
pile_entier b = a ;

8 - (C) Ajoute z à la clas s e pile_e ntie r le constructe ur de re copie pe rm e ttant de ré gler les problèm e s
pré cédents.
III. LES FO NCTIO NS A M IES

La P.O .O . pure im pos e l'e ncapsulation des données. Nous avons vu com m e nt la m e ttre e n œuvre e n C+ + :
les m e m bre s privés d'une clas s e ne s ont acce s s ibles q u'aux fonctions m e m bre de ce tte clas s e (publiq ue ou
privé e 1, m ais s e ules les fonctions publiq ue s pe uve nt ê tre appe lée s "de l'e xté rie ur").

D 'autre part, nous avons vu q u'e n C+ + "l'unité de prote ction" e s t la clas s e , c'e s t-à -dire q u'une m ê m e
fonction m e m bre pe ut accéder à tous les obje ts de sa clas s e . Nous e n avons re ncontré un e xe m ple dans la
fonction coincide (e xam e n de la coïncide nce de deux obje ts de type point) du paragraph e 4 du ch apitre VI.

En re vanch e , ce m ê m e principe d'encapsulation inte rdit à une fonction m e m bre d'une classe d'accéder à des
donné e s privées d'une autre clas s e . O r, ile xiste des circonstance s où une te lle contrainte s 'avè re gê nante .
Suppos e z, par e xe m ple, q ue vous ayez défini une clas s e ve cte ur (de taille fixe ou variable, pe u im porte !) e t
une clas s e m atrice . Ile s t probable q ue vous souh aite re z alors définir une fonction pe rm e ttant de calculer le
produit d'une m atrice par un ve cte ur. O r, ave c ce q ue nous connaissons actue llem e nt de C+ + , nous ne
pourrions définir ce tte fonction, ni com m e fonction m e m bre de la clas s e ve cte ur, ni com m e fonction
m e m bre de la clas s e m atrice , e t e ncore m oins com m e fonction indé pe ndante (c'e s t-à -dire m e m bre d'aucune
clas s e ).

Bie n e nte ndu, vous pourrie z toujours "vous e n sortir" e n re ndant publiq ue s les données de vos deux clas s e s ,
m ais vous perdriez alors le béné fice de leur prote ction. Vous pourrie z é galem e nt introduire , dans les deux
clas s e s , des fonctions publiq ue s pe rm e ttant d'accéder aux donné e s , m ais vous s e rie z alors pénalisé en te m ps
d'exécution...

En fait, la notion de fonction am ie 2 va apporte r à ce problèm e une s olution inté re s s ante s e pré s e ntant sous la
form e d'un com prom is entre e ncapsulation form e lle des données privé e s e t des données publiq ue s . En e ffe t,
ile s t possible, lors de la définition d'une clas s e , d'y déclare r q u'une ou plusieurs fonctions (e xté rie ure s à la
clas s e ) sont des "am ie s " ;une te lle déclaration d'am itié les autoris e alors à accéder aux donné e s privé e s , au
m ê m e titre q ue n'im porte q ue lle fonction m e m bre .

L'avantage de ce tte m é th ode e s t de perm e ttre le contrôle des accè s au nive au de la clas s e conce rné e : on ne
pe ut pas "s'im pos e r com m e fonction am ie d'une clas s e " si ce la n'a pas é té pré vu dans la clas s e . Nous
ve rrons toute fois q u'e n pratiq ue la prote ction e s t un pe u m oins e fficace q u'iln'y paraî
t, dans la m e s ure où,
dans ce rtains cas, une fonction pe ut s e faire pas s e r pour une autre !

Ile xiste plusieurs situations d'am itié s :

1 - Com m e nous l
'avons déjà dit depuis l
a ve rsion 1.2, ile xis te é gal
e m e nt l
e s tatut proté gé (prote cte d). Nous en parl
e rons dans l
e ch apitre
XI cons acré à l 'h é ritage ;pour l
'instant, vous pouvez considérer que l
e s m e m bres proté gé s s ont traité s com m e l
e s m e m bres privés.
2 - "Frie nd", e n angl ais.
116 Program m e r e n langage C+ +
• fonction indé pe ndante , am ie d'une clas s e ,
• fonction m e m bre d'une clas s e , am ie d'une autre clas s e ,
• fonction am ie de plusieurs clas s e s ,
• toute s les fonctions m e m bre d'une clas s e , am ies d'une autre clas s e .
La pre m iè re nous s e rvira à vous présente r les principe s gé né raux de déclaration, dé finition e t utilisation
d'une fonction am ie . Nous e xam ine rons e nsuite e n dé tailch acune de ce s s ituations d'am itié . Enfin, nous
ve rrons l'incide nce de l'e xiste nce é ve ntue lle de fonctions am ie s s ur l'e xploitation d'une clas s e .

1. EXEM PLE D E FO NCTIO N IND ÉPEND A NTE AM IE D 'UNE CLASSE

D ans le paragraph e 4 du ch apitre VI, nous vous avons proposé une fonction coincide e xam inant la
"coïncide nce " de deux obje ts de type point ;pour ce faire , nous e n avions fait une fonction m e m bre de la
clas s e point. Nous vous proposons ici de ré s oudre le m ê m e problèm e , e n faisant ce tte fois de la fonction
coincide , une fonction indé pe ndante am ie de la clas s e point.

Tout d'abord, ilnous faut introduire dans la clas s e point, la déclaration d'am itié approprié e , à savoir :

friend int coincide (point, point) ;

Ils'agit pré cis é m e nt du prototype de la fonction coincide , pré cédé du m ot clé frie nd. Nature llem e nt, ici,
nous avons prévu q ue coincide re ce vrait deux argum e nts de type point (ce tte fois, ilne s 'agit plus d'une
fonction m e m bre : e lle ne re ce vra donc pas d'argum e nt im plicite - th is - corre s pondant à l'obje t l'ayant
appe lé).

L'é criture de la fonction coincide ne pos e aucun problèm e particulie r.

Voici un e xe m ple de program m e :

___________________________________________________________________________

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // un constructeur ("inline")
{ x=abs ; y=ord ; }
// déclaration fonction amie (indépendante) nommée coincide
friend int coincide (point, point) ;
} ;
int coincide (point p, point q) // définition de coincide
{ if ((p.x == q.x) && (p.y == q.y)) return 1 ;
else return 0 ;
}
main() // programme d'essai
{ point a(1,0), b(1), c ;
if (coincide (a,b)) cout << "a coincide avec b \n" ;
else cout << "a et b sont différents \n" ;
if (coincide (a,c)) cout << "a coincide avec c \n" ;
else cout << "a et c sont différents \n" ;
}
_______________________
VIII. Le s fonctions am ie s 117

a coincide avec b
a et c sont différents
___________________________________________________________________________

Exe m ple de fonction indépe ndante (coincide ), am ie de la clas s e point

R e m arques :

1) L'e m place m e nt de la déclaration d'am itié , au s e in de la clas s e point, e s t absolum e nt indiffé re nt.

2) Iln'e s t pas né ce s s aire de déclare r la fonction am ie dans la fonction ou dans le fich ie r source où on
l'utilise, dans la m e s ure où e lle e s t déjà obligatoire m e nt déclarée dans la clas s e conce rné e . Ce ci re s te
valable dans le cas (usuel) où la clas s e a é té com pilée s é paré m e nt puis q u'ilfaudra alors e n introduire
la déclaration (gé né ralem e nt par #include ). Né anm oins, une déclaration superflue de la fonction am ie
ne constitue rait pas une erreur.

3) Com m e nous l'avons déjà fait re m arq ue r, nous n'avons plus ici d'argum e nt im plicite (th is). Ainsi,
contraire m e nt à ce q ui s e produisait dans notre fonction coincide du paragraph e 4 du ch apitre VI,
notre fonction coincide e s t m ainte nant parfaite m e nt sym é triq ue . Nous re trouve rons le m ê m e
ph é nom è ne lors q ue , pour surdéfinir un opé rate ur binaire , nous pourrons ch oisir entre une fonction
m e m bre (dissym é triq ue ) ou une fonction am ie (sym é triq ue ).

4) Ici, les deux argum e nts de coincide sont transm is par valeur. Ils pourraie nt l'ê tre par ré fé re nce ;note z
q ue , dans le cas d'une fonction m e m bre , l'obje t appe lant la fonction e s t d'office transm is par
ré fé re nce (sous la form e de th is).

5) Gé né ralem e nt, une fonction am ie d'une clas s e possédera un ou plusieurs argum e nts ou une valeur de
re tour du type de ce tte clas s e (c'e s t ce la q ui justifie ra son besoin d'accè s aux m e m bre s privés des
obje ts corre s pondants). Ce n'e s t toute fois pas là une obligation3 : on pourrait im agine r une fonction
ayant besoin d'accéder aux m e m bre s privés d'obje ts locaux à ce tte fonction...

6) Lors q u'une fonction am ie d'une clas s e fournit une valeur de re tour du type de ce tte clas s e , ile s t
fré q ue nt q ue ce tte valeur soit ce lle d'un obje t localà la fonction. D ans ce cas, ile s t alors im pé ratif
q ue s a transm ission ait lie u par valeur ;dans le cas d'une transm ission par ré fé re nce (ou par adre s s e ),
la fonction appe lante re ce vrait l'adresse d'un e m place m e nt m é m oire q ui aurait é té libéré à la sortie de
la fonction. Ce ph é nom è ne a déjà é té é voq ué dans le paragraph e 6 du ch apitre VI.

2. LES D IFFÉRENTES SITUA TIO NS D 'AM ITIÉ

Nous ve nons d'exam ine r le cas d'une fonction indé pe ndante am ie d'une clas s e . Ce lle-ci pe ut ê tre ré s um é e
par le s ch é m a suivant :

class point
{ int coincide (point ..., point
...)
// partie privée { // on a accès ici aux membres
privés

3 - M ais ce l
a e n s e ra une dans l
e cas des opérate urs s urdéfinis.
118 Program m e r e n langage C+ +
..... // de tout objet de type point
// partie publique }
friend int coincide (point, point) ;
.....
} ;

Fonction indépe ndante (coincide ) am ie d'une clas s e (point)

R appe lons q ue , bie n q u'ici nous l'ayons placée dans la partie publiq ue de point, la déclaration d'am itié pe ut
figure r n'im porte où dans la clas s e .

D 'autre s s ituations d'am itié s ont possibles ;bas é e s s ur le m ê m e principe , e lles pe uve nt conduire à des
déclarations d'am itié trè s légè re m e nt diffé re nte s . Nous allons m ainte nant les pas s e r e n re vue .

2.1 Fonction m e m bre d'une cl


as s e , am ie d'une autre cl
as s e

Ils'agit un pe u d'un cas particulie r de la situation pré cédente . En fait, il suffit sim plem e nt, dans la
déclaration d'am itié , de préciser la clas s e à laq ue lle appartie nt la fonction conce rné e , à l'aide de l'opé rate ur
de ré s olution de porté e (::).

Par e xe m ple, supposons q ue nous ayons à définir de ux clas s e s nom m é e s A e t B e t q ue , dans B, nous ayons
besoin d'une fonction m e m bre f, de prototype :

int f(char, A) ;

Si, com m e ile s t probable, f doit pouvoir accéder aux m e m bre s privés de A, e lle s e ra dé claré e am ie , au s e in
de la clas s e par :

friend int B::f(char, A) ;

Voici un sch é m a ré capitulatif de la situation :

class A class B
{ {
// partie privée .....
..... int f (char, A) ;
// partie publique .....
friend int B::f (char, A) ; }
..... int B::f (char ..., A ...)
} ; { // on a accès ici aux membres
privés
// de tout objet de type A
}

Fonction (f) d'une clas s e (B), am ie d'une autre clas s e (A)

R e m arque im portante :

Pour com piler conve nablem e nt les déclarations d'une clas s e A conte nant une déclaration d'am itié te lle
q ue :
friend int B::f(char, A) ;
VIII. Le s fonctions am ie s 119
le com pilate ur a be s oin de connaî tre les caracté ristiq ues de B ;ce la signifie q ue la déclaration de B (m ais
pas néce s s aire m e nt la définition de s e s fonctions m e m bre ) devra avoir é té com pilée avant ce lle de A.
En re vanch e , pour com piler conve nablem e nt la déclaration :
int f(char, A)

figurant au s e in de la clas s e B, le com pilate ur n'a pas besoin de connaître pré cis é m e nt les caracté ristiq ue s
de A. Illui suffit de savoir q u'ils'agit d'une clas s e . Com m e d'aprè s ce q ui vie nt d'ê tre dit, la déclaration
de B n'a pu apparaî tre avant, on fournira l'inform ation voulue au com pilate ur e n faisant pré céder la
déclaration de A de :
class A ;

Bie n e nte ndu, la com pilation de la définition de la fonction f né ce s s ite (e n gé né ral4) la connaissance des
caracté ristiq ues des clas s e s A e t B ;leurs déclarations devront donc apparaî tre avant.
A titre indicatif, voici une façon de com piler nos deux clas s e s A e t B e t la fonction f :
class A ;
class B
{ .....
int f(char, A) ;
.....
} ;
class A
{ .....
friend int B::f(char, A) ;
.....
} ;
int B::f(char..., A...)
{ .....
}

R e m arque :

Si l'on a be s oin de "déclarations d'am itié s crois é e s " e ntre fonctions de deux classes diffé re nte s , la s e ule
façon d'y parve nir consiste à déclare r au m oins une des clas s e s am ie de l'autre (com m e nous appre ndrons
à le faire dans le paragraph e 2.3).

2.2 Fonction am ie de pl
us ie urs cl
as s e s

R ie n n'e m pê ch e q u'une m ê m e fonction (q u'e lle s oit indé pe ndante ou fonction m e m bre ) fas s e l'obje t de
déclarations d'am itié dans diffé re nte s clas s e s . Voici un e xe m ple d'une fonction am ie de deux clas s e s A e t B.

class A class B
{ {
// partie privée // partie privée
..... .....
// partie publique // partie publique
friend void f(A, B) ; friend void f(A, B)
;
..... .....
} ; } ;

4 - Une e xce ption aurait l


ie u pour B si f n'accédait à aucun de s e s m e m bres (ce qui serait s urpre nant). Ile n irait de m ê m e pour A si aucun
argum e nt de ce type n'apparaissait dans f e t si cette derniè re n'accédait à aucun m e m bre de A (ce qui serait tout aussi surprenant).
120 Program m e r e n langage C+ +

void f(A..., B...)


{ // on a accès ici aux membres privés
// de n'importe quel objet de type A ou B
}

Fonction indépe ndante (f) am ie de de ux clas s e s (A e t B)

R e m arque

Ici, la déclaration de A pe ut ê tre com pilée s ans ce lle de B, e n la faisant pré céder de la déclaration :
class B ;

D e m ê m e , la déclaration de B pe ut ê tre com pilée s ans ce lle de A, en la faisant pré céder de la


déclaration :
class A ;

Si l'on com pile e n m ê m e te m ps les deux dé clarations de A et B, ilfaudra utiliser l'une des deux
déclarations cité e s (class A si B figure avant A, class B sinon).
Bie n e nte ndu, la com pilation de la définition de f né ce s s ite ra gé né ralem e nt les déclarations de A et de B.

2.3 Toute s l
e s fonctions d'une cl
as s e s ont am ie s d'une autre cl
as s e

C'e s t une gé né ralisation du cas é voq ué dans le paragraph e 2.1. O n pourrait d'ailleurs e ffe ctue r autant de
déclarations d'am itié q u'ily a de fonctions conce rné e s . Ile s t plus sim ple, dans ce cas, d'e ffe ctue r une
déclaration globale. Ainsi, pour dire q ue toute s les fonctions m e m bre de la clas s e B sont am ies de la clas s e
A, on place ra, dans la clas s e A , la déclaration :

friend class B ;

R e m arques :

1) Ce tte fois, pour com piler la déclaration de la clas s e A , ilsuffira de la faire pré céder de :
class B ;

2) Ce type de déclaration d'am itié é vite d'avoir à fournir les e n-tê tes des fonctions conce rné e s .

3. EXEM PLE

Nous vous proposons ici de ré s oudre le problèm e é voq ué e n introduction, à savoir ré aliser une fonction
pe rm e ttant de déte rm ine r le produit d'un ve cte ur (obje t de clas s e ve ct) par une m atrice (obje t de clas s e
m atrice ). Par souci de s im plicité , nous avons lim ité les fonctions m e m bre à :

- un constructe ur pour ve ct e t pour m atrice ,


- une fonction d'affich age (affich e ) pour m atrice .
Nous vous fournissons deux solutions bas é e s s ur l'e m ploi d'une fonction am ie nom m é e prod :
VIII. Le s fonctions am ie s 121
- prod e s t indé pe ndante e t am ie des deux clas s e s ve ct e t m atrice ,
- prod e s t m e m bre de m atrice e t am ie de la clas s e ve ct.

3.1 Fonction am ie indé pe ndante

___________________________________________________________________________

#include <iostream.h>
class matrice ; // pour pouvoir compiler la déclaration de vect

// *********** La classe vect *******************


class vect
{
double v[3] ; // vecteur à 3 composantes
public :
vect (double v1=0, double v2=0, double v3=0) // constructeur
{ v[0] = v1 ; v[1]=v2 ; v[2]=v3 ;
}
friend vect prod (matrice, vect) ; // prod = fonction amie indépendante
affiche ()
{ int i ;
for (i=0 ; i<3 ; i++) cout << v[i] << " " ;
cout << "\n" ;
}
} ;

// *********** La classe matrice *****************


class matrice
{ double mat[3] [3] ; // matrice 3 X 3
public :
matrice (double t[3][3]) // constructeur, à partir d'un tableau 3 x 3
{ int i ; int j ;
for (i=0 ; i<3 ; i++)
for (j=0 ; j<3 ; j++)
mat[i] [j] = t[i] [j] ;
}
friend vect prod (matrice, vect) ; // prod = fonction amie indépendante
} ;
// ********** La fonction prod *****************
vect prod (matrice m, vect x)
{ int i, j ;
double som ;
vect res ; // pour le résultat du produit
for (i=0 ; i<3 ; i++)
{ for (j=0, som=0 ; j<3 ; j++)
som += m.mat[i] [j] * x.v[j] ;
res.v[i] = som ;
}
return res ;
}
// ********** Un petit programme de test *********
main()
122 Program m e r e n langage C+ +
{
vect w (1,2,3) ;
vect res ;
double tb [3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
matrice a = tb ;
res = prod(a, w) ;
res.affiche () ;
}
_______________________

14 32 50
___________________________________________________________________________

Produit d'une m atrice par un ve cte ur à l'aide d'une fonction indépe ndante am ie de s d e u x clas s e s

3.2 Fonction am ie , m e m bre d'une cl


as s e
___________________________________________________________________________

#include <iostream.h>
// ********* Déclaration de la classe matrice ************
class vect ; // pour pouvoir compiler correctement
class matrice
{ double mat[3] [3] ; // matrice 3 X 3
public :
matrice (double t[3][3]) // constructeur, à partir d'un tableau 3 x 3
{ int i ; int j ;
for (i=0 ; i<3 ; i++)
for (j=0 ; j<3 ; j++)
mat[i] [j] = t[i] [j] ;
}
vect prod (vect) ; // prod = fonction membre (cette fois)
} ;
// ********* Déclaration de la classe vect **************
class vect
{ double v[3] ; // vecteur à 3 composantes
public :
vect (double v1=0, double v2=0, double v3=0) // constructeur
{ v[0] = v1 ; v[1]=v2 ; v[2]=v3 ; }
friend vect matrice::prod (vect) ; // prod = fonction amie
affiche ()
{ int i ;
for (i=0 ; i<3 ; i++) cout << v[i] << " " ;
cout << "\n" ;
}
} ;
// ********* Définition de la fonction prod ************
vect matrice::prod (vect x)
{ int i, j ;
double som ;
vect res ; // pour le résultat du produit
for (i=0 ; i<3 ; i++)
{ for (j=0, som=0 ; j<3 ; j++)
som += mat[i] [j] * x.v[j] ;
VIII. Le s fonctions am ie s 123
res.v[i] = som ;
}
return res ;
}
// ********** Un petit programme de test *********
main()
{
vect w (1,2,3) ;
vect res ;
double tb [3][3] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } ;
matrice a = tb ;
res = a.prod (w) ;
res.affiche () ;
} _______________________
14 32 50
___________________________________________________________________________

Produit d'une m atrice par un ve cte ur à l'aide d'une fonction m e m bre


am ie d'une autre clas s e

4. EXPLO ITA TIO N D E CLASSES D ISPO SANT D E FO NCTIO NS A M IES

Com m e nous l'avons déjà m e ntionné dans le ch apitre V, les clas s e s s e ront gé né ralem e nt com pilée s
s é paré m e nt. Le ur utilisation s e fe ra à partir d'un m odule obje t conte nant les fonctions m e m bre de la clas s e e t
d'un fich ie r e n-tê te conte nant la déclaration de la clas s e . Bie n e nte ndu, ile s t toujours possible de re groupe r
plusieurs classes dans un m ê m e m odule obje t e t é ve ntue llem e nt dans un m ê m e fich ie r e n-tê te .

D ans tous les cas, ce tte com pilation s é paré e d e s clas s e s pe rm e t d'en assurer la ré utilisabilité : le "clie nt" (q ui
pe ut é ve ntue llem e nt ê tre le conce pte ur de la clas s e ) ne pe ut pas inte rve nir sur le conte nu de s obje ts de ce tte
clas s e .

Que devie nne nt ce s possibilité s lors q ue l'on utilise des fonctions am ie s ?En fait, s'ils'agit de fonctions
am ie s , m e m bres d'une clas s e , rie n n'e s t ch angé (e n de h ors des éve ntue lles déclarations de clas s e s
né ce s s aire s à son em ploi). En re vanch e , s'ils'agit d'une fonction indé pe ndante , ilfaudra bie n voir q ue s i
l'on souh aite e n faire un m odule obje t s é paré , on court le ris q ue de voir l'utilisate ur de la clas s e violer le
principe d'encapsulation.

En e ffe t, dans ce cas, l'utilisate ur d'une classe disposant d'une fonction am ie pe ut toujours ne pas incorpore r
la fonction am ie à l'édition de lie ns e t fournir lui-m ê m e une autre fonction de m ê m e e n-tê te e t, par suite ,
accéder com m e ill'e nte nd aux donné e s privé e s ...

Ce ris q ue d'"e ffe t cam é léon" doit ê tre nuancé par le fait q u'ils'agit d'une action dé libérée (dem andant un
ce rtain travail), e t non pas d'une sim ple é tourde rie ...
IX. LA SURD ÉFINITIO N D 'O PÉRA TEURS

Nous avons vu, dans le ch apitre IV, com m e nt C+ + autoris e la "surdéfinition" de fonctions, q u'ils'agis s e
de fonctions m e m bre ou de fonctions indépendante s . R appe lons q ue ce tte te ch niq ue consiste à attribue r le
m ê m e nom à des fonctions diffé re nte s ;lors d'un appe l, le ch oix de la "bonne fonction" e s t e ffe ctué par le
com pilate ur, suivant le nom bre e t le type des argum e nts.

M ais C+ + pe rm e t é galem e nt, dans ce rtaine s conditions, de surdéfinir de s opé rate urs. En fait, le langage C,
com m e beaucoup d'autre s , ré alise déjà la surdéfinition de ce rtains opérate urs. Par e xe m ple, dans une
e xpre s s ion te lle q ue :

a + b

le sym bole + pe ut désigner, suivant le type de a e t b :

• l'addition de deux e ntie rs,


• l'addition de deux ré e ls (float),
• l'addition de deux ré e ls double pré cision (double),
• e tc.
D e la m ê m e m aniè re , le sym bole *pe ut, suivant le conte xte , re pré s e nte r la m ultiplication d'e ntie rs ou de
ré e ls ou une "indire ction" (com m e dans a = *adr).

En C+ + , vous pourre z surdéfinir n'im porte q ue lopé rate ur e xistant (unaire ou binaire ), dans la m e s ure où il
porte s ur au m oins un obje t1. Ils'agit là d'une te ch niq ue fort puissante puis q u'e lle va vous perm e ttre de
cré e r, par le biais des clas s e s , des type s à part e ntiè re , c'e s t-à -dire m unis, com m e les types de bas e ,
d'opé rate urs parfaite m e nt inté gré s ;la notation opé ratoire q ui e n dé coulera aura l'avantage s ur une notation
fonctionne lle (par appe l de fonction) d'ê tre beaucoup plus concis e e t (du m oins si l'on s'y pre nd
"inte llige m m e nt" !) plus lisible.

Par e xe m ple, si vous définis s e z une clas s e com plexe destiné e à re pré s e nte r de s nom bre s com plexe s , ilvous
s e ra possible de donner une signification à des expre s s ions te lles q ue :

a + b a - b a * b a/b

1 - Ce tte re s triction signifie s im pl


e m e nt q u'ilne s e ra pas possibl
e de surdéfinir l
e s opé rate urs portant s ur l
es diffé re nts types de base.
IX. La surdéfinition d'opérate urs 125
a e t b étant des obje ts de type com plexe 2.
Pour ce la, vous "surdéfinire z" les opé rate urs + , -, * e t / e n
spécifiant le rôle e xact q ue vous souh aite z leur attribue r. Ce tte définition se déroulera com m e ce lle d'une
fonction à laq ue lle ilsuffira sim plem e nt d'attribue r un nom spécialpe rm e ttant de spécifie r q u'ils'agit e n fait
d'un opé rate ur. Autre m e nt dit, la surdéfinition d'opé rate urs e n C+ + consiste ra sim plem e nt e n l'é criture de
nouve lles fonctions surdé finie s .

Nous com m e nce rons par vous présente r ce tte nouve lle te ch niq ue q u'e s t la surdéfinition d'opé rate urs. Puis
nous ve rrons q ue lles e n sont les possibilité s e t les lim ite s .

Nous étudie rons e nsuite deux e xe m ples im portants de surdéfinition d'opé rate urs : = e t []. Ce rte s , ilne
s'agira q ue d'applications, m ais e lles m ontre ront q u'à partir du m om e nt où l'on souh aite donner à de te ls
opé rate urs une signification nature lle e t acce ptable dans un conte xte de clas s e , un ce rtain nom bre de
pré cautions doive nt ê tre pris e s . En particulie r, nous ve rrons com m e nt la surdéfinition de l'affe ctation pe rm e t
de ré gler le problèm e déjà re ncontré , à savoir ce lui de s obje ts com portant des pointe urs sur de s
e m place m e nts dynam iq ue s .

Enfin, nous e xam ine rons com m e nt pre ndre e n ch arge la ge s tion de la m é m oire e n surdéfinissant les
opé rate urs ne w e t de lete .

1. LE M ÉCANISM E D E LA SURD ÉFINITIO N D 'O PÉRA TEUR

Considérons une clas s e point :

class point
{ int x, y ;
.....

e t supposons q ue nous souh aitons définir l'opé rate ur + afin de donner une signification à une e xpre s s ion
te lle q ue a + b, lors q ue a e t b sont de type point. Ici, nous convie ndrons q ue la "som m e " de deux points e s t
un point dont les coordonné e s s ont la som m e de leurs coordonné e s 3.

La conve ntion adopté e par C+ + pour surdéfinir ce t opé rate ur + consiste à définir une fonction de nom :

operator +
O n y trouve le m ot clé ope rator suivi de l'opé rate ur conce rné (dans le cas présent, ilne s e rait pas obligatoire
de prévoir un e s pace car, e n C, + s e rt de "s é parate ur").

Ici, notre fonction ope rator + doit disposer de deux argum e nts de type point e t fournir une valeur de re tour
du m ê m e type . En ce q ui conce rne s a nature , ce tte fonction pe ut, à notre gré , ê tre une fonction m e m bre de
la clas s e conce rné e ou une fonction indé pe ndante ;dans ce dernie r cas, ils'agira gé né ralem e nt d'une
fonction am ie , dans la m e s ure où illui faudra pouvoir accéder aux m e m bre s privés de la clas s e .

Exam inons ici les deux solutions, e n com m e nçant par ce lle q ui e s t la plus "nature lle", à savoir la fonction
am ie .

2 - Une notation fonctionne l


le conduirait à des ch os e s te l
le s q ue : som m e (a,b) ou a.som m e (b) s uivant q ue l
'on util
ise une fonction am ie ou
une fonction m e m bre.
3 - Nous aurions pu tout aussi bien prendre ici l
'exem pl
e de l
a cl
as s e com plexe é voq ué e e n introduction. Nous préfé rons ce pe ndant ch oisir
un e xe m pl
e dans l
e q ue ll
a signification de l
'opé rate ur n'a pas un caractè re aussi évident. En effe t, n'oubl
iez pas que n'im porte q ue l
sym bol
e opé rate ur pe ut, au bout du com pte, se voir attribue r n'im porte q ue l
le s ignification !
126 Program m e r e n langage C+ +
1.1 Surdé finition d'opé rate ur ave c une fonction am ie

Le prototype de notre fonction ope rator + s e ra :

point operator + (point, point) ;

Ses deux argum e nts corre s pondront aux opé randes de l'opé rate ur + lors q u'ils e ra appliq ué à des valeurs de
type point.

Le re s te du travaile s t classique :

• déclaration d'am itié au s e in de la clas s e point,


• définition de la fonction.
Voici un e xe m ple de program m e m ontrant la définition e t l'utilisation de notre "opé rate ur d'addition de
points".

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ;} // constructeur
friend point operator+ (point, point) ;
void affiche () { cout << "coordonnées : " << x << " " << y << "\n" ; }
} ;
point operator + (point a, point b)
{ point p ;
p.x = a.x + b.x ; p.y = a.y + b.y ;
return p ;
}
main()
{ point a(1,2) ; a.affiche() ;
point b(2,5) ; b.affiche() ;
point c ;
c = a+b ; c.affiche() ;
c = a+b+c ; c.affiche() ;
}
_______________________

coordonnées : 1 2
coordonnées : 2 5
coordonnées : 3 7
coordonnées : 6 14
_______________________________________________________________________________
______

Surdéfinition de l'opérate ur + pour de s obje ts d e type point,


e n e m ployant une fonction am ie

R e m arques :

1) Une e xpre s s ion te lle q ue a + b est e n fait inte rpré té e par le com pilate ur com m e l'appe l:
IX. La surdéfinition d'opérate urs 127
operator + (a, b)

Bie n q ue ce la ne pré s e nte guè re d'inté rê t, nous pourrions é crire :


c = operator + (a, b)

au lie u de c = a + b.

2) Une e xpre s s ion te lle q ue a + b + c e s t é valué e e n te nant com pte des rè gles de priorité e t
d'associativité "h abitue lles " de l'opé rate ur + . Nous re vie ndrons plus loin sur ce point d'une m aniè re
gé né rale. Pour l'instant, note z sim plem e nt q ue ce tte e xpre s s ion e s t é valué e com m e :
(a + b) + c

c'e s t-à -dire e n utilisant la notation fonctionne lle :


operator + (operator + (a, b), c)

1.2 Surdé finition d'opé rate ur ave c une fonction m e m bre

Ce tte fois, le pre m ie r opé rande de notre opé rate ur, corre s pondant au pre m ie r argum e nt de la fonction
ope rator + pré cédente , va s e trouve r transm is im plicite m e nt : ce s e ra l'obje t ayant appe lé la fonction
m e m bre . Par e xe m ple, une e xpre s s ion te lle q ue a + b sera alors inte rpré té e par le com pilate ur com m e :

a.operator + (b)

Le prototype de notre fonction m e m bre ope rator + s e ra donc :

point operator + (point)

Voici com m e nt pourrait ê tre adapté dans ce s e ns l'e xe m ple pré cédent :

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ;} // constructeur
point operator + (point) ;
void affiche () { cout << "coordonnées : " << x << " " << y << "\n" ; }
} ;
point point::operator + (point a)
{ point p ;
p.x = x + a.x ; p.y = y + a.y ;
return p ;
}
main()
{ point a(1,2) ; a.affiche() ;
point b(2,5) ; b.affiche() ;
128 Program m e r e n langage C+ +
point c ;
c = a+b ; c.affiche() ;
c = a+b+c ; c.affiche() ;
}
_______________________

coordonnées : 1 2
coordonnées : 2 5
coordonnées : 3 7
coordonnées : 6 14
_______________________________________________________________________________
______

Surdéfinition de l'opérate ur + pour de s obje ts d e type point,


e n e m ployant une fonction m e m bre

R e m arques :

1) Ce tte fois, la définition de la fonction ope rator + fait apparaî tre une dissym é trie e ntre les deux
opé rande s . Par e xe m ple, le m e m bre x e s t noté x pour le pre m ie r opé rande (argum e nt im plicite ) e t a.x
pour le s e cond. Ce tte dissym é trie pe ut parfois incite r l'utilisate ur à ch oisir une fonction am ie plutôt
q u'une fonction m e m bre . Ilfaut toute fois s e garde r de décide r trop vite dans ce dom aine . Nous y
re vie ndrons un pe u plus loin.
2) Ici, l'affe ctation :
c = a + b ;

e s t inte rpré té e com m e :


c = a.operator + (b) ;

Quant à l'affe ctation :


c = a + b + c ;

le langage C+ + ne pré cis e pas e xacte m e nt son inte rpré tation. Ce rtains com pilate urs cré e ront un
obje t te m poraire t :
t = a.operator + (b) ;
c = t.operator + (c) ;

D 'autre s procéderont ainsi, en transm e ttant com m e adresse de l'obje t appe lant ope rator + , l'adre s s e
de l'obje t re nvoyé par l'appe lpré cédent :
c = (a.operator + (b)).operator + (c) ;

O n pe ut déte cte r le ch oix fait par un com pilate ur e n faisant affich e r toute s les cré ations d'obje ts (e n
n'oubliant pas d'introduire un constructe ur de re copie pre nant la place du constructe ur par dé faut).
IX. La surdéfinition d'opérate urs 129
1.3 O pé rate urs e t trans m is s ion par ré fé re nce

D ans nos deux précédents e xe m ples , la transm ission des argum e nts (deux pour une fonction am ie , un pour
une fonction m e m bre ) e t de la valeur de re tour de ope rator + s e faisait par valeur4.

Bie n e nte ndu, e n particulie r dans le cas d'obje ts de grande taille, on pe ut e nvisage r de faire appe lau
transfe rt par ré fé re nce . Par e xe m ple, le prototype de la fonction am ie ope rator + pourrait ê tre :

point operator + (point & a, point & b) ;

En re vanch e , la transm ission par ré fé re nce pos e rait un problèm e s i on ch e rch ait à l'appliq ue r à la valeur de
re tour. En e ffe t, le point p e s t cré é localem e nt dans la fonction ;ils e ra donc dé truit dè s la fin de son
e xé cution. D ans ce s conditions, e m ploye r la transm ission par ré fé re nce re vie ndrait à transm e ttre l'adre s s e
d'un e m place m e nt de m é m oire libéré.

Ce rte s , ici, nous utilisons im m édiate m e nt la valeur de p, dè s le re tour dans la fonction m ain (ce q ui e s t
gé né ralem e nt le cas ave c un opé rate ur) ;né anm oins, nous ne pouvons faire aucune h ypoth è s e s ur la m aniè re
dont une im plém e ntation donné e libè re un e m place m e nt m é m oire : e lle pe ut sim plem e nt s e conte nte r de
"note r" q u'ile s t disponible, auq ue lcas son conte nu re s te "valable" pe ndant un... ce rtain te m ps ;e lle pe ut,
au contraire le "m e ttre à zé ro"... La pre m iè re s ituation e s t ce rtaine m e nt la pire puis q u'e lle pe ut donne r
l'illusion q ue "ce la m arch e " !

Pour é vite r la re copie de ce tte valeur de re tour, on pourrait songe r à alloue r dynam iq ue m e nt l'e m place m e nt
de p. Généralem e nt, ce la pre ndra plus de te m ps q ue s a re copie ulté rie ure e t, de plus, com pliq ue ra q ue lque
pe u le program m e (ilfaudra libérer conve nablem e nt l'e m place m e nt e n q ue s tion e t on ne pourra le faire
q u'e n de h ors de la fonction !).

Si l'on ch e rch e à proté ge r contre d'éve ntue lles m odifications un argum e nt transm is par ré fé re nce , on pourra
toujours faire appe lau m ot clé cons t ;par e xe m ple, l'e n-tê te de ope rator + pourrait ê tre :

point operator + (const point& a, const point& b) ;

Nature llem e nt, si l'on utilise cons t dans le cas d'obje ts com portant des pointe urs sur de s parties dynam iq ue s ,
s e uls ce s pointe urs s e ront ainsi "proté gé s " ;les parties dynam iq ue s re s te ront m odifiables .

2. LES PO SSIBILITÉS ET LES LIM ITES


D E LA SURD ÉFINITIO N D 'O PÉRA TEUR

Nous ve nons de voir un e xe m ple de surdé finition de l'opé rate ur binaire + , lors q u'ilre çoit deux opérandes
de type point, e t ce ci de deux façons : com m e fonction am ie , com m e fonction m e m bre .

Nous vous proposons de voir m ainte nant ce q u'ile s t possible de faire d'une m aniè re gé né rale.

2.1 Ilfaut s e l
im ite r aux opé rate urs e xis tants ...

4 - R appe l
ons q ue l
a trans m ission de l
'obje t appe l
ant une fonction m e m bre se fait par ré fé re nce.
130 Program m e r e n langage C+ +
Le sym bole s uivant le m ot clé ope rator doit obligatoire m e nt ê tre un opé rate ur dé jà défini pour les types de
bas e . Iln'e s t donc pas possible de cré e r de nouve aux sym boles . Nous ve rrons d'ailleurs q ue ce rtains
opé rate urs ne peuve nt pas ê tre redéfinis du tout (c'e s t le cas de .) e t q ue d'autre s im pos e nt q ue lque s
contrainte s s upplém e ntaire s .

Ilfaut cons e rve r la pluralité (unaire , binaire ) de l'opé rate ur initial. Ainsi, vous pourre z surdéfinir un
opé rate ur + unaire ou un opé rate ur + binaire , m ais vous ne pourrez pas définir de = unaire ou de + +
binaire .

Lors q ue plusieurs opérate urs sont com biné s au s e in d'une m ê m e e xpre s s ion (q u'ils soie nt surdéfinis ou non),
ils cons e rve nt leur priorité re lative e t leur associativité . Par e xe m ple, si vous surdé finis s e z les opé rate urs
binaire s + e t*pour le type com plexe , l'e xpre s s ion suivante (a, b e t c é tant supposés du type com plexe ) :

a * b + c

s e ra inte rpré té e com m e :

(a * b) + c

D e te lles rè gles pe uve nt, a priori, vous paraî tre re s trictive s . En fait, vous ve rre z à l'usage q u'e lles s ont
e ncore trè s large s e t q u'ile s t facile de re ndre un program m e incom pré h e nsible e n abusant de la surdéfinition
d'opé rate urs.

Le tableau de la page s uivante pré cis e les opé rate urs surdé finissables (e n fait, tous sauf .) e t ilrappe lle leur
priorité re lative e t leur associativité . Note z la pré s e nce :

• de l'opé rate ur de "cast" ;nous e n parlerons plus e n dé taildans le ch apitre X. Nous y ve rrons q u'ilpe ut
s'appliq ue r à la conve rsion d'une classe dans un type de bas e ou à la conve rsion d'une classe dans une
autre clas s e .
• des opérate urs ne w e t de lete : avant la ve rsion 2.0, ce s opé rate urs é taie nt traité s com m e d e s e xce ptions
puis q u'on ne pouvait pas les s urdé finir pour une clas s e e n particulie r ;on ne pouvait e n m odifie r la
signification q ue d'une façon globale. Depuis la ve rsion 2.0, ils sont surdéfinissables au m ê m e titre q ue
les autre s . Nous e n parlerons dans le paragraph e 6.
IX. La surdéfinition d'opérate urs 131
_______________________________________________________________________________
_____

PLURALITÉ OPÉRATEURS ASSOCIATIVITÉ


_______________________________________________________________________________
______

Binaire ()(3) [](3) ->(2)(3) ->

Unaire + - ++(5) --(5) ! ~ * &(1) <-


new(4) new [] (6) delete(4)
(cast)

Binaire * / % ->

Binaire + - ->

Binaire << >> ->

Binaire < <= > >= ->

Binaire == != ->

Binaire & ->

Binaire ^ ->

Binaire || ->

Binaire && ->

Binaire | ->

Binaire =(1)(3) += -= *= /= %= <-


&= ^= |= <<= >>=

Binaire ,(2) ->


_______________________________________________________________________________
______

Le s opérate urs surdéfinis s ables e n C+ + (classés par priorité décrois s ante )

(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.
(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, on ne peut pas distingue r e ntre l
e s notations "pré " e t "pos t". D e puis l
a ve rsion 3, ces 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".
(6) O n distingue bien new de new [].

2.2 ... au conte xte de cl


as s e

O n ne pe ut surdéfinir un opé rate ur q ue s 'ilcom porte au m oins un argum e nt (im plicite ou non) de type
clas s e . Autre m e nt dit, ildoit s'agir :

• Soit d'une fonction m e m bre : dans ce cas, e lle com porte à coup sûr un argum e nt (im plicite ) de type
clas s e , à savoir l'obje t l'ayant appe lé. S'il s'agit d'un opé rate ur unaire , e lle ne com porte ra aucun
argum e nt e xplicite . S'ils'agit d'un opé rate ur binaire , e lle com porte ra un argum e nt e xplicite auq ue l
132 Program m e r e n langage C+ +
aucune contrainte de type n'e s t im pos é e (dans nos précédents e xe m ples , ils'agissait du m ê m e type q ue la
clas s e e lle-m ê m e , m ais ilpourrait s'agir d'un autre type clas s e ou m ê m e d'un type de bas e ).
• Soit d'une fonction indé pe ndante ayant au m oins un argum e nt de type clas s e . En gé né ral, ils'agira d'une
fonction am ie .
Ce tte rè gle garantit à coup sûr l'im possibilité de surdé finir un opé rate ur portant sur des types de bas e
(im agine z ce q ue s e rait un program m e dans leq ue lon pourrait ch ange r la signification de 3 + 5 ou de
*adr !). Une e xce ption a lie u, ce pe ndant, pour les s e uls opérate urs ne w e t de lete dont la signification pe ut
ê tre m odifié e d e m aniè re globale (pour tous les obje ts e t les types de bas e ) ;nous e n re parlerons dans le
paragraph e 6.

D e plus, ce rtains opérate urs doive nt obligatoire m e nt ê tre définis com m e m e m bres d'une clas s e . Ils'agit de
[], ( ), -> 5, ne w 6 e t de lete 6.

2.3 ... e t ne pas faire d'h ypoth è s e s ur l


a "s ignification"
d'un opé rate ur

Com m e nous avons déjà e u l'occasion de l'indiq ue r, vous ê te s totalem e nt libre d'attribue r à un opé rate ur
surdéfini la signification q ue vous désirez. Cette liberté n'e s t lim ité e q ue par le bon sens qui doit vous incite r
à donne r à un sym bole une s ignification re lative m e nt nature lle : par e xe m ple + pour la som m e de deux
com plexe s , plutôt q ue -, *ou [].

M ais, q ui plus e s t, vous ne retrouve re z pas, pour les opé rate urs surdé finis, les lie ns q ui e xiste nt e ntre
ce rtains opérate urs de bas e . Par e xe m ple, si a e t b sont de type int :

a += b

e s t é q uivalent à :

a = a + b

Autre m e nt dit, le rôle de l'opé rate ur de bas e + = se déduit du rôle de l'opé rate ur + e t de ce lui de
l'opé rate ur =. En re vanch e , si vous surdé finis s e z, par e xe m ple, l'opé rate ur + e t l'opé rate ur = lors q ue leurs
deux opérandes sont de type com plexe , vous n'aure z pas, pour autant, défini la signification de + = lors q u'il
aura de ux opé randes de type com plexe . De plus, dans ce cas, vous pourre z trè s bien surdéfinir + = pour
q u'ilait une s ignification diffé re nte de ce lle atte ndue ;nature llem e nt, ce la n'e s t pas cons e illé...

D e m ê m e , e t de façon pe ut-ê tre plus surpre nante , C+ + ne fait aucune h ypoth è s e s ur la com m utativité
é ve ntue lle d'un opé rate ur surdéfini (alors q ue , rappe lons-le, ile n fait e n ce q ui conce rne s a priorité re lative
e t son associativité ). Ce tte re m arq ue e s t lourde de cons é q ue nce s . Suppos e z, par e xe m ple, q ue vous ayez
surdéfini l'opé rate ur + lors q u'ila com m e opé rande s un com plexe e t un double (dans ce t ordre ) ;son
prototype pourrait ê tre :

complexe operator + (complexe, double) ;

Eh bien, si ceci vous perm e t de donner un sens à une e xpre s s ion te lle q ue (a é tant com plexe ) :

a + 3.5

ce la ne pe rm e t pas pour autant d'inte rpré te r :

3.5 + a

5 - Iln'e s t s urdéfinis s abl


e q ue depuis la ve rsion 2.0.
6 - D ans l e cas où il s ne s ont pas s urdéfinis de m aniè re gl
obal
e (ce qui n'est possibl
e q ue depuis l
a ve rsion 2.0).
IX. La surdéfinition d'opérate urs 133

Pour ce faire , ilaurait fallu, e n e ffe t, surdéfinir l'opé rate ur + lors q u'ila com m e opé rande s un double e t un
( )
com plexe ave c, par e xe m ple 7 , com m e prototype :

complexe operator + (double, complexe) ;

Nous ve rrons ce pe ndant (ch apitre X) q ue les possibilités de conve rsions définie s par l'utilisate ur pe rm e ttront
(dans le cas où ce la pré s e nte de l'inté rê t) de sim plifie r q ue lque pe u les ch os e s . Par e xe m ple, nous ve rrons
q ue , dans ce cas précis, ilsuffira de définir l'opé rate ur + lors q u'ilporte s ur de ux com plexe s ainsi que la
conve rsion de double e n com plexe pour q ue les e xpre s s ions de l'une de ce s form e s aie nt un s e ns.

double + complexe
complexe + double
float + complexe
complexe + float

2.4 Cas d e s opé rate urs + + e t --

Jus q u'à la ve rsion 2.0 de C+ + , on ne pouvait pas distingue r l'opé rate ur + + e n notation pré fixé e (com m e
dans + + a) de ce m ê m e opé rate ur e n notation postfixé e (com m e dans a+ + ). Autre m e nt dit, pour un type
classe donné, on ne pouvait définir q u'un s e ulopé rate ur + + (ope rator + + ) q ui é tait utilisé dans les deux
cas.

D e puis la ve rsion 3, on pe ut définir à la fois un opé rate ur + + utilisable e n notation pré fixé e e t un autre
utilisable e n notation postfixé e . Plus précisém e nt, si T désigne un type clas s e q ue lconq ue :

• l'opé rate ur (usuel) d'en-tê te T ope rator + + () e s t utilisé en cas de notation pré fixé e ,
• l'opé rate ur d'e n-tê te T ope rator + + (int) e s t utilisé en cas de notation postfixé e . Note z bie n la pré s e nce
d'un second opé rande de type int. Ce lui-ci e s t totalem e nt fictif, e n ce s e ns q u'ilpe rm e t au com pilate ur de
ch oisir l'opé rate ur à utiliser m ais q u'aucune valeur ne s e ra ré e llem e nt transm ise lors de l'appe l.
Le s m ê m e s re m arq ue s s 'appliq ue nt à l'opé rate ur --.

Voici un e xe m ple dans leq ue lnous avons défini + + pour q u'ilincré m e nte d'une unité les deux coordonné e s
d'un point e t pour q u'ilfournis s e com m e valeur soit ce lle du point avant incré m e ntation dans le cas de la
notation postfixé e , soit ce lle du point aprè s incré m e ntation dans le cas de la notation pré fixé e .

_______________________________________________________________________________
____

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
point operator ++ () // notation préfixée
{ x++ ; y++ ; return *this ;
}
point operator ++ (int n) // notation postfixée
{ point p = *this ;
x++ ; y++ ;

7 - Nous ve rrons d'ail


le urs un pe u pl
us l
oin q ue, dans ce cas, on ne pourra pas surdéfinir ce t opé rate ur com m e une fonction m e m bre
(puisque son prem ie r opé rande n'e s t pl
us de type cl
as s e ).
134 Program m e r e n langage C+ +
return p ;
}
void affiche () { cout << x << " " << y << "\n" ; }
} ;

main()
{ point a1 (2, 5), a2(2, 5), b ;
b = ++a1 ; cout << "a1 : " ; a1.affiche () ; // affiche a1 : 3 6
cout << "b : " ; b.affiche () ; // affiche b : 2 5
b = a2++ ; cout << "a2 : " ; a2.affiche () ; // affiche a2 : 3 6
cout << "b : " ; b.affiche () ; // affiche b : 3 6
}
_______________________________________________________________________________
____

Exe m ple de s u rdéfinition de + + à la fois e n notation préfixé e e t e n notation pos tfixé e

R e m arque :

En th é orie , iln'e s t plus possible, depuis la ve rsion 3 e t donc, e n particulie r, de puis la norm e ANSI, de ne
définir q u'un s e ulopé rate ur + + q u'on utiliserait à la fois e n notation pré fixé e e t e n notation postfixé e .
En fait, la plupart des com pilate urs fournis s e nt dans ce cas un m e s s age d'ave rtissem e nt e n utilisant le
m ê m e opé rate ur ave c les deux notations.

2.5 Le s opé rate urs = et & ont une s ignification pré dé finie

Nous avons déjà e u l'occasion d'em ploye r l'opé rate ur = ave c deux opérandes du m ê m e type clas s e . Nous
n'avions pas eu, pour cela, à le s urdé finir. Effe ctive m e nt, e n l'abs e nce de surdé finition e xplicite , ce t
opé rate ur corre s pond à la re copie des valeurs de son second opé rande dans le pre m ie r. Nous avons d'ailleurs
déjà e u l'occasion de constate r q ue ce tte s im ple re copie pouvait s'avé re r insatisfaisante dè s lors q ue les
obje ts conce rné s com portaie nt des pointe urs sur de s e m place m e nts dynam iq ue s . Ils'agit là typiq ue m e nt
d'une s ituation q ui né ce s s ite la surdéfinition de l'opé rate ur =, dont nous donnerons un exem ple dans le
paragraph e s uivant.

O n note ra la grande analogie e xistant e ntre :

• le constructe ur de re copie : s'iln'e n e xiste pas d'explicite , ily a appe ld'un constructe ur de re copie par
défaut,
• l'opé rate ur d'affe ctation : s'iln'e n e xiste pas d'explicite , ily a e m ploi d'un opé rate ur d'affe ctation par
défaut.
Constructe ur de re copie par dé faut e t opé rate ur d'affe ctation par dé faut e ffe ctue nt le m ê m e travail: re copie
des valeurs de l'obje t. Dans le ch apitre VII, nous avons signalé q ue , dans le cas d'obje ts dont ce rtains
m e m bre s s ont e ux-m ê m es des obje ts, le constructe ur de re copie par dé faut travaillait m e m bre par m e m bre .
La m ê m e re m arq ue s 'appliq ue à l'opé rate ur d'affe ctation par dé faut : ilopè re m e m bre par m e m bre 8, ce q ui
lais s e la possibilité d'appe ler un opé rate ur d'affe ctation e xplicite , dans le cas où l'un de s m e m bre s e n
posséderait un. Ce ci pe ut é vite r d'avoir à é crire e xplicite m e nt un opé rate ur d'affe ctation pour de s obje ts sans
pointe urs (appare nts), m ais dont un ou plusieurs m e m bre s possè dent, q uant à e ux, de s parties dynam iq ue s .

8 - Là e ncore, depuis l
a ve rsion 2.0 de C+ + . Auparavant, ilopé rait de façon gl
obal
e ("m e m berw ise copy").
IX. La surdéfinition d'opérate urs 135

2.6 Le s conve rs ions


C e t C+ + autoris e nt fré q ue m m e nt les conve rsions entre types de bas e , e t ce ci de façon e xplicite ou
im plicite . Ce s possibilité s s 'é te nde nt aux obje ts. Par e xe m ple, com m e nous l'avons déjà é voq ué , si a e s t de
type com plexe e t si l'opé rate ur + a é té s urdé fini pour de ux com plexe s , une e xpre s s ion te lle q ue a + 3.5
pourra pre ndre un s e ns :

• soit si l'on a surdéfini l'opé rate ur + lors q u'ila un opé rande de type com plexe e t un opé rande de type
double,
• soit si l'on a dé fini une conve rsion de type double e n com plexe .
Nous avons toute fois préfé ré re groupe r dans un ch apitre à part (le s uivant) tout ce q ui conce rne les
problèm es de conve rsion ;c'e s t là q ue nous parlerons de la surdéfinition d'un opé rate ur de "cast".

2.7 Ch oix e ntre fonction m e m bre e t fonction am ie

Com m e nous l'avons dit, C+ + vous lais s e libre de surdé finir un opé rate ur à l'aide d'une fonction m e m bre
ou d'une fonction indé pe ndante (e n gé né ralam ie ). Ce la signifie donc q ue , dans ce rtains cas, vous pourre z
vous dem ande r sur q ue ls critè re s opé re r le ch oix. En toute rigue ur, vous ne possédez pas, pour l'instant,
toute s les inform ations néce s s aire s , com pte te nu de s possibilités de conve rsion q ue nous n'étudie rons q ue
dans le proch ain ch apitre .

Pour l'instant, note z sim plem e nt q ue si un opérateur doit absol


um ent recevoir un type de base en
prem ier argum ent, ilne peut pas ê tre défini com m e fonction m em bre (laq ue lle re çoit im plicite m e nt un
pre m ie r argum e nt du type de sa clas s e ).

Le cas, déjà é voq ué , de l'addition d'un double e t d'un com plexe (dans ce t ordre 9 ) pe ut s e m bler corre s pondre
à une te lle s ituation. En fait, com m e nous l'avons déjà dit dans le paragraph e 2.5, nous ve rrons, dans le
proch ain ch apitre q ue ce lui-ci pe ut é galem e nt s e ré s oudre par surdéfinition de l'addition de deux com plexe s
e t par la définition de la conve rsion double -> com plexe .

3. EXEM PLE D E SURD ÉFINITIO N D E L'O PÉRA TEUR =

Nous avons déjà e u l'occasion d'utiliser une clas s e ve ct, corre s pondant à des "ve cte urs dynam iq ue s " :

class vect
{ int nelem ; // nombre d'éléments
int * adr ; // adresse
public :
vect (int n) // constructeur
.....
} ;

Nous avons vu (paragraph e 3.2 du ch apitre VII) q u'alors, si fct é tait une fonction à un argum e nt de type
ve ct, les instructions suivante s :

vect a(5) ;

9 - Ilne s uffira pas d'avoir s urdéfini l


'addition d'un com plexe e t d'un double (l
aq ue l
le pe ut s e faire par une fonction m e m bre). En effe t,
com m e nous l
'avons dit, aucune h ypoth è s e n'e s t faite par C+ + s ur l
'opé rate ur s urdéfini, e n particul
ie r s ur s a com m utativité !
136 Program m e r e n langage C+ +
...
fct (a) ;

posaie nt problèm e : l'appe lde fct conduisait à la cré ation, par re copie de a, d'un nouve lobje t (q ue nous
nom m ions b) ;nous é tions alors e n pré s e nce de deux obje ts a e t b com portant un pointe ur (adr) ve rs le
m ê m e e m place m e nt :

En particulie r, si la clas s e ve ct possédait (com m e c'e s t souh aitbale !) un de s tructe ur ch argé de libérer
l'e m place m e nt m é m oire e n q ue s tion, on ris q uait d'aboutir à deux dem andes de libération du m ê m e
e m place m e nt m é m oire .

Nous avons vu alors q u'une s olution (parm i d'autre s ) consistait à définir un constructe ur de re copie ch argé
d'effe ctue r, non s e ulem e nt la re copie de l'obje t lui-m ê m e , m ais é galem e nt ce lle de sa partie dynam iq ue dans
un nouve le m place m e nt (une autre s olution consiste à e m ploye r un "com pte ur de ré fé re nce s " : nous vous la
pré s e nte rons dans le paragraph e s uivant).

O r, l'affe ctation d'obje ts de type ve ct pos e les m ê m e s problèm e s . Ainsi, ave c ce tte déclaration :

vect a(5), b(3) ;

q ui corre s pond au sch é m a suivant :

L'affe ctation :

b = a ;

conduit à :
IX. La surdéfinition d'opérate urs 137

Le problèm e e s t e ffe ctive m e nt voisin de ce lui de la construction par re copie . Voisin, m ais non ide ntiq ue , car
q ue lque s nuance s apparais s e nt, à savoir :

• on pe ut s e trouve r e n pré s e nce d'une affe ctation d'un obje t à lui-m ê m e ,


• ici, avant affe ctation, ile xiste deux obje ts "com plets" (c'e s t-à -dire ave c leur partie dynam iq ue ). Dans le
cas de la construction par re copie , iln'e xistait q u'un s e ule m place m e nt dynam iq ue , le s e cond é tant à
cré e r. O n va donc, ici, s e re trouve r ave c l'ancie n e m place m e nt dynam iq ue de b ;iln'e s t plus ré fé re ncé
par b, m ais e s t-on sûr q u'iln'e s t pas ré fé re ncé par ailleurs ?
En fait, nous pouvons ré gler les diffé re nts points e n surdéfinissant l'opé rate ur d'affe ctation, de m aniè re q ue
ch aq ue obje t de type ve ct com porte s on propre e m place m e nt dynam iq ue . Dans ce cas, on est sûr q u'iln'e s t
ré fé re ncé q u'une s e ule fois e t son éve ntue lle libération pe ut s e faire s ans problèm e . Note z ce pe ndant q ue
ce tte dém arch e ne convie nt totalem e nt q ue s i e lle e s t associé e à la définition conjointe du constructe ur de
re copie .

Voici donc com m e nt nous pourrions traite r une affe ctation te lle q ue b = a, dans le cas (pour l'instant) où a
e s t diffé re nt de b :

• libération de l'e m place m e nt pointé par b,


• cré ation dynam iq ue d'un nouve le m place m e nt dans leq ue lon re copie les valeurs de l'e m place m e nt pointé
par a,
• m ise en place des valeurs des m e m bres donnée de b.
Voici un sch é m a illustrant la situation à laq ue lle on aboutit :

Par ailleurs, ilnous faut pré voir de ne rie n faire lors q ue a e t b désignent le m ê m e obje t. Dans le cas
contraire , l'algorith m e propos é ne s e rait pas satisfaisant. En e ffe t, e n supposant q ue a e s t transm is par
valeur, ilconduirait à ce tte s ituation :
138 Program m e r e n langage C+ +

Ce lle-ci ne s e rait pas catastroph iq ue , m ais l'ancie n e m place m e nt pointé par a ne pourrait pas ê tre libéré. En
re vanch e , si a é tait transm is par ré fé re nce , on aboutirait à une double libération d'un m ê m e e m place m e nt
m é m oire .

Enfin, ilnous faut "décide r" de la valeur de re tour fournie par notre opé rate ur. A ce nive au, tout dépend de
l'usage q ue nous souh aitons e n faire :

• si nous nous conte ntons d'affe ctations sim ples (b = a), nous n'avons besoin d'aucune valeur de re tour
(void),
• si, en revanch e , nous souh aitons pouvoir traite r une affe ctation m ultiple ou, plus généralem e nt faire e n
sorte q ue (com m e on pe ut s'y atte ndre !) l'e xpre s s ion b = a ait une valeur (probablem e nt ce lle de b !), il
e s t né ce s s aire q ue notre opé rate ur fournis s e une valeur de re tour.
Nous ch oisissons ici la s e conde possibilité q ui a le m é rite d'ê tre plus générale10. Voici finalem e nt ce q ue
pourrait ê tre la définition de notre opé rate ur = (C+ + nous im pose de le définir com m e une fonction
m e m bre ) : par rapport à nos précédente s e xplications, b devie nt le pre m ie r opé rande 150 –ici th is –e t a
devie nt le s e cond opé rande - ici v. De plus, nous prévoyons de transm e ttre le s e cond opé rande par ré fé re nce .

vect vect::operator = (const vect & v) // notez const


{ if (this != &v)
{ delete adr ;
adr = new int [nelem = v.nelem] ;
for (int i=0 ; i<nelem ; i++) adr[i] = v.adr[i] ;
}
return * this ;
}
Note z q ue , com pte te nu de s a transm ission par ré fé re nce , ile s t né ce s s aire d'introduire le q ualificatif cons t
pour l'uniq ue argum e nt de notre fonction m e m bre ope rator=, afin de traite r conve nablem e nt le cas de
l'affe ctation d'un ve cte ur constant à un ve cte ur q ue lconq ue (n'oublie z pas q u'ainsi notre opé rate ur pourra
indiffé re m m e nt s'appliq ue r à des obje ts constants ou non ;dans le cas contraire , iln'aurait pu s'appliq ue r
q u'à des obje ts non constants).

Nous vous proposons d'inté gre r ce tte définition dans un program m e com plet s e rvant à illustre r le
fonctionne m e nt de l'opé rate ur. Pour ce faire , nous ajoutons, com m e d'h abitude , un ce rtain nom bre
d'instructions d'affich age (e n particulie r, nous suivons les adresses des obje ts e t des em place m e nts
dynam iq ue s q ui leur sont associé s ). Par contre , pour q ue le program m e ne s oit pas trop long, nous avons
réduit la clas s e ve ct au strict m inim um ;e n particulie r, nous n'y avons pas prévu de constructeur de
recopie ;or cel ui-ci deviendrait naturel lem ent indispensabl e dans une application ré e l
le.

Qui plus e s t, m ê m e ici, alors q ue notre fonction m ain s e lim ite à l'e m ploi de l'opé rate ur =, nous avons dû
pré voir une transm ission par ré férence pour l'argum e nt e t la valeur de re tour de ope rator=. En e ffe t, si

10 - Bie n e nte ndu, C+ + vous l


ais s e l
ibre de faire ce q ue vous voul
ez, y com pris de renvoyer une val
e ur autre q ue ce l
le de b (ave c tous
l
e s ris q ues de m anq ue de l
isibil
ité q ue ce l
a com porte !).
IX. La surdéfinition d'opérate urs 139
nous ne l'avions pas fait, l'appe lde ce t opé rate ur, traité , rappe lons-le, com m e une fonction, aurait e ntraî

un appe lde constructe ur de re copie (a = b est é q uivalent ici à : a.ope rator = (b)) ;ils e s e rait alors agi du
constructe ur de re copie par dé faut, ce q ui aurait e ntraî né les problèm es déjà é voq ués de double libération
d'un e m place m e nt11.

_______________________________________________________________________________
______

#include <iostream.h>
class vect
{ int nelem ; // nombre d'éléments
int * adr ; // pointeur sur ces éléments
public :
vect (int n) // constructeur
{ adr = new int [nelem = n] ;
for (int i=0 ; i<nelem ; i++) adr[i] = 0 ;
cout << "++ obj taille " << nelem << " en " << this
<< " - v. dyn en " << adr << "\n" ;
}
~vect () // destructeur
{ cout << "-- obj taille " << nelem << " en "
<< this << " - v. dyn en " << adr << "\n" ;
delete adr ;
}
vect & operator = (const vect &) ; // surdéfinition opérateur =
} ;

vect & vect::operator = (const vect & v)


{ cout << "== appel opérateur = avec adresses " << this << " " << &v << "\n" ;
if (this != &v)
{ cout << " effacement vecteur dynamique en " << adr << "\n" ;
delete adr ;
adr = new int [nelem = v.nelem] ;
cout << " nouveau vecteur dynamique en " << adr << "\n" ;
for (int i=0 ; i<nelem ; i++) adr[i] = v.adr[i] ;
}
else cout << " on ne fait rien \n" ;
return * this ;
}
main()
{ vect a(5), b(3), c(4) ;
cout << "** affectation a=b \n" ;
a = b ;
cout << "** affectation c=c \n" ;
c = c ;
cout << "** affectation a=b=c \n" ;
a = b = c ;
} ________________________________

++ obj taille 5 en 0x41140ffa - v. dyn en 0x42c60004


++ obj taille 3 en 0x41140ff4 - v. dyn en 0x42c70004
++ obj taille 4 en 0x41140fee - v. dyn en 0x42c80004
** affectation a=b

11 - Un des exercices de ce ch apitre vous s uggè re de l


e vé rifie r.
140 Program m e r e n langage C+ +
== appel opérateur = avec adresses 0x41140ffa 0x41140ff4
effacement vecteur dynamique en 0x42c60004
nouveau vecteur dynamique en 0x42c60004
** affectation c=c
== appel opérateur = avec adresses 0x41140fee 0x41140fee
on ne fait rien
** affectation a=b=c
== appel opérateur = avec adresses 0x41140ff4 0x41140fee
effacement vecteur dynamique en 0x42c70004
nouveau vecteur dynamique en 0x42c70004
== appel opérateur = avec adresses 0x41140ffa 0x41140ff4
effacement vecteur dynamique en 0x42c60004
nouveau vecteur dynamique en 0x42c60004
-- obj taille 4 en 0x41140fee - v. dyn en 0x42c80004
-- obj taille 4 en 0x41140ff4 - v. dyn en 0x42c70004
-- obj taille 4 en 0x41140ffa - v. dyn en 0x42c60004
_______________________________________________________________________________
____

Exe m ple d'utilisation d'une clas s e ve ct ave c un opérate ur d'affe ctation surdéfini

4. NO TIO N D E FO RM E CANONIQUE D'UNE CLASSE

Nous avons vu q ue , dè s lors q u'une classe dispose de pointe urs sur de s parties dynam iq ue s , la copie d'obje ts
de la clas s e (aussi bien par le constructe ur de re copie par dé faut q ue par l'opé rate ur d'affe ctation par dé faut)
n'e s t pas satisfaisante . Dans ces conditions, si l'on souh aite q ue ce tte re copie fonctionne conve nablem e nt, on
voit q u'ile s t né ce s s aire de m unir la classe d'au m oins les q uatre fonctions m e m bre s uivante s :

• constructe ur (ils e ra gé né ralem e nt ch argé de l'allocation de ce rtaine s parties de l'obje t),


• destructe ur (ildevra libérer correcte m e nt tous les e m place m e nts dynam iq ue s cré é s par l'obje t),
• constructe ur de re copie ,
• opé rate ur d'affe ctation.
Voici un cane vas ré capitulatif corre s pondant à ce m inim um q u'on nom m e s ouve nt "clas s e canoniq ue " :

_______________________________________________________________________________
____

class T
{ public :
T (...) ; // constructeurs autres que par recopie
T (const T &) ; // constructeur de recopie (forme
conseillée)
~T () ; // destructeur
T & T::operator = (const T &) ; // opérateur d'affectation (forme
conseillée)
.....
} ;
_______________________________________________________________________________
____

La form e canonique d'une clas s e


IX. La surdéfinition d'opérate urs 141
Note z q ue , bie n q ue ce ne s oit pas obligatoire , nous vous cons e illons :

• d'em ploye r le q ualificatif cons t pour l'argum e nt du constructe ur de re copie e t ce lui de l'affe ctation, dans
la m e s ure où ce s fonctions m e m bre n'ont aucune raison de m odifie r les valeurs des obje ts
corre s pondants,
• de prévoir (à m oins d'avoir de bonnes raisons de faire le contraire ) une valeur de re tour à l'opé rate ur
d'affe ctation, s e ulm oye n de gé re r corre cte m e nt les affe ctations m ultiples .
En re vanch e , l'argum e nt de l'opé rate ur d'affe ctation, ainsi que sa valeur de re tour pe uve nt ê tre
indiffé re m m e nt transm is par ré fé re nce ou par valeur ;ce pe ndant, on ne pe rdra pas de vue q ue les
transm issions par valeur e ntraî ne nt l'appe ldu constructe ur de re copie ;d'autre part, dè s lors q ue les obje ts
sont de taille re s pe ctable, la transm ission par ré fé re nce s 'avè re plus e fficace .

Note z bie n q ue s i vous cré e z une clas s e com portant des pointe urs, sans la dote r de ce "m inim um vital" e t
sans prendre de précautions particuliè re s , l'utilisate ur ne s e ve rra nullem e nt inte rdire la re copie ou
l'affe ctation d'obje ts.

S'ilvous arrive de cré e r une clas s e q ui n'a pas besoin de disposer des possibilités de copie (ou pour laq ue lle
ce s possibilité s n'ont pas de sens 12), plutôt q ue de com pte r sur la bonne volonté de l'utilisate ur, ile s t
pré fé rable d'utiliser quand m ê m e la form e canoniq ue , e n s'arrange ant pour inte rdire ce rtaine s actions. Voici
q ue lque s pistes dans ce s e ns :

• si l'opé rate ur d'affe ctation d'une class e e s t surdéfini sous form e privé e , toute te ntative d'affe ctation e ntre
obje ts de ce tte clas s e conduira à un m e s s age d'erreur en com pilation : on dispose donc là d'un m oye n
d'inte rdire l'affe ctation e ntre obje ts,
• si le constructe ur de re copie e s t défini sous form e privé e , toute te ntative d'initialisation (à la construction
ou e n transm ission par valeur) conduira à un m e s s age d'erreur en com pilation : là e ncore , on dispose
d'un m oye n d'inte rdire la re copie d'obje ts.

R e m arque :

Ce s ch é m a s e ra com plété dans le ch apitre XIII afin de pre ndre e n com pte la situation d'h é ritage .

5. EXEM PLE D E SURD ÉFINITIO N D E L'O PÉRA TEUR [ ]

Considérons à nouve au notre clas s e ve ct :

class vect
{ int nelem ;
int * adr ;
.....

Ch e rch ons à la m unir d'outils perm e ttant d'accéder à un é lém e nt de l'e m place m e nt pointé par adr, à partir
de la connaissance de sa position q ue l'on re pé re ra par un e ntie r com pris e ntre 0 e t ne le m -1

Nous pourrions bie n sûr é crire des fonctions m e m bre du genre :

void range (int valeur, int position)

pour introduire une valeur à une position donné e , e t :

12 - C'e s t gé né ral
e m e nt l
e cas des cl
as s e s "fe nê tre s " des systè m e s graph iq ue s te l
s q ue w indow s ...
142 Program m e r e n langage C+ +
int trouve (int position)

pour fournir la valeur situé e à une position donné e .

La m anipulation de nos ve cte urs ne serait alors guè re ais é e . Elle "re s s e m blerait" à ce ci :

vect a(5) ;
a.range (15, 0) ; // place 15 en position 0 de a
a.range (25, 1) ; // 25 en position 1
for (int i = 2 ; i < 5 ; i++)
a.range (0, i) ; // et O ailleurs
for i = 0 ; i < 5 ; i++) // pour afficher les valeurs de a
cout << a.trouve (i) ;

En fait, nous pouvons ch e rch e r à surdéfinir l'opé rate ur [] de m aniè re q ue a[i] "désigne" l'é lém e nt
d'em place m e nt i de a. La s e ule pré caution à pre ndre consiste à faire e n sorte q ue ce tte notation puis s e ê tre
utilisée non seulem e nt dans une expression (cas qui ne présente aucune difficulté ), m ais é galem e nt à gauch e
d'une affe ctation, c'e s t-à -dire com m e "lvalue ". Note z q ue , dans l'e xe m ple ci-de s s us, le problèm e ne s e
posait pas, dans la m e s ure où ch aq ue cas é tait traité par une fonction m e m bre diffé re nte .

Pour que a[i] soit une "l val


ue", ilest donc né cessaire que l
a val
eur de retour fournie par l
'opérateur []
soit transm ise par référence.

Par ailleurs, C+ + nous im pose de surdé finir ce t opé rate ur sous form e d'une fonction m e m bre , ce q ui
im pos e à son pre m ie r opé rande (note z bie n q ue le pre m ie r opé rande de a[i] e s t a) d'ê tre de type clas s e (ce
q ui s e m ble raisonnable!). Son prototype s e ra donc :

int & operator [] (int) ;

Si nous nous conte ntons de "re nvoye r" l'é lém e nt ch e rch é , sans e ffe ctue r de contrôle s ur la "validité " de la
position, le corps de notre fonction ope rator[] pe ut s e réduire à :

return adr[i] ;

Voici un e xe m ple s im ple d'utilisation d'une clas s e ve ct, réduite à son strict m inim um : constructe ur,
destructe ur e t opé rate ur []. Bie n e nte ndu, e n pratiq ue , ilfaudrait au m oins lui ajoute r un constructe ur de
re copie e t un opé rate ur d'affe ctation.

_______________________________________________________________________________
______

#include <iostream.h>
class vect
{
int nelem ;
int * adr ;
public :
vect (int n) { adr = new int [nelem=n] ; }
~vect () {delete adr ;}
int & operator [] (int) ;
} ;
int & vect::operator [] (int i)
{ return adr[i] ; }
main()
{ int i ;
vect a(5), b(3), c(3) ;
IX. La surdéfinition d'opérate urs 143
for (i=0 ; i<5 ; i++) {a[i] = i ; b[i] = 2*i ; }
for (i=0 ; i<3 ; i++) c[i] = a[i]+b[i] ;
for (i=0 ; i<3 ; i++) cout << c[i] << " " ;
}
_______________________
0 3 6
_______________________________________________________________________________
______

Exe m ple de s u rdéfinition de l'opérate ur[]

R e m arques :

1) Nous pourrions bie n sûr transm e ttre le s e cond opé rande par ré fé re nce , m ais ce la ne pré s e nte guè re
d'inté rê t, com pte te nu de la pe tite taille des obje ts du type ve ct.
2) Nous pourrions "proté ge r" la valeur du second opé rande contre une m odification accide nte lle au s e in
de ope rator[], e n dé clarant com m e prototype :
int & operator [] (const int) ;

3) C+ + nous inte rdit de définir l'opé rate ur [] sous form e d'une fonction am ie ;ile n allait déjà de
m ê m e pour l'opé rate ur =. De toute s façons, nous ve rrons (dans le proch ain ch apitre ) q ue , d'une
m aniè re gé né rale, iln'e s t pas cons e illé de définir par une fonction am ie un opé rate ur susce ptible de
m odifie r un obje t, com pte te nu de s "conve rsions im plicite s " pouvant é ve ntue llem e nt ê tre m ises en
je u.
4) Te lq ue nous l'avons conçu, notre opé rate ur [] ne pe ut pas ê tre appliq ué à un obje t constant (puis q ue
s e ules les fonctions m e m bre dotées du q ualificatif cons t pe uve nt l'ê tre ). Ce rte s , on pourrait s e
conte nte r de rajoute r ce q ualificatif cons t à notre opé rate ur m ais, dans ce cas, ilpourrait m odifie r un
te lobje t constant, ce q ui n'e s t pas souh aitable. En gé né ral, on pré fé re ra dé finir un s e cond opé rate ur
destiné uniq ue m e nt aux obje ts constants e n faisant e n sorte q u'ilpuis s e "consulte r" l'obje t e n q ue s tion
m ais non le m odifie r. D ans notre cas, voici ce q ue pourrait ê tre ce s e cond opé rate ur :
int vect::operator [] (int i) const
{ return adr[i] ; }

En e ffe t, une affe ctation te lle q ue v[i] = ..., v é tant un ve cte ur constant, s e ra re je té e e n com pilation
puis q ue notre opé rate ur transm e t son ré s ultat par valeur e t non plus par ré fé re nce .
5) L'opé rate ur [] é tait ici dicté par le bon sens, m ais nullem e nt im pos é par C+ + . Nous aurions pu tout
aussi bien utiliser :
- l'opé rate ur () : la notation a(i) aurait e ncore é té com pré h e nsible,
- l'opé rate ur < : q ue pe ns e r alors de la notation a < i ?
- l'opé rate ur , : notation a, i,
- e tc.

6. SURD EFINITIO N D E L'O PERA TEUR ()


Lors q u'une clas s e s urdé finit l'opé rate ur (), on dit q ue les obje ts auxq ue ls e lle donne naissance sont des obje ts
fonction car ils peuve nt ê tre utilisés de la m ê m e m aniè re q u'une fonction. En voici un e xe m ple s im ple, dans
leq ue lnous surdé finissons l'opé rate ur () pour q u'ilcorre s ponde à une fonction à deux argum e nts de type int
e t re nvoyant un int.
144 Program m e r e n langage C+ +
#include <iostream.h>
class cl_fct
{ public :
cl_fct(float x) { ..... } ; // constructeur
int operator() (int n, int p ) { ..... } // opérateur ()
} ;

D ans ce s conditions, une déclaration te lle q ue :

cl_fct obj_fct1(2.5) ;

construit bien sûr un obje t nom m é obj_fct1 de type cl_fct, e n transm e ttant le param è tre 2.5 à son
constructe ur. En re vanch e , la notation suivante ré alise l'appe lde l'opé rate ur ( ) de l'obje t obj_fct1, e n lui
transm e ttant les valeurs 3 et 5.

obj_fct1(3, 5)

Ce s possibilité s pe uve nt s e rvir lors q u'ile s t né ce s s aire d'effe ctue r ce rtaine s opé rations d'initialisation d'une
fonction ou de param é tre r son travail(par le biais des argum e nts passés à son constructe ur). M ais e lles
s'avé re ront e ncore plus inté re s s antes dans le cas des fonctions dites de rappe l, c’ e s t-à -dire des fonctions q ui
sont transm ises en argum e nt à une autre fonction. Nous e n ve rrons des exe m ples dans le ch apitre XXI
consacré aux algorith m e s s tandard.

$ 7. SURD ÉFINITIO N D ES O PÉRA TEURS NEW ET D ELETE

N.B. Ce ch apitre pe ut ê tre ignoré dans un pre m ie r te m ps.

Ce tte s urdé finition13, com m e ce lle de n'im porte q ue lautre opé rate ur, s e fait "s é lective m e nt" pour une clas s e
donné e . Bie n e nte ndu, ile s t possible de surdé finir ne w e t de lete pour ch acune des classes de votre ch oix. Le s
opé rate urs prédéfinis 14 continue ront d'ê tre e m ployé s pour les clas s e s où aucune s urdé finition n'a é té
ré alisée.

7.1 Surdé finition de ne w e t de l


e te

La surdéfinition de ne w s e fait obligatoire m e nt par une fonction m e m bre . Ce lle-ci doit :

• re ce voir un argum e nt de type size _t ;rappe lons q ue ce type , pré vu e n C ANSI, e s t défini dans le fich ie r
e n-tê te s tdde f.h (leq ue le s t é galem e nt inclus par s tdlib.h ). Ce t argum e nt corre s pond à la taille (e n octe ts)
de l'obje t à alloue r. Bie n q u'ilfigure dans la définition de ne w , iln'a pas à ê tre s pé cifié lors de son
appe l, car c'e s t le com pilate ur q ui le gé né re ra autom atiq ue m e nt (e n fonction de la taille de l'obje t
conce rné ).
• fournir e n re tour une valeur de type void * corre s pondant à l'adresse de l'e m place m e nt alloué pour
l'obje t.
Quant à la définition de la fonction m e m bre corre s pondant à l'opé rate ur de lete , e lle doit :

• re ce voir un argum e nt du type pointe ur sur la clas s e corre s pondante ;il re pré s e nte l'adresse de
l'e m place m e nt alloué à l'obje t à détruire ,
• ne fournir aucune valeur de re tour (void).

13 - Elle n'e s t possibl e q ue depuis la ve rsion 2.0.


14 - O n dit aussi l e s opé rate urs "gl
obaux".
IX. La surdéfinition d'opérate urs 145

R e m arques

1) M ê m e lors q ue l'opé rate ur ne w a é té s urdé fini pour une clas s e , ilre s te possible de faire appe là
l'opé rate ur prédéfini e n utilisant l'opé rate ur de ré s olution de porté e ;ile n va de m ê m e pour de lete .
2) Le s opé rate urs ne w e t de lete sont des fonctions m em bre statiques de leur clas s e (voye z le paragraph e
8 du ch apitre VI). En tant q ue te ls, ils n'ont donc accè s q u'aux m e m bre s s tatiq ues de la clas s e où ils
sont définis e t ils ne reçoive nt pas d'argum e nt im plicite (th is).

7.2 Exe m pl
e

Voici un program m e dans leq ue lla clas s e point surdéfinit les opé rate urs ne w e t de lete , dans le s e ulbut d'en
com ptabiliser les appe ls15. Ils font d'ailleurs appe laux opé rate urs prédéfinis (par e m ploi de ::) pour ce q ui
conce rne la ge s tion de la m é m oire .

_______________________________________________________________________________
____

#include <iostream.h>
#include <stddef.h> // pour size_t
class point
{ static int npt ; // nombre total de points
static int npt_dyn ; // nombre de points "dynamiques"
int x, y ;
public :
point (int abs=0, int ord=0) // constructeur
{ x=abs ; y=ord ;
npt++ ;
cout << "++ nombre total de points : " << npt << "\n" ;
}
~point () // destructeur
{ npt-- ;
cout << "-- nombre total de points : " << npt << "\n" ;
}
void * operator new (size_t sz) // new surdéfini
{ npt_dyn++ ;
cout << " il y a " << npt_dyn << " points dynamiques sur un \n" ;
return ::new char[sz] ;
}
void operator delete (void * dp)
{ npt_dyn-- ;
cout << " il y a " << npt_dyn << " points dynamiques sur un \n" ;
::delete (dp) ;
}
} ;
main()
{ point * ad1, * ad2 ;
point a(3,5) ;
ad1 = new point (1,3) ;
point b ;
ad2 = new point (2,0) ;
delete ad1 ;
point c(2) ;

15 - Bie n e nte ndu, gé né ral


e m e nt, dans un program m e ré e l
,l'opé rate ur ne w aura une tâ ch e pl
us é l
aborée.
146 Program m e r e n langage C+ +
delete ad2 ;
} _______________________

++ nombre total de points : 1


il y a 1 points dynamiques sur un
++ nombre total de points : 2
++ nombre total de points : 3
il y a 2 points dynamiques sur un
++ nombre total de points : 4
-- nombre total de points : 3
il y a 1 points dynamiques sur un
++ nombre total de points : 4
-- nombre total de points : 3
il y a 0 points dynamiques sur un
-- nombre total de points : 2
-- nombre total de points : 1
-- nombre total de points : 0
_______________________________________________________________________________
______

Exe m ple de s u rdéfinition de l'opérate ur ne w pour la clas s e point

R e m arques

1) Com m e le m ontre ce t e xe m ple, la surdéfinition de s opé rate urs ne w e t de lete n'a d'incide nce q ue s ur
les obje ts alloués dynam iq ue m e nt. Le s obje ts statiq ue s (alloué s à la com pilation) e t les obje ts
dynam iq ue s (alloué s lors de l'e xé cution, m ais sur la pile) ne s ont toujours pas conce rné s .
2) Que ne w soit surdéfini ou prédéfini, son appe l e s t toujours (h e ure us e m e nt) suivi de ce lui du
constructe ur (lors q u'ile xiste ). De m ê m e , q ue de lete soit surdéfini ou prédéfini, son appe le s t toujours
pré cédé de ce lui du de s tructe ur (lors q u'ile xiste ).
3) Lors q u'ils sont surdéfinis, les opé rate urs ne w e t de lete ne pe uve nt pas s'appliq ue r à des tableaux
d'obje ts. Ainsi, dans l'e xe m ple de program m e pré cédent, une instruction te lle q ue :
point * ad = new point [50] ;

fe ra appe l(50 fois) à l'opé rate ur ne w prédéfini.

4) Ile s t toujours possible16 de surdéfinir les opé rate urs ne w e t de lete de m aniè re globale. Ilsuffit de
définir l'opé rate ur corre s pondant sous form e d'une fonction indé pe ndante com m e dans ce t e xe m ple :
void operator new (size_t sz)
{ .....
}

D ans ce cas, ilfaut bien voir q ue :


- ce t opé rate ur s e ra appe lé pour tous les type s pour les q ue ls aucun opé rate ur ne w n'a é té s urdé fini, y
com pris pour l es types de base. Ainsi, la déclaration :
int * adi = new int ;

y fe ra appe l;

16 - D ans toute s l
e s ve rsions de C+ + .
IX. La surdéfinition d'opérate urs 147
- dans la définition de ce t opé rate ur, iln'e s t plus possible de faire appe là l'opé rate ur ne w prédéfini.
Toute te ntative d'appe lde ne w ou m ê m e de ::ne w fe ra e ntre r dans un proce s s us ré cursif.
Ce dernie r point lim ite l'inté rê t de la surdéfinition globale de ne w de de lete puis q ue , dans ce cas, le
program m e ur doit pre ndre com plète m e nt à sa ch arge la ge s tion dynam iq ue de m é m oire (par e xe m ple
e n ré alisant les "appe ls au systè m e " né ce s s aire s ...).

EXERCICES

N.B. Le s e xe rcice s m arqués (C) sont corrigé s e n fin de volum e .

1) D ans les deux e xe m ples de program m ation de s paragraph e s 1.1 e t 1.2, m e tte z e n é vidence les appe ls
d'un constructe ur de re copie . Pour ce faire , introduise z un constructe ur supplém e ntaire de la form e
point (point& ) dans la clas s e point. Voye z ce q ui s e produit lors q ue vous e m ploye z, pour le ou les
argum e nts de ope rator+ , la transm ission par ré fé re nce .

2) D ans l'e xe m ple du paragraph e 3, introduise z é galem e nt un constructe ur de re copie pour la clas s e
ve ct. Constate z q ue le re m place m e nt de la transm ission par ré fé re nce par une transm ission par valeur
e ntraîne la cré ation de nom bre ux obje ts supplém e ntaire s .

3 - (C)D ans une clas s e point de la form e :


class point
{ int x, y ;
public :
point (int abs = 0, int ord = 0)
{.....}
.....

introduise z un opé rate ur ==, te lq ue s i a e t b sont deux points , a==b fournis s e la valeur 1 lors q ue a
e t b ont les m ê m e s coordonné e s e t la valeur 0 dans le cas contraire . O n pré voira les deux situations :
a) fonction m e m bre ,
b) fonction am ie .

4 - (C)D ans une clas s e pile_e ntie r de la form e 17 :


class pile_entier
{ int dim ; // nombre maxi d'éléments de la pile
int * adr ; // adresse du tableau représentant la pile
int nelem ; // nombre d'éléments courant de la pile
public :
pile_entier (int n) {...}
~pile_entier () {...}
.....

introduise z les opé rate urs > e t < , te ls q ue s i p e s t un obje t de type pile_e ntie r e t n une variable
e ntiè re :

17 - R e voyez éve ntue l


le m e nt l
'exercice VII.5.
148 Program m e r e n langage C+ +
p < n ajoute la valeur de n sur la pile p (e n ne re nvoyant aucune valeur),
p > n supprim e la valeur du h aut de la pile e t la place dans n.
O n pré voira les deux situations :
a) fonctions m e m bre ,
b) fonctions am ie s .

5 (C) En langage C, il n'e xiste pas de vé ritable type ch aî ne , m ais sim plem e nt une "conve ntion" de
re pré s e ntation de s ch aî
ne s (suite de caractè re s , te rm iné e par un caractè re de code nul). Un ce rtain
nom bre de fonctions utilisant ce tte conve ntion pe rm e tte nt les "m anipulations" classiques (copie ,
concaté nation...).
Ce t e xe rcice vous dem ande de définir une clas s e nom m é e ch aine offrant des possibilité s plus proch e s
d'un vé ritable type ch aî ne (te lq ue ce lui du Basic ou du Pascal). Pour ce faire , on pré voira e n
m e m bres donnée :
• la longue ur courante de la ch aî
ne ,
• l'adresse d'une zone , allouée dynam iq ue m e nt, destiné e à re ce voir la suite de caractè re s (ilne s e ra
pas néce s s aire d'y range r le caractè re nulde fin, puis q ue la longue ur de la ch aîne e s t définie par
ailleurs).
Le conte nu d'un obje t de type ch aine pourra donc é volue r facilem e nt par un sim ple je u de ge s tion
dynam iq ue .
O n m unira la clas s e ch aine des constructe urs suivants :
• ch aine () : initialise une ch aî
ne vide,
• ch aine (ch ar*) : initialise la ch aî
ne ave c la ch aî
ne (au s e ns du C) dont on fournit l'adre s s e e n
argum e nt,
• ch aine (ch aine & ) : constructe ur de re copie .
O n y définira les opé rate urs :
• = pour l'affe ctation e ntre obje ts de type ch aine (pe ns e r à l'affe ctation m ultiple),
• == pour e xam ine r l'é galité de deux ch aî
ne s ,
• + pour ré aliser la concaté nation de deux ch aî ne s . Si a e t b sont de type ch aine , a + b s e ra une
(nouve lle) ch aî
ne form é e d e la concaté nation de a e t b (les ch aî
ne s a e t b devront ê tre inch angé e s ).
• [] pour accéder à un caractè re de rang donné d'une ch aî
ne (les affe ctations de la form e a[i] = 'x'
devront pouvoir fonctionne r.
O n pourra ajoute r une fonction d'affich age . O n ne pré voira pas d'em ploye r de com pte ur par
ré fé re nce , ce q ui signifie q u'on acce pte ra de dupliq ue r les ch aî
ne s identiq ue s .

N.B. O n trouve ra dans la biblioth è q ue s tandard pré vue par la norm e , une clas s e s tring offrant, e ntre autre s ,
les fonctionnalité s é voq ué e s ici.
X. LES CO NVERSIO NS D E TYPE
D ÉFINIES PAR L'UTILISATEUR

N.B. Le s possibilités décrite s ici sont considérées com m e as s e z dange re us e s ;e lles doive nt n'ê tre e m ployé e s
q u'e n toute connaissance de caus e . Ile s t possible d'ignore r ce ch apitre dans un pre m ie r te m ps.

En m atiè re de conve rsion d'un type de bas e e n un autre type de bas e , C+ + offre , nature llem e nt, les m ê m e s
possibilité s q ue le langage C. R appe lons q ue ce s conve rsions peuve nt ê tre e xplicite s ou im plicite s .

Ils'agit de conversions expl


icites lors q ue l'on fait appe là un opé rate ur de "cast", com m e dans :

int n ; double z ;
.....
z = double(n) ;

ou dans :

n = int(z) ;

Le s conversions im plicites ne s ont, q uant à e lles , pas m e ntionné e s par "l'utilisate ur1" e t e lles s ont m ises en
place par le com pilate ur, e n fonction du conte xte . Ce s conve rsions im plicite s s e re ncontre nt à diffé re nts
nive aux :

• dans les affe ctations : ily a alors conve rsion "forcé e " dans le type de la variable ré ce ptrice ,
• dans les appe ls de fonction : com m e le prototype e s t obligatoire e n C+ + , ily a é galem e nt conve rsion
"forcé e " d'un argum e nt dans le type déclaré dans le prototype ,
• dans les e xpre s s ions : dans ce cas, ily a, pour ch aq ue opé rate ur, conve rsion éve ntue lle de l'un de s
argum e nts dans le type de l'autre , suivant des rè gles pré cis e s 2. En particulie r, ce ci fait inte rve nir :
- des conve rsions systé m atiq ue s : ch ar e t s h ort e n int,
- des conve rsions d'ajuste m e nt de type , par e xe m ple int e n long pour une addition de deux valeurs de
type long...
O r, C+ + pe rm e t é galem e nt de définir de s conve rsions faisant inte rve nir de s type s clas s e cré é s par
l'utilisate ur. Par e xe m ple, pour un type com plexe , on pourra, m oye nnant l'é criture de fonctions approprié e s ,
donne r une s ignification aux conve rsions :

complexe -> double


double -> complexe

1 - C'e s t-à -dire en fait l


'aute ur du program m e. Nous avons toute fois cons e rvé l
e te rm e ré pandu d'util
isate ur ;ce te rm e s'oppose donc ici à
com pil ate ur.
2 - Ce s rè gle s s ont détail
lées dans C-norm e ANSI, guide com pl
e t de program m ation, du m ê m e aute ur.
150 Program m e r e n langage C+ +
Qui plus e s t, nous ve rrons q ue l'e xiste nce de te lles conve rsions perm e ttra de donner un sens à l'addition
d'un com plexe e t d'un double, ou m ê m e ce lle d'un com plexe e t d'un int.

Ce pe ndant, s'ilparaî t à la rigue ur logiq ue de disposer de conve rsions entre une clas s e com plexe e t les type s
num é riq ue s , iln'e n ira plus néce s s aire m e nt de m ê m e pour de s clas s e s n'ayant pas une "connotation"
m ath é m atiq ue aussi forte , ce q ui n'e m pê ch e ra pas le com pilate ur de m e ttre e n place le m ê m e ge nre de
conve rsions !

Ce ch apitre fait le point sur ces diffé re nte s possibilité s . Pour ne pas vous am e ne r trop vite à une conclusion
définitive s ur leur inté rê t ou sur leur abs e nce d'inté rê t, nous avons volontaire m e nt utilisé des exem ples ,
tantôt signifiants (à connotation m ath é m atiq ue ), tantôt non signifiants.

1. LES D IFFÉRENTES SO RTES D E CO NVERSIO NS


D ÉFINIES PAR L'UTILISATEUR

Considérons une clas s e point, possédant un constructeur à un argum ent, com m e :

point (int abs) { x = abs ; y = 0 ; }

O n pe ut dire q ue ce constructe ur ré alise une conve rsion d'un int e n un obje t de type point. Nous avons
d'ailleurs déjà vu com m e nt appe ler e xplicite m e nt ce constructe ur, par e xe m ple :

point a ;
.....
a = point(3) ;

Nous ve rrons q ue (à m oins de l'inte rdire au m om e nt de la définition de la clas s e ), ce constructe ur pe ut ê tre


appe lé im pl icitem ent dans des affe ctations, des appe ls de fonction ou de s calculs d'expression, au m ê m e
titre q u'une conve rsion "usue lle" (on parle aussi de "conve rsion standard").

D 'autre part, nous avons vu q ue , plus généralem e nt, si l'on considè re deux clas s e s nom m é e s point e t
com plexe , un constructe ur de la clas s e com plexe à un argum e nt de type point :
complexe (point) ;

pe rm e t de conve rtir un point e n com plexe . Là e ncore , nous ve rrons q ue ce tte conve rsion pe ut ê tre utilisée
im plicite m e nt dans les diffé re nte s s ituations é voq ué e s (à m oins q u'on l'ait inte rdit e xplicite m e nt).

En re vanch e , ile s t facile de voir q u'un constructe ur (q ui fournit un obje t du type de sa clas s e ) ne pe ut e n
aucun cas perm e ttre de ré aliser une conve rsion d'un obje t e n une valeur d'un type de bas e , par e xe m ple un
point e n int ou un com plexe e n double. Com m e nous le ve rrons, ce type de conve rsion pourra ê tre traité e n
définissant au s e in de la clas s e conce rné e , un opé rate ur de "cast" approprié , par e xe m ple, pour les deux cas
cité s :
operator int()

au s e in de la clas s e point,
operator double()

au s e in de la clas s e com plexe .

Ce tte derniè re dém arch e de définition d'un opé rate ur de "cast" pourra é galem e nt ê tre e m ployé e pour dé finir
une conve rsion d'un type clas s e e n un autre type clas s e . Par e xe m ple, ave c :
X. Le s conve rsions de type définie s par l'utilisate ur 151
operator complexe() ;

au s e in de la clas s e point, on dé finira la conve rsion d'un point e n com plexe , au m ê m e titre q u'ave c le
constructe ur :
complexe (point) ;

situé (ce tte fois) dans la clas s e com plexe .

Voici un sch é m a ré capitulant les diffé re nte s possibilité s q ue nous ve nons d'évoq ue r : A et B désignent deux
clas s e s , b un type de bas e q ue lconq ue .

Parm i les diffé re nte s possibilités de conve rsion q ue nous ve nons d'évoq ue r, s e ull'opé rate ur de "cast",
appliq ué à une clas s e , apparaî t com m e nouve au ;vous pourrie z pe ns e r q ue la suite de ce ch apitre va s e
réduire à son étude . C'e s t e ffe ctive m e nt de lui q ue nous allons m ainte nant parler. M ais il nous faut
é galem e nt e t surtout voir pré cis é m e nt q uand e t com m e nt les diffé re nte s conve rsions im plicite s s ont m ises en
œuvre , ainsi que les cas q ui sont re je té s par le com pilate ur.

2. L'O PÉRA TEUR D E "CAST" PO UR LA CONVERSIO N


D 'UN TYPE CLASSE D A NS UN TYPE D E BASE

2.1 D é finition de l
'opé rate ur de "cas t"

Considérons une clas s e point :

class point
{ int x, y ;
.....

Suppos e z q ue nous souh aitions la m unir d'un opé rate ur de "cast" pe rm e ttant la conve rsion de point e n int.
Nous le note rons sim plem e nt :

operator int()

Ils'agit là du m é canism e h abitue lde surdéfinition d'opé rate ur é tudié dans le ch apitre pré cédent : l'opé rate ur
s e nom m e ici int ;ile s t unaire (un s e ulargum e nt) e t, com m e ils'agit d'une fonction m e m bre , aucun
152 Program m e r e n langage C+ +
argum e nt n'apparaî t dans son e n-tê te ou son prototype . R e s te la valeur de re tour : e n principe , ce t opé rate ur
fournit un int, de sorte q u'on aurait pu pe ns e r à l'e n-tê te :

int operator int()

En fait, e n C+ + , un opérateur de cast doit toujours ê tre défini com m e une fonction m em bre et l e type
de l
a val eur de retour (q ui e s t alors ce lui dé fini par le nom de l'opé rate ur) ne doit pas ê tre m entionné .

En dé finitive , voici com m e nt nous pourrions dé finir notre opé rate ur de "cast" (ici "inline "), e n supposant
q ue le ré s ultat souh aité pour la conve rsion en int soit l'abscisse du point.

operator int()
{ return x ;
}

2.2 Exe m pl
e s im pl
e d'util
is ation

Voici un pre m ie r e xe m ple de program m e m ontrant :

• un appe le xplicite de l'opé rate ur int q ue nous ve nons de définir,


• un appe lim plicite e ntraî
né par une affe ctation.
Com m e à l'accoutum é e , nous avons introduit une instruction d'affich age dans l'opé rate ur lui-m ê m e pour
obte nir une trace de son appe l.

_______________________________________________________________________________
______
#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point : " << x << " " << y << "\n" ;
}
operator int() // "cast" point --> int
{ cout << "== appel int() pour le point " << x << " " << y << "\n" ;
return x ;
}
} ;
main()
{ point a(3,4), b(5,7) ;
int n1, n2 ;
n1 = int(a) ; // ou n1 = (int) a appel explicite de int ()
cout << "n1 = " << n1 << "\n" ;
n2 = b ; // appel implicite de int()
cout << "n2 = " << n2 << "\n" ;
} _______________________

++ construction point : 3 4
++ construction point : 5 7
== appel int() pour le point 3 4
n1 = 3
== appel int() pour le point 5 7
n2 = 5
X. Le s conve rsions de type définie s par l'utilisate ur 153
_______________________________________________________________________________
______

Exe m ple d'utilisation d'un opérate ur de "cas t" pour la conve rsion point -> int

Nous voyons claire m e nt q ue l'affe ctation :

n2 = b ;

a é té traduite par le com pilate ur e n :

• une conve rsion du point b en int,


• une affe ctation (classique) de la valeur obte nue à n2.

2.3 Appe lim pl


icite de l
'opé rate ur de "cas t"
l
ors d'un appe lde fonction

Nous définissons une fonction fct re ce vant un argum e nt de type e ntie r. Nous l'appe lons :

• une pre m iè re fois ave c un argum e nt e ntie r (6),


• une deuxiè m e fois ave c un argum e nt de type point (a).
En outre , nous avons introduit (artificie llem e nt) dans la clas s e point un constructe ur de re copie , ce ci afin de
m ontre r q u'ici iln'e s t pas appe lé.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point : " << x << " " << y << "\n" ;
}
point (point & p) // constructeur de recopie
{ cout << ":: appel constructeur de recopie \n" ;
x = p.x ; y = p.y ;
}
operator int() // "cast" point --> int
{ cout << "== appel int() pour le point " << x << " " << y << "\n" ;
return x ;
}
} ;
void fct (int n) // fonction
{ cout << "** appel fct avec argument : " << n << "\n" ;
}
main()
{ void fct (int) ;
point a(3,4) ;
fct (6) ; // appel normal de fct
154 Program m e r e n langage C+ +
fct (a) ; // appel avec conversion implicite de a en int
}
_______________________

++ construction point : 3 4
** appel fct avec argument : 6
== appel int() pour le point 3 4
** appel fct avec argument : 3
_______________________________________________________________________________
______

Appe lde l'opérate ur de "cas t" lors d'un appe lde fonction

O n voit q ue l'appe l:

fct(a)

a é té traduit par le com pilate ur e n :

• une conve rsion de a en int,


• un appe lde fct, à laq ue lle on fournit e n argum e nt la valeur ainsi obte nue .
Com m e on pouvait s'y atte ndre , la conve rsion est bien réalisée avant l'appe lde la fonction e t iln'y a pas de
cré ation par re copie d'un obje t de type point.

2.4 Appe lim pl


icite de l
'opé rate ur de "cas t"
dans l
'é val
uation d'une e xpre s s ion

Le program m e ci-de s s ous vous m ontre com m e nt sont é valué e s d e s e xpre s s ions te lles q ue a + 3 ou a + b
lors q ue a e t b sont de type point.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point : " << x << " " << y << "\n" ;
}
operator int() // "cast" point --> int
{ cout << "== appel int() pour le point " << x << " " << y << "\n" ;
return x ;
}
} ;
main()
{ point a(3,4), b(5,7) ;
int n1, n2, n3 ;
n1 = a + 3 ; cout << "n1 = " << n1 << "\n" ;
n2 = a + b ; cout << "n2 = " << n2 << "\n" ;
X. Le s conve rsions de type définie s par l'utilisate ur 155
double z1, z2 ;
z1 = a + 3 ; cout << "z1 = " << z1 << "\n" ;
z2 = a + b ; cout << "z2 = " << z2 << "\n" ;
}
_______________________

++ construction point : 3 4
++ construction point : 5 7
== appel int() pour le point 3 4
n1 = 6
== appel int() pour le point 3 4
== appel int() pour le point 5 7
n2 = 8
== appel int() pour le point 3 4
z1 = 6
== appel int() pour le point 3 4
== appel int() pour le point 5 7
z2 = 8
_______________________________________________________________________________
______

U tilisation de l'opérate ur de "cas t" dans l'évaluation d'une e xpre s s ion

Lors q u'ilre ncontre une e xpre s s ion com m e a + 3 ave c un opé rate ur portant sur un é lém e nt de type point e t
un e ntie r, le com pilate ur re ch e rch e tout d'abord s'ile xiste un opé rate ur + surdéfini corre s pondant à ce s
types d'opérandes. Ici, iln'e n trouve pas. Ilva alors ch e rch e r à m e ttre e n place des conve rsions des
opé rande s pe rm e ttant d'aboutir à une opé ration e xistante . Dans notre cas, pré cis é m e nt, ilva pré voir la
conve rsion de a en int, de m aniè re à s e ram e ne r à la som m e de deux entie rs, suivant le s ch é m a :

point int
| |
int |
|___ + ___|
|
int

Ce rte s , une te lle dém arch e pe ut ch oq ue r. En fait, ilfaut faire q ue lque s re m arq ue s :

• ici, aucune autre conve rsion n'e s t e nvisage able ;iln'e n irait pas de m ê m e s 'ile xistait un opé rate ur
(surdéfini) d'addition de deux points,
• la dém arch e paraî t m oins ch oq uante s i l'on ne ch e rch e pas à donne r une vé ritable s ignification à
l'opé ration a + 3,
• nous ch e rch ons à vous présente r les diffé re nte s s ituations q ue l'on ris q ue de re ncontre r, non pas pour
vous e ncourage r à les e m ploye r toute s , m ais plutôt pour vous m e ttre e n garde .
Quant à l'é valuation de a + b, elle s e fait carré m e nt suivant le s ch é m a suivant :

point point
| |
int int
|___ + ___|
|
int
156 Program m e r e n langage C+ +
Nous avons prévu, pour ch acune des deux expressions évoq ué e s , deux sortes d'affe ctation :

• à une variable e ntiè re ,


• à une variable de type double : dans ce cas, ily a conve rsion forcée du ré s ultat de l'e xpre s s ion e n
double.
Note z bie n q ue le type de la variable ré ce ptrice n'agit aucune m e nt sur la m aniè re dont l'e xpre s s ion e s t
é valué e pas plus q ue s ur son type final.

2.5 Conve rs ions e n ch aî


ne

Considérez cet e xe m ple :

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point : " << x << " " << y << "\n" ;
}
operator int() // "cast" point --> int
{ cout << "== appel int() pour le point " << x << " " << y << "\n" ;
return x ;
}
} ;

void fct (double v)


{ cout << "** appel fct avec argument : " << v << "\n" ;
}

main()
{
point a(3,4) ;
int n1 ;
double z1, z2 ;

n1 = a + 3.85 ; cout << "n1 = " << n1 << "\n" ;


z1 = a + 3.85 ; cout << "z1 = " << z1 << "\n" ;
z2 = a ; cout << "z2 = " << z2 << "\n" ;
fct (a) ;
}
_______________________

++ construction point : 3 4
== appel int() pour le point 3 4
n1 = 6
== appel int() pour le point 3 4
z1 = 6.85
X. Le s conve rsions de type définie s par l'utilisate ur 157
== appel int() pour le point 3 4
z2 = 3
== appel int() pour le point 3 4
** appel fct avec argument : 3
_______________________________________________________________________________
______

Conve rsions e n ch aî
ne

Ce tte fois, nous avons à é value r, à deux reprises, la valeur de l'e xpre s s ion :

a + 3.85

La diffé re nce ave c les s ituations précédente s ré s ide dans le fait q ue la constante 3.85 e s t de type double, e t
non plus de type int. Dans ce cas, on pourrait supposer, par analogie ave c ce q ui pré cè de, que le com pilate ur
va pré voir la conve rsion de 3.85 en int. O r, ils'agirait là d'une conve rsion d'un type de bas e double e n un
autre type de bas e int q ui ris q ue rait d'ê tre "d é gradante" e t q ui, com m e d'h abitude , n'e s t jam ais m ise en
œuvre de m aniè re im pl icite dans un cal culd'expression3.

En fait, l'é valuation s e fe ra suivant le s ch é m a ci-aprè s :

point double
| |
int |
| |
double |
|___ + ___|
|
double

La valeur affich é e pour z1 confirm e le type double de l'e xpre s s ion.

Ici, donc, la valeur de a a é té s oum ise à deux conversions successives avant d'ê tre transm ise à un opé rate ur.
Note z bie n q ue ce ci e s t indé pe ndant de l'usage q ui doit ê tre fait ulté rie ure m e nt de la valeur de l'e xpre s s ion,
à savoir :

• conve rsion en int pour affe ctation à n1 dans le pre m ie r cas,


• affe ctation à z2 dans le s e cond cas.
Quant à l'affe ctation z2 = a, e lle e ntraî
ne une double conve rsion de point e n int, puis de int e n double.

Ile n va de m ê m e pour l'appe l:

fct (a)

D 'une m aniè re gé né rale, C+ + pe ut ainsi, en cas de besoin, m e ttre e n œuvre une "ch aîne " de conve rsions, à
condition toute fois q ue ce lle-ci ne fas s e inte rve nir q u'une seul e C.D.U. (Conve rsion Définie par
l'Utilisate ur4). Plus précisém e nt, ce tte ch aî
ne pe ut ê tre form ée d'au m axim um trois conve rsions, à savoir :

3 - El
le pourrait l
'ê tre, bien sûr, dans une affe ctation ou un appe lde fonction, e n tant q ue conve rsion "forcé e ".
4 - Nous avons déjà re ncontré ce m é canis m e dans l e cas des fonctions s urdéfinies. Ici, on pe ut donc dire q u'ils'agit d'un m é canis m e
com parabl
e appl
iq ué à un opé rate ur prédéfini, e t non pl
us à une fonction dé finie par l
'util
isate ur. Nous retrouve rons par l
a s uite des
situations s e m bl
abl
es, rel
ative s ce tte fois à un opé rate ur défini par l
'util
isate ur (donc à une fonction) ;l
e s rè gl
e s appl
iq ué e s s e ront al
ors
bien cel
le s q ue nous avons é voq uées dans l
a re ch e rch e de l
a "bonne fonction s urdéfinie ".
158 Program m e r e n langage C+ +
é ve ntue llem e nt une conve rsion standard, suivie é ve ntue llem e nt d'une C.D .U, suivie é ve ntue llem e nt d'une
conve rsion standard.

2.6 En cas d'am biguïté

A partir du m om e nt où le com pilate ur acce pte de m e ttre e n place une ch aî ne de conve rsions, certaine s
am biguïté s pe uve nt apparaî
tre . Pre nons à nouve au l'e xe m ple de notre clas s e point, e n supposant ce tte fois
q ue nous l'avons m unie de deux opérate urs de "cast" :

operator int()
operator double()

Supposons que nous utilisions à nouve au une e xpre s s ion te lle q ue (a é tant de type point) :

a + 3.85

D ans ce cas, le com pilate ur s e trouve e n pré s e nce de deux sch é m as possibles de conve rsion :

point double point double


| | | |
double | int |
|____+____| | |
| double |
double |___ + ___|
|
double

Ici, pré cis é m e nt, ilre fus e ra l'e xpre s s ion e n fournissant un diagnostic d'am biguïté .

Ce tte am biguïté ré s ide dans le fait q ue deux ch aî nes de conve rsions perm e tte nt de pas s e r du type point au
type double. S'ils'agissait d'une am biguïté conce rnant le ch oix de l'opé rate ur à appliq ue r (ce q ui n'é tait pas
le cas ici), le com pilate ur appliq ue rait alors les rè gles h abitue lles de ch oix d'une fonction surdéfinie 5.

3. LE CO NSTRUCTEUR PO UR LA CONVERSIO N
D 'UN TYPE D E BASE EN UN TYPE CLASSE

3.1 Un pre m ie r e xe m pl
e

Nous avons déjà vu com m e nt appe ler e xplicite m e nt un constructe ur. Par e xe m ple, ave c la clas s e point
pré cédente , si a e s t de type point, nous pouvons é crire :

a = point (12) ;

Ce tte instruction provoq ue :

• la cré ation d'un obje t te m poraire de type point,


• l'affe ctation de ce t obje t à a.

5 - En toute rigue ur, ilfaudrait considérer que l


e s opé rate urs s ur l
e s types de base correspondent, eux aussi, à des fonctions de l
a form e
ope rator + .
X. Le s conve rsions de type définie s par l'utilisate ur 159
O n pe ut donc dire q ue l'e xpre s s ion :

point (12)

e xprim e la conve rsion de l'e ntie r 12 e n un point.

D 'une m aniè re gé né rale, tout constructe ur à un s e ulargum e nt d'un type de bas e 6 ré alise une conve rsion de
ce type de base dans le type de sa clas s e .

O r, tout com m e l'opé rate ur de "cast", ce constructe ur pe ut ê tre é galem e nt appe lé im plicite m e nt. C'e s t ainsi
q ue l'affe ctation :

a = 12

provoq ue ra e xacte m e nt la m ê m e ch os e q ue l'affe ctation :

a = point (12)

En e ffe t, à sa re ncontre , le com pilate ur ch e rch e ra s'il e xiste une conve rsion (voire une ch aî ne de
conve rsions) uniq ue , pe rm e ttant de pas s e r du type int au type point. Ici, le constructe ur fe ra l'affaire .

D e la m ê m e façon, si fct a pour prototype :

void fct (point) ;

un appe lte lq ue :

fct (4)

e ntraî
ne ra une conve rsion de l'e ntie r 4 e n un point te m poraire q ui s e ra transm is à fct. Note z bie n q ue , dans
ce cas, le langage C+ + ne pré cis e pas s'ily aura ou non appe ldu constructe ur de re copie 7.

Voici un pe tit program m e illustrant ce s pre m iè re s possibilités de conve rsion par un constructe ur :

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point " << x << " " << y
<< " en " << this << "\n" ;
}
point (point & p) // constructeur de recopie
{ x = p.x ; y = p.y ;
cout << ":: constr. recopie de " << &p << " en " << this << "\n" ;
}
} ;
void fct (point p) // fonction simple

6 - O u, é ve ntue l
le m e nt, com m e c'e s t l
e cas ici, à pl
usieurs argum e nts ayant des val
e urs par dé faut, à partir du m om e nt où ilpe ut ê tre
appe l
é ave c un s e ulargum e nt.
7 - Nous avons re ncontré l es deux possibil
ités.
160 Program m e r e n langage C+ +
{ cout << "** appel fct " << "\n" ;
}
main()
{ void fct (point) ;
point a(3,4) ;
a = point (12) ; // appel explicite constructeur
a = 12 ; // appel implicite
fct(4) ;
} _______________________

++ construction point 3 4 en 0x24526265E


++ construction point 12 0 en 0x24522662
++ construction point 12 0 en 0x24522666
++ construction point 4 0 en 0x2453266A
** appel fct
_______________________________________________________________________________
______

U tilisation d'un cons tructe ur pour réaliser des conve rsions int -> point

R e m arque

Bie n e nte ndu, si fct e s t surdéfinie , le ch oix de la bonne fonction s e fe ra suivant les rè gles déjà
re ncontrées dans le ch apitre IV. Ce tte fonction de vra ê tre uniq ue e t, de plus, les ch aî
nes de conve rsions
m ises en œuvre pour ch aq ue argum e nt devront ê tre uniq ue s .

3.2 Le cons tructe ur dans une ch aî


ne de conve rs ions

Suppos e z q ue nous disposions d'une clas s e com plexe :

class complexe
{ double reel, imag ;
public :
complexe (double r = 0 ; double i = 0) ;
.....

Son constructe ur pe rm e t des conve rsions double -> com plexe . M ais, com pte te nu de s possibilités de
conve rsion im plicite int -> double, ce constructe ur pe ut inte rve nir dans une ch aî
ne de conve rsions :

int -> double -> com plexe

Ce s e ra le cas, par e xe m ple, dans une affe ctation te lle q ue (c é tant de type com plexe ) :

c = 3 ;

Note z q u'ici ce tte possibilité de ch aî ne de conve rsions rejoint les rè gles conce rnant les conve rsions
h abitue lles à propos des fonctions (surdéfinie s ou non). En e ffe t, on pe ut considérer ici que l'e ntie r 3 e s t
conve rti e n double, com pte te nu du prototype de com plexe . Ce tte double inte rpré tation d'une m ê m e
possibilité n'e s t pas gê nante , dans la m e s ure où e lle conduit, dans les deux cas, à la m ê m e conclusion
conce rnant la faisabilité de la conve rsion.
X. Le s conve rsions de type définie s par l'utilisate ur 161
3.3 Ch oix e ntre cons tructe ur ou opé rate ur d'affe ctation

D ans l'e xe m ple d'affe ctation :

a = 12

du paragraph e 3.1, iln'e xistait pas d'opérate ur d'affe ctation d'un int à un point. Si te le s t le cas, on pe ut
pe ns e r q u'alors le com pilate ur s e trouve e n pré s e nce d'un conflit e ntre :

• utiliser la conve rsion int -> point offe rte par le constructe ur, suivie d'une affe ctation point -> point,
• utiliser l'opé rate ur d'affe ctation int -> point.
En fait, ile xiste une rè gle q ui pe rm e t de tranch e r : les conversions d é finies par l
'util
isateur ("cast" ou
constructe ur) ne sont m ises en œuvre que l orsque cel a est nécessaire.

C'e s t donc la s e conde s olution q ui s e ra ch oisie ici par le com pilate ur, com m e le m ontre le program m e
suivant. Nous y avons surdé fini l'opé rate ur d'affe ctation non s e ulem e nt dans le cas int -> point, m ais
é galem e nt dans le cas point -> point afin de bien m ontre r q ue ce tte derniè re ve rsion n'e s t pas e m ployé e
dans l'affe ctation a = 12.

_______________________________________________________________________________
______
#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point " << x << " " << y
<< " en " << this << "\n" ;
}
point & operator = (point & p) // surd_finition affectation point ->
point
{ x = p.x ; y = p.y ;
cout << "== affectation point --> point de " << &p << " en " << this ;
return * this ;
}
point & operator = (int n) // surd_finition affectation int ->
point
{ x = n ; y = 0 ;
cout << "== affectation int --> point de " << x << " " << y
<< " en " << this << "\n" ;
return * this ;
}
} ;
main()
{ point a(3,4) ;
a = 12 ;
}
_______________________

++ construction point 3 4 en 0x2564


== affectation int --> point de 12 en 0x2564
_______________________________________________________________________________
______
162 Program m e r e n langage C+ +

Le s conve rsions définie s par l'utilisate ur ne s ont m i s e s e n œuvre q u e lors q u e ce la e s t néce s s aire

3.4 Em ploi d'un cons tructe ur pour é l


argir l
a s ignification
d'un opé rate ur

Considérons une clas s e point, m unie d'un constructe ur à un argum e nt e ntie r e t d'un opé rate ur d'addition
fourni sous form e d'une fonction am ie (nous ve rrons un pe u plus loin ce q ui s e pas s e rait dans le cas d'une
fonction m e m bre ).

class point
{ int x, y ;
public :
point (int) ;
friend point operator + (point, point) ;
.....

D ans ce s conditions, si a e s t de type point, une e xpre s s ion te lle q ue :

a + 3

va avoir une s ignification. En e ffe t, dans ce cas, le com pilate ur va m e ttre e n œuvre :

• une conve rsion de l'e ntie r 3 e n point (par appe ldu constructe ur),
• l'addition de la valeur obte nue ave c ce lle de a (par appe lde ope rator + ).
Le ré s ultat s e ra du type point. Le s ch é m a suivant ré capitule la situation :

point int
| |
| point
|___ + ___|
|
point

O n pe ut dire é galem e nt q ue notre e xpre s s ion a + 3 e s t é q uivalente (ici) à :

operator + (a, point (3))

Le m ê m e m é canism e s 'appliq ue à une e xpre s s ion te lle q ue :

5 + a

q ui s e ra donc é q uivalente à :

operator + (5, a)

Toute fois, dans ce dernie r cas, on voit q u'iln'e n s e rait pas allé de m ê m e s i notre opé rate ur + avait é té
défini par une fonction m e m bre . En e ffe t, son pre m ie r opé rande aurait alors dû ê tre de type point ;aucune
conve rsion im plicite n'aurait pu ê tre m ise en place dans ce cas 8.

Voici un pe tit program m e illustrant les possibilité s q ue nous ve nons d'évoq ue r :

8 - D e s appe l
s te l
s q ue 5.ope rator + (a) ou n.ope rator + (a) (n é tant de type int) s e ront re je tés.
X. Le s conve rsions de type définie s par l'utilisate ur 163
_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur 0, 1 ou 2 arguments
{ x = abs ; y = ord ;
cout << "++ construction point : " << x << " " << y << "\n" ;
}
friend point operator + (point, point) ; // point + point --> point
void affiche ()
{ cout << "Coordonnées : " << x << " " << y << "\n" ;
}
} ;
point operator+ (point a, point b)
{ point r ;
r.x = a.x + b.x ; r.y = a.y + b.y ;
return r ;
}
main()
{
point a, b(9,4) ;
a = b + 5 ; a.affiche() ;
a = 2 + b ; b.affiche() ;
}
_______________________

++ construction point : 0 0
++ construction point : 9 4
++ construction point : 5 0
++ construction point : 0 0
Coordonnées : 14 4
++ construction point : 2 0
++ construction point : 0 0
Coordonnées : 9 4
_______________________________________________________________________________
______

Elargis s e m e nt de la signification de l'opérate ur +

R e m arques :

1) La situation é voq ué e pe ut re ndre de grands s e rvices dans une situation ré e lle puis q u'e lle pe rm e t de
donne r un s e ns à des expre s s ions m ixte s . L'e xe m ple le plus caracté ristiq ue e s t ce lui d'une classe de
nom bre s com plexe s (supposés constitués de deux valeurs de type double). Ilsuffit, e n e ffe t, de définir
la som m e de deux com plexe s e t un constructe ur à un argum e nt de type double :
class complexe
{ double reel, imag ;
public :
complexe (double v) { reel = v ; imag = 0 ; }
friend complexe operator + (complexe, complexe) ;
.....
164 Program m e r e n langage C+ +

Le s e xpre s s ions de la form e :


com plexe + double
double + com plexe
auront alors une signification (e t ici ce s e ra bie n ce lle q ue l'on souh aite ).
Com pte te nu de s possibilités de conve rsions, ile n ira de m ê m e de n'im porte q ue lle addition d'un
com plexe e t d'un float, d'un long, d'un s h ort ou d'un ch ar.

2) Si nous avions défini :


class complexe
{ float reel, imag
public :
complexe (float v) ;
friend complexe operator + (complexe, complexe) ;
.....

l'addition d'un com plexe e t d'un double ne s e rait pas possible. Elle le devie ndrait, par contre , e n
re m plaçant le constructe ur par :
complexe (double v)

(ce q ui ne pré juge pas toute fois du résultat de la conve rsion forcé e d e double e n float q ui y
figure ra !).

3.5 Pour inte rdire l 'util


is ation du cons tructe ur
dans d e s conve rs ions im pl icite s : l
e m ot cl
é e xpl
icit

Le proje t de norm e ANSI de C+ + pré voit q u'on puis s e inte rdire l'utilisation du constructe ur dans des
conve rsions im plicite s (sim ples ou e n ch aî
ne ), e n utilisant le m ot clé e xplicit lors de sa déclaration ;par
e xe m ple, ave c :

class point
{ public :
explicit point (int) ;
friend operator + (point, point) ;
.....
}

les instructions suivante s s e raie nt re je té e s (a e t b étant de type point) :

a = 12 ; // illégal car le constructeur possède le qualificatif explicit


a = b + 5 ; // idem

En re vanch e , la conve rsion pourrait toujours s e faire par un appe le xplicite , com m e dans :

a = point (3) ; // OK : conversion explicite par le constructeur


a = b + point (5) ; // idem
X. Le s conve rsions de type définie s par l'utilisate ur 165
4. LES CO NVERSIO NS D 'UN TYPE CLASSE
EN UN AUTRE TYPE CLASSE

En fait, les possibilité s q ue nous ve nons de re ncontre r, conce rnant les conve rsions d'un type de bas e e n un
type clas s e , s e gé né ralisent :

• au s e in d'une clas s e A , on pe ut définir un opé rate ur de "cast" ré alisant la conve rsion d'un autre type de
clas s e B, dans le type A ,
• un constructe ur de la clas s e A , re ce vant un argum e nt de type B, ré alise une conve rsion de B e n A.

4.1 Exe m pl
e s im pl
e d'opé rate ur de "cas t"

Le program m e ci-de s s ous illustre la pre m iè re s ituation : l'opé rate ur com plexe de la clas s e point pe rm e t des
conve rsions d'un obje t de type point e n un obje t de type com plexe .

_______________________________________________________________________________
______

#include <iostream.h>
class complexe ;
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) {x=abs ; y=ord ; }
operator complexe () ; // conversion point --> complexe
} ;
class complexe
{ double reel, imag ;
public :
complexe (double r=0, double i=0) { reel=r ; imag=i ; }
friend point::operator complexe () ;
void affiche () { cout << reel << " + " << imag <<"i\n" ; }
} ;
point::operator complexe ()
{ complexe r ; r.reel=x ; r.imag=y ;
cout << "cast "<<x<<" "<<y<<" en "<<r.reel<<" + "<<r.imag<<"i\n" ;
return r ;
}
main()
{ point a(2,5) ; complexe c ;
c = (complexe) a ; c.affiche () ; // conversion explicite
point b (9,12) ;
c = b ; c.affiche () ; // conversion implicite
}
_______________________

cast 2 5 en 2 + 5i
2 + 5i
cast 9 12 en 9 + 12i
9 + 12i
_______________________________________________________________________________
______
166 Program m e r e n langage C+ +
Exe m ple d'utilisation d'un opérate ur de "cas t" pour de s conve rsions point -> com plexe

R e m arque :

D ans ce t e xe m ple, on pe ut dire q ue la conve rsion point -> com plexe q ui s e ram è ne , au bout du com pte ,
à la conve rsion de deux entie rs e n ré e le s t as s e z nature lle e t, de toute façon, pas dégradante . M ais, bie n
e nte ndu, C+ + vous lais s e s e uljuge de la q ualité des conve rsions q ue vous pouve z définir de ce tte
m aniè re .

4.2 Exe m pl
e s im pl
e de conve rs ion par un cons tructe ur

Le program m e ci-aprè s illustre la deuxiè m e s ituation : le constructe ur com plexe (point) re pré s e nte une autre
façon de ré aliser des conve rsions d'un obje t de type point e n un obje t de type com plexe .

_______________________________________________________________________________
______

#include <iostream.h>
class point ;
class complexe
{ double reel, imag ;
public :
complexe (double r=0, double i=0) { reel=r ; imag=i ; }
complexe (point) ;
void affiche () { cout << reel << " + " << imag << "i\n" ; }
} ;
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
friend complexe::complexe (point) ;
} ;
complexe::complexe (point p)
{ reel = p.x ; imag = p.y ; }
main()
{ point a(3,5) ;
complexe c (a) ; c.affiche () ;
} _______________________

3 + 5i
_______________________________________________________________________________
______

Exe m ple d'utilisation d'un cons tructe ur pour de s conve rsions point -> com plexe

R e m arques :

1) La re m arq ue faite pré cédem m e nt à propos de la "q ualité " des conve rsions s'appliq ue tout aussi bien
ici. Nous aurions pu, par e xe m ple, introduire , dans la clas s e point, un constructe ur de la form e point
(com plexe ).
2) En ce q ui conce rne les conve rsions d'un type de bas e e n une clas s e , la s e ule possibilité q ui nous é tait
offe rte consistait à pré voir un constructe ur approprié au s e in de la clas s e . En re vanch e , pour les
X. Le s conve rsions de type définie s par l'utilisate ur 167
conve rsions A -> B (où A e t B sont deux clas s e s ), nous avons le ch oix e ntre place r dans B un
constructe ur B(A) ou place r dans A un opé rate ur de "cast" B().
3) Iln'e s t pas possible de définir sim ultané m e nt la m ê m e conve rsion A -> B e n pré voyant à la fois un
constructe ur B(A) dans B e t un "cast" B() dans A. En e ffe t, ce ci conduirait le com pilate ur à déce ler
une am biguïté dè s lors q u'une conve rsion A -> B s e rait né ce s s aire . Ilfaut signaler ce pe ndant q u'une
te lle anom alie pe ut re s te r cach é e tant q ue le besoin d'une te lle conve rsion ne s e fait pas s e ntir (e n
particulie r, les clas s e s A e t B s e ront com pilée s s ans problèm e , y com pris si elles figure nt dans le
m ê m e fich ie r source ).

4.3 Pour donne r, dans une cl as s e , une s ignification


à un opé rate ur dé fini dans une autre cl as s e

Considérons une clas s e com plexe pour laq ue lle l'opé rate ur + a é té s urdé fini par une fonction am ie 9 , ainsi
q u'une clas s e point m unie d'un opé rate ur de "cast" com plexe (). Supposons a de type point, x de type
com plexe e t considérons l'e xpre s s ion :

x + a

Com pte te nu de s rè gles h abitue lles re lative s aux fonctions surdé finie s (m ise en œuvre d'une ch aî
ne uniq ue de
conve rsions ne conte nant pas plus d'une C.D.U.), le com pilate ur e s t conduit à l'é valuation de ce tte
e xpre s s ion suivant le s ch é m a :

complexe point
| |
| complexe
|___ + ___|
|
complexe

Ce lui-ci fait inte rve nir l'opé rate ur + surdéfini par la fonction indé pe ndante ope rator+ . O n pe ut dire q ue
notre e xpre s s ion x + a e s t e n fait é q uivalente à :

operator + (x, a)

Le m ê m e raisonne m e nt s'appliq ue à l'e xpre s s ion a + x. Quant à l'e xpre s s ion :

a + b

où a e t b sont de type point, e lle e s t é q uivalente à :

operator + (a, b)

e t é valué e s uivant le s ch é m a :

point point
| |
complexe complexe
|____ + ____|
|
complexe

9 - Nous ve rrons q ue ce point e s t im portant : on n'obtie ndrait pas l


e s m ê m e s possibil
ité s ave c une fonction m e m bre.
168 Program m e r e n langage C+ +
Nous vous proposons ci-aprè s un exem ple com plet de program m e illustrant les possibilité s q ue nous ve nons
d'évoq ue r :

_______________________________________________________________________________
______
#include <iostream.h>
class complexe ;
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
operator complexe () ;
void affiche () { cout << "point : " << x << " " << y << "\n" ; }
} ;
class complexe
{ double reel, imag ;
public :
complexe (double r=0, double i=0) { reel=r ; imag=i ; }
void affiche () { cout << reel << " + " << imag << "i \n" ; }
friend point::operator complexe () ;
friend complexe operator + (complexe, complexe) ;
} ;
point::operator complexe ()
{ complexe r ; r.reel = x ; r.imag = y ; return r ; }
complexe operator + (complexe a, complexe b)
{ complexe r ;
r.reel = a.reel + b.reel ; r.imag = a.imag + b.imag ;
return r ;
}

main()
{ point a(3,4), b(7,9), c ;
complexe x(3.5,2.8), y ;
y = x + a ; y.affiche () ; // marcherait encore si + était fct membre
y = a + x ; y.affiche () ; // ne marcherait pas si + était fonction membre
y = a + b ; y.affiche () ; // ne marcherait pas si + était fonction membre
// (voir remarque)
// N.B. : c = a + b n'aurait pas de sens ici
}
_______________________
6.5 + 6.8i
6.5 + 6.8i
10 + 13i
_______________________________________________________________________________
______

Elargis s e m e nt de la signification de l'opérate ur + de la clas s e com plexe

R e m arques :

1) S'ile s t e ffe ctive m e nt possible ici d'é crire :


y = a + b

iln'e s t pas possible d'écrire :


X. Le s conve rsions de type définie s par l'utilisate ur 169
c = a + b

car iln'e xiste pas de conve rsion de com plexe (type de l'e xpre s s ion a + b) e n point.
Pour q ue ce la soit possible, ilsuffirait, par e xe m ple, d'introduire dans la clas s e point un constructe ur
de la form e point (com plexe ). Bie n e nte ndu, ce la ne pré juge nullem e nt de la signification d'une te lle
opé ration, e t e n particulie r de s on aspect dégradant.
2) Si l'opé rate ur + de la clas s e com plexe avait é té défini par une fonction m e m bre de prototype :
complexe complexe::operator + (complexe) ;

l'e xpre s s ion a + x n'aurait pas e u de s e ns, pas plus q ue a + b. En e ffe t, l'appe lde ope rator + , dans
le pre m ie r cas, n'aurait pu ê tre q ue :
a.operator + (x)

Ce ci n'aurait pas é té pe rm is. En re vanch e , l'e xpre s s ion x + a aurait pu corre cte m e nt ê tre é valué e
com m e :
x.operator + (a)

3) Iln'e s t pas toujours aussi avantage ux q ue dans ce t e xe m ple de définir un opé rate ur sous form e d'une
fonction am ie . En particulie r, si un opé rate ur m odifie s on pre m ie r opé rande (supposé ê tre un obje t), il
e s t pré fé rable d'en faire une fonction m e m bre . Dans le cas contraire , e n e ffe t, on ris q ue de voir ce t
opé rate ur agir tout bê te m e nt, non pas sur l'obje t conce rné , m ais sur un obje t (ou une variable)
te m poraire d'un autre type , cré é par une conve rsion im plicite 10. Note z d'ailleurs q ue c'e s t pour ce tte
raison q ue C+ + im pos e q ue les opé rate urs =, [], () e t -> soient toujours surdé finis par de s fonctions
m e m bre .

5. QUELQUES CO NSEILS

Le s possibilités de conve rsions im plicite s ne s ont ce rte s pas infinie s , puis q u'e lles s ont lim ité e s à une ch aî
ne
d'au m axim um trois conve rsions (standard, C.D .U., standard) e t q ue la C.D .U. n'e s t m ise en oeuvre q ue s i
e lle e s t utile.

Elles n'e n re s te nt pas m oins trè s (trop !) rich e s ;une te lle rich e s s e pe ut lais s e r craindre q ue ce rtaine s
conve rsions ne soient m ises en place s ans q ue le conce pte ur de s clas s e s conce rné e s ne l'ait souh aité .

En fait, ilfaut bien voir q ue :

• l'opé rate ur de "cast" doit ê tre introduit délibérém e nt par le conce pte ur de la clas s e ,
• dans la proposition de norm e ANSI, le conce pte ur d'une clas s e pe ut inte rdire l'usage im plicite du
constructe ur dans une conve rsion, e n faisant appe lau m ot clé e xplicit.
Ave c la norm e , ils e ra donc possible d e s e proté ge r totalem e nt contre l'usage des conve rsions im plicite s
re lative s aux clas s e s : ilsuffira de q ualifie r tous les constructe urs ave c e xplicit e t de ne pas introduire
d'opé rate ur de cast.

D 'une m aniè re gé né rale, on aura inté rê t à ré s e rve r ce s possibilités de conve rsions im plicite s à des clas s e s
ayant une forte "connotation m ath é m atiq ue ", dans les q ue lles on aura probablem e nt surdéfini un ce rtain
nom bre d'opérate urs (+ , -, e tc.).

10 - A ucune conve rsion im pl


icite ne pe ut avoir l
ie u s ur l
'obje t appe l
ant une fonction m e m bre.
170 Program m e r e n langage C+ +
L'e xe m ple le plus classique d'une te lle clas s e e s t ce rtaine m e nt ce lui de la clas s e com plexe 11 (q ue nous avons
re ncontrée dans ce ch apitre ). Dans ce cas, ilparaî t nature lde disposer de conve rsions de com plexe e n float,
de float e n com plexe , de int e n com plexe (par le biais de float), e tc.

D e m ê m e , ilparaît nature lde pouvoir ré aliser aussi bien la som m e d'un com plexe e t d'un float q ue ce lle de
deux com plexe s e t donc de profite r de s possibilités de conve rsions im plicite s pour ne définir q u'un s e ul
opé rate ur d'addition (ce lle de deux com plexe s ).

11 - Le proje t de norm e ANSI de C+ + contie nt l


a dé finition de cl
as s e s gé né riq ues de com pl
e xes.
XI. LES PA TRO NS
D E FO NCTIO NS

Nous avons déjà vu com m e nt la surdéfinition de fonctions perm e ttait de donner un nom uniq ue à plusieurs
fonctions ré alisant un travaildiffé re nt. La notion de "patron1" de fonction (on parle aussi de "fonction
gé né riq ue " ou de "m odè le de fonction"), introduite par la ve rsion 3, e s t à la fois plus puissante e t plus
re s trictive ;plus puissante car ilsuffira d'é crire une s e ule fois la définition d'une fonction pour q ue le
com pilate ur puis s e autom atiq ue m e nt l'adapte r à n'im porte q ue ltype ;plus re s trictive puis q ue , par nature
m ê m e , toute s les fonctions ainsi fabriq ué e s par le com pilate ur de vront corre s pondre à la m ê m e définition,
donc au m ê m e algorith m e .

Nous allons com m e nce r par vous présente r ce tte nouve lle notion sur un e xe m ple s im ple ne faisant inte rve nir
q u'un s e ul"param è tre de type ". Nous ve rrons e nsuite q u'e lle s e gé né ralise à un nom bre q ue lconq ue de te ls
param è tre s e t q u'on pe ut é galem e nt faire inte rve nir de s "param è tre s e xpre s s ion". Puis nous étudie rons
com m e nt un patron de fonctions peut, à son tour, ê tre s urdé fini. Enfin, nous ve rrons com m e nt toute s ce s
possibilité s pe uve nt e ncore ê tre affiné e s e n "spécialisant" une ou plusieurs des fonctions d'un patron.

1. EXEM PLE D E CRÉA TIO N ET D 'UTILISATIO N


D 'UN PA TRO N D E FO NCTIO N

1.1 Cré ation d'un patron de fonctions

Suppos e z q ue nous ayons besoin d'écrire une fonction fournissant le m inim um de deux valeurs de m ê m e
type re çue s e n argum e nt. Nous pourrions é crire une définition pour le type int :

int min (int a, int b)


{
if (a < b) return a ; // ou return a < b ? a : b ;
else return b ;
}

1 - En angl
ais : te m pl
ate.
172 Program m e r e n langage C+ +
Bie n e nte ndu, ilnous faudrait probablem e nt é crire une autre définition pour le type float, c'e s t-à -dire (e n
supposant q ue nous lui donnons le m ê m e nom m in, ce q ue nous avons tout inté rê t à faire ) :

float min (float a, float b)


{
if (a < b) return a ; // ou return a < b ? a : b ;
else return b ;
}

Nous serions ainsi am e né à é crire de nom bre uses définitions trè s proch e s les unes des autre s ;e n e ffe t, s e ul
le type conce rné s e rait am e né à ê tre m odifié .

D e puis la ve rsion 3 de C+ + , nous pouvons sim plifie r considérablem e nt les ch os e s e n dé finissant un seul
patron de fonctions, de la m aniè re s uivante :

_______________________________________________________________________________
____

#include <iostream.h>
// création d'un patron de fonctions
template <class T> T min (T a, T b)
{
if (a < b) return a ; // ou return a < b ? a : b ;
else return b ;
}
_______________________________________________________________________________
____

Création d'un patron de fonctions

Com m e vous le constate z, s e ule (ici) l'e n-tê te de notre fonction a ch angé (iln'e n ira pas toujours ainsi) :

template <class T> T min (T a, T b)

La m e ntion te m plate < class T> pré cis e q ue l'on a affaire à un patron (te m plate ) dans leq ue lapparaî t un
2
"param è tre de type " nom m é T ;note z q ue C+ + a décidé d'em ploye r le m ot clé class pour pré cis e r q ue T
e s t un param è tre de type (on aurait pré fé ré type !). Autre m e nt dit, dans la définition de notre fonction, T
re pré s e nte un type q ue lconq ue .

Le re s te de l'e n-tê te :

T min (T a, T b)

pré cis e q ue m in e s t une fonction re ce vant deux argum e nts de type T e t fournissant un ré s ultat du m ê m e type .

1.2 Pre m iè re s util


is ations d e notre patron de fonctions

Pour utiliser le patron m in q ue nous ve nons de cré e r, ilsuffit tout sim plem e nt d'utiliser la fonction m in dans
des conditions approprié e s (c'e s t-à -dire ici de ux argum e nts de m ê m e type ). Ainsi, si dans un program m e
dans leq ue l n e t p sont de type int, nous faisons inte rve nir l'e xpre s s ion m in (n, p), le com pilate ur

2 - O u argum e nt ;ici, nous avons conve nu d'em pl


oyer l
e te rm e param è tre pour l
e s patrons e t l
e te rm e argum e nt pour l
e s fonctions ;m ais
ilne s'agit aucune m e nt d'une conve ntion unive rs e l
le.
XI. Le s patrons d e fonctions 173
"fabriq ue ra" (on dit aussi "instancie ra") autom atiq ue m e nt la fonction m in (dite "fonction patron3")
corre s pondant à des argum e nts de type int. Si nous appe lons m in ave c deux argum e nts de type float, le
com pilate ur "fabriq ue ra" autom atiq ue m e nt une autre fonction patron m in corre s pondant à des argum e nts de
type float e t ainsi de suite .

Com m e on pe ut s'y atte ndre , pour q ue la ch os e s oit possible, ile s t né ce s s aire q ue le com pilate ur dispose de
la définition du patron e n q ue s tion, autre m e nt dit q ue les instructions précédente s pré cè dent une q ue lconq ue
utilisation de m in.

Voici un e xe m ple com plet illustrant ce ci :

_______________________________________________________________________________
____

#include <iostream.h>
// création d'un patron de fonctions
template <class T> T min (T a, T b)
{
if (a < b) return a ; // ou return a < b ? a : b ;
else return b ;
}

// exemple d'utilisation du patron de fonctions min


main()
{
int n=4, p=12 ;
float x=2.5, y=3.25 ;
cout << "min (n, p) = " << min (n, p) << "\n" ; // int min(int, int)
cout << "min (x, y) = " << min (x, y) << "\n" ; // float min (float,
loat)
}
________________________________
min (n, p) = 4
min (x, y) = 2.5
_______________________________________________________________________________
____

D é finition e t utilisation d'un patron de fonctions

R e m arque :

Le s instructions de définition d'un patron re s s e m blent à des instructions e xé cutables de définition de


fonction. Né anm oins, le m é canism e m ê m e des patrons fait q ue ce s instructions sont utilisées par le
com pilate ur pour fabriq ue r (instancie r) ch aq ue fois q u'ile s t né ce s s aire les instructions corre s pondant à la
fonction re q uis e ;e n ce s e ns, ce s ont donc des déclarations : leur pré s e nce e s t toujours néce s s aire e t il
n'e s t pas possible de cré e r un "m odule obje t" corre s pondant à un patron de fonctions.
En fait, tout s e pas s e com m e s i, ave c la notion de patron de fonctions, apparaissaie nt deux nive aux de
déclarations. O n re trouve ra le m ê m e ph é nom è ne pour les patrons de clas s e s . Par la suite , nous
continue rons à parler de "définition d'un patron".
En pratiq ue , on place ra les définitions de patron dans un fich ie r approprié d'exte nsion h .

3 - A tte ntion au vocabul


aire : "patron de fonction" pour l
a fonction gé né riq ue, "fonction patron" pour une ins tance donnée.
174 Program m e r e n langage C+ +

1.3 D 'autre s util


is ations d e notre patron

D e façon gé né rale, notre patron m in pe ut ê tre utilisé pour des argum e nts de n'im porte queltype, q u'il
s'agisse d'un type prédéfini (s h ort, ch ar, double, int *, ch ar *, int * *, e tc.) ou d'un type défini par
l'utilisate ur (notam m e nt structure ou clas s e ).

Par e xe m ple, si n e t p sont de type int, un appe lte lq ue m in (& n, & p) conduira le com pilate ur à instancie r
une fonction int * m in (int *, int *).

Exam inons ici plus e n dé taildeux situations précises :

• argum e nts de type ch ar *,


• argum e nts de type clas s e .

a)Appl
ication au type ch ar *
Voici un pre m ie r e xe m ple dans leq ue lnous e xploitons notre patron m in pour fabriq ue r une fonction portant
sur des ch aî
nes de caractè re s :

_______________________________________________________________________________
____

#include <iostream.h>
template <class T> T min (T a, T b)
{
if (a < b) return a ; // ou return a < b ? a : b ;
else return b ;
}
main()
{
char * adr1 = "monsieur", * adr2 = "bonjour" ;
cout << "min (adr1, adr2) = " << min (adr1, adr2) ;
}
________________________________

min (adr1, adr2) = monsieur


_______________________________________________________________________________
____

Lors q u e l'on applique le patron m in au type ch ar *

Le ré s ultat pe ut surpre ndre , dans la m e s ure où vous vous atte ndie z (pe ut-ê tre ) à ce q ue m in fournis s e "la
ch aî
ne " "bonjour". En fait, ilfaut bien voir q ue , à la re ncontre de l'e xpre s s ion m in (adr1, adr2), le
com pilate ur a gé né ré la fonction suivante :

char * min (char * a, char * b)


{
if (a < b) return a ;
else return b ;
}
XI. Le s patrons d e fonctions 175
La com paraison a<b porte donc sur les valeurs des pointe urs re çus e n argm e nt (ici, a é tait infé rie ur à b,
m ais ilpe ut e n aller autre m e nt dans d'autre s im plém e ntations...). En re vanch e , l'affich age obte nu par
l'opé rate ur < < porte , non plus sur ce s adre s s e s , m ais sur les ch aî
ne s s itué e s à ce s adre s s e s .

b)Appl
ication à un type cl
as s e
Pour pouvoir appliq ue r notre patron m in à une clas s e , ile s t bien sûr nécessaire que l'opé rate ur < puis s e
s'appliq ue r à deux opérandes de ce type clas s e . En voici un e xe m ple dans leq ue lnous appliq uons m in à deux
obje ts de type ve ct dans leq ue ll'opé rate ur < fournit un ré s ultat bas é s ur le "m odule" des ve cte urs :

_______________________________________________________________________________
____

#include <iostream.h>
// le patron de fonctions min
template <class T> T min (T a, T b)
{ if (a < b) return a ;
else return b ;
}
// la classe vect
class vect
{ int x, y ;
public :
vect (int abs=0, int ord=0) { x=abs ; y=ord; }
void affiche () { cout << x << " " << y ; }
friend int operator < (vect, vect) ;
} ;
int operator < (vect a, vect b)
{ return a.x*a.x + a.y*a.y < b.x*b.x + b.y*b.y ;
}
// un exemple d'utilisation de min
main()
{
vect u (3, 2), v (4, 1), w ;
w = min (u, v) ;
cout << "min (u, v) = " ; w.affiche() ;
} ________________________________

min (u, v) = 3 2
_______________________________________________________________________________
____

U tilisation du patron m in pour la clas s e ve ct

Nature llem e nt, si nous ch e rch ions à appliq ue r notre patron m in à une clas s e pour laq ue lle l'opé rate ur <
n'e s t pas défini, le com pilate ur le s ignalerait e xacte m e nt de la m ê m e m aniè re q ue s i nous avions é crit nous-
m ê m e s la fonction m in pour ce type .

R e m arque :

Un patron de fonctions pourra s'appliq ue r à des clas s e s patron, c'e s t-à -dire à un type de clas s e instancié
par un patron de clas s e . Nous e n ve rrons des exe m ples dans le proch ain ch apitre .
176 Program m e r e n langage C+ +

2. LES PARAMÈTRES D E TYPE D 'UN PA TRO N D E FO NCTIO NS

Ce paragraph e fait le point sur la m aniè re dont pe uve nt inte rve nir les param è tres de type dans un patron de
fonctions, sur l'algorith m e q ui pe rm e t au com pilate ur d'instancie r la fonction voulue e t sur les problèm e s
particulie rs q u'ilpe ut pos e r.

Note z q u'un patron de fonctions peut é galem e nt com porte r ce q ue l'on nom m e des "param è tre s e xpre s s ion",
les q ue ls corre s ponde nt e n fait à la notion usuelle d'argum e nt d'une fonction. Ils s e ront é tudiés dans le
paragraph e s uivant.

2.1 Util
is ation de s param è tre s de type dans l
a dé finition d'un patron

D 'une m aniè re gé né rale, un patron de fonctions peut donc com porte r un ou plusieurs param è tres de type ,
ch acun de vant ê tre pré cédé du m ot clé class, par e xe m ple :

template <class T, class U> fct (T a, T * b, U c)


{ ...
}

Ce s param è tre s pe uve nt inte rve nir à n'im porte q ue le ndroit de la définition d'un patron4, c'e s t-à -dire :

• dans l'e n-tê te (c'é tait le cas de nos exem ples pré cédents),
• dans des déclarations 5 de variables locales (de l'un de s types des param è tre s ),
• dans les instructions e xé cutables 6 (par e xe m ple ne w , size of (...)).
En voici un sim ple e xe m ple d'école :

template <class T, class U> fct (T a, T * b, U c)


{
T x ; // variable locale x de type T
U * adr ; // variable locale adr de type U *
...
adr = new T [10] ; // allocation tableau de 10 éléments de type T
...
n = sizeof (T) ;
...
}

D ans tous les cas, ile s t né ce s s aire q ue ch aque param è tre de type apparais s e au m oins une fois dans l 'en-
tê te du patron ;com m e nous le ve rrons, ce tte condition e s t parfaite m e nt logiq ue puis q ue c'e s t pré cis é m e nt
grâ ce à la nature de ce s argum e nts q ue le com pilate ur s e ra e n m e s ure d'instancie r corre cte m e nt la fonction
né ce s s aire .

4 - De la m ê m e m aniè re q u'un nom de type peut inte rve nir dans l


a dé finition d'une fonction.
5 - Notez bien qu'ils'agit al ors de déclarations, au sein de l a dé finition du patron, c'e s t-à -dire final
e m e nt de décl
arations au s e in de
déclarations.
6 - Nous parl ons d'instructions e xé cutabl
es bien qu'il s'agisse toujours de décl
arations (puisque l
a dé finition d'un patron e s t une
décl
aration) ;e n toute rigue ur, ce s ins tructions donneront nais s ance à des instructions e xé cutabl
e s à ch aq ue ins tanciation d'une nouve l
le
fonction.
XI. Le s patrons d e fonctions 177
2.2 Ide ntification de s param è tre s de type d'une fonction patron

Nos pré cédents e xe m ples é taie nt suffisam m e nt sim ples pour q ue l'on "de vine " q ue lle é tait la fonction
instancié e pour un appe ldonné . M ais, considérons à nouve au notre patron m in :

template <class T> T min (T a, T b)


{ if (a < b) return a ;
else return b ;
}

ave c ces déclarations :

int n ; char c ;

Que va faire le com pilate ur e n pré s e nce d'un appe lte lq ue m in (n,c) ou m in(c,n) ?En fait, la rè gle pré vue
par C+ + dans ce cas e s t q u'ildoit y avoir correspondance exacte des type s . Ce la signifie q ue nous ne
pouvons utiliser notre patron m in q ue pour de s appe ls dans les q ue ls les deux argum e nts ont l e m ê m e type.
M anife s te m e nt, ce n'e s t pas le cas dans nos deux appels, q ui aboutiront à une e rre ur de com pilation. O n
note ra q ue , dans ce tte corre s pondance e xacte , les é ve ntue ls q ualifie urs cons t ou volatile inte rvie nne nt.

Voici, à titre indicatif, q ue lque s e xe m ples d'appe ls de m in q ui pré cis e nt q ue lle s e ra la fonction instancié e
lors q ue l'appe le s t corre ct :

int n ; char c ; unsigned int q ;


const int ci1 = 10, ci2 = 12 ;
int t[10] ;
int * adi ;
...
min (n, c) // erreur
min (n, q) // erreur
min (n, ci1) // erreur : const int et int ne correspondent pas
min (ci1, ci2) // min (const int, const int)
min (t, adi) // min (int *, int *) car ici, t est converti en int *, avant
appel

Ile s t toute fois possible, dans un appe lde fonction patron, de s pé cifie r tout ou partie des param è tres de type
à utiliser. Voici q ue lque s e xe m ples utilisant les déclarations précédente s :

min<int> (c, n) /* force l'utilisation de min<int>, et donc la conversion


*/
/* de c en int ; le résultat sera de type int
*/
min<char> (q, n) /* force l'utilisation de min<char>, et donc la conversion
*/
/* de q et de n en char ; le résultat sera de type char
*/

Voici un autre e xe m ple faisant inte rve nir plusieurs param è tres de type :

template <class T, class U> T fct (T x, U y, T z)


{ return x + y + z ;
}

main ()
{ int n = 1, p = 2, q = 3 ;
float x = 2.5, y = 5.0 ;
178 Program m e r e n langage C+ +
cout << fct (n, x, p) << "\n" ; // affiche la valeur (int) 5
cout << fct (x, n, y) << "\n" ; // affiche la valeur (float) 8.5
cout << fct (n, p, q) << "\n" ; // affiche la valeur (int) 6
cout << fct (n, p, x) << "\n" ; // erreur : pas de correspondance
}

Ici, e ncore , on pe ut force r ce rtains des param è tres de type , com m e dans ce s e xe m ples :

fct<int,float> (n, p, x) // force l'utilisation de fct<int,float> et donc la


// conversion de p en float et de x en int
fct<float> (n, p, x ) // force l'utilisation de float pour T ; U est
déterminé
// par les règles habituelles, c’est-à-dire int (type
de p)
// n sera converti en float

2.3 Nouve l le s y ntaxe d'initial


is ation de s variabl
es
de s type s s tandard

D è s lors q ue , dans un patron de fonctions, un param è tre de type e s t susce ptible de corre s pondre tantôt à un
type s tandard, tantôt à un type clas s e , un problèm e apparaît si l'on doit déclare r, au s e in du patron, un obje t
de ce type e n transm e ttant un ou plusieurs argum e nts à son constructe ur. Voye z ce t e xe m ple :

template <class T> fct (T a)


{ T x (3) ; // x est un objet local de type x qu'on construit
// en transmettant la valeur 3 à son constructeur
// ...
}

Tant q ue l'on utilise une fonction fct pour un type clas s e , tout va bien. En re vanch e , si l'on ch e rch e à
l'utiliser pour un type s tandard, par e xe m ple int, le com pilate ur e s t am e né à gé né re r la fonction suivante :

fct (int a)
{ int x (3) ;
// ...
}

Pour q ue l'instruction int x(3) ne pos e pas de problèm e , C+ + a pré vu q u'e lle s oit sim plem e nt inte rpré té e
com m e une initialisation de x ave c la valeur 3, c'e s t-à -dire com m e :

int x = 3 ;

En th é orie , ce tte possibilité e s t utilisable dans n'im porte q ue lle instruction C+ + , de sorte q ue vous pourrie z
trè s bien écrire :

double x(3.5) ; // au lieu de double x = 3.5 ;


char c('e') ; // au lieu de char c = 'e' ;

En pratiq ue , ce la s e ra rare m e nt utilisé de ce tte façon.


XI. Le s patrons d e fonctions 179
2.4 Lim itations d e s patrons d e fonctions

Lors q ue l'on dé finit un patron de clas s e , à un param è tre de type pe ut th é oriq ue m e nt corre s pondre n'im porte
q ue l type e ffe ctif (standard ou clas s e ). Il n'e xiste a priori aucun m é canism e intrinsè q ue pe rm e ttant
d'inte rdire l'instanciation pour ce rtains type s .

Ainsi, si un patron a un e n-tê te de la form e :

template <class T> void fct (T)

on pourra appe ler fct ave c un argum e nt de n'im porte q ue ltype : int, float, int *, int **t, t *ou m ê m e t **
(t désignant un type clas s e q ue lconq ue )...

Ce pe ndant, un ce rtain nom bre d'élém e nts peuve nt inte rve nir indire cte m e nt pour faire é ch oue r
l'instanciation.

Tout d'abord, on pe ut im pos e r q u'un param è tre de type corre s ponde à un pointe ur. Ainsi, ave c un patron
d'en-tê te :

template <class T> void fct (T *)

on ne pourra appe ler fct q u'ave c un pointe ur sur un type q ue lconq ue : int *, int **, t *ou t **. Dans les
autre s cas, on aboutira à une e rre ur de com pilation.

Par ailleurs, dans la définition d'un patron pe uve nt apparaître des instructions q ui s'avé re ront incorre cte s
lors de la te ntative d'instanciation pour ce rtains type s .

Par e xe m ple, notre patron m in :

template <class T> T min (T a, T b)


{ if (a < b) return a ;
else return b ;
}

ne pourra pas s'appliq ue r si T corre s pond à un type classe dans leq ue ll'opé rate ur < n'a pas é té s urdé fini.

D e m ê m e , un patron de ce ge nre :

template <class T> void fct (T)


{ ...
T x (2, 5) ; // objet local de type T, initialisé par un constructeur à 2
arguments
...
}

ne pourra pas s'appliq ue r à un type clas s e pour leq ue ln'e xiste pas un constructe ur à deux argum e nts.

En dé finitive , bie n q u'iln'e xiste pas de m é canism e form e lde lim itation, les patrons de fonctions peuve nt
né anm oins com porte r dans leur dé finition m ê m e un ce rtain nom bre d'élém e nts q ui e n lim ite ront la porté e .

3. LES PARAMÈTRES EXPRESSIO N D 'UN PA TRO N D E FO NCTIO NS

Com m e nous l'avons déjà é voq ué , un patron de fonctions peut com porte r de s "param è tre s e xpre s s ion". Il
s'agit e n fait tout sim plem e nt de param è tre s (m ue ts) "ordinaire s ", analogue s à ce ux q u'on trouve dans la
180 Program m e r e n langage C+ +
définition d'une fonction. Voye z ce t e xe m ple dans leq ue l nous définissons un patron nom m é com pte
pe rm e ttant de fabriq ue r de s fonctions com ptabilisant le nom bre d'élém e nts nuls d'un tableau de type
q ue lconq ue e t de taille q ue lconq ue .

_______________________________________________________________________________
____

#include <iostream.h>
template <class T> int compte (T * tab, int n)
{ int i, nz=0 ;
for (i=0 ; i<n ; i++) if (!tab[i]) nz++ ;
return nz ;
}
main ()
{ int t [5] = { 5, 2, 0, 2, 0} ;
char c[6] = { 0, 12, 0, 0, 0} ;
cout << "compte (t) = " << compte (t, 5) << "\n" ;
cout << "compte (c) = " << compte (c, 6) << "\n" ;
} ________________________________

compte (t) = 2
compte (c) = 4
_______________________________________________________________________________
____

Exe m ple de patron de fonctions com portant un param è tre e xpre s s ion (n)

O n pe ut dire q ue notre patron com pte définit une fam ille de fonctions com pte , dans laq ue lle le type du
pre m ie r argum e nt e s t variable (e t donc dé fini par l'appe l), tandis q ue le s e cond e s t de type im pos é (ici int).
Com m e on pe ut s'y atte ndre , dans un appe lde com pte , s e ulle type du prem ie r argum e nt inte rvie nt dans le
code de la fonction instancié e .

D 'une m aniè re gé né rale un patron de fonctions peut disposer d'un ou de plusieurs param è tre s e xpre s s ion.
Lors de l'appe l, leur type n'a plus besoin de corre s pondre e xacte m e nt à ce lui atte ndu : ilsuffit q u'ilsoit
acce ptable par affe ctation, com m e dans n'im porte q ue lappe ld'une fonction ordinaire .

4. SURD ÉFINITIO N D E PA TRO NS

D e m ê m e q u'ile s t possible de surdé finir une fonction classique, ile s t possible de surdé finir un patron de
fonctions, c'e s t-à -dire de définir plusieurs patrons possédant des argum e nts diffé re nts. O n note ra q ue ce tte
situation conduit e n fait à définir plusieurs "fam illes " de fonctions (ily a bie n plusieurs définitions de
fam illes , e t non plus sim plem e nt plusieurs définitions de fonctions) ;e lle ne doit pas ê tre confondue ave c la
spécialisation d'un patron de fonctions q ui consiste à surdéfinir une ou plusieurs des fonctions de la fam ille
e t q ue nous é tudie rons dans le paragraph e s uivant.

4.1 Exe m pl e s de s urdé finition de patron de fonctions ne com portant q ue de s


param è tre s de type

Voye z ce t e xe m ple, dans leq ue lnous avons surdé fini de ux patrons de fonctions m in, de façon à disposer :
XI. Le s patrons d e fonctions 181
• d'une pre m iè re fam ille de fonctions à deux argum e nts de m ê m e type q ue lconq ue (com m e dans nos
pré cédents e xe m ples ),
• d'une s e conde fam ille de fonctions à trois argum e nts de m ê m e type q ue lconq ue .

_______________________________________________________________________________
____

#include <iostream.h>
// patron numero I
template <class T> T min (T a, T b)
{
if (a < b) return a ;
else return b ;
}
// patron numero II
template <class T> T min (T a, T b, T c)
{
return min (min (a, b), c) ;
}
main()
{
int n=12, p=15, q=2 ;
float x=3.5, y=4.25, z=0.25 ;
cout << min (n, p) << "\n" ; // patron no I int min (int, int)
cout << min (n, p, q) << "\n" ; // patron no II int min (int, int, int)
cout << min (x, y, z) << "\n" ; // patron no II float min (float, float,
float)
}
_______________________________________________________________________________
____

Exe m ple de s u rdéfinition de patron de fonctions (1)

D 'une m aniè re gé né rale, on pe ut surdéfinir de s patrons possédant un nom bre diffé re nt de param è tres de type
(dans notre e xe m ple, il n'y e n avait q u'un dans ch aq ue patron m in) e t les e n-tê tes des fonctions
corre s pondante s pe uve nt ê tre aussi varié s q u'on le désire . M ais il e s t souh aitable q u'il n'y ait aucun
re coupe m e nt e ntre les diffé re nte s fam illes de fonctions corre s pondant à ch aq ue patron. Si te ln'e s t pas le cas,
une am biguïté ris q ue d'apparaî tre ave c ce rtains appe ls.

Voici un autre e xe m ple dans leq ue lnous avons défini plusieurs patrons de fonctions m in à deux argum e nts,
afin de traite r conve nablem e nt les trois situations suivante s :

• deux valeurs de m ê m e type (com m e dans les paragraph e s pré cédents),


• un pointe ur sur une valeur d'un type donné et une valeur de ce m ê m e type ,
• une valeur d'un type donné et un pointe ur sur une valeur de ce m ê m e type .

_______________________________________________________________________________
____

#include <iostream.h>
// patron numéro I
182 Program m e r e n langage C+ +
template <class T> T min (T a, T b)
{ if (a < b) return a ;
else return b ;
}
// patron numéro II
template <class T> T min (T * a, T b)
{ if (*a < b) return *a ;
else return b ;
}
// patron numéro III
template <class T> T min (T a, T * b)
{ if (a < *b) return a ;
else return *b ;
}
main()
{ int n=12, p=15 ;
float x=2.5, y=5.2 ;
cout << min (n, p) << "\n" ; // patron numéro I int min (int, int)
cout << min (&n, p) << "\n" ; // patron numéro II int min (int *, int)
cout << min (x, &y) <<"\n" ; // patron numéro III float min (float, float
*)
cout << min (&n, &p) << "\n" ; // patron numéro I int * min (int *, int *)
}
________________________________
12
12
2.5
0x210d2336
_______________________________________________________________________________
____

Exe m ple de s u rdéfinition de patron de fonctions (2)

Le s trois prem ie rs appe ls ne posent pas de problèm e . En re vanch e , un appe lte lq ue m in (& n, & p) conduit à
instancie r, à l'aide du patron num é ro I la fonction :

int * min (int *, int *)

La valeur fournie alors par l'appe le n q ue s tion e s t la plus petite des deux valeurs (de type int *) & n e t & p. Il
e s t probable q ue ce ne s oit pas le ré s ultat atte ndu par l'utilisate ur (nous avons déjà re ncontré ce ge nre de
problèm e dans le paragraph e 1 e n appliq uant m in à des ch aî ne s 7).

Pour l'instant, note z q u'ilne faut pas e s pé re r am é liore r la situation e n dé finissant un patron supplém e ntaire
de la form e :

template <class T> T min (T * a, T * b)


{ if (*a < *b) return *a ;
else return *b ;
}

7 - M ais ce probl
è m e pourra s e ré gl
e r conve nabl
e m e nt ave c l
a s pé cial
isation de patron, ce q ui n'e s t pas l
e cas du probl
è m e q ue nous
e xpos ons ici.
XI. Le s patrons d e fonctions 183
En e ffe t, les q uatre fam illes de fonctions ne seraie nt alors plus totalem e nt indé pe ndante s . Plus précisém e nt,
si les trois prem ie rs appe ls fonctionne nt toujours conve nablem e nt, l'appe lm in (& n, & p) conduit alors à une
am biguïté puis q ue deux patrons convie nne nt m ainte nant (ce lui q ue nous ve nons d'introduire e t le pre m ie r).

4.2 Exe m pl
e s de s urdé finition de patron de fonctions
com portant de s param è tre s e xpre s s ion

R appe lons q ue ce rtaine s im plém e ntations autoris e nt les param è tre s e xpre s s ion. D ans ce s conditions, la
surdéfinition de patron pre nd un caractè re plus général. Dans l'e xe m ple s uivant, nous avons défini de ux
fam illes de fonctions m in :

• l'une pour dé te rm ine r le m inim um de deux valeurs de m ê m e type q ue lconq ue ,


• l'autre pour dé te rm ine r le m inim um des valeurs d'un tableau de type q ue lconq ue e t de taille q ue lconq ue
(fournie e n argum e nt sous form e d'un entie r).

_______________________________________________________________________________
____

#include <iostream.h>
// patron I
template <class T> T min (T a, T b)
{ if (a < b) return a ;
else return b ;
}
// patron II
template <class T> T min (T * t, int n)
{ int i ;
T min = t[0] ;
for (i=1 ; i<n ; i++) if (t[i] < min) min=t[i] ;
return min ;
}
main()
{ long n=2, p=12 ;
float t[6] = {2.5, 3.2, 1.5, 3.8, 1.1, 2.8} ;
cout << min (n, p) ; // patron I long min (long, lon)
cout << min (t, 6) ; // patron II float min (float *, int)
}
_______________________________________________________________________________
____

Exe m ple de s u rdéfinition de patrons com portant un param è tre e xpre s s ion

Note z q ue s i plusieurs patrons sont susce ptibles d'ê tre e m ployé s e t q u'ils ne se distingue nt q ue par le type de
leurs param è tre s e xpre s s ion, ce s ont alors les rè gles de ch oix d'une fonction surdéfinie ordinaire q ui
s'appliq ue nt.

5. SPÉCIA LISATIO N D E FO NCTIO NS D E PA TRO N

Un patron de fonctions définit une fam ille de fonctions à partir d'une s e ule définition. Autre m e nt dit, toute s
les fonctions de la fam ille ré alisent le m ê m e algorith m e . Dans certains cas, ce ci pe ut s'avé re r pé nalisant.
184 Program m e r e n langage C+ +
Nous l'avons d'ailleurs déjà re m arq ué dans le cas du patron m in du paragraph e 1 : le com porte m e nt obte nu
lors q u'on l'appliq uait au type ch ar *ne nous satisfaisait pas.

La notion de s pé cialisation offre une s olution à ce problèm e . En e ffe t, C+ + vous autoris e à fournir, outre la
définition d'un patron, la définition d'une ou de plusieurs fonctions pour ce rtains types d'argum e nts. Voici,
par e xe m ple, com m e nt am é liore r notre patron m in du paragraph e 1 e n fournissant une ve rsion spécialisée
pour les ch aîne s :

_______________________________________________________________________________
____

#include <iostream.h>
#include <string.h> // pour strcmp
// patron min
template <class T> T min (T a, T b)
{ if (a < b) return a ; else return b ;
}
// fonction min pour les chaines
char * min (char * cha, char * chb)
{ if (strcmp (cha, chb) < 0) return cha ;
else return chb ;
}
main()
{ int n=12, p=15 ;
char * adr1 = "monsieur", * adr2 = "bonjour" ;
cout << min (n, p) << "\n" ; // patron int min (int, int)
cout << min (adr1, adr2) ; // fonction char * min (char *, char *)
}
________________________________
12
bonjour
_______________________________________________________________________________
____

Exe m ple de s pécialisation d'une fonction d'un patron

R e m arque

En th é orie , d'aprè s la norm e ANSI (m ais pas dans la ve rsion 3), ile s t possible d'effe ctue r ce q ue l'on
nom m e des spé cialisations partie lles , c’
e s t-à -dire de définir de s fam illes de fonctions, ce rtaine s é tant plus
gé né rales q ue d'autre s , com m e dans :
template <class T, class U> void fct (T a, U b) { ..... }
template <class T> void fct (T a, T b) { ..... }

M anife s te m e nt la deuxiè m e définition e s t plus spé cialisée que la pre m iè re e t devrait ê tre utilisée dans des
appe ls de fct dans les q ue ls les deux argum e nts sont de m ê m e type .
En pratiq ue , toute s les im plém e ntations ne traite nt pas e ncore conve nablem e nt de te lles s ituations e t nous
n'e ntre rons pas plus dans les détails.
XI. Le s patrons d e fonctions 185
6. LES PA TRO NS D E FO NCTIO NS D 'UNE M A NIÈRE GÉNÉRA LE

D 'une m aniè re gé né rale, on pe ut donc dé finir un ou plusieurs patrons de m ê m e nom (surdéfinition), ch acun
possédant s e s propre s param è tres de type e t é ve ntue llem e nt des param è tre s e xpre s s ion. D e plus, ile s t
possible de fournir de s fonctions "ordinaire s " portant le m ê m e nom q u'un patron ;on parle dans ce cas de
spécialisation d'une fonction de patron.

Ce paragraph e s e propose de faire le point conce rnant l'algorith m e utilisé par le com pilate ur dans
l'instanciation (ou l'appe l) de la fonction corre s pondant à un appe ldonné .

D ans un pre m ie r te m ps, on e xam ine toute s les fonctions "ordinaire s " ayant le nom voulu e t on s'inté re s s e
aux corre s pondance s e xacte s . Si une s e ule convie nt, le problèm e e s t ré s olu. S'ile n e xiste plusieurs, ily a
am biguïté ;une e rre ur de com pilation e s t déte cté e e t la re ch e rch e e s t inte rrom pue .

Si aucune fonction ordinaire ne ré alise de corre s pondance e xacte , on e xam ine alors tous les patrons ayant le
nom voulu, e n ne considérant q ue les param è tres de type . Si une s e ule corre s pondance e xacte e s t trouvé e , la
fonction corre s pondante e s t instancié e 8 e t le problèm e e s t ré s olu. S'ily en a plusieurs, on exam ine tout
d'abord si l'on e s t e n pré s e nce d'une spécialisation partie lle, auq ue lcas l'on ch oisit le patron le plus
spécialisé 9 ;sinon l'am biguïté conduit à une e rre ur de com pilation e t la re ch e rch e e s t inte rrom pue

Enfin, si aucun patron de fonctions ne convie nt, on e xam ine à nouve au toute s les fonctions "ordinaire s " e n
les traitant ce tte fois com m e de sim ples fonctions surdé finie s (prom otions num é riq ue s , conve rsions
standard10...).

R e m arque

Ile s t tout à fait possible q ue la définition d'un patron fas s e inte rve nir à son tour une fonction patron
(c'e s t-à -dire une fonction susce ptible d'ê tre instancié e à partir d'un autre patron).

8 - D u m oins, si el
le n'a pas déjà é té ins tanciée.
9 - R appe l
ons q ue l a possibilité de spécial isation partie l
le des patrons de fonctions n'e s t pas corre cte m e nt gé ré e par toute s l
es
im plé m e ntations.
10 - R e voyez éve ntue l
le m e nt l
e paragraph e 5.3 du ch apitre 4.
XII. LES PA TRO NS D E CLASSES

Nous avons vu dans le pré cédent ch apitre com m e nt C+ + pe rm e ttait, grâ ce à la notion de patron de
fonctions, de définir une fam ille de fonctions param é tré e s par un ou plusieurs type s e t, é ve ntue llem e nt, des
e xpre s s ions. D'une m aniè re com parable, C+ + vous perm e t (é galem e nt depuis la ve rsion 3) de définir de s
"patrons de clas s e s ". Là e ncore , ilsuffira dé crire une s e ule fois la définition de la clas s e pour q ue le
com pilate ur puis s e autom atiq ue m e nt l'adapte r à diffé re nts type s .

Com m e nous l'avons fait pour les patrons de fonctions, nous com m e nce rons par vous présente r ce tte notion
de patron de clas s e s s ur un e xe m ple s im ple ne faisant inte rve nir q u'un param è tre de type . Nous ve rrons
e nsuite q u'e lle s e gé né ralise à un nom bre q ue lconq ue de param è tres de type e t de param è tre s e xpre s s ion.
Puis nous exam ine rons la possibilité de spé cialiser un patron de clas s e s , soit e n spécialisant ce rtaines de ses
fonctions m e m bre , soit e n spécialisant toute une clas s e . Nous fe rons alors le point sur l'instanciation de
clas s e s patron, notam m e nt e n ce q ui conce rne l'ide ntité de deux clas s e s . Nous ve rrons e nsuite com m e nt s e
gé né ralisent les déclarations d'am itiés dans le cas de patrons de clas s e s . Nous te rm ine rons sur un e xe m ple
d'utilisation de clas s e s patrons im briq ué e s e n vue de m anipuler de s tableaux (d'obje ts) à deux indice s .

Signalons dè s m ainte nant q ue , m algré leurs re s s e m blance s , les notions de patron de fonctions e t de patron de
clas s e s re cè lent des diffé re nce s as s e z im portante s . Com m e vous le ve rre z, ce ch apitre n'e s t nullem e nt
l'e xtrapolation aux classes du précédent ch apitre consacré aux fonctions.

1. EXEM PLE D E CRÉA TIO N ET D 'UTILISATIO N


D 'UN PA TRO N D E CLASSES

1.1 Cré ation d'un patron de cl


as s e s

Nous avons souve nt é té am e né à cré e r une clas s e point de ce ge nre (nous ne fournissons pas ici la définition
des fonctions m e m bre ) :

class point
{ int x ; int y ;
public :
point (int abs=0, int ord=0) ;
void affiche () ;
// .....
}

Lors q ue nous procédons ainsi, nous im posons aux coordonnées d'un point d'ê tre des valeurs de type int. Si
nous souh aitons disposer de points à coordonnées d'un autre type (float, double, long, unsigne d int...), nous
devons définir une autre clas s e e n re m plaçant sim plem e nt, dans notre pré cédente clas s e , le m ot clé int par le
nom de type voulu.
XII. Le s patrons d e clas s e s 187
Nous pouvons, ici e ncore , sim plifie r considérablem e nt les ch os e s e n dé finissant un s e ulpatron de clas s e e n
procédant ainsi :

template <class T> class point


{ T x ; T y ;
public :
point (T abs=0, T ord=0) ;
void affiche () ;
} ;

Com m e dans le cas des patrons de fonctions, la m e ntion te m plate < class T> pré cis e q ue l'on a affaire à un
patron (te m plate ) dans leq ue lapparaî t un param è tre de type nom m é T ;rappe lons q ue C+ + a décidé
d'em ploye r le m ot clé class pour pré cis e r q ue T e s t un argum e nt de type (pas forcé m e nt clas s e ...).

Bie n e nte ndu, la définition de notre patron de clas s e s n'e s t pas e ncore com plète puis q u'ily m anq ue la
définition de s fonctions m e m bre , à savoir, ici, le contructe ur point e t la fonction affich e . Pour ce faire , la
dém arch e va légè re m e nt diffé re r suivant q ue la fonction conce rné e e s t e n ligne ou non.

Pour une fonction e n ligne , les ch os e s re s te nt nature lles ;ilsuffit sim plem e nt d'utiliser le param è tre T à bon
e s cie nt. Voici par e xe m ple com m e nt pourrait ê tre défini notre constructe ur :

point (T abs=0, T ord=0)


{ x = abs ; y = ord ;
}

En re vanch e , lors q ue la fonction e s t définie e n de h ors de la définition de la clas s e , ile s t né ce s s aire de


rappe ler au com pilate ur :

• q ue , dans la définition de ce tte fonction, vont apparaî tre des param è tres de type ;pour ce faire , on
fournira à nouve au la liste de param è tre s ous la form e :
template <class T>

• le nom du patron conce rné (de m ê m e q u'ave c une clas s e "ordinaire ", ilfallait pré fixe r le nom de la
fonction du nom de la clas s e ...) ;par e xe m ple, si nous définissons ainsi la fonction affich e , son nom
s e ra :
point<T>::affiche ()

En dé finitive , voici com m e nt s e pré s e nte rait l'e n-tê te de la fonction affich e si nous le définissions ainsi en
deh ors de la clas s e :

template <class T> void point<T>::affiche ()

Note z q u'e n toute rigue ur le rappe ldu param è tre T à la suite du nom de patron (point) e s t "redondant1"
puis q ue ce param è tre a déjà é té s pé cifié dans la liste de param è tre s s uivant le m ot clé te m plate .

Voici ce q ue pourrait ê tre finalem e nt la définition de notre patron point :

_______________________________________________________________________________
____

#include <iostream.h>
// création d'un patron de classe
template <class T> class point

1 - Strous trup, l
ui-m ê m e, se conte nte de m e ntionne r ce tte redondance, sans l
a jus tifie r.
188 Program m e r e n langage C+ +
{ T x ; T y ;
public :
point (T abs=0, T ord=0)
{ x = abs ; y = ord ;
}
void affiche () ;
} ;
template <class T> void point<T>::affiche ()
{
cout << "Coordonnées : " << x << " " << y << "\n" ;
}
_______________________________________________________________________________
____

Création d'un patron de clas s e s

1.2 Util
is ation d'un patron de cl
as s e s

Une fois ainsi cré é un te lpatron, une déclaration te lle q ue :

point <int> ai ;

am è ne ra le com pilate ur à "instancie r" la définition d'une clas s e point dans laq ue lle le param è tre T pre nd la
valeur int. Autre m e nt dit, tout s e pas s e ra com m e s i nous avions fourni une définition com plète de ce tte
clas s e .

Si nous déclarons :

point <double> ad ;

le com pilate ur instancie ra la définition d'une clas s e point dans laq ue lle le param è tre T pre nd la valeur
double, e xacte m e nt com m e s i nous avions fourni une autre définition com plète de ce tte clas s e .

Si nous avons besoin de fournir de s argum e nts au constructe ur, nous le fe rons classiquem e nt com m e dans :

point <int> ai (3, 5) ;


point <double> ad (3.5, 2.3) ;

R e m arque :

Com m e on pe ut s'y atte ndre , les instructions définissant un patron de clas s e s s ont des déclarations au
m ê m e titre q ue le s ont les instructions définissant une clas s e (y com pris les instructions de définition de
fonctions e n ligne ).
M ais ile n va de m ê m e pour les fonctions m e m bre q ui ne s ont pas e n ligne : leurs instructions sont
né ce s s aire s au com pilate ur pour instancie r ch aq ue fois q ue né ce s s aire les instructions re q uis e s . O n
re trouve ici la m ê m e re m arq ue q ue ce lle q ue nous avons form ulée pour les patrons de fonctions.
Ainsi n'est-ilpas possible de livre r à un utilisate ur une clas s e patron toute com pilée : ilfaudra lui e n
fournir les instructions source de toute s les fonctions m e m bre (alors q ue pour une clas s e "ordinaire " il
suffit de lui fournir la déclaration de la clas s e e t un m odule obje t corre s pondant aux fonctions m e m bre ).
XII. Le s patrons d e clas s e s 189
1.3 Exe m pl
e ré capitul
atif

Voici un e xe m ple com plet re pre nant à la fois :

• la cré ation d'un patron de clas s e s point, com portant un constructe ur e n ligne e t une fonction m e m bre
(affich e ) non e n ligne ,
• un e xe m ple d'utilisation.

_______________________________________________________________________________
____

#include <iostream.h>
// création d'un patron de classe
template <class T> class point
{
T x ; T y ;
public :
point (T abs=0, T ord=0)
{ x = abs ; y = ord ;
}
void affiche () ;
} ;
template <class T> void point<T>::affiche ()
{
cout << "Coordonnées : " << x << " " << y << "\n" ;
}

main ()
{
point <int> ai (3, 5) ; ai.affiche () ;
point <char> ac ('d', 'y') ; ac.affiche () ;
point <double> ad (3.5, 2.3) ; ad.affiche () ;
}
________________________________
coordonnées : 3 5
coordonnées : d y
coordonnées : 3.5 2.3
_______________________________________________________________________________
____

Création e t utilisation d'un patron de clas s e s

R e m arques :

1) Le com porte m e nt de point< ch ar> e s t satisfaisant si nous souh aitons e ffe ctive m e nt disposer de points
re pé ré s par de s (vrais) caractè re s . Si, e n re vanch e , nous avons utilisé le type ch ar pour dispose r de
"pe tits e ntie rs", le ré s ultat e s t m oins satisfaisant ;e n e ffe t, nous pourrons ce rte s toujours déclare r un
point de ce tte façon :
point <char> pc (4, 9) ;

M ais le com porte m e nt de la fonction affich e ne nous convie ndra plus (nous obtie ndrons les caractè re s
ayant pour code les coordonnées du point !).
19 0 Program m e r e n langage C+ +
Nous ve rrons q u'ilre s te toujours possible de m odifie r ce la e n "spécialisant" notre clas s e point pour le
type ch ar ou e ncore e n spécialisant la fonction affich e pour la clas s e point< ch ar> .
2) A priori, on a plutôt e nvie d'appliq ue r notre patron point à des type s T standard. Toute fois, rie n
n'inte rdit de l'appliq ue r à un type clas s e T q ue lconq ue . H orm is le fait q ue , dans ce cas, ilpe ut ê tre
difficile d'attribue r une s ignification à la clas s e patron ainsi obte nue , ile s t né ce s s aire q u'ile xiste
alors une conve rsion de int e n T (utile pour conve rtir la valeur 0 dans le type T lors de l'initialisation
des argum e nts du constructe ur de point). De plus, ile s t né ce s s aire q ue la re copie e t l'affe ctation
d'obje ts de type T soient corre cte m e nt pris e s e n com pte .

2. LES PARAMÈTRES D E TYPE D 'UN PA TRO N D E CLASSES

Tout com m e les patrons de fonctions, les patrons de clas s e s pe uve nt com porte r de s param è tres de type e t des
param è tre s e xpre s s ion. Ce paragraph e é tudie les pre m ie rs ;les s e conds s e ront é tudiés dans le paragraph e
suivant. Une fois de plus, note z bie n q ue , m algré leur re s s e m blance ave c les patrons de fonctions, les
contrainte s re lative s à ces diffé re nts types de param è tre s ne s e ront pas les m ê m e s .

2.1 Le s param è tre s de type dans l


a cré ation d'un patron de cl
as s e s

Le s param è tres de type pe uve nt ê tre e n nom bre q ue lconq ue e t ils sont utilisés com m e bon vous s e m ble dans
la définition du patron de clas s e s . En voici un e xe m ple :

template <class T, class U, class V> // liste de trois param. de nom (muet) T,
U et V
class essai
{ T x ; // un membre x de type T
U t[5] ; // un tableau t de 5 éléments de type U
...
V fm1 (int, U) ; // déclaration d'une fonction membre recevant 2 arguments
// de type int et U et renvoyant un résultat de type V
...
} ;

2.2 Ins tanciation d'une cl


as s e patron

R appe lons q ue nous nom m ons "clas s e patron" une instance particuliè re d'un patron de clas s e .

Une clas s e patron se déclare s im plem e nt e n fournissant à la suite du nom de patron un nom bre d'argum e nts
e ffe ctifs (nom s de type s ) é galau nom bre de param è tre s figurant dans la liste (te m plate < ...> ) du patron.
Voici des déclarations de clas s e s patron obte nue s à partir du patron e s s ai pré cédent (note z bie n q u'ilne
s'agit q ue de sim ples e xe m ples d'école auxq ue ls il ne faut pas ch e rch e r à attribue r une s ignification
pré cis e ) :

essai <int, float, int> ce1 ;


essai <int, int *, double > ce2 ;
essai <char *, int, obj> ce3 ;

La derniè re s uppose bien sûr que le type obj a é té pré alablem e nt défini (ilpe ut s'agir d'un type clas s e ).
XII. Le s patrons d e clas s e s 19 1
Ile s t m ê m e possible d'utiliser com m e param è tre de type e ffe ctif un type instancié à l'aide d'un patron de
clas s e ;par e xe m ple, si nous disposons du patron de clas s e s nom m é point, te lq u'ila é té défini dans le
paragraph e pré cédent, nous pouvons déclare r :

essai <float, point<int>, double> ce4 ;


essai <point<int>, point<float>, char *> ce5 ;

R e m arques

1) Le s problèm es de corre s pondance e xacte re ncontrés dans le cas des patrons de fonctions n'existe nt
plus pour les patrons de clas s e s (du m oins pour les param è tres de type s é tudié s ici). En e ffe t, dans le
cas des patrons de fonctions, l'instanciation se basait non pas sur la liste des param è tre s indiq ué s à la
suite du m ot clé te m plate , m ais sur la liste des param è tres de l'e n-tê te de la fonction ;dans ce cas, un
m ê m e nom (m ue t) pouvait apparaî tre deux fois e t ily avait donc ris q ue d'absence de corre s pondance .
2) Ile s t tout à fait possible q u'un argum e nt form e l(figurant dans l'e n-tê te ) d'une fonction patron soit
une clas s e patron. En voici un e xe m ple, dans leq ue lnous supposons défini le patron de clas s e s
nom m é point (ce pe ut ê tre le pré cédent) :
template <class T> void fct (point<T>)
{ .....
}

Lors q u'ildevra instancie r une fonction fct pour un type T donné , le com pilate ur instancie ra é galem e nt
(si ce la n'a pas e ncore é té fait) la clas s e patron point< T> .
3) Com m e dans le cas des patrons de fonctions, on pe ut re ncontre r des difficulté s lors q ue l'on doit
initialiser (au sein de fonctions m e m bre ) des variables dont le type figure e n param è tre puis q ue alors,
ilpe ut, suivant les cas, s'agir d'un type de bas e ou, au contraire , d'un type clas s e . Là e ncore , la
nouve lle syntaxe d'initialisation de s type s s tandard (pré s e ntée dans le paragraph e 2.4 du pré cédent
ch apitre ) pe rm e t de ré s oudre le problèm e .
4) Un patron de clas s e s pe ut com porte r de s m e m bre s (donné e ou fonction) statiq ue s . Dans ce cas, ilfaut
savoir q ue ch aq ue instance de la classe dispose de son propre je u de m e m bre s s tatiq ue s : on e s t e n
q ue lque s orte "statiq ue au nive au de l'instance e t non au nive au du patron". Ce ci e s t logiq ue dans la
m e s ure où le patron de clas s e s n'e s t q u'un m oule utilisé pour instancie r diffé re nte s clas s e s ;plus
pré cis é m e nt, un patron de clas s e s pe ut toujours ê tre re m placé par autant de définitions diffé re ntes de
clas s e s q ue de clas s e s instancié e s .

3. LES PARAMÈTRES EXPRESSIO N D 'UN PA TRO N D E CLASSES

Un patron de clas s e s pe ut com porte r de s param è tre s e xpre s s ion. Bie n q u'ils'agis s e , ici e ncore , d'une notion
voisine de ce lle pré s e nté e pour les patrons de fonctions, ce rtaines diffé re nce s im portante s e xiste nt ;e n
particulie r les valeurs e ffe ctives d'un param è tre e xpre s s ion de vront obligatoire m e nt ê tre constantes dans le
cas des clas s e s .

3.1 Exe m pl
e

Suppos e z q ue nous souh aitions définir une clas s e tableau susce ptible de m anipuler de s tableaux d'obje ts d'un
type q ue lconq ue . Ilvie nt tout nature llem e nt à l'e s prit l'idée d'e n faire une clas s e patron possédant un
param è tre de type . Ile s t é galem e nt possible de pré voir un s e cond param è tre pe rm e ttant de préciser le
nom bre d'élém e nts du tableau.
19 2 Program m e r e n langage C+ +
D ans ce cas, la cré ation de notre clas s e s e pré s e nte ra ainsi :

template <class T, int n> class tableau


{ T tab [n] ;
public :
// .....
} ;

La liste de param è tre s (te m plate < ...> ) com porte deux param è tres de nature totalem e nt diffé re nte :

• un param è tre (désorm ais classique) de type , introduit par le m ot clé class,
• un "param è tre e xpre s s ion" de type int ;on pré cis e ra sa valeur lors de la déclaration d'une instance
particuliè re de la clas s e tableau.

Par e xe m ple, ave c la déclaration :

tableau <int, 4> ti ;

nous déclare rons une clas s e nom m é e ti corre s pondant finalem e nt à la déclaration suivante :

class ti
{ int tab [4] ;
public :
// .....
} ;

Voici un e xe m ple com plet de program m e définissant un pe u plus com plète m e nt une te lle clas s e patron
nom m é e tableau ;nous l'avons sim plem e nt doté e d e l'opé rate ur [] e t d'un constructe ur (sans argum e nts) q ui
ne s e justifie q ue par le fait q u'ilaffich e un m e s s age approprié . Nous avons instancié des "tableaux" d'obje ts
de type point (ici, point e s t à nouve au une clas s e "ordinaire " e t non une clas s e patron).

_______________________________________________________________________________
____

#include <iostream.h>
template <class T, int n> class tableau
{ T tab [n] ;
public :
tableau () { cout << "construction tableau \n" ; }
T & operator [] (int i)
{ return tab[i] ;
}
} ;
class point
{ int x, y ;
public :
point (int abs=1, int ord=1 ) // ici init par défaut à 1
{ x=abs ; y=ord ;
cout << "constr point " << x << " " << y << "\n" ;
}
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;
main()
XII. Le s patrons d e clas s e s 19 3
{ tableau <int,4> ti ;
int i ; for (i=0 ; i<4 ; i++) ti[i] = i ;
cout << "ti : " ;
for (i=0 ; i<4 ; i++) cout << ti[i] << " " ;
cout << "\n" ;
tableau <point, 3> tp ;
for (i=0 ; i<3 ; i++) tp[i].affiche() ;
} ________________________________

construction tableau
ti : 0 1 2 3
const point 1 1
const point 1 1
const point 1 1
construction tableau
coordonnées : 1 1
coordonnées : 1 1
coordonnées : 1 1
_______________________________________________________________________________
____

Exe m ple de clas s e patron com portant un param è tre e xpre s s ion

R e m arque :

Notre clas s e tableau, te lle q u'e lle e s t pré s e nté e ici n'a pas vé ritablem e nt d'inté rê t pratiq ue . En e ffe t, on
obtie ndrait le m ê m e ré s ultat e n dé clarant de sim ples tableaux d'obje ts, par e xe m ple int ti[4] au lie u de
tableau <int,4> ti. En fait, ilne s 'agit ici q ue d'un cadre initialq u'on pe ut com pléte r à loisir. Par
e xe m ple, on pourrait facilem e nt y ajoute r un contrôle d'indice e n adaptant la définition de l'opé rate ur [] ;
on pourrait é galem e nt pré voir d'initialiser les é lém e nts du tableau. C'e s t d'ailleurs ce q ue nous aurons
l'occasion de faire dans le paragraph e 7 où nous utiliserons notre patron tableau pour m anipuler de s
tableaux à plusieurs indices.

3.2 D 'une m aniè re gé né ral


e

O n pe ut faire apparaî tre autant de param è tre s e xpre s s ion q u'on le désire dans une liste de param è tres d'un
patron de clas s e s . Ce s param è tre s pe uve nt inte rve nir n'im porte où dans la définition du patron, au m ê m e
titre q ue n'im porte q ue lle e xpre s s ion constante pe ut apparaî tre dans la définition d'une clas s e .

Lors de l'instanciation d'une clas s e com portant des param è tre s e xpre s s ion, les param è tre s e ffe ctifs
corre s pondants doive nt obligatoire m e nt ê tre d e s e xpre s s ions constante s 2 d'un type rigoure us e m e nt identiq ue
(aux conve rsions triviales prè s) à ce lui pré vu dans la liste d'argum e nts ;autre m e nt dit, aucune conve rsion
n'e s t possible.

Contraire m e nt à ce q ui passait pour les patrons de fonctions, iln'e s t pas possible de "surdéfinir" un patron
de clas s e s , c'e s t-à -dire de cré e r plusieurs patrons de m ê m e nom m ais com portant une liste de param è tre s (de
type ou e xpre s s ion) diffé re nts. En cons é q ue nce , les problèm es d'am biguïté é voq ué s lors de l'instanciation
d'une fonction patron ne pe uve nt plus s e pos e r dans le cas de l'instanciation d'une clas s e patron.

Sur un plan m é th odologiq ue , on pourra souve nt h é s ite r e ntre l'e m ploi de param è tre s e xpre s s ion e t la
transm ission d'argum e nts au constructe ur. Ainsi, dans notre e xe m ple de clas s e tableau, nous aurions pu ne
pas prévoir le param è tre e xpre s s ion n e t, e n re vanch e , transm e ttre au constructe ur le nom bre d'élém e nts

2 - Ce tte contrainte n'e xis tait pas pour l


e s param è tre s e xpre s s s ion de s patrons de fonctions ;m ais l
e ur rôl
e n'é tait pas l
e m ê m e.
19 4 Program m e r e n langage C+ +
souh aité s . Dans ce cas, une diffé re nce im portante s e rait apparue au nive au de la ge s tion de s e m place m e nts
m é m oire corre s pondants aux diffé re nts é lém e nts du tableau :

• attribution d'e m place m e nt à la com pilation (statiq ue ou autom atiq ue s uivant la classe d'allocation de
l'obje t de type tableau<...,...> corre s pondant) dans le pre m ie r cas,
• allocation dynam iq ue par le constructe ur dans le s e cond cas.

4. SPÉCIA LISATIO N D 'UN PA TRO N D E CLASSES

Nous avons vu q u'ilé tait possible de "spécialiser" certaine s fonctions d'un patron de fonctions. La m ê m e
possibilité e xiste pour les patrons de clas s e s ;e lle pre nd toute fois un aspect légè re m e nt diffé re nt, à la fois au
nive au de s a syntaxe e t de ses possibilité s com m e nous le ve rrons aprè s un exem ple d'introduction.

4.1 Exe m pl
e de s pé cial
is ation d'une fonction m e m bre

Un patron de classes définit une fam ille de classes dans laq ue lle ch aq ue clas s e com porte à la fois sa
définition e t la définition de s e s fonctions m e m bre . Ainsi, toute s les fonctions m e m bre de nom donné
ré alisent le m ê m e algorith m e . Si l'on souh aite adapte r une fonction m e m bre à une s ituation particuliè re , il
e s t possible d'en fournir une nouve lle.

Voici un e xe m ple q ui re pre nd le patron de clas s e s point défini dans le pre m ie r paragraph e . Nous y avons
spécialisé la fonction affich e dans le cas du type ch ar, afin q u'e lle affich e non plus des caractè re s m ais des
nom bre s e ntie rs.

_______________________________________________________________________________
____

include <iostream.h>
// création d'un patron de classe
template <class T> class point
{ T x ; T y ;
public :
point (T abs=0, T ord=0)
{ x = abs ; y = ord ;
}
void affiche () ;
} ;
// définition de la fonction affiche
template <class T> void point<T>::affiche ()
{
cout << "Coordonnées : " << x << " " << y << "\n" ;
}
// ajout d'une fonction affiche spécialisée pour les caractères
void point<char>::affiche ()
{
cout << "Coordonnées : " << (int)x << " " << (int)y << "\n" ;
}
main ()
{
point <int> ai (3, 5) ; ai.affiche () ;
point <char> ac ('d', 'y') ; ac.affiche () ;
point <double> ad (3.5, 2.3) ; ad.affiche () ;
XII. Le s patrons d e clas s e s 19 5
}
________________________________

coordonnées : 3 5
coordonnées : 100 121
coordonnées : 3.5 2.3
_______________________________________________________________________________
____

Exe m ple de s pécialisation d'une fonction m e m bre d'une clas s e patron

Note z q u'ilnous a suffi d'é crire l'e n-tê te de affich e sous la form e :

void point<char>::affiche ()

pour pré cis e r au com pilate ur q u'ildevait utiliser cette fonction à la place de la fonction affich e du patron
point, c'e s t-à -dire à la place de l'instance point< ch ar> .

4.2 D 'une m aniè re gé né ral


e

a)O n pe ut s pé cial
is e r pour l
e s val
e urs de tous l
e s param è tre s

D ans notre e xe m ple, la clas s e patron point ne com portait q u'un param è tre de type . Ile s t possible de
spécialiser une fonction m e m bre e n se basant sur plusieurs param è tres de type , ainsi que sur des valeurs de
param è tre s e xpre s s ion (bie n q ue ce tte derniè re possiblité nous paraisse d'un inté rê t lim ité ). Par e xe m ple,
considérons le patron tableau défini dans le paragraph e 3.1 :

template <class T, int n> class tableau


{ T tab [n] ;
public :
tableau () { cout << "construction tableau \n" ; }
// .....
} ;

Nous pouvons é crire une ve rsion spécialisée de son constructe ur pour les tableaux de 10 é lém e nts de type
point (ilne s 'agit vraim e nt q ue d'un exem ple d'école !) e n procédant ainsi :

tableau<point,10>::tableau (...) { ... }

b)O n pe ut s pé cial
is e r une fonction m e m bre ou une cl
as s e
D ans nos précédents e xe m ples , nous avons spé cialisé une fonction m e m bre d'un patron. En fait, on pe ut
indiffé re m m e nt :

• spécialiser une ou plusieurs fonctions m e m bre , sans m odifie r la définition de la clas s e e lle-m ê m e (ce s e ra
la situation la plus fré q ue nte ),
• spécialiser la clas s e e lle-m ê m e , e n e n fournissant une nouve lle définition ;ce tte deuxiè m e possibilité
pouvant s'accom pagne r de la spécialisation de ce rtaine s fonctions m e m bre s .
19 6 Program m e r e n langage C+ +
Par e xe m ple, aprè s avoir dé fini le patron te m plate < class T> class point (com m e dans le paragraph e 4.1),
nous pourrions dé finir une ve rsion spécialisée de la clas s e point pour le type ch ar, c'e s t-à -dire une ve rsion
approprié e d e l'instance point< ch ar> , e n procédant ainsi :

class point <char>


{ // nouvelle définition
}

Nous pourrions é galem e nt indiffé re m m e nt définir de s ve rsions spécialisées de ce rtaines des fonctions
m e m bre de point< ch ar> e n procédant com m e pré cédem m e nt ou ne pas e n dé finir, auq ue lcas l'on fe rait
appe l, dans ce cas, aux fonctions m e m bre du patron.

c)Spé cial
is ation partie l
le de patrons de cl
as s e s
Nous avons déjà é té am e né à parler de s pé cialisation partie lle dans le cas de patrons de fonctions. La m ê m e
possibilité e xiste th é oriq ue m e nt pour les patrons de classe dans la norm e ANSI (m ais pas dans la ve rsion 3),
bien q u'e lle s 'e xprim e de façon diffé re nte . En voici un e xe m ple :

template <class T, class U> class A { ..... } ; // patron 1


template <class T> class A<T, T*> { ..... } ; // patron 2

Une déclaration te lle q ue A<int, float> a1 utilisera le patron 1, tandis q ue A<int, int*> a2 utilisera le
patron 2 m oins spé cialisé.

En pratiq ue , la re m arq ue e ffe ctué e à propos des spécialisations partie lles de patrons de fonctions s'appliq ue
e ncore ici, à savoir q ue toute s les im plém e ntations ne traite nt pas e ncore conve nablem e nt ce s s ituations.
Nous n'e ntre rons pas plus dans les détails.

5. PARAMETRES PAR DEFAUT

D ans la définition d'un patron de clas s e s , ile s t possible (depuis la norm e ANSI s e ulem e nt) de spécifie r de s
valeurs par dé faut pour ce rtains param è tre s , suivant un m é canism e s e m blable à ce lui q ui e s t utilisé pour les
param è tres de fonctions usuelles . Voici q ue lque s e xe m ples :

template <class T, class U=float> class A { ..... } ;


template <class T, int=3> class B { ..... } ;
.....
A<int,long> a1 ; /* instanciation usuelle */
A<int> a2 ; /* équivaut à A<int, float> a2 ; */
B<int, 3> b1 ; /* instanciation usuelle */
B<int> b2 ; /* équivaut à B<int, 3> b2 ; */

R e m arque :

La notion de param è tre s par dé faut n'a pas de signification pour les patrons de fonctions.
XII. Le s patrons d e clas s e s 19 7
6. PA TRO NS D E FO NCTIO NS M EM BRE

Le m é canism e de définition de patrons de fonctions peut s'appliq ue r à une fonction m e m bre d'une clas s e
ordinaire , com m e dans ce t e xe m ple :

class A
{ .....
template <class T> void fct (T a) { ..... }
.....
} ;

En th é orie , la norm e (m ais pas la ve rsion 3) pe rm e t de l'appliq ue r à une fonction m e m bre d'une clas s e
patron, com m e dans ce t e xe m ple :

template <class T> class A


{ .....
template <class U> void fct (U x, T y) /* ici le type T est utilisé, mais
*/
{ ..... } /* il pourrait ne pas l'être
*/
.....
} ;

D ans ce dernie r cas, l'instanciation de la bonne fonction fct se bas e ra, à la fois sur la clas s e à laq ue lle e lle
appartie nt, ainsi que sur la nature de son pre m ie r argum e nt.

Ce tte fois e ncore , ilfaut re m arq ue r q ue toute s les im plém e ntations ne traite nt pas e ncore conve nablem e nt
ces deux situations e t nous n'entre rons pas plus dans les détails.

7. ID ENTITÉ D E CLASSES PA TRO N

Nous avons déjà vu q ue l'opé rate ur d'affe ctation pe ut s'appliq ue r à deux obje ts d'un m ê m e type . Le te rm e
"m ê m e type " e s t parfaite m e nt défini, tant q ue l'on n'utilise pas d'instances de patron de clas s e s : deux obje ts
sont de m ê m e type s 'ils sont déclaré s ave c le m ê m e nom de clas s e . M ais q ue devie nt ce tte définition dans le
cas d'obje ts dont le type e s t une instance particuliè re d'un patron de clas s e ?

En fait, deux clas s e s patron corre s pondront à un m ê m e type s i leurs param è tres de type corre s ponde nt
e xacte m e nt au m ê m e type e t si leurs param è tre s e xpre s s ion ont la m ê m e valeur.

Ainsi (en supposant q ue nous disposions du patron tableau défini dans le paragraph e 3.1), ave c ce s
déclarations :

tableau <int, 12> t1 ;


tableau <float, 12> t2 ;

vous n'aure z pas le droit d'écrire :

t2 = t1 ; // incorrect car valeurs différentes du premier paramètre (float


et int)
19 8 Program m e r e n langage C+ +

D e m ê m e , ave c ces déclarations :

tableau <int, 15> ta ;


tableau <int, 20> tb ;

vous n'aure z pas le droit d'écrire :

ta = tb ; // incorrect car valeurs différentes du second paramètre (15 et


20)

Ce s rè gles , appare m m e nt re s trictive s , ne s e rve nt e n fait q u'à assure r un bon fonctionne m e nt de l'affe ctation,
q u'ils'agisse de l'affe ctation par dé faut (m e m bre à m e m bre : ilfaut donc bie n disposer exacte m e nt des
m ê m e s m e m bres dans les deux obje ts) ou de l'affe ctation surdéfinie (pour q ue ce la fonctionnne toujours, il
faudrait com pte r sur le conce pte ur du patron de clas s e pour q u'ilpré voie toute s les com binaisons possibles
e t, de plus, ê tre s û r q u'une é ve ntue lle s pé cialisation ne ris q ue pas de pertube r les ch os e s ...).

Ce rte s , dans le pre m ie r cas (t2=t1), une conve rsion int-> float nous aurait pe ut-ê tre conve nu m ais pour q ue
le com pilate ur puis s e la m e ttre e n œuvre , ilfaudrait q u'il"sach e " q u'une clas s e tableau<int, 10> ne
com porte q ue des m e m bres de type int, q u'une clas s e tableau<float, 10> ne com porte q ue des m e m bres de
type float, q ue les deux clas s e s ont le m ê m e nom bre de m e m bres donnée...

8. CLASSES PA TRO N ET D ÉCLARATIO NS D 'AM ITIÉS

L'e xiste nce des patrons de clas s e s introduit de nouve lles possibilités de déclaration d'am itié .

Au sein d'un patron de clas s e , on pe ut e ffe ctue r trois sortes de déclarations d'am itié .

8.1 D é cl
aration de cl
as s e s ou fonctions "ordinaire s " am ie s

La dém arch e re s te ce lle q ue nous avons déjà re ncontrée dans le cas des clas s e s ordinaire s Par e xe m ple, si A
e s t une clas s e ordinaire e t fct une fonction ordinaire :

template <class T>


class essai
{ int x ;
public :
friend class A ; // A est amie de toute instance du patron essai
friend int fct (float) ; // fct est amie de toute instance du patron essai
...
} ;

8.2 D é cl
aration d'ins tance s particul
iè re s de cl
as s e s patron
ou de fonctions patron

En fait, ce tte possibilité pe ut pre ndre deux aspects diffé re nts suivant q ue les param è tre s utilisés pour définir
l'instance conce rné e s ont des param è tre s e ffe ctifs ou m ue ts (définis dans la liste de param è tres du patron de
clas s e ).
XII. Le s patrons d e clas s e s 19 9
Si nous supposons que point e s t une clas s e patron dé finie ainsi :

template <class T> class point { ... } ;

e t fct une fonction patron dé finie ainsi :

template <class T> int fct (T) { ... }

Voici un e xe m ple illustrant le pre m ie r aspect :

template <class T, class U>


class essai1
{ int x ;
public :
friend class point<int> ; // la classe patron point<int> est amie
// de toutes les instances de essai1
friend int fct (double) ; // la fonction patron int fct (double
// de toutes les instances de essai1
...
} ;

Voici un e xe m ple illustrant le s e cond aspect :

template <class T, class U>


class essai2
{ int x ;
public :
friend class point<T> ;
friend int fct (U) ;
}

Note z bie n, q ue dans le s e cond cas, on é tablit un "couplage " e ntre la clas s e patron gé né ré e par le patron
e s s ai2 e t les déclarations d'am itié s corre s pondante s . Par e xe m ple, pour l'intance e s s ai2 < int, double> , les
déclarations d'am itié porte ront sur point< int> e t int fct (double).

8.3 D é cl
aration d'un autre patron de fonctions ou de cl
as s e s

Voici un e xe m ple faisant appe laux m ê m e s patrons point e t fct q ue ci-de s s us :

template <class T, class U>


class essai2
{ int x;
public :
template <class X> friend class point <X> ;
template <class X> friend int fct (point <X>) ;
}

Ce tte fois, toute s les instances du patron point sont am ies de n'im porte q ue lle instance du patron e s s ai2. De
m ê m e toute s les instances du patron de fonctions fct sont am ies du n'im porte instance du patron e s s ai2.
200 Program m e r e n langage C+ +

9 . UN EXEM PLE D E CLASSE TA BLEAU À D EUX IND ICES

Nous avons vu à plusieurs reprises com m e nt surdéfinir l'opé rate ur [] au s e in d'une clas s e tableau.
Né anm oins, nous nous som m e s toujours lim ité à des tableaux à un indice .

Ici, nous allons voir com m e nt, une fois défini un patron de tableau com m e nous l'avons fait pré cédem m e nt
(donc à un indice ), ile s t trè s facile, par le s im ple je u de la com position de s patrons, de l'appliq ue r à un
tableau à deux indice s (ou davantage ).

Si nous considérons pour l'instant la clas s e tableau définie de ce tte façon sim plifié e :

template <class T, int n> class tableau


{ T tab [n] ;
public :
T & operator [] (int i) // opérateur []
{ return tab[i] ;
}
} ;

nous pouvons tout à fait déclare r :

tableau <tableau<int,2>,3> t2d ;

D ans ce cas, t2d e s t, e n e ffe t, un tableau de 3 é lém e nts ayant ch acun le type tableau <int,2> ;autre m e nt
dit, ch acun de ce s 3 é lém e nts e s t lui-m ê m e un tableau de 2 e ntie rs.

Une notation te lle q ue t2d [1] [2] a un s e ns ;e lle re pré s e nte la ré fé re nce au troisiè m e é lém e nt de t2d [1],
c'e s t-à -dire au troisiè m e é lém e nt du deuxiè m e tableau de deux e ntie rs de t2d.

Voici un e xe m ple com plet (m ais toujours sim plifié ) illustrant ce ci ;nous y avons sim plem e nt ajouté
artificie llem e nt un constructe ur afin d'obte nir une trace des diffé re nte s constructions.

_______________________________________________________________________________
____

// implémentation d'un tableau à deux dimensions


#include <iostream.h>
template <class T, int n> class tableau
{
T tab [n] ;
public :
tableau () // constructeur
{cout << "construction tableau à " << n << " éléments\n" ;
}
T & operator [] (int i) // opérateur []
{ return tab[i] ;
}
} ;

main()
{
tableau <tableau<int,2>,3> t2d ;
t2d [1] [2] = 15 ;
cout << "t2d [1] [2] = " << t2d [1] [2] << "\n" ;
XII. Le s patrons d e clas s e s 201
cout << "t2d [0] [1] = " << t2d [0] [1] << "\n" ;
}
________________________________

construction tableau à 2 éléments


construction tableau à 2 éléments
construction tableau à 2 éléments
construction tableau à 3 éléments
t2d [1] [2] = 15
t2d [0] [1] = 2226
_______________________________________________________________________________
____

U tilisation du patron tableau pour m anipuler de s tableaux à de ux indice s (1)

O n note ra bie n q ue notre patron tableau e s t, a priori, un tableau à un indice ;c'e s t sim plem e nt la m aniè re
dont on l'utilise qui perm e t de l'appliq ue r à des tableaux à un nom bre q ue lconq ue d'indice s .

M anife s te m e nt, ce t e xe m ple e s t trop sim pliste ;d'ailleurs, te lq ue l, iln'apporte rie n de plus q u'un banal
tableau. Pour le re ndre plus ré aliste , nous allons prévoir :

• de gérer les "débordem e nts d'indice s " : ici, nous nous conte nte rons d'affich e r un m e s s age e t de "faire
com m e s i" l'utilisate ur avait fourni un indice nul,
• d'initialiser, lors de sa construction, tous les é lém e nts du tableau : nous utiliserons pour ce faire la valeur
0 ;e ncore faut-ilq ue la ch os e s oit possible, c'e s t-à -dire q ue , q ue lq ue s oit le type T des élém e nts du
tableau, on puis s e leur affe cte r la valeur 0 ;ce la signifie q u'ildoit e xiste r une conve rsion de T e n int ;il
e s t facile de la ré aliser ave c un constructe ur à un é lém e nt de type int ;du m ê m e coup, ce la pe rm e ttra de
pré voir une valeur initiale lors de la déclaration d'un tableau (par s é curité , nous prévoirons la valeur 0
par dé faut).

Voici notre nouve lle clas s e ainsi m odifié e e t un e xe m ple d'utilisation :

_______________________________________________________________________________
____

// implémentation d'un tableau 2d avec test débordement d'indices


#include <iostream.h>
template <class T, int n> class tableau
{ T tab [n] ;
int limite ; // nombre d'éléments du tableau
public :

tableau (int init=0)


{ int i ;
for (i=0 ; i<n ; i++) tab[i] = init ;
// il doit exister un constructeur à un argument
// pour le cas où tab[i] est un objet
limite = n-1 ;
202 Program m e r e n langage C+ +
cout << "appel constructeur tableau de taille " << n
<< " init = " << init << "\n" ;
}
T & operator [] (int i)
{ if (i<0 || i>limite) { cout << "--débordement " << i << "\n" ;
i=0 ; // choix arbitraire
}
return tab[i] ;
}
} ;
main()
{ tableau <tableau<int,3>,2> ti ; // pas d'initialisation
tableau <tableau<float,4>,2> td (10) ; // initialisation à 10
ti [1] [6] = 15 ;
ti [8] [-1] = 20 ;
cout << ti [1] [2] << "\n" ; // élément initialisé à valeur par défaut
(0)
cout << td [1] [0] << "\n" ; // élément initialisé explicitement
} ________________________________

appel constructeur tableau de taille 3 init = 0


appel constructeur tableau de taille 3 init = 0
appel constructeur tableau de taille 3 init = 0
appel constructeur tableau de taille 3 init = 0
appel constructeur tableau de taille 2 init = 0
appel constructeur tableau de taille 4 init = 0
appel constructeur tableau de taille 4 init = 0
appel constructeur tableau de taille 4 init = 10
appel constructeur tableau de taille 4 init = 10
appel constructeur tableau de taille 2 init = 10
--débordement 6
--débordement 0
--débordement -1
0
10
_______________________________________________________________________________
____
U tilisation du patron tableau pour m anipuler de s tableaux à de ux indice s (2)

R e m arque :

Si vous e xam ine z bie n les m e s s ages de construction des diffé re nts tableaux, vous constate re z q ue l'on e n
obtie nt deux fois plus q ue pré vu pour les tableaux à un indice . L'e xplication ré s ide dans l'instruction
tab[i] = init du constructe ur tableau. En e ffe t, lors q ue tab[i] désigne un élém e nt de type de bas e , ily a
sim plem e nt conve rsion de la valeur e ntiè re init dans ce type de bas e . En re vanch e , lors q ue l'on a affaire
à un obje t de type T (ici T e s t de la form e tableau<...> ), ce tte instruction provoq ue l'appe ldu
constructe ur tableau(int) pour cré e r un obje t te m poraire de ce type . Ce ci s e voit trè s claire m e nt dans le
cas du tableau td pour leq ue lon trouve une construction d'un tableau te m poraire initialisé ave c la valeur
0 e t une construction d'un tableau initialisé ave c la valeur 10.
XII. LA TECH NIQUE
D E L'H ÉRITAGE

Com m e nous l'avons déjà é voq ué dans le pre m ie r ch apitre , le conce pt d'h é ritage (on parle é galem e nt de
classes dérivé e s ) constitue l'un de s fonde m e nts de la P.O .O . En particulie r, ile s t à la base des possibilités de
ré utilisation de com posants logicie ls (e n l'occurre nce , de clas s e s ). En e ffe t, ilvous autoris e à définir une
nouve lle clas s e , dite "dérivé e ", à partir d'une clas s e e xistante dite "de bas e ". La classe dérivé e "h é rite ra"
des "pote ntialité s " de la classe de bas e , tout e n lui e n ajoutant de nouve lles , e t ce la sans q u'ilsoit né ce s s aire
de re m e ttre e n q ue s tion la classe de bas e . Ilne s e ra pas utile de la re com piler ;d'ailleurs, ilne s e ra m ê m e
pas néce s s aire de disposer du program m e s ource corre s pondant (e xce ption faite de sa déclaration).

Ce tte te ch niq ue va donc pe rm e ttre de déve loppe r de nouve aux outils e n s e fondant sur un ce rtain acq uis, ce
q ui justifie le te rm e d'h é ritage . Bie n e nte ndu, plusieurs clas s e s pourront ê tre dérivées d'une m ê m e classe de
bas e ;d'autre part, l'h é ritage n'e s t pas lim ité à un s e ulnive au : une classe dérivé e pouvant deve nir à son
tour classe de bas e pour une autre clas s e . O n voit ainsi apparaî tre la notion d'h é ritage com m e outilde
spécialisation croissante .

Qui plus e s t, nous ve rrons q ue C+ + (depuis la ve rsion 2.0) autoris e l'h é ritage m ultiple dans leq ue lune
clas s e pe ut ê tre dérivé e d e plusieurs classes de bas e .

Nous com m e nce rons, dans ce ch apitre , par vous présente r la m ise en œuvre de l'h é ritage e n C+ + sur un
e xe m ple trè s sim ple. Nous e xam ine rons e nsuite com m e nt, à l'im age de ce q ui s e passait dans le cas d'obje ts
m e m bre , C+ + offre un m é canism e inté re s s ant de transm ission d'inform ation e ntre constructe urs (de la
classe dérivé e e t de la classe de bas e ). Puis nous ve rrons la souples s e q ue pré s e nte le C+ + e n m atiè re de
contrôle des accè s de la classe dérivé e aux m e m bres de la classe de bas e (aussi bien au nive au de la
conce ption de la classe de bas e q ue ce lle de la classe dérivé e ).

Nous aborde rons e nsuite les problèm es de com patibilité e ntre une classe de bas e e t une classe dérivé e , tant
au nive au de s obje ts e ux-m ê m e s q ue des pointe urs sur ce s obje ts ou des réfé re nce s à ce s obje ts. Nous
e xam ine rons alors ce q u'iladvie nt du constructe ur de re copie , de l'opé rate ur d'affe ctation e t des patrons de
clas s e s , dans le cadre de l'h é ritage .

Enfin, aprè s avoir fait la distinction e ntre h é ritage s im ple e t h é ritage m ultiple, nous appre ndrons à e xploite r
concrè te m e nt une classe dérivé e .

Quant à l'h é ritage m ultiple, ilfe ra l'obje t du ch apitre s uivant.


204 Program m e r e n langage C+ +

1. M ISE EN ŒUVRE D E L'H ÉRITAGE EN C+ +

Tout d'abord, nous allons vous e xpos e r les bases de la m ise en œuvre de l'h é ritage e n C+ + sur un e xe m ple
sim ple ne faisant pas inte rve nir de constructe ur ou de destructe ur e t où le contrôle des accè s e s t lim ité .

Considérons la pre m iè re clas s e point q ue nous avions définie dans le ch apitre V, dont nous fournissons à
nouve au la définition ci-de s s ous :

_______________________________________________________________________________
______

#include <iostream.h>
/* ------------ Déclaration de la classe point ------------- */
class point
{ /* déclaration des membres privés */
int x ;
int y ;
/* déclaration des membres publics */
public :
void initialise (int, int) ;
void deplace (int, int) ;
void affiche () ;
} ;
/* ----- Définition des fonctions membres de la classe point ---- */
void point::initialise (int abs, int ord)
{ x = abs ; y = ord ;
}
void point::deplace (int dx, int dy)
{ x += dx ; y += dy ;
}
void point::affiche ()
{ cout << "Je suis en " << x << " " << y << "\n" ;
}
_______________________________________________________________________________
______

Une clas s e d e b a s e : point

Suppos e z q ue nous ayons besoin de définir un nouve au type clas s e nom m é pointcol, destiné à m anipuler de s
points colorés d'un plan. Un te lpoint coloré pe ut ê tre défini par s e s coordonné e s (com m e un obje t de type
point), auxq ue lles on adjoint une inform ation de couleur (par e xe m ple de type ch ar). Dans ces conditions,
nous pouvons ê tre te nté de définir pointcolcom m e une classe dérivé e d e point. Si nous prévoyons (pour
l'instant) une fonction m e m bre s pé cifiq ue à pointcol, nom m é e colore , destiné e à attribue r une couleur à un
point coloré , voici ce q ue pourrait ê tre la déclaration de pointcol(la fonction colore e s t ici "e n ligne ").

_______________________________________________________________________________
______

#include <point.h>
class pointcol : public point // pointcol dérive de point
{ short couleur ;
public :
XIII. La te ch nique de l'h é ritage 205
void colore (short cl)
{ couleur = cl ; }
} ;
_______________________________________________________________________________
______

Une clas s e pointcol, dérivé e d e point

Note z la déclaration :

class pointcol : public point

Elle s pé cifie q ue pointcole s t une classe dérivé e d e la clas s e (de bas e ) point. De plus, le m ot public signifie
q ue les m em bres publ ics de l a classe de base (point) seront des m em bres publ ics de l a classe dérivé e
(pointcol) ;ce la corre s pond à l'idé e la plus fré q ue nte q ue l'on pe ut avoir de l'h é ritage , sur le plan gé né ralde
la P.O .O . Nous ve rrons plus loin, dans le paragraph e consacré au contrôle des accè s, à q uoi conduirait
l'om ission du m ot public.

Notre clas s e pointcolainsi définie , nous pouvons déclare r de s obje ts de type pointcolde m aniè re usuelle :

pointcol p, q ;

Ch aq ue obje t de type pointcolpe ut alors faire appe l:

• aux m é th ode s publiq ues de pointcol(ici colore ),


• aux m é th ode s publiq ues de la classe de bas e point (ici init, de place e t affich e ).
Voici un program m e illustrant ce s possibilité s . Vous n'y trouve re z pas la liste de la clas s e point car nous
nous som m e s placé dans les conditions h abitue lles d'utilisation d'une classe déjà au point ;plus précisém e nt,
nous supposons que nous disposons :

• d'un m odule obje t re latif à la clas s e point : ile s t né ce s s aire de l'incorpore r au m om e nt de l'édition de
lie ns,
• d'un fich ie r nom m é ici point.h 1, conte nant la déclaration de la clas s e point.
_______________________________________________________________________________
______

#include <iostream.h>
#include <point.h>
class pointcol : public point // pointcol dérive de point
{ short couleur ;
public :
void colore (short cl) { couleur = cl ; }
} ;
main()
{ pointcol p ;
p.initialise (10,20) ; p.colore (5) ;
p.affiche () ;
p.deplace (2,4) ;
p.affiche () ;

1 - Son e xte nsion pourra varie r s uivant l


'environne m e nt util
isé. De pl
us, suivant s a l
ocal
isation, on util
isera l
'une ou l
'autre des deux
syntaxes de l
a dire ctive #include (<.....> ou ".....").
206 Program m e r e n langage C+ +
} _______________________

Je suis en 10 20
Je suis en 12 24
_______________________________________________________________________________
______

Exe m ple d'utilisation d'une clas s e pointcol, dérivé e d e point

2. UTILISATIO N, D A NS UNE CLASSE D ERIVÉE,


D ES M EM BRES D E LA CLASSE D E BASE

Com m e nous l'avons dit, l'e xe m ple pré cédent n'é tait destiné q u'à m ontre r com m e nt s'e xprim e l'h é ritage e n
C+ + , sans ch e rch e r à e n e xplore r toute s les possibilité s , notam m e nt e n m atiè re de contrôle des accè s. Dans
ce dom aine , nous avons sim plem e nt appris q ue , grâ ce à l'e m ploi du m ot public, les m e m bre s publics de
point é taie nt é galem e nt m e m bre s publics de pointcol;c'e s t ce q ui nous a pe rm is d'y faire appe l, au s e in de
la fonction m ain (par e xe m ple dans l'instruction p.initialise (10, 20)).

O r, la clas s e pointcol, te lle q ue nous l'avons définie , souffre de lacune s . Par e xe m ple, lors q ue nous appe lons
affich e pour un obje t de type pointcol, nous n'obte nons aucune inform ation sur sa couleur. Une pre m iè re
façon d'am é liore r ce tte s ituation consiste à é crire une nouve lle fonction m e m bre publiq ue de pointcol,
ce ns é e affich e r à la fois les coordonné e s e t la couleur. Appelons-la pour l'instant affich e c (nous ve rrons plus
tard q u'ile s t possible de l'appe ler é galem e nt affich e ).

A ce nive au, vous pourrie z pe ns e r dé finir affich e c de la m aniè re s uivante :

void affichec ()
{ cout << "Je suis en " << x << " " << y << "\n" ;
cout << " et ma couleur est : " << couleur << "\n" ;
}

M ais alors ce la signifie rait q ue la fonction affich e c, m e m bre de pointcol, aurait accè s aux m e m bre s privés de
point. Ce ci s e rait contraire au principe d'encapsulation : e n e ffe t, ildevie ndrait alors possible d'écrire une
fonction accédant dire cte m e nt2 aux donné e s privé e s d'une clas s e , sim plem e nt e n cré ant une classe dérivé e !
D 'où la rè gle adopté e par C+ + :

Une cl asse de base 3.


asse dérivée n'a pas accè s aux m em bres privés de sa cl
En re vanch e , rie n n'e m pê ch e à une classe dérivée d'accéder à n'im porte q ue lm e m bre public de s a classe de
bas e . Ainsi, dans le cas q ui nous préoccupe, si notre fonction m e m bre affich e c ne pe ut pas accéder
dire cte m e nt aux donné e s privé e s x e t y de la clas s e point, e lle pe ut né anm oins faire appe là la fonction
affich e de ce tte m ê m e clas s e . D'où une définition possible de affich e c.

_______________________________________________________________________________
______

void pointcol::affichec ()
{ affiche () ;
cout << " et ma couleur est : " << couleur << "\n" ;
}

2 - C'e s t-à -dire sans passer par l 'inte rface obligatoire cons titué e par le s fonctions m e m bre publ
iq ues.
3 - M ais nous ve rrons q ue l 'existe nce de m e m bres proté gé s pe rm e t de m odifie r ce l
a.
XIII. La te ch nique de l'h é ritage 207
_______________________________________________________________________________
______

Une fonction d'affich age pour un obje t de type pointcol

Note z bie n com m e nt, au s e in de affich e c, nous avons fait dire cte m e nt appe là affich e , sans avoir à spécifier
à quelobjet cette fonction devait ê tre appl iquée : par conve ntion, ils'agit de ce lui ayant appe lé affich e c.
Nous re trouvons la m ê m e rè gle q ue ce lle q ui s'appliq ue dans le cas de fonctions m e m bre d'une m ê m e
clas s e . En fait, ilfaut désorm ais considérer ici que affich e e s t une fonction m e m bre de pointcol4.

D 'une m aniè re analogue , nous pouvons définir dans pointcol, une nouve lle fonction d'initialisation nom m é e
initialise c, ch argée d'attribue r de s valeurs aux donné e s x, y e t couleur, à partir de trois valeurs re çue s e n
argum e nt.

_______________________________________________________________________________
______

void pointcol::initialisec (int abs, int ord, short cl)


{ initialise (abs, ord) ;
couleur = cl ;
}
_______________________________________________________________________________
______

Une fonction d'initialisation pour un obje t de type pointcol

Voici un e xe m ple com plet de program m e re pre nant la définition de la clas s e pointcol(ici e ncore , nous avons
supposé que la clas s e point é tait fournie s é paré m e nt).

_______________________________________________________________________________
______

#include <iostream.h>
#include <point.h>
class pointcol : public point
{ short couleur ;
public :
void colore (short cl)
{ couleur = cl ; }
void affichec () ;
void initialisec (int, int, short) ;
} ;
void pointcol::affichec ()
{ affiche () ;
cout << " et ma couleur est : " << couleur << "\n" ;
}
void pointcol::initialisec (int abs, int ord, short cl)
{ initialise (abs, ord) ;
couleur = cl ;
}
main()

4 - Ce ne s e rait toute fois pas l


e cas si affich e n'é tait pas une fonction publ
iq ue de point.
208 Program m e r e n langage C+ +
{ pointcol p ;
p.initialisec (10,20, 5) ; p.affichec () ; p.affiche () ;
p.deplace (2,4) ; p.affichec () ;
p.colore (2) ; p.affichec () ;
}
_______________________

Je suis en 10 20
et ma couleur est : 5
Je suis en 10 20
Je suis en 12 24
et ma couleur est : 5
Je suis en 12 24
et ma couleur est : 2
_______________________________________________________________________________
______

Une nouve lle clas s e pointcole t s on utilisation

3. RED ÉFINITIO N D ES FO NCTIO NS M EM BRE

D ans notre dernie r e xe m ple de clas s e pointcol, nous disposions à la fois :

• dans point, d'une fonction m e m bre nom m é e affich e ,


• dans pointcol, d'une fonction m e m bre nom m é e affich e c.
O r, ces deux m é th ode s font un travailanalogue , à savoir affich e r les valeurs des données de leur clas s e ;
dans ce s conditions, on pourrait souh aite r leur donne r le m ê m e nom . Ce ci e s t e ffe ctive m e nt possible e n
C+ + , m oye nnant sim plem e nt une pe tite pré caution. En e ffe t, iln'e s t alors plus possible, au s e in de la
fonction affich e de pointcol, d'appe ler la fonction affich e de point, com m e auparavant : ce la provoq ue rait un
appe lré cursif de la fonction affich e de pointcol. Ilfaut alors faire appe là l'opé rate ur de ré s olution de porté e
(::) pour localiser conve nablem e nt la m é th ode voulue (ici, on appe llera point::affich e ).

D e m aniè re com parable, si, pour un obje t p de type pointcol, on appe lle la fonction p.affich e , ils'agira de la
fonction redéfinie dans pointcol. Si l'on tie nt absolum e nt à utiliser la fonction affich e de la clas s e point, on
appe llera p.point::affich e .

A titre d'exem ple, voici com m e nt nous pouvons transform e r l'e xe m ple du paragraph e pré cédent e n nom m ant
affich e e t initialise les nouve lles fonctions m e m bre de pointcol.

_______________________________________________________________________________
______

#include <iostream.h>
#include <point.h>
class pointcol : public point
{ short couleur ;
public :
void colore (short cl)
{ couleur = cl ; }
void affiche () ; // redéfinition de affiche de point
void initialise (int, int, short) ; // redéfinition de initialise de point
} ;
void pointcol::affiche ()
XIII. La te ch nique de l'h é ritage 209
{ point::affiche () ; // appel de affiche de la classe point
cout << " et ma couleur est : " << couleur << "\n" ;
}
void pointcol::initialise (int abs, int ord, short cl)
{ point::initialise (abs, ord) ; // appel de initialise de la classe point
couleur = cl ;
}

main()
{ pointcol p ;
p.initialise (10,20, 5) ; p.affiche () ;
p.point::affiche () ; // pour forcer l'appel de affiche de point
p.deplace (2,4) ; p.affiche () ;
p.colore (2) ; p.affiche () ;
}
_______________________

Je suis en 10 20
et ma couleur est : 5
Je suis en 10 20
Je suis en 12 24
et ma couleur est : 5
Je suis en 12 24
et ma couleur est : 2
_______________________________________________________________________________
______

Une clas s e pointcoldans laque lle les m é th ode s initialise e t affich e s ont re définie s

R e m arque :

Bie n q ue ce la soit d'un e m ploi m oins courant, ce q ue nous avons dit à propos de la redéfinition de
fonctions m e m bre s 'appliq ue tout aussi bien aux m e m bres donnée. Plus précisém e nt, si une clas s e A e s t
définie ainsi :
class A
{ .....
int a ;
char b ;
.....
} ;

Une clas s e B dérivé e d e A pourra, par e xe m ple, définir un autre m e m bre donnée nom m é a :
class B : public A
{ float a ;
.....
} ;

D ans ce cas, si l'obje t b est de type B, b.a fe ra ré fé re nce au m e m bre a de type float de b. Ils e ra toujours
possible d'accéder au m e m bre donnée a de type int (h é rité de A) par b.A::a5.
Note z bie n q ue le m e m bre a défini dans B s'ajoute au m e m bre a h é rité de A ;ilne le re m place pas.

5 - En supposant, bien sûr, que l


e s accè s e n q ue s tion s oie nt autorisés.
210 Program m e r e n langage C+ +

4. A PPELD ES CO NSTRUCTEURS ET D ES D ESTRUCTEURS

4.1 Rappe l
s

R appe lons l'e s s e ntie ldes rè gles conce rnant l'appe ld'un constructe ur ou du de s tructe ur d'une clas s e (dans le
cas où ilne s 'agit pas d'une classe dérivé e ) :

• S'ile xiste au m oins un constructe ur, toute cré ation d'un obje t (par dé claration ou par ne w ) e ntraî ne ra
l'appe ld'un constructe ur. Le ch oix é ve ntue ldu constructe ur e s t ré alisé en fonction de s inform ations
fournie s ;si aucun constructe ur ne convie nt, ily a e rre ur de com pilation : iln'e s t donc pas possible, dans
ce cas, de cré e r un obje t sans appe ler l'un de s e s constructe urs.
• S'iln'e xiste aucun constructe ur, iln'e s t pas possible de pré cis e r de s inform ations lors de la cré ation d'un
obje t.
• S'ile xiste un de s tructe ur, ils e ra appe lé avant la destruction de l'obje t.

4.2 La h ié rarch is ation de s appe l


s

Ce s rè gles s e gé né ralisent au cas des classes dérivé e s , e n te nant com pte de l'aspect h ié rarch iq ue q u'e lles
introduise nt. Pour fixe r les idées, supposons que ch aq ue clas s e possè de un constructe ur e t un de s tructe ur.

class A class B : public A


{ ..... { .....
public : public :
A (...) B (...)
~A () ~B ()
..... .....
} ; } ;

O n conçoit q ue , pour cré e r un obje t de type B, ilfaut tout d'abord cré e r un obje t de type A , donc faire appe l
au constructe ur de A , puis le com pléte r par ce q ui e s t spécifiq ue à B e t faire appe lau constructe ur de B. Ce
m é canism e e s t pris e n ch arge par C+ + : autre m e nt dit, iln'y aura pas à pré voir dans le constructe ur de B
l'appe ldu constructe ur de A .

La m ê m e dém arch e s 'appliq ue aux de s tructe urs : lors de la destruction d'un obje t de type B, ily aura
autom atiq ue m e nt appe ldu destructe ur de B, puis appe lde ce lui de A (les destructe urs sont bien appe lés dans
l'ordre inve rse de l'appe ldes constructe urs).

4.3 Trans m is s ion d'inform ations e ntre cons tructe urs

Toute fois, vous voye z q u'un problèm e s e pose dans le cas où le constructe ur de A né ce s s ite des argum e nts.
En e ffe t, les inform ations fournie s lors de la cré ation d'un obje t de type B sont, a priori, de s tiné s à son
constructe ur ! En fait, C+ + a pré vu la possibilité de spé cifie r, dans la définition d'un constructe ur d'une
classe dérivé e , les inform ations q ue l'on souh aite transm e ttre à un constructe ur de la classe de bas e . Le
m é canism e e s t le m ê m e q ue ce lui q ue nous vous avons e xposé dans le cas des obje ts m e m bre (paragraph e 7
du ch apitre VII). Par e xe m ple, si l'on a ce ci :

class point class pointcol : public point


{ ..... { .....
XIII. La te ch nique de l'h é ritage 211
public : public :
point (int, int) ; pointcol (int, int, char) ;
..... .....
} ; } ;

e t q ue l'on souh aite q ue pointcolre transm e tte à point les deux pre m iè re s inform ations re çue s , on é crira son
e n-tê te de ce tte m aniè re :

pointcol (int abs, int ord, char cl) : point (abs, ord)

Le com pilate ur m e ttra e n place la transm ission au constructe ur de point des inform ations abs e t ord
corre s pondant (ici) aux de ux pre m ie rs argum e nts de pointcol. Ainsi, la déclaration :

pointcol a (10, 15, 3) ;

e ntraî
ne ra :

• l'appe lde point q ui re ce vra les argum e nts 10 et 15,


• l'appe lde pointcolq ui re ce vra les argum e nts 10, 15 e t 3.
En re vanch e , la déclaration :

pointcol q (5, 2)

s e ra re je té e par le com pilate ur puis q u'iln'e xiste aucun constructe ur pointcolà deux argum e nts.

Bie n e nte ndu, ilre s te toujours possible de m e ntionne r de s argum e nts par dé faut dans pointcol, par e xe m ple :

pointcol (int abs = 0, int ord = 0, char cl = 1) : point (abs, ord)

D ans ce s conditions, la déclaration :

pointcol b (5) ;

e ntraî
ne ra :

• l'appe lde point ave c les argum e nts 5 et 0,


• l'appe lde pointcolave c les argum e nts 5, 0 e t 1.
Note z q ue la pré s e nce é ve ntue lle d'argum e nts par dé faut dans point n'a aucune incide nce ici (m ais on pe ut
les avoir pré vus pour les obje ts de type point).

4.4 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant ce tte s ituation : les clas s e s point e t pointcoly ont é té
lim ité e s à leurs constructe urs e t destructe urs (ce q ui leur e nlève rait, bie n sûr, tout inté rê t e n pratiq ue ).

_______________________________________________________________________________
______

#include <iostream.h>
// ************ classe point *********************
class point
{ int x, y ;
public :
212 Program m e r e n langage C+ +
point (int abs=0, int ord=0) // constructeur de point ("inline")
{ cout << "++ constr. point : " << abs << " " << ord << "\n" ;
x = abs ; y =ord ;
}

~point () // destructeur de point ("inline")


{ cout << "-- destr. point : " << x << " " << y << "\n" ;
}
} ;
// ************ classe pointcol ******************
class pointcol : public point
{ short couleur ;
public :
pointcol (int, int, short) ; // déclaration constructeur pointcol
~pointcol () // destructeur de pointcol ("inline")
{ cout << "-- dest. pointcol - couleur : " << couleur << "\n" ;
}
} ;
pointcol::pointcol (int abs=0, int ord=0, short cl=1) : point (abs, ord)
{ cout << "++ constr. pointcol : " << abs << " " << ord << " " << cl << "\n" ;
couleur = cl ;
}

// ************ programme d'essai ****************


main()
{ pointcol a(10,15,3) ; pointcol b (2,3) ; // objets
pointcol c (12) ; pointcol d ; // automatiques
pointcol * adr ;
adr = new pointcol (12,25) ; // objet dynamique
delete adr ;
}
_______________________

++ constr. point : 10 15
++ constr. pointcol : 10 15 3
++ constr. point : 2 3
++ constr. pointcol : 2 3 1
++ constr. point : 12 0
++ constr. pointcol : 12 0 1
++ constr. point : 0 0
++ constr. pointcol : 0 0 1
++ constr. point : 12 25
++ constr. pointcol : 12 25 1
-- dest. pointcol - couleur : 1
-- destr. point : 12 25
-- dest. pointcol - couleur : 1
-- destr. point : 0 0
-- dest. pointcol - couleur : 1
-- destr. point : 12 0
-- dest. pointcol - couleur : 1
-- destr. point : 2 3
-- dest. pointcol - couleur : 3
-- destr. point : 10 15
_______________________________________________________________________________
______
XIII. La te ch nique de l'h é ritage 213

Appe lde s cons tructe urs e t de s tructe urs de la clas s e d e b a s e e t de la clas s e d é rivé e

R e m arque :

D ans le m e s s age affich é par ~ pointcol, vous aurie z pe ut ê tre s ouh aité voir apparaî
tre les valeurs de x et
de y. Or, ceci n'est pas possible, du m oins te lle q ue la clas s e point a é té conçue . En e ffe t, un m e m bre
d'une classe dérivé e n'a pas accè s aux m e m bre s privés de la classe de bas e . Nous re vie ndrons sur ce t
aspect q ui s'avè re fondam e ntaldans la conce ption de clas s e s "ré utilisables ".

4.5 D 'une m aniè re gé né ral


e

Nous ve nons d'exam ine r un cas q u'on pourrait q ualifie r d'usue l: la classe de bas e e t la classe dérivé e
possédaie nt leur constructe ur (au m oins un).

Si la classe de bas e ne possè de pas de constructe ur, aucun problèm e particulie r ne s e pos e . Ile n va de m ê m e
si elle ne possè de pas de destructe ur.

En re vanch e , si la classe dérivé e ne possè de pas de constructe ur, alors q ue la classe de bas e e n com porte , on
va voir s e pos e r à nouve au le problèm e de la transm ission des inform ations atte ndue s par le constructe ur de
la classe de bas e . Com m e ce lles -ci ne pe uve nt plus prove nir du constructe ur de la classe dérivé e , on
com pre nd q ue la s e ule s ituation acce ptable s oit ce lle où la classe de base dispose d'un constructe ur sans
argum e nt. Dans les autre s cas, on aboutira à une e rre ur de com pilation.

Par ailleurs, lors q ue l'on m e ntionne les inform ations à transm e ttre à un constructe ur de la classe de bas e , on
n'e s t pas obligé d e s e lim ite r, com m e nous l'avons fait jus q u'ici, à des nom s d'argum e nts. O n pe ut e m ploye r
n'im porte q ue lle e xpre s s ion. Par e xe m ple, bie n q ue ce la n'ait guè re d e s e ns ici, nous pourrions é crire :

pointcol (int abs, int ord, char cl) : point (abs + ord, abs - ord)

R e m arque :

Le cas du constructe ur de re copie s e ra e xam iné un pe u plus loin car sa bonne m ise en œuvre né ce s s ite la
connaissance des possibilités de conve rsion im plicite d'une classe dérivé e e n un classe de bas e q ue nous
n'avons pas encore exam iné e s .

5. CO NTRÔ LE D ES ACCÈS

Com m e nous l'avons indiq ué dans le pre m ie r paragraph e , nous n'avons e xam iné jus q u'ici q ue la situation
d'h é ritage la plus nature lle, c'e s t-à -dire ce lle dans laq ue lle :

• la classe dérivé e 6 a accè s aux m e m bre s publics de la classe de bas e ,


• les "utilisate urs 7" de la classe dérivé e ont accè s à s e s m e m bre s publics, ainsi qu'aux m e m bre s publics de
sa classe de bas e .
Com m e nous allons le voir m ainte nant, C+ + pe rm e t d'inte rve nir e n partie s ur ces deux sorte s
d'autorisation d'accè s, e t ce ci à deux nive aux :

6 - Sous-ente ndu : toute fonction m e m bre d'une classe dérivée.


7 - Sous-ente ndu : tout obje t du type de l
a classe dérivée.
214 Program m e r e n langage C+ +
Lors de l a conception de l a cl asse de base : e n e ffe t, e n plus des statuts publics e t privé s q ue nous
connaissons, il e xiste un troisiè m e s tatut dit "proté gé " (m ot clé prote cte d). Le s m e m bre proté gé s s e
com porte nt com m e des m e m bre s privé s pour l'utilisate ur de la classe dérivé e m ais com m e des m e m bre s
publics pour la classe dérivé e e lle-m ê m e .

Lors de l a conception de l
a cl
asse dérivé e , on pe ut re s tre indre les possibilités d'accè s aux m e m bres de la
classe de bas e .

5.1 Le s m e m bre s proté gé s

Jus q u'ici, nous avons considéré qu'iln'e xistait q ue deux "statuts" possibles pour un m e m bre de clas s e :

• privé : le m e m bre n'e s t acce s s ible q u'aux fonctions m e m bre (publiq ue s ou privé e s ) e t aux fonctions
am ies de la clas s e ,
• public : le m e m bre e s t acce s s ible non s e ulem e nt aux fonctions m e m bre ou aux fonctions am ie s , m ais
é galem e nt à l'utilisate ur de la clas s e (c'e s t-à -dire à n'im porte q ue lobje t du type de ce tte clas s e ).
Nous avons vu com m e nt l'e m ploi de s m ots clés public e t private pe rm e ttait de distingue r les m e m bre s privé s
des m e m bre s publics.

Ile xiste e n fait un troisiè m e "statut" : proté gé ;ile s t défini par le m ot clé protected q ui s'e m ploie com m e
les deux m ots clés pré cédents. La définition d'une clas s e pe ut, par e xe m ple, pre ndre alors l'allure s uivante :

class X
{ private :
..... // partie privée
protected :
..... // partie protégée
public :
..... // partie publique
} ;

Le s m e m bre s proté gé s re s te nt inacce s s ibles à "l'utilisate ur" de la clas s e , pour q ui ils apparais s e nt analogue s
à des m e m bre s privé s . M ais ils s e ront acce s s ibles aux m e m bres d'une éve ntue lle classe dérivé e , tout e n
re s tant (dans tous les cas) inacce s s ibles aux "utilisate urs" de ce tte clas s e .

5.2 Exe m pl
e

D ans le début du paragraph e 2, nous avions é voq ué l'im possibilité , pour une fonction m e m bre d'une clas s e
pointcoldérivé e d e point, d'accéder aux m e m bre s privé s x e t y de point. Si nous définissons ainsi notre
clas s e point :

class point
{ protected :
int x, y ;
public :
point ( ... ) ;
affiche () ;
.....
} ;
XIII. La te ch nique de l'h é ritage 215

ildevie nt possible de définir, dans pointcol, une fonction m e m bre affich e de la m aniè re s uivante :

class pointcol : public point


{
short couleur ;
public :
void affiche ()
{ cout << "Je suis en " << x << " " << y << "\n" ;
cout << " et ma couleur est " << couleur << "\n" ;
}

5.3 Inté rê t du s tatut proté gé

Le s m e m bre s privés d'une clas s e s ont d é finitivem ent inaccessibl es depuis ce que nous appellerons
"l'e xté rie ur" de la clas s e (obje ts de ce tte clas s e , ou fonctions m e m bre d'une classe dérivé e , ou obje ts de
ce tte classe dérivé e ...). Ce ci pe ut pos e r de s problèm e s au conce pte ur d'une classe dérivé e , notam m e nt dans
le cas où ce s m e m bre s s ont des données, dans la m e s ure où ile s t contraint, com m e un "banalutilisate ur", de
pas s e r par "l'inte rface " obligatoire . De plus, ce tte façon de faire pe ut nuire à l'e fficacité du code gé né ré .

L'introduction du statut proté gé constitue donc un progrè s m anife s te : les m e m bre s proté gé s re s te nt
com parables à des m e m bre s privé s pour l'utilisate ur de la clas s e , m ais ils sont com parables à des m e m bre s
publics pour le conce pte ur d'une classe dérivé e (tout e n re s tant com parables à des m e m bre s privé s pour
l'utilisate ur de ce tte derniè re ). Né anm oins, ilfaut re connaî
tre q ue , du m ê m e coup, on offre les m oye ns de
violer (conscie m m e nt) le principe d'encapsulation des données. En effe t, rie n n'e m pê ch e un utilisate ur d'une
clas s e com portant une partie proté gé e , de cré e r une classe dérivé e conte nant les fonctions approprié e s
pe rm e ttant d'accéder aux donné e s corre s pondante s . Bie n e nte ndu, il s'agit d'un viol voulu e t conçu
délibérém e nt par l'utilisate ur ;ce la n'a plus rie n à voir ave c des ris q ues de m odification accidentel le des
donné e s .

R e m arques :

1) Lors q u'une classe dérivé e possè de des fonctions am ie s , ces derniè res disposent e xacte m e nt des
m ê m e s autorisations d'accè s q ue les fonctions m e m bre (de la classe dérivé e ). En particulie r, les
fonctions am ies d'une classe dérivé e auront bien accè s aux m e m bres déclaré s proté gés dans sa clas s e
de bas e .
2) En re vanch e , les déclarations d'am itié ne s 'h é rite nt pas. Ainsi, si f a é té déclaré e am ie d'une clas s e A
e t si B dérive de A, f n'e s t pas autom atiq ue m e nt am ie de B (ile s t bien sûr possible de pré voir une
déclaration appropriée d'am itié dans B).

5.4 A ction sur l


e s tatut de s m e m bre s d'une cl
as s e dé rivé e : dé rivation publ
iq ue
ou privé e

a)Rappe l
s conce rnant l
a dé rivation publ
iq ue
Nos pré cédents e xe m ples faisaie nt inte rve nir la form e la plus courante de dérivation dite "dérivation
publiq ue " car introduite par le m ot clé public dans la déclaration de la classe dérivé e , com m e dans :

class pointcol : public point { ... } ;


216 Program m e r e n langage C+ +
D ans ce cas, rappe lons q ue :

• les m e m bre s publics de la classe de bas e s ont acce s s ibles à "tout le m onde ", c'e s t-à -dire à la fois aux
fonctions m e m bre e t aux fonctions am ies de la classe dérivé e ainsi qu'aux utilisate urs de la clas s e
dérivé e ,
• les m e m bre s proté gés de la classe de bas e s ont acce s s ibles aux fonctions m e m bre e t aux fonctions am ie s
de la classe dérivé e m ais pas aux utilisate urs de ce tte classe dérivé ,
• les m e m bre s privés de la classe de bas e s ont inacce s s ibles à la fois aux fonctions m e m bre ou am ies de la
classe dérivé e e t aux utilisate urs de ce tte classe dérivé e .
D e plus, tous les m e m bres de la classe de bas e cons e rve nt, dans la classe dérivé e , le s tatut q u'ils avaie nt
dans la classe de bas e . Ce tte re m arq ue n'inte rvie nt q u'e n cas de dérivation d'une nouve lle classe de la clas s e
dérivé e .

Voici un tableau ré capitulant la situation :

Statut dans la clas s e Accè s aux fonctions Accè s à un uti- Nouve au statut dans
de bas e m e m bre e t am ies de lisate ur de la clas s e la classe dérivé e , e n
la classe dérivé e dérivé e cas de nouve lle déri-
vation

public oui oui public

proté gé oui non proté gé

privé non non privé

La dérivation publique

Ce s possibilité s pe uve nt ê tre re s tre inte s e n dé finissant ce q ue l'on nom m e des dérivations privé e s ou
proté gé e s .

b)D é rivation privé e

Ile s t possible, m oye nnant l'utilisation du m ot clé private au lie u du m ot clé public, d'inte rdire à un
utilisate ur d'une classe dérivé e l'accè s aux m e m bre s publics de sa classe de bas e . Par e xe m ple, ave c ce s
déclarations :

class point class pointcol : private point


{ ..... { .....
public : public :
point (...) ; pointcol (...) ;
void affiche () ; void colore (...) ;
void deplace (...) ; ...
... } ;
} ;
XIII. La te ch nique de l'h é ritage 217
Si p e s t de type pointcol, les appe ls suivants s e ront re je té s par le com pilate ur8 :

p.affiche () ou m ê m e p.point::affiche ()
p.deplace (...) ou m ê m e p.point::deplace (...)

alors q ue , nature llem e nt, ce lui-ci s e ra acce pté :

p.colore (...)

O n pe ut, à juste titre , pe ns e r q ue ce tte te ch niq ue lim ite l'inté rê t de l'h é ritage . Plus précisém e nt, le
conce pte ur de la classe dérivé e pe ut, q uant à lui, utiliser libre m e nt les m e m bre s publics de la classe de bas e
(com m e un utilisate ur ordinaire ) ;e n re vanch e , ildécide de fe rm e r totalem e nt ce t accè s à l'utilisate ur de la
classe dérivé e . O n pe ut dire q ue l'utilisate ur connaî tra toute s les fonctionnalités de la clas s e e n lisant sa
déclaration, sans q u'iln'ait aucune m e nt besoin de lire ce lle de sa classe de bas e (iln'e n allait pas de m ê m e
dans la situation usuelle : dans nos exem ples des paragraph e s pré cédents, pour connaî tre l'e xiste nce de la
fonction m e m bre de place pour la clas s e pointcol, ilfallait connaî tre la déclaration de point).

Ce la m ontre q ue ce tte te ch niq ue de fe rm e ture des accè s à la classe de bas e ne s e ra e m ployé e q ue dans des
cas bien précis, par exem ple :

• lors q ue toute s les fonctions utiles de la classe de bas e s ont redéfinies dans la classe dérivé e e t q u'iln'y a
aucune raison de lais s e r l'utilisate ur accéder aux ancie nne s ,
• lors q ue l'on souh aite adapte r l'inte rface d'une clas s e , de m aniè re à ré pondre à ce rtaine s e xige nce s ;dans
ce cas, la classe dérivé e pe ut, à la lim ite , ne rie n apporte r de plus (pas de nouve lles données, pas de
nouve lles fonctionnalité s ) : e lle fait la "m ê m e ch os e " q ue la classe de bas e , s e ule s on utilisation e s t
diffé re nte !

R e m arques :

1) D ans le cas d'une dérivation privé e , les m e m bre s proté gés de la classe de bas e re s te nt acce s s ibles aux
fonctions m e m bre e t aux fonctions am ies de la classe dérivé e ;e n re vanch e , ils s e ront considérés
com m e privé s pour une dérivation future .
2) Le s te rm es de dérivation publ ique ou de dérivation privé e s e ront, e n toute rigue ur, am bigus dans le
cas d'h é ritage m ultiple ;plus précisém e nt, ilfaudra alors dire, pour ch aq ue classe de bas e , q ue le s t le
type de dérivation (publiq ue ou privé e ).

5.5 Le s pos s ibil


ité s de dé rivation proté gé e (ve rs ion 3)

La ve rsion 3 de C+ + a introduit une possibilité s upplém e ntaire de dérivation, dite dérivation proté gé e ,
inte rm édiaire e ntre la dérivation publiq ue e t la dérivation privé e . Dans ce cas, les m e m bre s publics de la
classe de bas e s e ront considérés com m e proté gé s lors de dérivation ulté rie ure s .

R e m arque :

Ne confonde z pas le m ode de dérivation d'une clas s e par rapport à sa classe de bas e (publiq ue , proté gé e
ou privé e ), définie par l'un de s m ots public, prote cte d ou private ave c le s tatut des m e m bres d'une clas s e
(public, proté gé ou privé ) défini é galem e nt par l'un de ce s trois m ots.

8 - A m oins q ue l
'une des fonctions m e m bre affich e ou de place ait é té redéfinie dans pointcol.
218 Program m e r e n langage C+ +
5.6 Ré capitul
ation

Voici un tableau ré capitulant les proprié tés des diffé re nte s s ortes de dérivation (la m e ntion "Accè s FM A "
signifie : accè s aux fonctions m e m bre ou am ies de la clas s e ;la m e ntion "nouve au statut" signifie : statut
q u'aura ce m e m bre dans une éve ntue lle classe dérivé e ).

Cl
asse de base Dérivé e publ
ique Dérivé e proté gé e Dérivé e privé e

Statut Accè s Accè s Nouve au Accè s Nouve au Accè s Nouve au Accè s


initial FM A utilisate ur statut utilisate ur statut utilisate ur statut utilisate ur
public O O public O proté gé N privé N
proté gé O N proté gé N proté gé N privé N
privé O N privé N privé N privé N

Les diffé re nte s s orte s d e d é rivation

R e m arque :

O n voit claire m e nt q u'une dérivation proté gé e ne se distingue d'une dérivation privé e q ue lors q ue l'on e s t
am e né à dérive r de nouve lles classes de la classe dérivé e e n q ue s tion.

6. CO M PA TIBILITÉ ENTRE O BJETS D 'UNE CLASSE D E BASE


ET O BJETS D 'UNE CLASSE D ÉRIVÉE

D 'une m aniè re gé né rale, e n P.O .O ., on considè re q u'un obje t d'une classe dérivé e pe ut "re m place r" un
obje t d'une classe de bas e ou e ncore q ue : là où un obje t de clas s e A e s t atte ndu, tout obje t d'une clas s e
dérivé e d e A pe ut "faire l'affaire ".

Ce tte idée repose sur le fait q ue tout ce q ue l'on trouve dans une classe de bas e (fonctions ou donné e s ) s e
trouve é galem e nt dans la classe dérivé e . De m ê m e , toute action ré alisable s ur une classe de bas e pe ut
toujours ê tre ré alisée sur une classe dérivé e (ce q ui ne ve ut pas dire pour autant q ue le ré s ultat s e ra aussi
satisfaisant dans le cas de la classe dérivé e q ue dans ce lui de la classe de bas e –on affirm e s e ulem e nt q u'e lle
e s t possible !). Par e xe m ple, un point coloré pe ut toujours ê tre traité com m e un point : ilpossè de des
coordonné e s ;on pe ut affich e r ces derniè re s com m e on le fe rait pour ce lles d'un point.

Bie n e nte ndu, les ré ciproq ues de ces deux propositions sont faus s e s ;par e xe m ple, on ne pe ut pas colore r un
point ou s'inté re s s e r à sa couleur.

Ce tte com patibilité e ntre une classe dérivé e e t sa classe de bas e 9 va s e re trouve r e n C+ + , ave c une légè re
nuance : e lle ne s 'appliq ue ra q ue dans le cas de dérivation publiq ue 10. Concrè te m e nt, ce tte com patibilité s e
ré s um e à l'e xiste nce de conve rsions im plicite s :

• d'un obje t d'un type dérivé dans un obje t d'un type de bas e ,
• d'un pointe ur (ou d'une ré fé re nce ) sur une classe dérivé e e n un pointe ur (ou une ré fé re nce ) sur une clas s e
de bas e .

9 - Ou l'une d e s e s cl asses de base dans l e cas de l'h é ritage m ul


tipl
e q ue nous aborde rons dans l e ch apitre s uivant.
10 - Ce q ui s e jus tifie par le fait q ue, dans l
e cas contraire, ils uffirait de conve rtir un obje t d'une cl asse dérivée dans l
e type de sa cl
as s e
de base pour passer outre l
a privatisation de s m e m bres publ
ics du type de base.
XIII. La te ch nique de l'h é ritage 219
Nous allons voir ici l'incide nce de ce s conve rsions dans le cas d'affe ctations e ntre obje ts d'abord, e ntre
pointe urs e nsuite . La derniè re s ituation, au de m e urant la plus ré pandue , nous perm e ttra de m e ttre e n
é vidence :

• le typage s tatiq ue des obje ts q ui e n dé coule ;ce point constitue ra e n fait une introduction à la notion de
m é th ode virtue lle pe rm e ttant le typage dynam iq ue (e t q ui fe ra l'obje t du ch apitre XV).
• les ris q ues de violation du principe d'encapsulation q ui e n dé coulent.

6.1 Conve rs ions d'un obje t dé rivé dans un obje t d'un type de bas e

Soit nos deux clas s e s "h abitue lles " :

class point class pointcol : public point


{ ..... { .....

Ave c les déclarations :

point a ;
pointcol b ;

l'affe ctation :

a = b ;

e s t légale. Elle e ntraî ne une conve rsion de b dans le type point11 e t l'affe ctation du ré s ultat à a ;ce tte
affe ctation s e fait, suivant les cas :

• par appe lde l'opé rate ur d'affe ctation (de la clas s e point) si ce lui-ci a é té s urdé fini,
• par e m ploi de l'affe ctation par dé faut, dans le cas contraire .
En re vanch e , l'affe ctation suivante s e rait re je té e :

b = a ;

6.2 Conve rs ions d'un pointe ur sur une cl


as s e dé rivé e e n un pointe ur sur une
cl
as s e de bas e

Considérons à nouve au une clas s e point e t une clas s e pointcoldérivé e d e point, com portant ch acune une
fonction m e m bre affich e .

class point class pointcol : public point


{ int x, y ; { short couleur ;
public : public :
..... .....
void affiche () ; void affiche () ;
..... .....
} ; } ;

Soit ces déclarations :

point * adp ;

11 - En général
, une te l
le conve rsion est assez fictive e t n'e ntraî
ne pas l
a cré ation d'un nouve lobje t de type point.
220 Program m e r e n langage C+ +
pointcol * adpc ;

Là e ncore , C+ + autoris e l'affe ctation :

adp = adpc ;

laq ue lle corre s pond à une conve rsion du type pointcol*dans le type point *.

L'affe ctation inve rs e :

adpc = adp ;

s e rait nature llem e nt re je té e . Elle e s t ce pe ndant ré alisable, e n faisant appe là l'opé rate ur de "cast". Ainsi,
bien q ue s a signification soit ici discutable12, ilvous s e ra toujours possible d'écrire l'instruction :

adpc = (pointcol *) adp ;

R e m arque im portante :

S'ile s t possible de conve rtir e xplicite m e nt un pointe ur de type point *e n un pointe ur de type pointcol*,
iln'e s t, par contre , pas possible de conve rtir un obje t de type pointcole n un obje t de type point. La
diffé re nce vie nt de ce q ue l'on a affaire à une "conve rsion prédéfinie " dans le pre m ie r cas 13, alors q ue
dans le s e cond cas, le com pilate ur ne pe ut "im agine r" ce q ue vous souh aite z faire .

6.3 Lim itations l


ié e s au "typage s tatiq ue " de s obje ts

Considérons à nouve au les déclarations du paragraph e pré cédent accom pagné e s d e 14 :

point p (3, 5) ; pointcol pc (8, 6, 2) ;


adp = & p ; adpc = & pc ;

La situation e s t alors ce lle-ci :

A ce nive au, l'instruction :

adp -> affiche () ;

appe llera la m é th ode point::affich e , tandis q ue l'instruction :

12 - Et m ê m e dange re use, com m e nous l


e ve rrons dans l
e paragraph e 6.4.
13 - Laq ue ll
e se borne en fait à un ch ange m e nt de type (sur l
e plan syntaxiq ue ), accom pagné é ve ntue l
le m e nt d'un al
igne m e nt d'adresse
(atte ntion, rie n ne garantit q ue l
'appl
ication s ucce s s ive des deux conve rsions réciproques (point *-> pointcol*puis pointcol*-> point *)
fournis s e e xacte m e nt l
'adre s s e initial
e !).
14 - En supposant q u'ile xis te des cons tructe urs appropriés.
XIII. La te ch nique de l'h é ritage 221
adpc -> affiche () ;

appe llera la m é th ode pointcol::affich e .

Nous aurions obte nu les m ê m e s ré s ultats ave c :

p.affiche () ;
pc.affiche () ;

Si nous e xé cutons alors l'affe ctation :

adp = adpc ;

nous aboutissons à ce tte s ituation :

Que va faire , à ce nive au, une instruction te lle q ue :

adp -> affiche () ;

Y aura-t-ilappe lde point::affich e ou de pointcol::affich e ?

En e ffe t, adp e s t du type point m ais l'obje t pointé par adp e s t du type pointcol. En fait, le ch oix de la
m é th ode à appe ler e s t ré alisé par le com pilate ur, ce q ui signifie q ue la m é th ode appe lée e s t définie une fois
pour toute s e t q u'e lle ne pourra pas é volue r au fildes ch ange m e nts é ve ntue ls de type de l'obje t pointé . Bie n
e nte ndu, dans ce s conditions, on com pre nd q ue le com pilate ur ne pe ut q ue décide r de m e ttre e n place l'appe l
de la m é th ode corre s pondant au type défini par le pointe ur. Ici, ils'agira donc de point::affich e , puis q ue adp
e s t du type point *.

Note z bie n q ue s i pointcoldispose d'une m é th ode colore (n'e xistant pas dans point) un appe lte lq ue :

adp -> colore (8) ;

s e ra re je té par le com pilate ur.

O n pe ut donc dire q ue , pour l'instant, le type des obje ts pointé s par adp e t adpc e s t décidé e t figé au m om e nt
de la com pilation. O n pe ut alors considérer com m e un leurre le fait q ue C+ + tolère ce rtaine s conve rsions
de pointe urs ;e n fait, d'ailleurs, iltolère ce lles q ui, au bout du com pte , ne pos e ront pas de problèm e vis-à -
vis du ch oix fait au m om e nt de la com pilation (com m e nous l'avons dit, on pourra toujours affich e r un
pointcol"com m e s 'il" s'agissait d'un point). En e ffe t, nous pouvons désigner, à l'aide d'un m ê m e pointe ur,
des obje ts de type diffé re nt, m ais nous n'avons (pour l'instant) aucun m oye n de te nir ré e llem e nt com pte du
type de l'obje t pointé (par e xe m ple affich e traite un pointcolcom m e un point, m ais e lle ne pe ut pas savoir
s'ils'agit d'un point ou d'un pointcol).

En ré alité , nous ve rrons q ue C+ + pe rm e t d'effe ctue r ce tte identification d'un obje t au m om e nt de


l'e xé cution (e t non plus, arbitraire m e nt, à la com pilation) e t de ré aliser ce que l'on nom m e du "typage
222 Program m e r e n langage C+ +
dynam iq ue " (alors q ue , jus q u'ici, nous n'avions affaire q u'à du typage "statiq ue "). Ce ci né ce s s ite ra l'e m ploi
des fonctions virtuel l
es q ue nous aborde rons dans le ch apitre XV.

Voici m ainte nant un e xe m ple de program m e illustrant les lim itations q ue nous ve nons d'évoq ue r ;re m arq ue z
q ue , dans la m é th ode affich e de pointcol, nous n'avons pas fait appe là la m é th ode affich e de point ;pour
q u'e lle puis s e accéder aux m e m bre s x e t y de point, nous avons prévu de leur donne r le s tatut proté gé .

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ protected : // pour que x et y soient accesibles à pointcol
int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
void affiche ()
{ cout << "Je suis un point \n" ;
cout << " mes coordonnées sont : " << x << " " << y << "\n" ;
}
} ;
class pointcol : public point
{
short couleur ;
public :
pointcol (int abs=0, int ord=0, short cl=1) : point (abs, ord)
{ couleur = cl ;
}
void affiche ()
{ cout << "Je suis un point coloré \n" ;
cout << " mes coordonnées sont : " << x << " " << y ;
cout << " et ma couleur est : " << couleur << "\n" ;
}
} ;
main()
{ point p(3,5) ; point * adp = &p ;
pointcol pc (8,6,2) ; pointcol * adpc = &pc ;
adp->affiche () ; adpc->affiche () ;
cout << "-----------------\n" ;
adp = adpc ; // adpc = adp serait rejeté
adp->affiche () ; adpc->affiche () ;
} _______________________
Je suis un point
mes coordonnées sont : 3 5
Je suis un point coloré
mes coordonnées sont : 8 6 et ma couleur est : 2
-----------------
Je suis un point
mes coordonnées sont : 8 6
Je suis un point coloré
mes coordonnées sont : 8 6 et ma couleur est : 2
_______________________________________________________________________________
______

Le s lim itations liée s au typage s tatique de s obje ts


XIII. La te ch nique de l'h é ritage 223

$ 6.4 Le s ris q ue s de viol


ation de s prote ctions d e l
a cl
as s e de bas e

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

Nous avons vu q u'ile s t possible, dans une classe dérivé e , de rendre privé s les m e m bre s publics de la clas s e
de bas e . En voici un e xe m ple :

class A class B : private A


{ int x ; { int u ;
public : public :
float z ; double v ;
void fa () ; void fb () ;
..... .....
} ; } ;
A a ; B b ;

Ici, l'obje t a aura accè s aux m e m bre s z e t fa de A. On pourra écrire par exem ple :

a.z = 5.25 ;
a.fa () ;

Par contre , l'obje t b n'aura pas accè s à ce s m e m bre s , com pte te nu du m ot private figurant dans la
déclaration de la clas s e B. D ans ce s conditions, les instructions :

b.z = 8.3 ;
b.fa () ;

s e ront re je té e s par le com pilate ur (à m oins, bie n sûr, q ue les m e m bre s z e t fa ne s oie nt redéfinis dans la
clas s e B).

Né anm oins, ile xiste , pour l'utilisate ur de la clas s e B un m oye n de pas s e r outre ce tte prote ction m ise en
place par le conce pte ur de la clas s e . En e ffe t, illui suffit de procéder ainsi :

A * ada ; B * adb ;
adb = &b ;
ada = (A *) adb ;

ou e ncore , plus briè ve m e nt :

A * ada = (A *) & b ;

D ans ce s conditions, ada contie nt e ffe ctive m e nt l'adresse de b (nous avons dû em ploye r le "cast" car
n'oublie z pas q ue , sinon, la conve rsion dérivé e -> bas e s e rait re je té e ) ;m ais ada a toujours le type A *. O n
pe ut donc m ainte nant accéder aux m e m bre s publics de la clas s e A , bie n q ue privé s pour la clas s e B. Ce s
instructions s e ront acce pté e s :

ada -> z = 8.3 ;


ada -> fa () ;
224 Program m e r e n langage C+ +
7. CAS DU CONSTRUCTEUR D E RECO PIE

R appe lons q ue le constructe ur de re copie (q u'ils'agisse de ce lui par dé faut ou de ce lui q ui e s t fourni
e xplicite m e nt) e s t appe lé e n cas :

• d'initialisation d'un obje t par un obje t de m ê m e type ,


• de transm ission de la valeur d'un obje t e n argum e nt ou e n re tour d'une fonction.
Le s rè gles q ue nous avons é noncées dans le paragraph e 4 s'appliq ue nt à tous les constructe urs, e t donc
é galem e nt au constructe ur de re copie . Toute fois, dans ce dernie r cas, ilfaut aussi te nir com pte de l'e xiste nce
d'un constructe ur de re copie par dé faut. Voyons plus précisém e nt ce q u'ile n e s t, e n e xam inant les dive rs e s
situations possibles . Nous supposerons, pour fixe r les idées, que l'on a affaire aux instructions suivante s (B
dérive donc de A) :

class A { ... } ;
class B : public A { ... } ;
void fct (B) ; // fct est une fonction recevant un argument de type B
...
B b1 (...) ; // arguments éventuels pour un "constructeur usuel"
fct (b1) ; // appel de fct à qui on doit transmettre b1 par valeur, ce qui
// implique l'appel d'un constructeur de recopie de la classe
B

Bie n e nte ndu, tout ce q ue nous allons dire s'appliq ue rait é galem e nt aux autre s s ituations d'initialisation par
re copie c'e s t-à -dire au cas où une fonction re nve rrait par valeur un ré s ultat de type B ou e ncore à ce lui où
l'on initialiserait un obje t de type B ave c un autre obje t de type B, com m e dans B b2 = b1 ou e ncore B b2
(b1) (re voye z é ve ntue llem e nt les paragraph e s 3 e t 4 du ch apitre VII).

7.1 La cl
as s e dé rivé e (B) n'a pas dé fini de cons tructe ur de re copie

Ily a donc appe ldu constructe ur de re copie par dé faut de B. R appe lons q ue la re copie s e fait m e m bre par
m e m bre . Nous avons vu ce q ue ce la signifiait dans le cas des "obje ts m e m bre ". Ici, ce la signifie q ue la
"partie " de b1 apparte nant à la clas s e A s e ra traité e com m e un m e m bre de type A . Ily aura donc appe ldu
constructe ur de re copie de A pour les m e m bres donnée corre s pondants. Note z bie n q u'alors, si A a défini
un telconstructeur, ilsera appel é ;dans le cas contraire , on s e s e rvira du constructe ur de re copie par
défaut de A 15.

R e m arque im portante :

Ce tte gé né ralisation de la re copie m e m bre par m e m bre au cas des classes dérivé e s pourrait lais s e r
supposer q u'ile n ira de m ê m e pour l'opé rate ur d'affe ctation (dont nous avons vu q u'ilfonctionnait de
façon s e m blable à la re copie ). En fait, ce ne s e ra pas le cas ;nous y revie ndrons dans le paragraph e 9 .

7.2 La cl
as s e dé rivé e (B) a dé fini un cons tructe ur de re copie

D ans ce cas, le constructe ur de re copie de B e s t nature llem e nt appe lé. La q ue s tion q ui s e pos e alors e s t de
savoir s'ily a appe ld'un constructe ur de A . En fait, C+ + a décidé de ne pré voir aucun appe lautom atiq ue
de constructe ur de la classe de base dans ce cas (m ê m e s 'ile xiste un constructe ur de re copie dans A !). Ce la

15 - D ans l
e s ve rsions anté rie ure s à l
a 2.0, on avait affaire à une re copie gl
obal
e.
XIII. La te ch nique de l'h é ritage 225
signifie donc q ue le constructe ur de re copie de la classe dérivée doit pre ndre e n ch arge l'inté gralité de la
re copie de l'obje t e t non s e ulem e nt sa partie h é rité e .

M ais, ilre s te possible d'utiliser le m é canism e de transm ission d'inform ations e ntre constructe urs (é tudié e
dans le paragraph e 4.3). Ainsi, si le constructe ur de B pré voit des inform ations pour un constructe ur de A
ave c un e n-tê te de la form e :

B (B & x) : A (...)

ily aura appe ldu constructe ur corre s pondant de A.

En gé né ral, on souh aite ra q ue le constructe ur de A appe lé à ce nive au soit le constructe ur de re copie de A 16.
D ans ce s conditions, on voit q ue ce constructe ur doit re ce voir e n argum e nt, non pas l'obje t x tout e ntie r,
m ais s e ulem e nt ce q ui, dans x, est de type A . C'e s t là q u'inte rvie nt pré cis é m e nt la possibilité de conve rsion
im plicite d'une classe dérivée dans une classe de bas e (é tudiée dans le paragraph e 6). Ilnous suffira de
définir ainsi notre constructe ur pour aboutir à une re copie s atisfaisante :

B (B & x) : A (x) // x, de type B, est converti dans le type A pour être


transmis
// au constructeur de recopie de A
{ // recopie de la partie de x spécifique à B (non héritée de A)
}

Voici un program m e illustrant ce tte possibilité : nous y définissons sim plem e nt nos deux clas s e s h abitue lles
point e t pointcole n les m unissant toute s les deux d'un constructe ur de re copie 17 e t nous provoq uons l'appe l
de ce lui de pointcole n appe lant une fonction fct à un argum e nt de type pointcoltransm is par valeur.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) // constructeur usuel
{ x = abs ; y = ord ;
cout << "++ point " << x << " " << y << "\n" ;
}
point (point & p) // constructeur de recopie
{ x = p.x ; y = p.y ;
cout << "CR point " << x << " " << y << "\n" ;
}
} ;
class pointcol : public point
{ char coul ;
public :

16 - Bie n e nte ndu, en th é orie, ilre s te possibl


e au cons tructe ur par re copie de l
a cl
asse dérivé e B d'appe l
e r n'im porte q ue lcons tructe ur de
A, autre q ue s on cons tructe ur par re copie. Dans ce cas, ilfaut ê tre e n m e s ure de reporte r conve nabl
e m e nt dans l
'obje t l
e s val
e urs de l
a
partie de x qui est un A ;dans certains cas, on pourra e ncore y parve nir par l
e m é canis m e de trans m ission d'inform ations e ntre
cons tructe urs ;dans l
e cas contraire, ilfaudra e ffe ctue r l
e travailau s e in du constructe ur de recopie de B, ce qui peut s'avé re r dél
icat,
com pte te nu d'éve ntue l
s probl
è m es de droits d'accè s...
17 - Ce q ui, dans ce cas précis de cl as s e ne com portant pas de pointe urs, n'est pas util
e, l
a re copie par dé faut décrite pré cédem m e nt
s'avé rant s uffisante dans tous l
e s cas. Mais, ici, l
'obje ctif e s t sim pl
e m e nt d'il
lus te r l
e m é canis m e de trans m ission d'inform ations e ntre
cons tructe urs.
226 Program m e r e n langage C+ +
pointcol (int abs=0, int ord=0, int cl=1) : point (abs, ord) // constructeur
usuel
{ coul = cl ;
cout << "++ pointcol " << int(coul) << "\n" ;
}
pointcol (pointcol & p) : point (p) // constructeur de recopie
// il y aura conversion implicite
// de p dans le type point
{ coul = p.coul ;
cout << "CR pointcol " << int(coul) << "\n" ;
}
} ;
void fct (pointcol pc)
{
cout << "*** entrée dans fct ***\n" ;
}

main()
{ void fct (pointcol) ;
pointcol a (2,3,4) ;
fct (a) ; // appel de fct, à qui on transmet a par valeur
}
_______________________
++ point 2 3
++ pointcol 4
CR point 2 3
CR pointcol 4
*** entrée dans fct ***
_______________________________________________________________________________
______

Pour force r l'appe ld'un cons tructe ur de re copie de la clas s e d e b a s e

8. O PÉRA TEUR D 'AFFECTA TIO N ET H ÉRITAGE

Nous avons déjà vu com m e nt C+ + définit l'affe ctation par dé faut e ntre deux obje ts de m ê m e type . D'autre
part, nous avons vu com m e nt ilé tait possible de surdé finir ce t opé rate ur d'affe ctation (obligatoire m e nt sous
form e d'une fonction m e m bre ).

Voyons ce q ue devie nne nt ce s possibilité s e n cas d'h é ritage . Supposons que la clas s e B h é rite (publiq ue m e nt)
de A et considérons, com m e nous l'avons fait pour le constructe ur de re copie (paragraph e 4.6) les
diffé re nte s s ituations possibles .

8.1 La cl
as s e dé rivé e (B) n'a pas s urdé fini l
'opé rate ur =

L'affe ctation de deux obje ts de type B se déroule m e m bre à m e m bre e n considérant q ue la "partie h é rité e d e
A" constitue un m e m bre . Ainsi, les m e m bre s propre s à B sont traité s par l'affe ctation pré vue pour leur type
(par dé faut ou surdéfinie , suivant le cas). La partie h é rité e d e A e s t traité e par l'affe ctation pré vue dans la
clas s e A , c'e s t-à -dire par l'opé rate ur = surdéfini dans A s'ile xiste , par l'affe ctation par dé faut dans le cas
contraire .
XIII. La te ch nique de l'h é ritage 227
O n re trouve un com porte m e nt tout à fait analogue à ce lui dé crit dans le cas du constructe ur de re copie .

8.2 La cl
as s e dé rivé e (B) a surdé fini l
'opé rate ur =

D ans ce cas, l'affe ctation de deux obje ts de type B fe ra né ce s s aire m e nt appe là l'opé rate ur = défini dans B.
Ce lui de A ne s e ra pas appe lé, m ê m e s 'ila é té s urdé fini. Ilfaudra donc que l 'opérateur = de B prenne en
ch arge tout ce qui concerne l 'affectation d'objets de type B, y com pris pour ce q ui e s t des m e m bre s
h é rités de A.

Voici un pre m ie r e xe m ple de program m e q ui illustre ce la : la clas s e pointcoldérive de point. Les deux
clas s e s ont surdéfini l'opé rate ur =.

_______________________________________________________________________________
____

#include <iostream.h>
class point
{ protected :
int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ;}
point & operator = (point & a)
{ x = a.x ; y = a.y ;
cout << "opérateur = de point \n" ;
return * this ;
}
} ;

class pointcol : public point


{ protected :
int coul ;
public :
pointcol (int abs=0, int ord=0, int cl=1) : point (abs, ord) { coul=cl ; }
pointcol & operator = (pointcol & b)
{ coul = b.coul ;
cout << "opérateur = de pointcol\n" ;
return * this ;
}
void affiche () { cout << "pointcol : " << x << " " << y << " " << coul <<
"\n" ;
}
} ;
main()
{ pointcol p(1, 3, 10) , q(4, 9, 20) ;
cout << "p = " ; p.affiche () ;
cout << "q avant = " ; q.affiche () ;
q = p ;
cout << "q après = " ; q.affiche () ;
}
________________________________

p = pointcol : 1 3 10
q avant = pointcol : 4 9 20
228 Program m e r e n langage C+ +
opérateur = de pointcol
q après = pointcol : 4 9 10
_______________________________________________________________________________
____

Quand la clas s e d e b a s e e t la clas s e d é rivé e s u rdéfinis s e nt l'opérate ur =

O n y voit claire m e nt q ue l'opé rate ur = défini dans la clas s e point n'a pas é té appe lé lors d'une affe ctation
e ntre obje ts de type pointcol.

Le problèm e e s t voisin de ce lui re ncontré à propos du constructe ur de re copie , ave c ce tte diffé re nce q u'on
ne dispose plus ici du m é canism e de transfe rt d'argum e nts q ui e n pe rm e ttait un appe l(pre s q ue ) im plicite .
Ici, si l'on ve ut pouvoir profite r de l'opé rate ur = défini dans A, ilfaudra l'appe ler e xplicite m e nt. Le plus
sim ple pour ce faire e s t d'utiliser les possibilités de conve rsions de pointe urs e xam inées dans le pré cédent
paragraph e .

Voici, par e xe m ple, com m e nt nous pourrions m odifie r dans ce s e ns l'opé rate ur = de pointcol:

pointcol & operator = (pointcol & b)


{ point * ad1, * ad2 ;
cout << "opérateur = de pointcol\n" ;
ad1 = this ; // conversion pointeur sur pointcol en pointeur sur
point
ad2 = & b ; // idem
* ad1 = * ad2 ; // affectation de la "partie point" de b
coul = b.coul ; // affectation de la partie propre à pointcol
return * this ;
}

Nous conve rtissons les pointe urs (th is e t & b) sur des obje ts de pointcole n de s pointe urs sur de s obje ts de
type point. Ilsuffit e nsuite de ré aliser une affe ctation e ntre les nouve aux obje ts pointé s (*ad1 e t *ad2) pour
e ntraîne r l'appe lde l'opé rate ur = de la clas s e point. Voici le nouve au program m e com plet ainsi m odifié .
Ce tte fois, les ré s ultats m ontre nt q ue l'affe ctation e ntre obje ts de type pointcole s t satisfaisante .

_______________________________________________________________________________
____

#include <iostream.h>
class point
{ protected :
int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ;}
point & operator = (point & a)
{ x = a.x ; y = a.y ;
cout << "opérateur = de point \n" ;
return * this ;
}
} ;
class pointcol : public point
{ protected :
int coul ;
public :
pointcol (int abs=0, int ord=0, int cl=1) : point (abs, ord) { coul=cl ; }
XIII. La te ch nique de l'h é ritage 229
pointcol & operator = (pointcol & b)
{ point * ad1, * ad2 ;
cout << "opérateur = de pointcol\n" ;
ad1 = this ; // conversion pointeur sur pointcol en pointeur sur
point
ad2 = & b ; // idem
* ad1 = * ad2 ; // affectation de la "partie point" de b
coul = b.coul ; // affectation de la partie propre à pointcol
return * this ;
}
void affiche ()
{ cout << "pointcol : " << x << " " << y << " " << coul << "\n" ;
}
} ;
main()
{ pointcol p(1, 3, 10) , q(4, 9, 20) ;
cout << "p = " ; p.affiche () ;
cout << "q avant = " ; q.affiche () ;
q = p ;
cout << "q après = " ; q.affiche () ;
}
________________________________

p = pointcol : 1 3 10
q avant = pointcol : 4 9 20
opérateur = de pointcol
opérateur = de point
q après = pointcol : 1 3 10
_______________________________________________________________________________
____

Pour force r, dans une clas s e d é rivé e , l'utilisation de l'opérate ur = surdéfini


dans la clas s e d e b a s e

R e m arque :

O n dit souve nt q u'e n C+ + , l'opé rate ur d'affe ctation n'est pas h érité . Une te lle affirm ation e s t e n fait
source de confusions. En effe t, on pe ut considérer qu'elle e s t e xacte , dans la m e s ure où, lors q ue B n'a
pas défini l'opé rate ur =, on ne s e conte nte pas de faire appe là ce lui dé fini (é ve ntue llem e nt) dans A (ce
q ui re vie ndrait à ré aliser une affe ctation partie lle ne conce rnant q ue la partie h é rité e d e A !). En
re vanch e , on pe ut considérer que cette affirm ation e s t faus s e puis q ue , lors q ue B ne s urdé finit pas l'opé ra-
te ur =, ce tte clas s e pe ut q uand m ê m e "profite r" (autom atiq ue m e nt) de l'opé rate ur dé fini dans A;
Ce tte am biguïté s e re trouve d'ailleurs dans ce rtaine s im plém e ntations q ui, suivant ce tte affirm ation à la
lettre , n'ont pas prévu d'appe ler l'opé rate ur = défini dans A lors q ue B n'e n dé finissait aucun. Le ré s ultat
e s t alors as s e z déconce rtant...

9 . H ÉRITAGE ET FO RM E CANONIQUE D'UNE CLASSE

D ans le paragraph e 4 du ch apitre IX, nous avons défini ce q ue l'on nom m e la "form e canoniq ue " d'une
clas s e , c'e s t-à -dire le cane vas suivant leq ue ldevrait ê tre construite toute clas s e non triviale (disposant de
pointe urs).
230 Program m e r e n langage C+ +
Voici com m e nt ce s ch é m a pourrait ê tre gé né ralisé dans le cadre de l'h é ritage (par souci de briè ve té ,
ce rtaine s fonctions ont é té placé e s "e n ligne "). Plus précisém e nt, nous y trouvons :

• une classe de bas e nom m é e T, re s pe ctant la form e canoniq ue déjà pré s e nté e ,
• une classe dérivé e nom m é e U, re s pe ctant e lle aussi la form e canoniq ue , m ais s'appuyant sur ce rtaine s
des fonctionnalités de sa classe de bas e (constructe ur par re copie e t opé rate ur d'affe ctation). Note z bie n
q ue nous ne faisons que récapituler ici ce q ui a é té pré s e nté dans les paragraph e s 7 e t 8 de ce ch apitre .
_______________________________________________________________________________
______

class T
{ public :
T (...) ; // constructeurs de T, autres que par recopie
T (const T &) ; // constructeur de recopie de T (forme
conseillée)
~T () ; // destructeur
T & T::operator = (const T &) ; // opérateur d'affectation (forme
conseillée)
.....
} ;
class U : public T
{ public :
U (...) ; // constructeurs autres que recopie
U (const U & x) : T (x) // constructeur de recopie de U : il utilise
celui de T
{
// prévoir ici la copie de la partie de x spécifique à T (qui n'est pas
un T)
}
~U () ;
U & U::operator = (const U & x) // opérateur d'affectation (forme
conseillée)
{ T * ad1 = this, * ad2 = &x ;
*ad1 = *ad2 ; // affectation (à l'objet courant) de la
partie
// de x héritée de T
// prévoir ici l'affectation (à l'objet courant)
// de la partie de x spécifique à U (non héritée de T)
}
_______________________________________________________________________________
______

Form e canonique d'une clas s e d é rivé e

10. CE QU'EST L'H ÉRITAGE ET CE QU'ILN'EST PAS

Nous avons vu com m e nt une classe dérivé e pe ut tire r parti des possibilités d'une classe de bas e . O n traduit
parfois ce la e n disant q u'e lle h é rite de ses "fonctionnalité s ". Ce dernie r te rm e pe ut, ce pe ndant, prê te r à
confusion en laissant croire q ue l'h é ritage e s t plus généralq u'ilne l'e s t e n ré alité .

Pre nons l'e xe m ple d'une clas s e point q ui a surdéfini l'opé rate ur + (point + point -> point) e t d'une clas s e
pointcol q ui h é rite publiq ue m e nt de point (e t q ui ne redéfinit pas + ). Pourra-t-e lle utiliser cette
"fonctionnalité " de la clas s e point q u'e s t l'opé rate ur + ?En fait, on voit à ce nive au q u'un ce rtain nom bre
XIII. La te ch nique de l'h é ritage 231
de ch os e s s ont floue s . La som m e de deux points coloré s s e ra-t-e lle un point coloré ?Si oui, q ue lle pourrait
bien ê tre s a couleur ?Se ra-t-e lle s im plem e nt un point ?D ans ce cas, on ne pe ut pas vraim e nt dire q ue
pointcola h é rité des possibilités d'addition de point.

Pre nons m ainte nant un autre e xe m ple : ce lui de la clas s e point, m unie d'une fonction (m e m bre ou am ie )
coincide , te lle q ue nous l'avions considérée dans le paragraph e 1 du ch apitre VIII e t une clas s e pointcol
h é ritant de point. Notre fonction coincide pourra-t-e lle (te lle q u'e lle e s t) ê tre utilisée pour te s te r la
coïncide nce de deux points coloré s ?

Nous vous proposons d'apporte r de s é lém e nts de ré pons e à ces diffé re nte s q ue s tions. Pour ce faire , nous
allons préciser exacte m e nt ce q u'e s t l'h é ritage , ce q ui nous perm e ttra de conclure q ue les s ituations q ue nous
ve nons d'évoq ue r ne re lève nt pas (uniq ue m e nt) de l'h é ritage . Nous ve rrons e nsuite com m e nt la conjugaison
de l'h é ritage e t des rè gles de com patibilité e ntre obje ts dérivé s (dont nous avons parlé ci-de s s us) pe rm e t de
donne r un s e ns à ce rtaines des situations é voq ué e s ;les autre s né ce s s ite ront le re cours à des m oye ns
supplém e ntaire s (conve rsions, par e xe m ple).

10.1 La s ituation d'h é ritage

Considérons ce canevas (t désignant un type q ue lconq ue ) :

class A class B : public A


{ ..... { .....
public : } ;
t f(.....) ;
.....
} ;

La clas s e A possè de une fonction m e m bre f, dont nous ne précisons pas ici les argum e nts, fournissant un
ré s ultat de type t (type de bas e ou dé fini par l'utilisate ur). La clas s e B h é rite des m e m bre s publics de A,
donc de f. Soit deux obje ts a e t b :

A a ; B b ;

Bie n e nte ndu, l'appe l:

a.f (.....) ;

a un s e ns e t ilfournit un ré s ultat de type t.

Le fait q ue B h é rite publiq ue m e nt de A perm e t alors d'affirm e r q ue l


'appel:

b.f (.....) ;

a lui aussi un sens, autre m e nt dit, q ue f agira sur b (ou ave c b) com m e s 'ilé tait du type A . Son résul
tat
sera toujours de type t e t s e s argum e nts auront toujours le type im pos é par son prototype .

Tout l'h é ritage e s t conte nu dans ce tte affirm ation à laq ue lle ilfaut absolum e nt s e te nir. Expliq uons-nous.

a)Le type du ré s ul
tat de l
'appe l
Gé né ralem e nt, tant q ue t e s t un type usuel, l'affirm ation ci-de s s us apparaî t triviale. M ais des doute s
apparais s e nt dè s q ue t e s t un type obje t, surtout s'ils'agit du type de la classe dont f e s t m e m bre . Ainsi, ave c
le prototype :
232 Program m e r e n langage C+ +
A f(.....)

le ré s ultat de l'appe l b.f(.....) s e ra bie n de type A (e t non de type B com m e on pourrait parfois le
souh aite r...).

b)Le type de s argum e nts de f


La re m arq ue faite à propos de la valeur de re tour s'appliq ue aux argum e nts de f. Par e xe m ple, supposons
q ue f ait pour prototype :

t f(A) ;

e t q ue nous ayons déclaré :

A a , a ; B b b ;
1 2 1 2

L'h é ritage (public) donne e ffe ctive m e nt une s ignification à :

b .f(a )
1 1

Quant à l'appe l:

b .f(b )
1 2

s'ila un s e ns, c'e s t grâ ce à l'e xiste nce de conve rsions im plicite s :

• de l'obje t b1 de type B e n un obje t du type A si f re çoit son argum e nt par valeur. N'oublie z pas q u'alors
ily aura appe ld'un constructe ur de re copie (par dé faut ou surdéfini),
• d'une ré fé re nce à b1 de type B e n une ré fé re nce à un obje t de type A s i f re çoit s e s argum e nts par
ré fé re nce .

10.2 Exe m pl
es

R e ve nons m ainte nant aux e xe m ples é voq ué s e n introduction de ce paragraph e .

a)H é ritage dans pointcold'un opé rate ur + dé fini dans point


En fait, q ue l'opé rate ur + soit défini sous form e d'une fonction m e m bre ou d'une fonction am ie , la
"som m e " de deux obje ts a e t b de type pointcol s e ra de type point. En e ffe t, dans le pre m ie r cas,
l'e xpre s s ion :

a + b

s e ra é valué e com m e :

a.operator+ (b)

Ily aura appe lde la fonction m e m bre ope rator+ 18 pour l'obje t a (dont on ne considérera que ce qui est du
type point), à laq ue lle on transm e ttra e n argum e nt le ré s ultat de la conve rsion de b en un point19 . Son
ré s ultat s e ra de type point.

18 - Fonction m e m bre de pointcol, m ais h é ritée de point.


XIII. La te ch nique de l'h é ritage 233
D ans le s e cond cas, l'e xpre s s ion s e ra é valué e com m e :

operator+ (a, b)

Ily aura appe lde la fonction am ie 20 ope rator+ , à laq ue lle on transm e ttra le ré s ultat de la conve rsion de a et
b dans le type point. Le ré s ultat s e ra toujours de type point.

D ans ce s conditions, vous voye z q ue s i c e s t de type pointcol, une banale affe ctation te lle q ue :

c = a + b ;

s e ra re je té e , faute de disposer de la conve rsion de point e n pointcol. O n pe ut d'ailleurs logiq ue m e nt s e


dem ande r q ue lle couleur une te lle conve rsion pourrait attribue r à son ré s ultat ?Si m ainte nant on souh aite
définir la som m e de deux points coloré s , ilfaudra redéfinir l'opé rate ur + au s e in de pointcol, q uitte à ce
q u'ilfas s e appe là ce lui dé fini dans point pour la som m e des coordonné e s .

b)H é ritage dans pointcolde l


a fonction coincide de point

Ce tte fois, ile s t facile de voir q u'aucun problèm e particulie r ne s e pos e 21, à partir du m om e nt où l'on
considè re q ue la coïncide nce de deux points coloré s corre s pond à l'é galité de leurs s e ules coordonné e s (la
couleur n'inte rve nant pas).

A titre indicatif, voici un e xe m ple de program m e com plet, dans leq ue lcoincide e s t défini com m e une
fonction m e m bre de point.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{
int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
friend int coincide (point &, point &) ;
} ;

int coincide (point & p, point & q)


{ if ((p.x == q.x) && (p.y == q.y)) return 1 ;
else return 0 ;
}
class pointcol : public point
{ short couleur ;
public :
pointcol (int abs=0, int ord=0, short cl=1) : (abs, ord)
{ couleur = cl ; }
} ;

main() // programme d'essai


{

19 - Suivant l e s cas, ily aura conve rsion d'obje ts ou conve rsion de réfé re nces.
20 - A m ie de point e t de pointcolpar h é ritage, m ais, ici, c'e s t s e ul
e m e nt l
a re l
ation d'am itié ave c point q ui e s t e m pl
oyée.
21 - M ais, ici, l e ré s ul
tat fourni par coincide n'e s t pas d'un type cl as s e !
234 Program m e r e n langage C+ +
pointcol a(2,5,3), b(2,5,9), c ;
if (coincide (a,b)) cout << "a coincide avec b \n" ;
else cout << "a et b sont différents \n" ;
if (coincide (a,c)) cout << "a coincide avec c \n" ;
else cout << "a et c sont différents \n" ;
}
_______________________

a coincide avec b
a et c sont différents
_______________________________________________________________________________
______

H é ritage , dans pointcol, de la fonction coincide de point

11. EXEM PLE D E CLASSE D ÉRIVÉE

Suppos e z q ue nous disposions de la clas s e ve ct te lle q ue nous l'avions définie dans le paragraph e 5 du
ch apitre IX. Ce tte clas s e e s t m unie d'un constructe ur, d'un de s tructe ur e t d'un opé rate ur d'indiçage [] (note z
bien q ue , pour ê tre e xploitable, ce tte clas s e q ui contie nt des parties dynam iq ue s , devrait com porte r
é galem e nt un constructe ur par re copie e t la surdéfinition de l'opé rate ur d'affe ctation).

_______________________________________________________________________________
______

class vect
{ int nelem ;
int * adr ;
public :
vect (int n) { adr = new int [nelem=n] ; }
~vect () {delete adr ;}
int & operator [] (int) ;
} ;
int & vect::operator [] (int i)
{ return adr[i] ; }
_______________________________________________________________________________
______

Suppos e z q ue nous ayons besoin de ve cte urs dans les q ue ls on puisse fixe r, non s e ulem e nt le nom bre
d'élém e nts, m ais les bornes (m inim um e t m axim um ) des indices (supposés toujours e ntie rs). Par e xe m ple,
nous pourrions dé clare r (si ve ct1 e s t le nom de la nouve lle clas s e ) :

vect1 t (15, 24) ;

Ce q ui signifie rait q ue t e s t un tableau de dix entie rs d'indice s variant de 15 à 24.

Il s e m ble alors nature l d'essayer de dérive r une classe de ve ct. Il nous faut pré voir de ux m e m bre s
supplém e ntaire s pour cons e rve r les bornes de l'indice , d'où le début de la déclaration de notre nouve lle
clas s e :

class vect1 : public vect


{ int debut, fin ;
XIII. La te ch nique de l'h é ritage 235
M anife s te m e nt, ve ct1 né ce s s ite un constructe ur à deux argum e nts e ntie rs corre s pondant aux bornes de
l'indice . Son e n-tê te s e ra de la form e :

vect1 (int d, int f)

M ais l'appe lde ce constructe ur e ntraî ne ra autom atiq ue m e nt ce lui du constructe ur de ve ct ;iln'e s t donc pas
q ue s tion de faire dans ve ct1 l'allocation dynam iq ue de notre ve cte ur ;au contraire , nous ré utilisons le travail
e ffe ctué par ve ct : ilnous suffit de lui transm e ttre le nom bre d'élém e nts souh aité s , d'où l'e n-tê te com plet de
ve ct1 :

vect1 (int d, int f) : vect (f-d+1)

Quant à la tâ ch e s pé cifiq ue de ve ct1, e lle s e lim ite à re ns e igne r les valeurs de début e t fin.

A priori, la clas s e ve ct1 n'a pas besoin de destructe ur, dans la m e s ure où e lle n'alloue aucun e m place m e nt
dynam iq ue autre q ue ce lui dé jà alloué par ve ct.

Nous pourrions aussi pe ns e r q ue ve ct1 n'a pas besoin de surdéfinir l'opé rate ur [], dans la m e s ure où e lle
"h é rite " de ce lui de ve ct. Qu'e n e s t-ile xacte m e nt ?D ans ve ct, la fonction m e m bre ope rator[] re çoit un
argum e nt im plicite e t un argum e nt de type int ;e lle fournit une valeur de type int. Sur ce plan, donc,
l'h é ritage va fonctionne r corre cte m e nt e t C+ + acce pte ra q u'on fas s e appe là ope rator[] pour un obje t de
type dérivé ve ct1. Ainsi, ave c :

vect1 t (15, 24)

la notation :

t[i]

q ui signifie ra

t.operator[] (i)

aura bie n une s ignification.


è me
Le s e ule nnui... c'e s t q ue ce tte notation dé s igne ra toujours le i é lém e nt du tableau dynam iq ue de l'obje t t.
Et ce n'e s t plus ce q ue nous voulons. Ilnous faut donc surdéfinir l'opé rate ur [] pour la clas s e ve ct1.

A ce nive au, (au m oins) deux solutions s'offre nt à nous :

• utiliser l'opé rate ur e xistant dans ve ct, ce q ui nous conduit à :


int & operator[] (int i)
{ return vect::operator[] (i-debut) ; }

• ne pas utiliser l'opé rate ur e xistant dans ve ct, ce q ui nous conduirait à :


int & operator [] (int i)
{ return adr [i-debut] ; }

(à condition q ue adr soit acce s s ible à la fonction ope rator [], donc dé claré public ou, plus raisonnablem e nt,
privé ).

t pe ut-ê tre plus séduisante 22.


Ce tte derniè re s olution paraî

22 - D u m oins ici, car l


e travailà e ffe ctue r é tait sim pl
e. Dans l
a pratiq ue, on ch e rch e ra pl
utôt à ré cupé re r l
e travaildéjà e ffe ctué, en se
conte ntant de l
e com pl
é te r si nécessaire.
236 Program m e r e n langage C+ +
Voici un e xe m ple com plet faisant appe là la pre m iè re s olution. Nous y avons fait figure r la clas s e ve ct e lle-
m ê m e pour vous facilite r son exam e n e t nous avons, com m e à l'accoutum é e , introduit q ue lque s affich age s
d'inform ation, au s e in de ce rtaine s fonctions m e m bre de ve ct e t de ve ct1.

_______________________________________________________________________________
______

#include <iostream.h>
// **************** la classe vect **********************************
class vect
{ int nelem ; // nombre d'éléments
int * adr ; // pointeur sur ces éléments
public :
vect (int n) // constructeur vect
{ adr = new int [nelem = n] ;
cout << "+ Constr. vect de taille " << n << "\n" ;
}
~vect () // destructeur vect
{ cout << "- Destr. vect " ;
delete adr ;
}
int & operator [] (int) ;
} ;
int & vect::operator [] (int i)
{ return adr[i] ;
}
// **************** la classe dérivée : vect1 **********************
class vect1 : public vect
{ int debut, fin ;
public :
vect1 (int d, int f) : vect (f - d + 1) // constructeur vect1
{ cout << "++ Constr. vect1 - bornes : " << d << " " << f << "\n" ;
debut = d ; fin = f ;
}
int & operator [] (int) ;
} ;
int & vect1::operator [] (int i)
{ return vect::operator [] (i-debut) ; }
// **************** un programme d'essai ****************************
main()
{ const int MIN=15, MAX = 24 ;
vect1 t(MIN, MAX) ;
int i ;
for (i=MIN ; i<=MAX ; i++) t[i] = i ;
for (i=MIN ; i<=MAX ; i++) cout << t[i] << " " ;
cout << "\n" ;
} _______________________

+ Constr. vect de taille 10


++ Constr. vect1 - bornes : 15 24
15 16 17 18 19 20 21 22 23 24
- Destr. vect
_______________________________________________________________________________
______
XIII. La te ch nique de l'h é ritage 237

R e m arque :

Bie n e nte ndu, là e ncore , pour ê tre e xploitable, la clas s e ve ct1 devrait définir un constructe ur par re copie
e t l'opé rate ur d'affe ctation. A ce propos, on pe ut note r q u'ilre s te possible de définir ces deux fonctions
dans ve ct1, m ê m e s i e lles n'ont pas é té définie s corre cte m e nt dans ve ct.

12. PA TRO NS D E CLASSES ET H ÉRITAGE

Ile s t trè s facile de com bine r la notion d'h é ritage ave c ce lle de patron de clas s e s . Ce tte com binaison pe ut
re vê tir plusieurs aspects :

• Cl asse "ordinaire" dérivé e d 'une cl asse patron (c'e s t-à -dire d'une instance particuliè re d'un patron de
clas s e ) ;par e xe m ple, si A est une clas s e patron dé finie par te m plate < class T> A :
class B : public A <int> // B dérive de la classe patron A<int>

on 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 T> class B : public A

O n obtie nt une fam ille de clas s e s (de param è tre de type T). L'aspect "patron" a é té introduit ici au
m om e nt de la dérivation.

• Patron de cl asses dérivé d 'un patron de cl asses. Ce tte possibilité pe ut re vê tir de ux aspects suivant q ue
l'on introduit ou non de nouve aux param è tre s lors de la dérivation. 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 T> class B : public A <T>

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 T, class U> class B : public A <T>

D ans ce cas, on pe ut dire q ue ch aq ue classe de bas e possible pe ut e nge nde r une fam ille de clas s e s
dérivé e s (de param è tre de type U).
D 'une m aniè re gé né rale, vous pouve z "joue r" à volonté ave c les param è tre s , à savoir e n introduire ou e n
supprim e r à volonté .

Voici trois e xe m ples corre s pondant à ce rtaines des situations q ue nous ve nons d'évoq ue r.

a)Cl
as s e "ordinaire " pointcol
_int dé rivant d'une cl
as s e patron point<int>
_______________________________________________________________________________
____
238 Program m e r e n langage C+ +
#include <iostream.h>
template <class T> class point
{ T x ; T y ;
public :
point (T abs=0, T ord=0) { x = abs ; y = ord ; }
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;
class pointcol_int : public point <int>
{ int coul ;
public :
pointcol_int (int abs=0, int ord=0, int cl=1) : point <int> (abs, ord)
{ coul = cl ;
}
void affiche ()
{ point<int>::affiche () ; cout << " couleur : " << coul << "\n" ;
}
} ;
main ()
{ point <float> pf (3.5, 2.8) ; pf.affiche () ; // instanciation d'une classe
patron
pointcol_int p (3, 5, 9) ; p.affiche (); // emploi (classique) de la
classe
// pointcol_int
} ________________________________

Coordonnées : 3.5 2.8


Coordonnées : 3 5
couleur : 9
_______________________________________________________________________________
____

b)Patron de cl as s e s pointcoldé rivant d'un patron de cl


as s e s point,
ave c l
e s m ê m e s param è tre s
A partir du patron te m plate < class T> class point, nous dérivons un patron nom m é pointcoldans leq ue lle
nouve au m e m bre introduit e s t du m ê m e type T q ue les coordonnées du point.

_______________________________________________________________________________
____

#include <iostream.h>
template <class T> class point
{ T x ; T y ;
public :
point (T abs=0, T ord=0) { x = abs ; y = ord ; }
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;
template <class T> class pointcol : public point <T>
{ T coul ;
public :
pointcol (T abs=0, T ord=0, T cl=1) : point <T> (abs, ord) { coul = cl ; }
void affiche () { point<T>::affiche () ; cout << " couleur : " << coul
; }
} ;
XIII. La te ch nique de l'h é ritage 239
main ()
{ point <long> p (34, 45) ; p.affiche () ;
pointcol <short> q (12, 45, 5) ; q.affiche () ;
}
________________________________
Coordonnées : 34 45
Coordonnées : 12 45
couleur : 5
_______________________________________________________________________________
____

c)Patron de cl as s e s dé rivant d'un patron de cl


as s e s
e t introduis ant un nouve au param è tre
A partir du patron te m plate < class T> class point, nous dérivons un patron nom m é pointcoldans leq ue lle
nouve au m e m bre introduit e s t d'un type U diffé re nt de ce lui de s coordonnées du point.

_______________________________________________________________________________
____
#include <iostream.h>
template <class T> class point
{ T x ; T y ;
public :
point (T abs=0, T ord=0) { x = abs ; y = ord ; }
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;
template <class T, class U> class pointcol : public point <T>
{ U coul ;
public :
pointcol (T abs=0, T ord=0, U cl=1) : point <T> (abs, ord) { coul = cl ; }
void affiche ()
{ point<T>::affiche () ; cout << " couleur : " << coul << "\n" ;
}
} ;
main ()
{
// un point à coordonnées de type float et couleur de type int
pointcol <float, int> p (3.5, 2.8, 12) ; p.affiche () ;
// un point à coordonnées de type unsigned long et couleur de type
short
pointcol <unsigned long, short> q (295467, 345789, 8) ; q.affiche () ;
}
________________________________
Coordonnées : 3.5 2.8
couleur : 12
Coordonnées : 295467 345789
couleur : 8
_______________________________________________________________________________
____
240 Program m e r e n langage C+ +

$ 13. RETO UR SUR LES PO INTEURS SUR D ES FO NCTIO NS M EM BRE

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

Le paragraph e 9 d u ch apitre VI vous a m ontré com m e nt déclare r e t utiliser des pointe urs sur de s fonctions
m e m bre . Voyons ce q ue devie nt ce tte notion dans le conte xte de l'h é ritage . Considérons ces deux clas s e s :

class point class pointcol : public point


{ ..... { .....
public : public :
void dep_hor (int) ; void colore (int) ;
void dep_vert (int) ; .....
..... } ;
} ;

Nous pouvons déclare r un pointe ur adfp sur des fonctions m e m bre de point par :

void (point:: * adfp) (int) ;

Ce la signifie q ue adfp pe ut re ce voir l'adresse de n'im porte q ue lle fonction m e m bre de point, dans la m e s ure
où son prototype e s t de la form e void f (int).

D e m ê m e , nous pouvons déclare r :

void (pointcol:: * adfpc) (int) ;

Bie n e nte ndu, ce s affe ctations sont légales :

adfp = point::dep_hor ;
adfp = point::dep_vert ;
adfpc = pointcol::colore ;

Ile n va de m ê m e pour :

adfpc = pointcol::dep_hor ;
adfpc = pointcol::dep_vert ;

puis q ue les fonctions de p_h or e t de p_ve rt sont e ffe ctive m e nt (é galem e nt) des m e m bres de pointcol23.

M ais on pe ut aussi s'inte rroge r sur la "com patibilité " e xistant e ntre adfp e t adfpc. Autre m e nt dit, leq ue lpe ut
ê tre affe cté à l'autre ?Nous donne rons un pe u plus loin la rè gle adopté e par C+ + m ais, auparavant, nous
allons vous m ontre r q ue ce lle-ci e s t logiq ue .

Il suffit, e n e ffe t, de penser à l'usage q ui e s t fait de te ls pointe urs, à savoir l'appe l de la fonction
corre s pondante . Si l'on acce pte q ue adfpc re çoive une valeur du type pointe ur sur une fonction m e m bre de
point (de m ê m e prototype ), ce la signifie q u'on pourra ê tre am e né à appe ler, pour un obje t de type
pointcol24, une fonction h é rité e d e point. Ce la ne pose donc aucun problèm e . En re vanch e , si l'on acce ptait
q ue adfp re çoive une valeur du type pointe ur sur une fonction m e m bre de pointcol, ce la signifie rait q u'on
pourrait ê tre am e né à appe ler, pour un obje t de type point, n'im porte q ue lle fonction de pointcol.

23 - Pour l
e com pil
ate ur, point::de p_h or e t pointcol::de p_h or s ont de type diffé re nt. Ce l
a n'e m pê ch e pas ces deux sym bol
es de désigner l
a
m ê m e adresse.
24 - Car, bie n e nte ndu, une affe ctation te l
le q ue adfpc = adfp ne m odifie pas l
e type de adfpc.
XIII. La te ch nique de l'h é ritage 241
M anife s te m e nt, ce rtaine s fonctions (ce lles définies dans pointcol, c'e s t-à -dire ce lles q ui ne s ont pas h é rité e s
de point) ris q ue raie nt de ne pas pouvoir travailler corre cte m e nt !

D 'où la rè gle pré vue par C+ + :

Ilexiste une conversion im plicite d'un pointeur sur une fonction m em bre d'une cl
asse dérivée en un
pointeur sur une fonction m em bre (de m ê m e prototype) d'une cl
asse de base.

R e m arque :

Si on s e lim ite aux appare nce s (c'e s t-à -dire s i on ne ch e rch e pas à com pre ndre les raisons profonde s ),
ce tte rè gle s e m ble "dive rge r" par rapport aux conve rsions im plicite s e ntre obje ts ou pointe urs sur de s
obje ts : ces derniè re s s e font dans le s e ns dérivé e -> bas e , alors q ue , dans le cas des fonctions m e m bre ,
e lles ont lie u dans le s e ns bas e -> dérivé e .

14. L'H ÉRITAGE EN GÉNÉRA L

Nous ve nons de vous e xpos e r les principes de base de l'h é ritage e n nous lim itant à des situations ne faisant
inte rve nir q ue deux clas s e s à la fois : une classe de bas e e t une classe dérivé e .

En fait, ce s notions de classe de bas e e t de classe dérivé e s ont re lative s puis q ue :

• d'une m ê m e clas s e pe uve nt ê tre dérivé e s plusieurs classes diffé re nte s (é ve ntue llem e nt utilisées au s e in
d'un m ê m e program m e ),
• une classe dérivé e pe ut, à son tour, s e rvir de classe de bas e pour une autre classe dérivé e .
Autre m e nt dit, les diffé re nte s classes dérivées d'une m ê m e classe de bas e pe uve nt ê tre re pré s e nté e s par une
"arbore s ce nce " te lle q ue la suivante :
A

B F

C D E G

Ici, C e s t dérivé e d e B, e lle-m ê m e dérivé e d e A (on dit aussi que C h é rite de B q ui, e lle-m ê m e h é rite de A).
Pour traduire la re lation e xistant e ntre A e t C, on dira q ue C e s t une desce ndante de A ou e ncore q ue A e s t
une asce ndante de C. Nature llem e nt, C e s t aussi une desce ndante de B ;lors q u'on aura be s oin d'ê tre plus
pré cis, on dira q ue C e s t une desce ndante directe de B.

Par ailleurs, C+ + (depuis la ve rsion 2) é largit les possibilités d'h é ritage e n introduisant ce q ue l'on nom m e
l'h éritage m ul
tiple : une classe donnée peut h é rite r sim ultané m e nt de plusieurs clas s e s . Dans ces conditions,
on n'a plus affaire à une arbore s ce nce de clas s e s , m ais à un graph e q ui pe ut é ve ntue llem e nt deve nir
com plexe . En voici un sim ple e xe m ple :
242 Program m e r e n langage C+ +

Tout ce q ui a é té dit jus q u'à m ainte nant s e gé né ralise sans aucun problèm e à toute s les s ituations d'h é ritage
sim ple (syntaxe , appe ldes constructe urs...). D'une m aniè re gé né rale, lors q ue nous parlerons d'une clas s e
dérivée d'une classe de bas e , ilpourra s'agir d'une desce ndante q ue lconq ue (dire cte ou non). De m ê m e ,
lors q ue nous parlerons de dérivation publiq ue , ilfaudra com pre ndre q ue la clas s e conce rné e s 'obtie nt par
une ou plusieurs dérivations succe s s ive s publiq ues de sa classe de bas e . Note z qu'ilsuffira qu'une seul e de
ces dérivations soit privé e pour qu'au bout du com pte, on parl e gl
obal em ent de dérivation privé e .

En ce q ui conce rne les s ituations d'h é ritage m ultiple, leur m ise en œuvre né ce s s ite q ue lque s connaissance s
supplém e ntaire s . Nous avons préfé ré les re groupe r dans un ch apitre s é paré (XIV), com pte te nu, notam m e nt,
de ce q ue leur usage e s t pe u ré pandu.

15. EXPLO ITA TIO N D 'UNE CLASSE D ÉRIVÉE

L'h é ritage pe ut ê tre utilisé dans des buts trè s diffé re nts.

O n pe ut, par e xe m ple, disposer d'une clas s e (é ve ntue llem e nt dérivée d'autre s clas s e s ) q ui ré s out
partie llem e nt un problèm e donné. On adapte alors ce tte clas s e e n cré ant une classe dérivé e pour ré s oudre le
problèm e pos é . Dans ce cas, on gagne du te m ps de program m ation puis q u'on ré utilise une partie de logicie l.
M ê m e s i l'on n'e xploite pas toute s les fonctions de la classe de départ, on ne s e ra pas trop pé nalisé dans la
m e s ure où les fonctions non utilisées ne seront pas incorporé e s à l'édition de lie ns. Le s e ulris q ue e ncouru
s e ra ce lui d'une pe rte de te m ps dans des appe ls im briq ué s q ue l'on aurait pu lim ite r e n ré é crivant totalem e nt
la clas s e . En re vanch e , les m e m bres donnée non utilisés (s'ily en a) occupe ront de l'e s pace dans tous les
obje ts du type .

D ans ce tte caté gorie , on pe ut é galem e nt range r le cas où, disposant d'une clas s e , on souh aite e n m odifie r
l'inte rface utilisate ur pour q u'e lle ré ponde à des critè res donnés. La classe dérivé e fait la m ê m e ch os e q ue la
classe de bas e ;s e ule la façon de l'utiliser est diffé re nte .

D ans un tout autre e s prit, on pe ut, au contraire , e n "partant de rie n", ch e rch e r à ré s oudre un problèm e e n
l'e xprim ant sous form e d'un graph e (ou d'un arbre s i l'on ne dispose pas de l'h é ritage m ultiple) de clas s e s .
O n pe ut m ê m e ê tre am e né à cré e r ce q ue l'on nom m e des "clas s e s abstraite s ", c'e s t-à -dire des classes dont la
vocation n'e s t pas de donner naissance à des obje ts, m ais sim plem e nt d'ê tre utilisées com m e classes de bas e
pour d'autre s classes dérivé e s .

En ce q ui conce rne l'utilisation (com pilation, édition de lie ns) d'une classe dérivé e au s e in d'un program m e ,
les ch os e s s ont trè s sim ples s i la classe de bas e e t la classe dérivé e s ont cré é e s d ans le program m e lui-m ê m e
XIII. La te ch nique de l'h é ritage 243
(un s e ulfich ie r source , un m odule obje t...). Ile n ira rare m e nt ainsi. Voici un sch é m a illustrant la m aniè re
de com piler succe s s ive m e nt :

• une classe de bas e ,


• une classe dérivé e ,
• un program m e utilisant ce tte classe dérivé e .

Exploitation d'une clas s e d é rivé e

En gé né ral, les "déclarations" figure ront dans un fich ie r e n-tê te , introduit par #include pour la com pilation.

Nature llem e nt, ce s ch é m a devra ê tre adapté pour les cas où l'on a plus de deux clas s e s ou lors q ue la clas s e
de bas e e t la classe dérivé e figure nt dans un m ê m e fich ie r source (le fich ie r e n-tê te corre s pondant é tant alors
probablem e nt uniq ue ).
XIV. L'H ÉRITAGE M ULTIPLE

Com m e nous l'avons signalé dans le ch apitre pré cédent, C+ + dispose (depuis la ve rsion 2) de possibilité s
d'h é ritage m ultiple. Il s'agit là d'une gé né ralisation cons é q ue nte , dans la m e s ure où e lle pe rm e t de
s'affranch ir de la contrainte h ié rarch iq ue im pos é e par l'h é ritage s im ple.

M algré tout, son usage reste as s e z pe u ré pandu ;la principale raison ré s ide ce rtaine m e nt dans les difficulés
q u'ilim pliq ue au nive au de la conce ption de s logicie ls. Ile s t, e n e ffe t, m anife s te m e nt plus facile de
structure r un e ns e m ble de clas s e s s uivant un ou plusieurs "arbres" (cas de l'h é ritage s im ple) q ue s uivant un
sim ple "graph e orie nté s ans circuit" (cas de l'h é ritage m ultiple).

Bie n e nte ndu, la plupart des ch os e s q ue nous avons dite s à propos de l'h é ritage s im ple s e gé né ralisent au cas
de l'h é ritage m ultiple. Né anm oins, un ce rtain nom bre d'inform ations supplém e ntaires doive nt ê tre
introduite s pour ré pondre aux q ue s tions suivante s :

• Com m e nt e xprim e r ce tte dépe ndance "m ultiple", au s e in d'une classe dérivé e ?
• Com m e nt s e ront appe lés les constructe urs e t destructe urs conce rné s : ordre , transm ission d'inform ation,
e tc. ?
• Com m e nt ré gler les conflits q ui ris q ue nt d'apparaî
tre dans des situations te lles q ue ce lle-ci où D h é rite de
B e t C q ui h é rite nt toutes deux de A ?
XIV. L'h é ritage m ultiple 245
1. M ISE EN ŒUVRE D E L'H ÉRITAGE M ULTIPLE

Considérons une situation sim ple, ce lle où une clas s e , q ue nous nom m e rons pointcoul, h é rite de deux autre s
clas s e s nom m é e s point e t coul.

Supposons, pour fixe r les idées, que les clas s e s point e t couls e pré s e nte nt ainsi (nous les avons réduite s à ce
q ui é tait indispensable à la dém onstration) :

class point class coul


{ int x, y ; { short couleur ;
public : public :
point (...) {...} coul (...) {...}
~point () {...} ~coul () {...}
affiche () {...} affiche () {...}
} ; } ;

Nous pouvons définir une clas s e pointcoulh é ritant de ces deux clas s e s e n la déclarant ainsi (ici, nous avons
ch oisi public pour ch acune de nos deux clas s e s , m ais, le cas é ch é ant, nous pourrions e m ploye r private 1 ou
prote cte d 2).

class pointcoul : public point, public coul


{ ... } ;

Note z q ue nous nous som m e s conte nté de re m place r la m e ntion d'une classe de bas e par une liste de
m e ntions de classes de bas e .

Au sein de ce tte clas s e , nous pouvons définir de nouve aux m e m bre s . Ici, nous nous lim itons à un
constructe ur, un de s tructe ur e t une fonction d'affich age .

D ans le cas de l'h é ritage s im ple, le constructe ur de vait pouvoir re transm e ttre des inform ations au
constructe ur de la classe de bas e . Ile n va de m ê m e ici, ave c ce tte diffé re nce q u'ily a de ux classes de bas e .
L'e n-tê te du constructe ur s e pré s e nte ra ainsi :

pointcoul ( .......) : point (.......), coul (.......)


| | |
arguments arguments arguments
de pointcoul à transmettre à transmettre
à point à coul

L'ordre d'appe ldes constructe urs e s t le s uivant :

• constructe urs des classes de bas e , dans l'ordre où les classes de bas e s ont déclarées dans la classe dérivé e
(ici, point puis coul),
• constructe ur de la classe dérivé e (ici, pointcoul).

1 - D e puis l
a ve rsion 2.0.
2 - D e puis l
a ve rsion 3.
246 Program m e r e n langage C+ +
Les destructe urs é ve ntue ls s e ront, là e ncore , appe lés dans l'ordre inve rs e lors de la destruction d'un obje t de
type pointcoul.

D ans la fonction d'affich age q ue nous nom m e rons, e lle aussi, affich e , nous vous proposons de lui faire
e m ploye r succe s s ive m e nt les fonctions affich e de point e t de coul. Com m e dans le cas de l'h é ritage s im ple,
on pe ut, dans une fonction m e m bre de la classe dérivé e , utiliser toute fonction m e m bre publiq ue (ou
proté gé e ) d'une classe de bas e . Lors q ue plusieurs fonctions m e m bre porte nt le m ê m e nom dans diffé re nte s
clas s e s , on pe ut leve r l'am biguïté e n e m ployant l'opé rate ur de ré s olution de porté e . Ainsi, ici, notre fonction
affich e de pointcouls e ra :

void affiche ()
{ point::affiche () ; coul::affiche () ;
}

Bie n e nte ndu, si les fonctions d'affich age de point e t de couls e nom m aie nt, par e xe m ple, affp e t affc, notre
fonction affich e aurait pu s'é crire s im plem e nt :

void affiche ()
{ affp () ; affc () ;
}

L'utilisation de la clas s e pointcoule s t "classique". Un obje t de type pointcoulpe ut faire appe laux fonctions
m e m bre de pointcoulou, é ve ntue llem e nt, aux fonctions m e m bre des classes de bas e point e t coul(e n s e
s e rvant é ve ntue llem e nt de l'opé rate ur de ré s olution de porté e pour leve r de s am biguïté s ). Par e xe m ple,
ave c :

pointcoul p(3, 9, 2) ;

p.affich e () appe llera la fonction affich e de pointcoul, tandis q ue p.point::affich e () appe llera la fonction
affich e de point.

Nature llem e nt, si l'une des clas s e s point e t coul é tait e lle-m ê m e dérivée d'une autre clas s e , il s e rait
é galem e nt possible d'en utiliser l'un de s m e m bre s (e n ayant é ve ntue llem e nt plusieurs fois re cours à
l'opé rate ur de ré s olution de porté e ).

Voici un e xe m ple com plet de définition e t d'utilisation de notre clas s e pointcoul, dans laq ue lle ont é té
introduits q ue lque s affich age s inform atifs.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs, int ord)
{ cout << "++ Constr. point \n" ; x=abs ; y=ord ;
}
~point () { cout << "-- Destr. point \n" ; }
void affiche ()
{ cout << "Coordonnées : " << x << " " << y << "\n" ;
}
} ;
class coul
{ short couleur ;
public :
XIV. L'h é ritage m ultiple 247
coul (int cl)
{ cout << "++ Constr. coul \n" ; couleur = cl ;
}
~coul () { cout << "-- Destr. coul \n" ; }
void affiche ()
{ cout << "Couleur : " << couleur << "\n" ;
}
} ;
class pointcoul : public point, public coul
{ public :
pointcoul (int, int, int) ;
~pointcoul () { cout << "---- Destr. pointcoul \n" ; }
void affiche ()
{ point::affiche () ; coul::affiche () ;
}
} ;
pointcoul::pointcoul (int abs, int ord, int cl) : point (abs, ord), coul (cl)
{ cout << "++++ Constr. pointcoul \n" ;
}

main()
{ pointcoul p(3,9,2) ;
cout << "------------\n" ;
p.affiche () ; // appel de affiche de pointcoul
cout << "------------\n" ;
p.point::affiche () ; // on force l'appel de affiche de point
cout << "------------\n" ;
p.coul::affiche () ; // on force l'appel de affiche de coul
cout << "------------\n" ;
}
_______________________

++ Constr. point
++ Constr. coul
++++ Constr. pointcoul
------------
Coordonnées : 3 9
Couleur : 2
------------
Coordonnées : 3 9
------------
Couleur : 2
------------
---- Destr. pointcoul
-- Destr. coul
-- Destr. point
_______________________________________________________________________________
______

Un e xe m ple d'h é ritage m ultiple : pointcoulh é rite de point e t de coul


248 Program m e r e n langage C+ +
R e m arque :

Nous avons vu com m e nt distingue r de ux fonctions m e m bre de m ê m e nom apparte nant à deux clas s e s
diffé re nte s (par e xe m ple affich e ). La m ê m e dém arch e s 'appliq ue rait à des m e m bres donnée (dans la
m e s ure où leur accè s e s t autoris é ). Par e xe m ple, ave c :

class A class B
{ ..... { .....
public : public :
int x ; int x ;
..... .....
} ; } ;

class C : public A, public B


{ .....
} ;

C possédera de ux m e m bre s nom m é s x, l'un h é rité de A, l'autre de B. Au sein des fonctions m e m bre de
C, on fe ra la distinction à l'aide de l'opé rate ur de ré s olution de porté e : on parlera de A::x ou de B::x.

2. PO UR RÉGLER LES ÉVENTUELS CO NFLITS :


LES CLASSES VIRTUELLES

Considérons la situation ci-aprè s :

corre s pondant à des déclarations te lles q ue :

class A
{ .....
int x, y ;
} ;
class B : public A {.....} ;
class C : public A {.....} ;
class D : public B, public C
{ .....
} ;

O n pe ut dire , e n q ue lque s orte , q ue D h é rite deux fois de A ! D ans ce s conditions, les m e m bres de A
(fonctions ou donné e s ) vont apparaî tre deux fois dans D . En ce q ui conce rne les fonctions m e m bre , ce la e s t
m anife s te m e nt inutile (ce s ont les m ê m e s fonctions) m ais sans im portance puis q ue les fonctions ne sont pas
ré e llem e nt dupliq ué e s (iln'e n e xiste q u'une pour la classe de bas e ). Par contre , e n ce q ui conce rne les
XIV. L'h é ritage m ultiple 249
m e m bres donnée (te ls q ue x e t y dans notre e xe m ple), ils s e ront e ffe ctive m e nt dupl
iqués dans tous l
es
objets de type D.

Y a-t-ilredondance ?En fait, la ré ponse dépe nd du problèm e . Si l'on souh aite q ue D dispose de deux je ux
de données (de A), on ne fe ra rie n de particulie r e t on s e conte nte ra de les distingue r à l'aide de l'opé rate ur
de ré s olution de porté e ;par e xe m ple, ici, on distingue ra :

A::B::x de A ::C::x
ou, é ve ntue llem e nt, si B e t C ne possè dent pas de m e m bre x :

B::x de C::x
En gé né ral, ce pe ndant, on ne s ouh aite ra pas ce tte duplication des données. Dans ce s conditions, on pe ut
toujours "se débrouiller" pour travailler ave c l'un des deux je ux (toujours le m ê m e !) m ais ce la ris q ue d'ê tre
fastidie ux e t dange re ux. En fait, vous pouve z dem ande r à C+ + de n'incorpore r q u'une s e ule fois les
m e m bres de A dans la clas s e D . Pour ce la, ilvous faut pré cis e r, dans les déclarations des clas s e s B e t C
(atte ntion, pas dans ce lle d e D !) q ue la clas s e A e s t "virtue lle" (m ot clé virtual) :

class B : public virtual A {.....} ;


class C : public virtual A {.....} ;
class D : public B, public C {.....} ;

Note z bie n q ue virtual apparaî t ici dans B e t C. En e ffe t, m e ntionne r A com m e "virtue lle" dans la
déclaration de B signifie q ue A ne devra ê tre introduite q u'une s e ule fois dans les desce ndants é ve ntue ls de
C. Autre m e nt dit, ce tte déclaration n'a guè re d'effe t sur les clas s e s B e t C e lles -m ê m e s (si ce n'e s t une
inform ation "cach é e " m ise en place par le com pilate ur pour m arq ue r au s e in de B e t C, A com m e é tant
virtue lle !). Ave c ou sans le m ot virtual, les clas s e s B e t C, tant q u'e lles n'ont pas de desce ndants, s e
com porte nt de la m ê m e m aniè re .

R e m arque :

Le m ot virtualpe ut ê tre placé indiffé re m m e nt avant ou aprè s le m ot public (ou le m ot private ).

3. A PPELS D ES CO NSTRUCTEURS ET D ES D ESTRUCTEURS –


CAS DES CLASSES VIRTUELLES

Nous avons vu com m e nt sont appe lés les constructe urs e t les destructe urs dans des situations te lles q ue :

D e plus, nous avons vu com m e nt dem ande r de s transfe rts d'inform ation e ntre un constructe ur d'une clas s e e t
les constructe urs de ses asce ndants directs (C pour B, B pour A, F pour D e t E). En re vanch e , nous ne
pouvons pas dem ande r à un constructe ur de transfé re r de s inform ations à un constructe ur d'un asce ndant
250 Program m e r e n langage C+ +
indire ct (C pour A, par e xe m ple) e t nous n'avons d'ailleurs aucune raison de le vouloir (puis q ue ch aq ue
transfe rt d'inform ation d'un nive au ve rs le nive au supérieur était spécifié dans l'e n-tê te du constructe ur du
nive au corre s pondant). M ais considérons m ainte nant la situation suivante :

Si A n'e s t pas déclaré e virtue lle dans B e t C, on pe ut considérer que, la clas s e A é tant dupliq ué e , tout s e
pas s e com m e s i l'on é tait e n pré s e nce de la situation suivante dans laq ue lle les notations A e t A
1 2
sym bolisent toute s les deux la clas s e A .

Si D a déclaré les clas s e s B e t C dans ce t ordre , les constructe urs s e ront appe lés dans l'ordre s uivant :

A B A C D
1 2
En ce q ui conce rne les transfe rts d'inform ation, on pe ut trè s bien im agine r q ue B e t C n'aie nt pas prévu les
m ê m e s ch os e s e n ce q ui conce rne A .

Par e xe m ple, on pe ut avoir :

B (int n, int p, double z) : A (n, p)


C (int q, float x) : A (q)

Ce ci n'a aucune im portance puis q ue , e n dé finitive , ily aura construction de deux obje ts distincts de type A .

M ais si A a é té déclaré e virtue lle dans B e t C, les ch os e s s ont totalem e nt diffé re nte s (le dernie r sch é m a n'e s t
plus valable). En e ffe t, dans ce cas, on ne construira q u'un s e ulobje t de type A . Que ls argum e nts faut-il
transm e ttre alors au constructe ur ?Ce ux pré vus par B ou ce ux pré vus par C ?En fait, C+ + ré s out ce tte
am biguïté de la façon suivante :

Le ch oix de s inform ations à fournir au constructe ur de A s e fait, non plus dans B ou C, m ais dans D . Pour
ce faire , C+ + vous autoris e (uniq ue m e nt dans ce cas) à spécifie r, dans le constructe ur de D , des
inform ations destiné e s à A. Ainsi, nous pourrons avoir :

D (int n, int p, double z) : B (n, p, z), A (n, p)

Bie n e nte ndu, ils e ra inutile de pré cis e r de s inform ations pour A au nive au de s constructe urs B e t C (com m e
nous l'avions prévu pré cédem m e nt, alors q ue A n'avait pas é té déclaré e virtue lle dans B e t C).
XIV. L'h é ritage m ultiple 251
En ce q ui conce rne l'ordre des appe ls, l
e constructeur d'une cl
asse virtuel le est toujours appel é avant les
autres. Dans notre cas, ce la nous conduit à l'ordre (probablem e nt atte ndu) A, B, C e t D . M ais, dans une
situation te lle q ue :

ce la conduit à l'ordre (m oins é vident) F, E, G, H , I (ou F, E, H , G, I suivant l'ordre dans leq ue lfigure nt G
e t H dans la déclaration de I).

4. EXEM PLE D 'UTILISATIO N D E L'H ÉRITAGE M ULTIPLE :


LISTE CH A ÎNÉE D E PO INTS

Nous vous proposons ici de ré aliser une clas s e pe rm e ttant de gérer une liste ch aî née d'obje ts de type point.
Ce rte s , nous pourrions e n faire une clas s e à part e ntiè re . M ais nous pouvons tout nature llem e nt pe ns e r
q u'e lle pourrait h é rite r de la clas s e point. Une ré flexion supplém e ntaire nous conduit alors à pe ns e r q ue
ce rtaine s ch oses déve loppé e s pour une liste ch aî né e d e points doive nt pouvoir s'appliq ue r à une liste ch aîné e
d'autre s types d'obje ts 3. D'où l'idé e d e conce voir tout d'abord une clas s e particuliè re pre nant e n ch arge tout
ce q ui conce rne la ge s tion de la liste ch aî né e , sans e ntre r dans les détails spé cifiq ue s aux types des obje ts
conce rné s . Bie n e nte ndu, une te lle clas s e n'aura aucun inté rê t e n soi ;e lle s e ra uniq ue m e nt conçue e n vue
d'ê tre dérivé e ;ce s e ra une classe abstraite .

4.1 Une cl
as s e abs traite : l
is te ch aî
né e

Nous nous lim ite rons ici à une liste ch aî né e s im ple, c'e s t-à -dire définie par un pre m ie r é lém e nt e t où ch aq ue
é lém e nt com porte un pointe ur sur le s uivant. Le s ch é m a le plus classique d'une te lle liste ch aî né e e s t ce lui-
ci :

3 - M ie ux, nous pourrions e nvisager des l


iste s ch aî
nées d'obje ts q ue l
conq ues. Dans ce cas, ilnous faudra connaî
tre l
e m é canis m e des
procédures virtue l
les, du m oins si nous souh aitons, com m e ce l
a e s t probabl
e, pouvoir "ide ntifie r" conve nabl
e m e nt ch aq ue obje t. Ce
m é canis m e s e ra e xposé dans l
e proch ain ch apitre.
252 Program m e r e n langage C+ +

Toute fois, ici, la nature de l'inform ation associé e à ch aq ue é lém e nt de la liste n'e s t pas connue . Aussi, faut-
ils e tourne r ve rs un autre s ch é m a. Ce lui-ci convie nt (ilporte s ouve nt le nom de liste de "conte ne urs 4") :

Bie n e nte ndu, notre clas s e liste s e conte nte ra de gé re r de s é lém e nts sim ples réduits ch acun à :

• un pointe ur sur l'é lém e nt suivant,


• un pointe ur sur l'inform ation associé e (e n fait, ici, un obje t).
O n voit donc q ue notre clas s e va posséder, au m oins :

• un m e m bre donnée : pointe ur sur le pre m ie r é lém e nt (de but, dans notre s ch é m a5),
• une fonction m e m bre destiné e à ins é re r dans la liste (nous ch oisirons en début de liste , par souci de
sim plification) un obje t dont on lui fournira l'adre s s e . Note z q ue , au s e in de la clas s e liste , ce tte adre s s e
doit ê tre de type void *(puis q ue l'on souh aite pouvoir gé re r n'im porte q ue ltype d'obje t).
D 'où une pre m iè re ébauch e de notre clas s e liste :

struct element // structure d'un élément de liste


{ element * suivant ; // pointeur sur l'élément suivant
void * contenu ; // pointeur sur un objet quelconque
} ;
class liste
{ element * debut ; // pointeur sur premier élément

public :
liste () ; // constructeur
~liste () ; // destructeur
void ajoute (void *) ; // ajoute un élément en début de liste
.....
} ;

Bie n e nte ndu, nous allons avoir be s oin d'autre s possibilité s , te lles q ue :

• affich e r les obje ts pointé s par la liste ,

4 - De l 'anglais "containe rs l ist".


5 - A tte ntion, ici, l
e s obje ts de notre cl
as s e l
iste s e ront des l
iste s e t non de s é l
é m e nts de l
iste !
XIV. L'h é ritage m ultiple 253
• re ch e rch e r un é lém e nt,
• supprim e r un é lém e nt,
• e tc.
Ce s actions pourraie nt e ffe ctive m e nt ê tre ré alisées par la clas s e liste e lle-m ê m e , si elle connaissait la nature
des obje ts. Ce n'e s t toute fois pas le cas ave c la dém arch e q ue nous avons adopté e .

Ce pe ndant, les activité s é voq ué e s font toute s appe là un m é canism e de "parcours" de la liste . Ce rte s , ce
parcours devra pouvoir ê tre contrôlé (initialisé, poursuivi, inte rrom pu...) depuis "l'e xté rie ur" de la liste ;
m ais ile s t possible de pré voir de s fonctions é lém e ntaire s te lles q ue :

• initialiser le parcours,
• avance r d'un é lém e nt.
Ce lles -ci né ce s s ite nt un "pointe ur sur un é lém e nt courant" ;ils e ra m e m bre donnée de notre clas s e liste ;
nous le nom m e rons courant. Par ailleurs, les deux fonctions m e m bre é voq ué e s pe uve nt fournir e n re tour une
inform ation conce rnant l'obje t courant : à ce nive au, on pe ut ch oisir entre :

• l'adresse de l'é lém e nt courant,


• l'adresse de l'obje t courant,
• la valeur de l'é lém e nt courant.
La pre m iè re s olution contie nt la s e conde ;si ptr e s t l'adresse de l'é lém e nt courant, ptr-> conte nu fournit
ce lle de l'obje t courant. M algré tout, on pourrait obje cte r q ue l'utilisate ur de la clas s e n'a pas à accéder aux
é lém e nts de la liste .

La troisiè m e s olution pe ut paraî tre plus sûre . En fait, e lle n'e m pê ch e pas l'utilisate ur d'aller e xam ine r lui-
m ê m e d'autre s é lém e nts de la liste e t de les m odifie r (iln'a q ue la "valeur" de l'é lém e nt courant, m ais ce lle-
ci lui donne accè s aux "adre s s e s " de tous les é lém e nts suivants).

Ch oisissons donc la s e conde s olution. D ans ce cas, l'utilisate ur n'a alors plus de m oye n de déte cte r la fin de
liste . Nous pré voirons donc une fonction supplém e ntaire pe rm e ttant de savoir si la fin de liste e s t atte inte (e n
toute rigue ur, nous aurions pu égalem e nt conve nir de fournir dans ce cas, un pointe ur nulcom m e adresse de
l'obje t courant ;m ais ce s e rait m oins pratiq ue car ilfaudrait obligatoire m e nt agir sur le pointe ur de liste
avant de savoir si l'on e s t à la fin).

En dé finitive , nous introduisons trois nouve lles fonctions m e m bre :

void * premier () ;
void * prochain () ;
int fini () ;

Voici, ci-aprè s, la liste définitive de notre clas s e liste

_______________________________________________________________________________
______

#include <stddef.h> // pour la définition de NULL


// ********************* classe liste **************************************
struct element // structure d'un élément de liste
{ element * suivant ; // pointeur sur l'élément suivant
void * contenu ; // pointeur sur un objet quelconque
} ;
class liste
{ element * debut ; // pointeur sur premier élément
254 Program m e r e n langage C+ +
element * courant ; // pointeur sur élément courant
public :
liste () // constructeur
{ debut = NULL ; courant = debut ; }
~liste () ; // destructeur
void ajoute (void *) ; // ajoute un élément en début de liste
void premier () // positionne sur premier élément
{ courant = debut ; }
void * prochain () // fournit l'adresse de l'élément courant (0 si
inexistant)
// et se positionne sur le prochain élément (rien si
fin)
{ void * adel = NULL ;
if (courant != NULL){ adel = courant -> contenu ;
courant = courant -> suivant ;
}
return adel ;
}
int fini () { return (courant == NULL) ; }
} ;
liste::~liste ()
{ element * suiv ;
courant = debut ;
while (courant != NULL )
{ suiv = courant->suivant ; delete courant ; courant = suiv ; }
}
void liste::ajoute (void * chose)
{ element * adel = new element ;
adel->suivant = debut ;
adel->contenu = chose ;
debut = adel ;
}
_______________________________________________________________________________
______

Une clas s e abstraite : liste ch aî


née

Voye z la m aniè re dont nous avons program m é le destructe ur ~ liste . Ce lui-ci libè re tous les e m place m e nts
alloué s pour les é lém e nts de la clas s e liste . Iln'a toute fois aucune action sur les obje ts pointé s . Pour q u'ile n
soit ainsi, ilfaudrait faire des h ypoth è s e s s ur la m aniè re dont les obje ts sont cré é s . Dans le cas d'obje ts
dynam iq ue s , on pourrait e nvisage r de les faire détruire par ~ liste . Encore faudrait-ilpouvoir ré gler de ux
problèm e s :

• connaî tre le type de ce s obje ts. Ce n'e s t pas le cas ici. Nous ve rrons toute fois q ue ce point pe ut ê tre
ré s olu par l'utilisation de procédures virtue lles ,
• ê tre e n m e s ure de savoir si la destruction d'un pointe ur sur un obje t nous autoris e à détruire l'obje t lui-
m ê m e . Ilfaut pour ce la q ue l'obje t conce rné ne s oit pas ré fé re ncé par ailleurs. Une s olution gé né rale6 à
ce problèm e ré s ide, com m e nous l'avons déjà dit, dans l'utilisation d'un "com pte ur de ré fé re nce s ".

6 - C'e s t-à -dire ne fais ant appe là aucune h ypoth è s e particul


iè re.
XIV. L'h é ritage m ultiple 255
R e m arque :

Nous aurions pu pré voir une fonction m e m bre ch argé e d e s upprim e r un é lém e nt courant. Ce la n'aurait
rie n apporté de nouve au sur le plan de la conce ption e t aurait donc alourdi inutilem e nt notre e xe m ple.
Bie n e nte ndu, ce tte fonction s e rait indispensable dans une clas s e "e n vraie grande ur".

4.2 Cré ation par h é ritage m ul


tipl
e d'une cl
as s e l
is te _points

Supposons que nous disposions, par ailleurs, d'une clas s e point q ue nous lim ite rons ici au strict m inim um :

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;
_______________________________________________________________________________
______

La clas s e point

Nous allons m ainte nant ch e rch e r à cré e r une nouve lle clas s e nous perm e ttant de gérer une liste ch aî né e
d'obje ts de type point. Ilvie nt alors (pre s q ue ) nature llem e nt l'idé e d e cré e r une clas s e liste _points h é ritant
sim ultané m e nt de liste e t de point :

A ce propos, ile s t inté re s s ant de note r q ue ce t h é ritage appare m m e nt nature lconduit à introduire dans la
clas s e liste _points deux m e m bres donnée (x et y) n'ayant pas vraim e nt d'inté rê t : les obje ts conce rné s s e ront
cré é s d e m aniè re indé pe ndante de l'obje t de type liste _points (on pourrait dire q u'on cré e ra ainsi un point
pour rie n !).

Supposons que nous souh aitions, dans la clas s e liste _points , pouvoir sim plem e nt :

• introduire un nouve au point e n début de liste ,


• affich e r tous les obje ts de la liste .
M anife s te m e nt, la pre m iè re fonction e s t autom atiq ue m e nt assuré e par la fonction m e m bre ajoute de la clas s e
liste . Iln'e s t m ê m e pas néce s s aire de la surdéfinir.

Quant à la fonction d'affich age q ue nous nom m e rons affich e , e lle va e xploite r :

• les fonctions pre m ie r, proch ain e t fini pour e xplore r toute la liste ,
• la fonction affich e de la clas s e point pour affich e r le conte nu d'un point.
Voici notre clas s e liste _points :
256 Program m e r e n langage C+ +
_______________________________________________________________________________
______

class liste_points : public liste, public point


{ public :
liste_points () {}
void affiche () ;
} ;
void liste_points::affiche ()
{ point * ptr = (point *) premier() ;
while ( ! fini() ) { ptr->affiche () ; ptr = (point *) prochain() ; }
}
_______________________________________________________________________________
______

La clas s e liste _points , h é ritant de liste e t de point

A sim ple titre de com m odité de lecture de l'e ns e m ble, nous vous fournissons à nouve au, de façon groupé e ,
la liste de nos trois clas s e s accom pagnées d'un e xe m ple d'utilisation.

_______________________________________________________________________________
______

#include <iostream.h>
#include <stddef.h> // pour la définition de NULL

// ********************* classe liste **************************************


struct element // structure d'un élément de liste
{ element * suivant ; // pointeur sur l'élément suivant
void * contenu ; // pointeur sur un objet quelconque
} ;

class liste
{ element * debut ; // pointeur sur premier élément
element * courant ; // pointeur sur élément courant
public :
liste () // constructeur
{ debut = NULL ; courant = debut ;
}
~liste () ; // destructeur
void ajoute (void *) ; // ajoute un élément en début de liste
void premier () // positionne sur premier élément
{ courant = debut ;
}
void * prochain () // fournit l'adresse de l'élement courant (0 si
inexistant)
// et se positionne sur le prochain élément (rien si
fin)
{ void * adel = NULL ;
if (courant != NULL){ adel = courant -> contenu ;
courant = courant -> suivant ;
}
return adel ;
}
int fini () { return (courant == NULL) ; }
XIV. L'h é ritage m ultiple 257
} ;
liste::~liste ()
{ element * suiv ;
courant = debut ;
while (courant != NULL )
{ suiv = courant->suivant ; delete courant ; courant = suiv ; }
}
void liste::ajoute (void * chose)
{ element * adel = new element ;
adel->suivant = debut ; adel->contenu = chose ;
debut = adel ;
}

// **************** classe point *******************************************


class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
void affiche () { cout << "Coordonnées : " << x << " " << y << "\n" ; }
} ;

// **************** classe liste_points ************************************


class liste_points : public liste, public point
{ public :
liste_points () {}
void affiche () ;
} ;
void liste_points::affiche ()
{ premier() ;
while ( ! fini() ) { point * ptr = (point *) prochain() ; ptr->affiche () ;
}
}

// **************** programme d'essai de liste_points **********************


main()
{ liste_points l ;
point a(2,3), b(5,9), c(0,8) ;
l.ajoute (&a) ; l.affiche () ; cout << "---------\n" ;
l.ajoute (&b) ; l.affiche () ; cout << "---------\n" ;
l.ajoute (&c) ; l.affiche () ; cout << "---------\n" ;
}
_______________________

Coordonnées : 2 3
---------
Coordonnées : 5 9
Coordonnées : 2 3
---------
Coordonnées : 0 8
Coordonnées : 5 9
Coordonnées : 2 3
---------
_______________________________________________________________________________
______
258 Program m e r e n langage C+ +

Exe m ple d'utilisation de la clas s e liste _points


XV. LES FO NCTIO NS VIRTUELLES
ET LE TYPAGE D Y NA M IQUE

Nous avons vu q u'e n C+ + un pointe ur sur un type d'obje t pouvait re ce voir l'adresse de n'im porte q ue l
obje t desce ndant. Toute fois, ce t avantage s e trouvait com pe ns é par une lacune im portante : l'appe ld'une
m é th ode pour un obje t pointé conduisait systé m atiq ue m e nt à appe ler la m é th ode corre s pondant au type du
pointe ur e t non pas au type e ffe ctif de l'obje t pointé lui-m ê m e (re voye z é ve ntue llem e nt le paragraph e 6.3 du
ch apitre XIII).

Ce tte lacune provie nt e s s e ntie llem e nt de ce q ue , dans les s ituations re ncontré e s jus q u'ici, C+ + ré alise ce
q ue l'on nom m e une ligature s tatiq ue 1, ou e ncore un typage s tatiq ue . Le type d'un obje t (pointé ) y est
déte rm iné au m om e nt de la com pilation. D ans ce s conditions, le m ie ux q ue puis s e faire le com pilate ur e s t
e ffe ctive m e nt de considérer que l'obje t pointé a le type du pointe ur.

Pour pouvoir obte nir l'appe lde la m é th ode corre s pondant au type de l'obje t pointé , ile s t né ce s s aire q ue le
type de l'obje t ne s oit pris e n com pte q u'au m om e nt de l'e xé cution (le type de l'obje t désigné par un m ê m e
pointe ur pourra varie r au fildu déroulem e nt du program m e ). O n parle alors de ligature dynam iq ue 2 ou de
typage dynam iq ue .

Com m e nous allons le voir m ainte nant, e n C+ + , le typage dynam iq ue pe ut ê tre m is en œuvre e n faisant
appe lau m é canism e des fonctions virtue lles .

1. RAPPELD 'UNE SITUA TIO N O Ù LE TYPAGE D Y NA M IQUE


EST NÉCESSA IRE

Considérons la situation suivante , déjà re ncontrée dans le ch apitre XIII :

class point class pointcol : public point


{ ..... { .....
void affiche () ; void affiche () ;
..... .....

1 - En angl
ais, "earl y binding".
2 - En angl
ais, "late binding" ou encore "dynam ic binding".
260 Program m e r e n langage C+ +
} ; } ;

point p ;
pointcol pc ;
point * adp = &p ;

L'instruction :

adp -> affiche () ;

appe lle alors la m é th ode affich e du type point.

M ais si nous exécutons ce tte affe ctation (autoris é e ) :

adp = & pc ;

le pointe ur adp pointe m ainte nant sur un obje t de type pointcol. Né anm oins, l
'instruction :

adp -> affiche () ;

fait toujours appelà la m é th ode affich e du type point alors q ue le type pointcoldispose, lui aussi, d'une
m é th ode affich e .

En e ffe t, com m e nous l'avons é voq ué e n introduction, le ch oix de la m é th ode à appe ler a é té ré alisé lors de
la com pilation ;ila donc é té fait e n fonction du type de la variable adp. C'e s t la raison pour laq ue lle on
parle de "ligature s tatiq ue ".

2. LE M ÉCANISM E D ES FO NCTIO NS VIRTUELLES

Le m é canism e des fonctions virtue lles propos é par C+ + va nous perm e ttre de faire e n sorte q ue
l'instruction :

adp -> affiche ()

appe lle, non plus systé m atiq ue m e nt la m é th ode affich e de point, m ais ce lle corre s pondant au type de l'obje t
ré e llem e nt désigné par adp (ici point ou pointcol).

Pour ce faire , ilsuffit tout sim plem e nt de déclare r "virtue lle" (m ot clé virtual) la m é th ode affich e de la
clas s e point :

class point
{ .....
virtual void affiche () ;
.....
} ;

Ce ci pré cis e au com pilate ur q ue les é ve ntue ls appe ls de la fonction affich e doive nt utiliser une ligature
dynam iq ue e t non plus une ligature s tatiq ue . Autre m e nt dit, lors q ue le com pilate ur re ncontre ra un appe lte l
q ue :

adp -> affiche () ;


XV. Le s fonctions virtue lles e t le typage dynam ique 261
ilne décide ra pas de la procédure à appe ler. Ils e conte nte ra de m e ttre e n place un dispositif pe rm e ttant de
n'e ffe ctue r le ch oix de la fonction q u'au m om e nt de l'e xé cution de ce tte instruction3, ce ch oix é tant bas é s ur
le type e xact de l'obje t ayant e ffe ctué l'appe l.

D ans la clas s e pointcol, on ne procédera à aucune m odification : iln'e s t pas néce s s aire de déclare r virtue lle
dans les classes dérivé e s une fonction dé claré e virtue lle dans une classe de bas e (ce tte inform ation s e rait e n
fait redondante ).

A titre d'exem ple, le program m e s uivant corre s pond à ce lui du paragraph e 6.3 du ch apitre XIII, dans leq ue l
nous nous som m e s conte nté de re ndre virtue lle la fonction affich e .

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ protected : // pour que x et y soient accessibles à pointcol
int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
virtual void affiche ()
{ cout << "Je suis un point \n" ;
cout << " mes coordonnées sont : " << x << " " << y << "\n" ;
}
} ;
class pointcol : public point
{ short couleur ;
public :
pointcol (int abs=0, int ord=0, short cl=1) : (abs, ord)
{ couleur = cl ;
}
void affiche ()
{ cout << "Je suis un point coloré \n" ;
cout << " mes coordonnées sont : " << x << " " << y ;
cout << " et ma couleur est : " << couleur << "\n" ;
}
} ;

main()
{ point p(3,5) ; point * adp = &p ;
pointcol pc (8,6,2) ; pointcol * adpc = &pc ;
adp->affiche () ; adpc->affiche () ;
cout << "-----------------\n" ;
adp = adpc ; // adpc = adp serait rejeté
adp->affiche () ; adpc->affiche () ;
}
_______________________

Je suis un point
mes coordonnées sont : 3 5
Je suis un point coloré
mes coordonnées sont : 8 6 et ma couleur est : 2
-----------------

3 - Pl
usieurs exécutions de ce tte m ê m e ins truction pouvant appe l
e r des fonctions diffé re ntes.
262 Program m e r e n langage C+ +
Je suis un point coloré
mes coordonnées sont : 8 6 et ma couleur est : 2
Je suis un point coloré
mes coordonnées sont : 8 6 et ma couleur est : 2
_______________________________________________________________________________
______

M i s e e n œuvre de ligature dynam ique (ici pour affich e ) par la te ch nique


de s fonctions virtue lles

R e m arques :

1) Par défaut, C+ + m e t e n place des ligature s s tatiq ue s . A l'aide du m ot virtual, on pe ut ch oisir la ou


les fonctions pour les q ue lles on souh aite m e ttre e n place une ligature dynam iq ue .
2) Ce t aspect ligature dynam iq ue e s t lim ité à un e ns e m ble de classes dérivé e s les unes des autre s .

3. UNE AUTRE SITUA TIO N O Ù LA LIGATURE D Y NA M IQUE


EST IND ISPENSA BLE

D ans notre pré cédent e xe m ple, nous pouvons dire que, lors de la conce ption de la clas s e point, nous avons
pré vu q ue ch acune de ses desce ndante s redéfinirait à sa guis e la fonction affich e . Ce ci conduit à pré voir,
dans ch aq ue fonction, de s instructions d'affich age des coordonné e s . Pour é vite r ce tte redondance 4, nous
pouvons définir notre fonction affich e (de la clas s e point) de m aniè re q u'e lle :

• affich e les coordonné e s (action com m une à toute s les clas s e s ),


• fas s e appe là une autre fonction (nom m é e , par e xe m ple, ide ntifie ), ayant pour vocation d'affich e r les
inform ations spé cifiq ue s à ch aq ue obje t. Bie n e nte ndu, ce faisant, nous supposons que ch aq ue
desce ndante de point redéfinira ide ntifie de façon approprié e (m ais e lle n'aura plus à pre ndre e n ch arge
l'affich age des coordonné e s ).
Ce tte dém arch e nous conduit à définir notre clas s e point de la façon suivante :

class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }

void identifie ()
{ cout << "Je suis un point \n" ; }
void affiche ()
{ identifie () ;
cout << "Mes coordonnées sont : " << x << " " << y << "\n" ;
}
} ;

D é rivons une clas s e pointcole n redéfinissant com m e voulu la fonction ide ntifie :

class pointcol : public point


{ short couleur ;
public :

4 - Bie n e nte ndu, ici, l


'enje u e s t trè s l
im ité. Mais ilpourrait ê tre im portant dans un cas réel
.
XV. Le s fonctions virtue lles e t le typage dynam ique 263
pointcol (int abs=0, int ord=0, int cl=1 ) : point (abs, ord)
{ couleur = cl ; }
void identifie ()
{ cout << "Je suis un point coloré de couleur : " << couleur << "\n" ; }
} ;

Si nous ch e rch ons alors à utiliser pointcolde la façon suivante :

pointcol pc (8, 6, 2) ;
pc.affiche () ;

nous obte nons alors le ré s ultat :

Je suis un point
Mes coordonnées sont : 8 6

ce q ui n'e s t m anife s te m e nt pas ce q ue nous e s pé rions !

Ce rte s , la com pilation de l'appe l:

pc.affiche ()

a conduit le com pilate ur à appe ler la fonction affich e de la clas s e point (puis q ue ce tte fonction n'e s t pas
redéfinie dans pointcol). En re vanch e , à ce m om e nt-là, l'appe l:

identifie ()

figurant dans ce tte fonction a d é jà é té com pil


é e n un appe l... d'ide ntifie de la clas s e point.

Com m e vous le constate z, bie n q u'ici la fonction affich e ait é té appe lée e xplicite m e nt pour un obje t (e t non,
com m e pré cédem m e nt, à l'aide d'un pointe ur), nous nous trouvons à nouve au e n pré s e nce d'un problèm e de
ligature s tatiq ue .

Pour le ré s oudre , il nous suffit, dans la clas s e point, de déclare r virtue lle la fonction ide ntifie . Ce la
pe rm e ttra au com pilate ur de m e ttre e n place les instructions assurant l'appe l de la fonction ide ntifie
corre s pondant au type de l'obje t l'ayant e ffe ctive m e nt appe lée . Ici, vous note re z ce pe ndant q ue la situation
e s t légè re m e nt diffé re nte de ce lle q ui nous a s e rvi à pré s e nte r les fonctions virtue lles (paragraph e 1). En
e ffe t, l'appe ld'ide ntifie e s t ré alisé, cette fois, non plus directe m e nt par l'obje t lui-m ê m e , m ais indire cte m e nt
par la fonction affich e . Nous ve rrons com m e nt le m é canism e des fonctions virtue lles e s t é galem e nt capable
de prendre en ch arge ce t aspect.

Voici un program m e com plet re pre nant les définitions de nos clas s e s point e t pointcol. Nous y m ontrons
com m e nt un appe lte lq ue pc.affich e () e ntraî ne bien l'appe lde ide ntifie du type pointcol(ce q ui constituait
le but de ce paragraph e ). A titre indicatif, nous y avons é galem e nt introduit q ue lque s appe ls par pointe ur,
afin de m ontre r q ue , là aussi, les ch oses se déroulent conve nablem e nt.

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
virtual void identifie ()
{ cout << "Je suis un point \n" ; }
264 Program m e r e n langage C+ +
void affiche ()
{ identifie () ;
cout << "Mes coordonnées sont : " << x << " " << y << "\n" ;
}
} ;
class pointcol : public point
{ short couleur ;
public :
pointcol (int abs=0, int ord=0, int cl=1 ) : point (abs, ord)
{ couleur = cl ; }
void identifie ()
{ cout << "Je suis un point coloré de couleur : " << couleur << "\n" ; }
} ;

main()
{ point p(3,4) ; pointcol pc(5,9,5) ;
p.affiche () ; pc.affiche () ; cout << "---------------\n" ;
point * adp = &p ; pointcol * adpc = &pc ;
adp->affiche () ; adpc->affiche () ; cout << "---------------\n" ;
adp = adpc ;
adp->affiche () ; adpc->affiche () ;
}
_______________________

Je suis un point
Mes coordonnées sont : 3 4
Je suis un point coloré de couleur : 5
Mes coordonnées sont : 5 9
---------------
Je suis un point
Mes coordonnées sont : 3 4
Je suis un point coloré de couleur : 5
Mes coordonnées sont : 5 9
---------------
Je suis un point coloré de couleur : 5
Mes coordonnées sont : 5 9
Je suis un point coloré de couleur : 5
Mes coordonnées sont : 5 9

_______________________________________________________________________________
______

M i s e e n œuvre de ligature dynam ique (ici pour identifie ) par la te ch nique


de s fonctions virtue lles

4. LES FO NCTIO NS VIRTUELLES EN GÉNÉRA L

Les deux pré cédents e xe m ples constituaie nt des cas particulie rs d'utilisation de m é th ode s virtue lles . Nous
vous proposons ici de voir q ue lles e n sont les possibilité s e t les lim itations.
XV. Le s fonctions virtue lles e t le typage dynam ique 265
4.1 Le urs l
im itations s ont ce l
le s de l
'h é ritage

A partir du m om e nt où une fonction f a é té déclaré e virtue lle dans une clas s e A , e lle s e ra soum ise à la
ligature dynam iq ue dans A e t dans toute s les classes desce ndantes de A : on n'e s t donc pas lim ité aux
desce ndantes directe s . Ainsi, on pe ut im agine r une h ié rarch ie 5 de form e s gé om é triq ue s :

Si la fonction affich e e s t déclaré e virtue lle dans la clas s e point e t redéfinie dans les autre s classes desce ndant
de point, e lle s e ra bie n soum ise à la ligature dynam iq ue . Ile s t m ê m e e nvisage able q ue les s ix clas s e s ci-
dessus soient parfaite m e nt définie s e t com pilée s e t q u'on vie nne e n ajoute r de nouve lles , sans re m e ttre e n
caus e les pré cédente s d e q ue lque façon q ue ce s oit. Ce dernie r point s e rait d'ailleurs e ncore plus flagrant si,
com m e dans notre s e cond e xe m ple (paragraph e 3), la fonction affich e , non virtue lle, faisait e lle-m ê m e appe l
à une fonction virtue lle ide ntifie , redéfinie dans ch aq ue clas s e . En e ffe t, dans ce cas, on voit q ue la fonction
affich e aurait pu ê tre ré alisée et com pilée (au s e in de point), sans q ue toute s les fonctions ide ntifie q u'e lle
é tait susce ptible d'appe ler soient connue s . O n trouve là un aspect séduisant de ré utilisabilité : on a dé fini
dans affich e un ce rtain "scé nario" dont ce rtaine s partie s pourront ê tre e xplicité e s plus tard, lors de la
cré ation de classes dérivé e s .

D e m ê m e , si l'on dispose de l'h é ritage m ultiple e t q ue l'on a dé fini ce tte s tructure (com m e dans le
paragraph e 4 du ch apitre XIV) :

Si, dans point, la fonction affich e a é té déclaré e virtue lle, ildevie nt possible d'utiliser la clas s e liste -points
pour gé re r une liste d'obje ts "h é té rogè ne s " e n dé rivant les clas s e s voulues de point e t e n y redéfinissant
affich e . Nous e n ve rrons un exem ple dans le paragraph e s uivant.

4.2 La re dé finition d'une fonction virtue l


le n'e s t pas obl
igatoire

Jus q u'ici, nous avons toujours redéfini dans les classes desce ndante s une m é th ode déclaré e virtue lle dans une
classe de bas e . Ce la n'e s t pas plus indispensable q ue dans le cas des fonctions m e m bre ordinaire s . Ainsi,
considérons à nouve au la pré cédente h ié rarch ie de figure s , e n supposant q ue affich e n'a é té redéfinie q ue
dans les clas s e s q ue nous avons m arq uées d'une é toile (e t définie , bie n sûr, com m e virtue lle dans point).

5 - M ais, depuis l
a ve rsion 2.0, com pte te nu des possibil
ités d'h é ritage m ul
tipl
e, on peut e nvisager n'im porte q ue lgraph e orie nté.
266 Program m e r e n langage C+ +

D ans ce s conditions, l'appe ld'affich e conduira, pour ch aq ue clas s e , à l'appe lde la fonction m e ntionné e à
côté :

ve cte ur ve cte ur::affich e

carre point::affich e

re ctangle point::affich e

ce rcle point::affich e

e llips e e llips e ::affich e

Le m ê m e m é canism e s 'appliq ue rait e n cas d'h é ritage m ultiple, à condition de le com pléte r, le cas é ch é ant,
par les rè gles conce rnant les am biguïté s .

4.3 Fonctions virtue l


le s e t surdé finition

O n pe ut surdéfinir6 une fonction virtue lle, ch aq ue fonction surdéfinie pouvant ê tre ou ne pas ê tre déclaré e
virtue lle.

Par ailleurs, si l'on a dé fini une fonction virtue lle dans une clas s e e t q u'on la surdéfinit dans une clas s e
dérivé e ave c des argum e nts diffé re nts, ils'agira alors bele t bien d'une autre fonction. Si ce tte derniè re
n'e s t pas déclaré e virtue lle, e lle s e ra, q uant à e lle, soum ise à une ligature s tatiq ue .

En fait, on pe ut considérer que le s tatut virtue l/non virtue ljoue , lui aussi, un rôle discrim inate ur dans le
ch oix d'une fonction surdéfinie . D'une m aniè re gé né rale, par souci de s im plicité e t de lisibilité , nous ne
saurions trop vous cons e iller d'é vite r d'e xploite r ce tte possibilité . Plus précisém e nt, si vous deve z surdéfinir
une fonction virtue lle, ile s t pré fé rable q ue toute s les fonctions de m ê m e nom re s te nt virtue lles .

4.4 O n pe ut dé cl
are r une fonction virtue l
le
dans n'im porte q ue ll
e clas s e

D ans tous nos exem ples , nous avions déclaré virtue lle une fonction d'une clas s e q ui n'é tait pas, e lle-m ê m e ,
dérivée d'une autre . Ce la n'e s t pas obligatoire . Ainsi, dans nos exem ples de h ié rarch ie de form e s , point
pourrait e lle-m ê m e dérive r d'une autre clas s e . Dans ce cas, cependant, deux situations doive nt ê tre
distingué e s :

6 - Ne confondez pas surdéfinition e t redéfinition.


XV. Le s fonctions virtue lles e t le typage dynam ique 267
• la fonction affich e de la clas s e point n'a jam ais é té définie dans les clas s e s asce ndante s : aucun problèm e
particulie r ne s e pos e ,
• la fonction affich e a déjà é té définie , ave c les m ê m e s argum e nts, dans une clas s e asce ndante . Dans ce
cas, ilfaut considérer la fonction virtue lle affich e com m e une nouve lle fonction (com m e s 'ily avait e u
surdéfinition – le caractè re virtue l/non virtue l s e rvant, com m e nous l'avons déjà dit, à faire la
distinction). Bie n e nte ndu, toute s les nouve lles définitions d'affich e dans les classes desce ndante s s e ront
soum ises à la ligature dynam iq ue , sauf si l'on e ffe ctue un appe le xplicite d'une fonction d'une clas s e
asce ndante au m oye n de l'opé rate ur de ré s olution de porté e . R appe lons toute fois q ue nous vous
décons e illons forte m e nt ce type de situation.

4.5 Q u e l
q ue s re s trictions

Seul e une fonction m em bre peut ê tre virtuel le. Ce la s e justifie par le m é canism e e m ployé pour e ffe ctue r
la ligature dynam iq ue , à savoir un ch oix bas é s ur le type de l'obje t ayant appe lé la fonction ;ce la ne pourrait
m anife s te m e nt pas s'appliq ue r à une fonction "ordinaire " (m ê m e s i e lle é tait am ie d'une clas s e ).

Un constructeur ne peut pas ê tre virtuel


. En re vanch e , un de s tructe ur pe ut l'ê tre .

5. LES FO NCTIO NS VIRTUELLES PURES : UN O UTIL


PO UR LA CRÉATIO N D E CLASSES ABSTRA ITES

Nous avons déjà e u l'occasion de dire qu'on pouvait ê tre am e né à définir de s classes destiné e s , non pas à
instancie r de s obje ts, m ais sim plem e nt à donne r naissance à d'autre s clas s e s par h é ritage . En P.O .O ., on dit
q u'on a affaire à des "clas s e s abstraite s ".

En C+ + , vous pouve z toujours définir de te lles clas s e s . M ais ils e pe ut q ue vous soye z am e né à y introduire
ce rtaine s fonctions virtue lles dont vous ne pouve z e ncore donner aucune définition. Im agine z, par e xe m ple
une clas s e abstraite form e _ge o, destiné e à gé re r le dessin sur un écran de diffé re nte s form e s gé om é triq ue s
(carré , ce rcle...). Suppos e z q ue vous souh aitie z déjà y faire figure r une fonction de place destiné e à déplace r
une figure . Ile s t probable q ue ce lle-ci fe ra alors appe là une fonction d'affich age de la figure (nom m é e , par
e xe m ple, de s s ine ). La fonction de s s ine s e ra dé claré e virtue lle dans la clas s e form e _ge o e t devra ê tre
redéfinie dans ses desce ndants. M ais q ue lle définition lui fournir dans form e _ge o ? Ave c ce q ue vous
connais s e z de C+ + , vous ave z toujours la re s s ource de pré voir une définition vide 7 :

Toute fois, deux lacune s apparais s e nt alors :

a) R ie n n'inte rdit à un utilisate ur de déclare r un obje t de clas s e form e _ge o, alors q ue dans l'e s prit du
conce pte ur, ils'agissait d'une clas s e abstraite . L'appe lde de place pour un te lobje t conduira à un appe l
de de s s ine ne faisant rie n ;m ê m e s i aucune e rre ur n'e n dé coule, ce la n'a guè re d e s e ns !
b) R ie n n'oblige une classe desce ndant de form e _ge o à redéfinir de s s ine . Si e lle ne le fait pas, on re trouve
les problèm e s é voq ué s ci-de s s us.
C+ + vous propose (depuis la ve rsion 2.0) un outilfacilitant la définition de clas s e s abstraite s : ils'agit des
"fonctions virtue lles pure s ". Ce s ont des fonctions virtue lles dont la définition e s t nulle (0), e t non plus
s e ulem e nt vide. Par e xe m ple, nous aurions pu faire de notre fonction de s s ine de la clas s e form e _ge o une
fonction virtue lle pure e n la déclarant8 ainsi :

7 - Notez bien qu'ilvous faut absol um e nt définir de s s ine dans form e _ge o puis q u'e l
le e s t appe l
é e par de place .
8 - Ici, on ne pe ut pl
us distingue r déclaration e t définition.
268 Program m e r e n langage C+ +
virtual void dessine (...) = 0 ;

Ce rte s , à ce nive au, l'inté rê t de ce tte conve ntion n'apparaî


t pas e ncore . M ais, e n fait, C+ + adopte les
rè gles s uivante s :

• une clas s e com portant au m oins une fonction virtue lle pure e s t considérée com m e abstraite e t iln'e s t plus
possible de déclare r de s obje ts de son type ,
• une fonction dé claré e virtue lle pure dans une classe de base doit obligatoire m e nt ê tre redéfinie 9 dans une
classe dérivé e ou dé claré e à nouve au virtue lle pure 10 ;dans ce dernie r cas, la classe dérivé e e s t, e lle
aussi, abstraite .
Com m e vous le voye z, l'e m ploi de fonctions virtue lles pure s rè gle les deux problèm e s s oulevé s par l'e m ploi
de définitions vides. Dans le cas de notre clas s e form e _ge o, le fait d'avoir re ndu de s s ine virtue lle pure
inte rdit :

• la déclaration d'obje ts de type form e _ge o,


• la définition de classes dérivé e s d e form e _ge o, dans les q ue lles on om e ttrait la définition de de s s ine .

R e m arque :

La notion de fonction virtue lle pure dépas s e ce lle de clas s e abstraite . Si C+ + s'é tait conte nté de déclare r
une clas s e com m e é tant abstraite , ce ci n'aurait s e rvi q u'à e n inte rdire l'utilisation ;ilaurait fallu une
s e conde conve ntion pour pré cis e r les fonctions devant obligatoire m e nt ê tre redéfinie s .

6. EXEM PLE D 'UTILISATIO N D E FO NCTIO NS VIRTUELLES :


LISTE H ÉTÉRO GÈNE

D ans le program m e du paragraph e 4 du ch apitre XIV, nous vous avons fourni un e xe m ple de ge s tion d'une
liste ch aî
né e d e points. Tous les obje ts de la liste é taie nt du m ê m e type : on dit q u'on avait affaire à une liste
h om ogè ne .

Te lle q ue nous avons conçu notre clas s e liste , nous aurions pu l'e m ploye r pour cré e r (par dé rivation)
d'autre s clas s e s pe rm e ttant la ge s tion d'obje ts d'un autre type . M ais peut-on aller plus loin e t définir une
clas s e pe rm e ttant de gérer une liste com portant des obje ts de type diffé re nt ?Com pte te nu de la m aniè re
dont notre clas s e liste a é té conçue , ce la corre s pondrait à un sch é m a de ce type :

9 Toujours ave c l e s m ê m e s argum e nts, sinon ils'agit d'une autre fonction.


10 - D e puis l
a ve rsion 3.0, si une fonction virtue l le pure d'une cl asse de bas e n'e s t pas redéfinie dans une cl
asse dérivée, el
le re s te une
fonction virtue l
le pure de ce tte cl
asse dérivé e ;dans l
e s ve rsions anté rie ures, on obte nait une e rre ur.
XV. Le s fonctions virtue lles e t le typage dynam ique 269

Ce rte s , la nature variable du type des obje ts ne présente pas de difficulté s puis q u'ils sont re pé ré s par de s
pointe urs de type void *. En re vanch e , on voit q ue l'affich age de la liste va devoir ê tre e n m e s ure
d'appliq ue r à ch aq ue obje t la m é th ode approprié e . Ce ci im pliq ue la m ise en œuvre de la ligature
dynam iq ue : la fonction d'affich age s e ra dé finie virtue lle dans un pre m ie r type d'obje t (ici point) e t redéfinie
dans ch acun de ses desce ndants.

En dé finitive , on voit q u'on va pouvoir gé re r une liste d'obje ts de types diffé re nts sous ré s e rve q ue les
clas s e s corre s pondante s s oie nt toutes dérivées d'une m ê m e classe de bas e . Ce la pe ut s e m bler q ue lque pe u
re s trictif. En fait, ce t aspect "fam ille de clas s e s " pe ut toujours ê tre obte nu par la cré ation d'une clas s e
abstraite (réduite au m inim um , é ve ntue llem e nt à une fonction affich e vide ou virtue lle pure ) destiné e
sim plem e nt à donne r naissance aux clas s e s conce rné e s ;bien ente ndu, ce ci n'e s t conce vable q ue s i les
clas s e s e n q ue s tion ne s ont pas déjà figé e s (car ilfaut q u'e lles h é rite nt de ce tte clas s e abstraite ).

Nous vous proposons, à titre d'exem ple, une autre utilisation de la clas s e liste du paragraph e 4 du ch apitre
XIV. Nous lui avons adjoint une clas s e abstraite m e re , destiné e à donne r naissance aux type s s usce ptibles
d'ê tre gé ré s par notre liste . Ici, nous avons e m ployé la possibilité de définir une fonction virtue lle pure
(affich e ). Nous avons com plété notre clas s e liste ave c une fonction d'affich age (affich e _liste ) de la liste .

A sim ple titre indicatif, nous avons défini de ux clas s e s point e t com plexe (les q ue lles n'ont pas besoin de
dérive r l'une de l'autre ), dérivé e s d e la clas s e abstraite m e re e t doté e s ch acune d'une fonction affich e
approprié e . Voici un e xe m ple com plet :

_______________________________________________________________________________
______

#include <iostream.h>
#include <stddef.h> // pour la définition de NULL
// **************** classe mere ********************************************
class mere
{ public :
virtual void affiche () = 0 ; // fonction virtuelle pure
} ;

// ********************* classe liste **************************************


struct element // structure d'un élément de liste
{ element * suivant ; // pointeur sur l'élément suivant
void * contenu ; // pointeur sur un objet quelconque
} ;

class liste
{ element * debut ; // pointeur sur premier élément
element * courant ; // pointeur sur élément courant
public :
270 Program m e r e n langage C+ +
liste () // constructeur
{ debut = NULL ; courant = debut ; }
~liste () ; // destructeur
void ajoute (void *) ; // ajoute un élément
void premier () // positionne sur premier élément
{ courant = debut ;
}
void * prochain () // fournit l'adresse de l'élément courant (0 si
fin)
// et positionne sur prochain élément (rien si
fin)
{ void * adsuiv = NULL ;
if (courant != NULL){ adsuiv = courant -> contenu ;
courant = courant -> suivant ;
}
return adsuiv ;
}
void affiche_liste () ; // affiche tous les éléments de la
liste
int fini () { return (courant == NULL) ; }
} ;
liste::~liste ()
{ element * suiv ;
courant = debut ;
while (courant != NULL )
{ suiv = courant->suivant ; delete courant ; courant = suiv ; }
}
void liste::ajoute (void * chose)
{ element * adel = new element ;
adel->suivant = debut ;
adel->contenu = chose ;
debut = adel ;
}

void liste::affiche_liste ()
{ mere * ptr ; // attention, mere * et pas void *
premier() ;
while ( ! fini() )
{ ptr = (mere *) prochain() ;
ptr->affiche () ;
}
}
// **************** classe point *******************************************
class point : public mere
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
void affiche ()
{ cout << "Point de coordonnées : " << x << " " << y << "\n" ; }
} ;
// **************** classe complexe ****************************************
class complexe : public mere
{ double reel, imag ;
public :
XV. Le s fonctions virtue lles e t le typage dynam ique 271
complexe (double r=0, double i=0) { reel=r ; imag=i ; }
void affiche ()
{ cout << "Complexe : " << reel << " + " << imag << "i\n" ; }
} ;
// **************** programme d'essai **************************************
main()
{ liste l ;
point a(2,3), b(5,9) ;
complexe x(4.5,2.7), y(2.35,4.86) ;
l.ajoute (&a) ; l.ajoute (&x) ; l.affiche_liste () ; cout << "--------\n" ;
l.ajoute (&y) ; l.ajoute (&b) ; l.affiche_liste () ;
} _______________________
Complexe : 4.5 + 2.7i
Point de coordonnées : 2 3
--------
Point de coordonnées : 5 9
Complexe : 2.35 + 4.86i
Complexe : 4.5 + 2.7i
Point de coordonnées : 2 3
_______________________________________________________________________________
______

U tilisation de fonctions virtue lles : liste h é té rogè ne

R e m arque :

D ans la clas s e liste , beaucoup de pointe urs de type void *pourraie nt ê tre re m placé s par de s pointe urs de
type m e re *(pour pe u q u'on ne ch e rch e pas à utiliser cette m ê m e clas s e pour de s obje ts d'un type non
dérivé de m e re ). En re vanch e , le pointe ur ptr utilisé dans affich e _liste doit bien reste r de type m e re *car
c'e s t sur lui q ue re pos e ici le m é canism e de la ligature dynam iq ue de la fonction affich e .

$ 7. LE M ÉCANISM E D 'ID ENTIFICA TIO N D Y NA M IQUE DES OBJETS

N.B. Ce paragraph e pe ut ê tre ignoré dans un pre m ie r te m ps.

Nous avons vu q ue la te ch niq ue des fonctions virtue lles pe rm e ttait de m e ttre e n œuvre la ligature dynam iq ue
pour les fonctions conce rné e s . Ce pe ndant, pour l'instant, ce tte te ch niq ue pe ut vous apparaî tre com m e une
sim ple re ce tte . La com pré h e nsion plus fine du m é canism e , e t donc sa porté e vé ritable, pas s e par la
connaissance de la m aniè re dont ile s t e ffe ctive m e nt im planté . Bie n q ue ce tte im plém e ntation ne s oit pas
e xplicite m e nt im pos é e par le langage , nous vous proposons de décrire ici la dém arch e couram m e nt adopté e
par les diffé re nts com pilate urs e xistants.

Pour ce faire , nous allons considérer un exem ple un pe u plus généralq ue le pré cédent, à savoir :

• une clas s e point com portant deux fonctions virtue lles :


class point
{ .....
virtual void identifie () ;
virtual void deplace (...) ;
.....
} ;

• une clas s e pointcol, dérivé e d e point, ne redéfinissant q ue ide ntifie :


272 Program m e r e n langage C+ +
class pointcol : public point
{ .....
void identifie () ;
.....
} ;

D 'une m aniè re gé né rale, lors q u'une clas s e com porte au m oins une fonction virtue lle, le com pilate ur lui
associe une table conte nant les adresses de ch acune des fonctions virtue lles corre s pondante s . Ave c l'e xe m ple
cité , nous obtie ndrons les deux tables s uivante s :

• lors de la com pilation de point :

Table de point

• lors de la com pilation de pointcol:

Table de pointcol

Note z q u'ici la s e conde adresse de la table de pointcole s t la m ê m e q ue pour la table de point, dans la
m e s ure où la fonction de place n'a pas é té redéfinie .

D 'autre part, tout obje t d'une clas s e com portant au m oins une fonction virtue lle s e voit attribue r par le
com pilate ur, outre l'e m place m e nt m é m oire né ce s s aire à s e s m e m bres donnée, un em place m e nt
supplém e ntaire de type pointe ur, conte nant l'adresse de la table associé e à sa clas s e . Par e xe m ple, si nous
déclarons (e n supposant q ue nous disposons des constructe urs h abitue ls) :

point p (3, 5) ;
pointcol pc (8, 6, 2) ;

nous obtie ndrons :

O n pe ut ainsi dire que ce pointe ur, introduit dans ch aq ue obje t, re pré s e nte l'inform ation pe rm e ttant
d'identifie r la classe de l'obje t. C'e s t e ffe ctive m e nt ce tte inform ation q ui e s t e xploité e pour m e ttre e n œuvre
la ligature dynam iq ue . Ch aq ue appe ld'une fonction virtue lle e s t traduit par le com pilate ur de la façon
suivante :
XV. Le s fonctions virtue lles e t le typage dynam ique 273
• pré lève m e nt dans l'obje t de l'adresse de la table corre s pondante (q ue lle q ue s oit la m aniè re dont une
fonction e s t appe lée –dire cte m e nt ou par pointe ur –, e lle re çoit toujours l'adresse de l'obje t e n argum e nt
im plicite ),
• branch e m e nt à l'adre s s e figurant dans ce tte table à un rang donné . Note z bie n q ue ce rang e s t
parfaite m e nt défini à la com pilation : toute s les tables com porte ront l'adresse de de place 11, par e xe m ple,
e n position 2. En re vanch e , c'e s t lors de l'e xé cution q ue s e ra e ffe ctué le "ch oix de la bonne table".

11 - Eve ntue l
le m e nt, l
e s tabl
es de ce rtaine s cl
as s e s pourront conte nir pl
us d'adresses si el
le s introduisent de nouve l
le s fonctions virtue l
les,
m ais ce l
le s q u'e l
le s partage nt ave c l
e urs as ce ndante s occupe ront toujours l
a m ê m e pl
ace e t c'e s t l
à l
'essentie lpour l
e bon déroul
e m e nt des
opé rations.
XVI. LES FLO TS

Au cours des précédents ch apitre s , nous avons souve nt é té am e né à é crire s ur la "sortie s tandard". Pour ce
faire , nous utilisions des instructions te lles q ue :

cout << n ;

Ce tte derniè re fait appe là l'opé rate ur < < , e n lui fournissant deux opérandes correspondant, d'une part au
"flot de sortie " conce rné (ici cout), d'autre part à l'e xpre s s ion dont on souh aite é crire la valeur (ici n).

D e m aniè re com parable, nous avons é té am e né à lire s ur "l'e ntré e s tandard" e n utilisant des instructions
te lles q ue :

cin >> x ;

Ce lle-ci fait appe là l'opé rate ur > > , e n lui fournissant deux opérandes correspondant, d'une part au "flot
d'entré e " conce rné (ici cin), d'autre part à la "lvalue " dans laq ue lle on souh aite lire une inform ation.

D 'une m aniè re gé né rale, un flot pe ut ê tre considéré com m e un "canal" :

• re ce vant de l'inform ation, dans le cas d'un flot de sortie ,


• fournissant de l'inform ation, dans le cas d'un flot d'entré e .
Le s opé rate urs < < ou > > s e rve nt à assure r le transfe rt de l'inform ation, ainsi que son éve ntue l
"form atage ".

Un flot pe ut ê tre conne cté à un pé riph é riq ue ou à un fich ie r. Le flot prédéfini cout e s t, par conve ntion,
conne cté à ce q ue l'on nom m e la "sortie s tandard", corre s pondant au fich ie r prédéfini s tdout du langage C.
D e m ê m e , le flot prédéfini cin e s t, par conve ntion, conne cté à ce q ue l'on nom m e "l'e ntré e s tandard",
corre s pondant au fich ie r prédéfini s tdin du langage C. Gé né ralem e nt, l'e ntré e s tandard corre s pond au clavie r
e t la sortie s tandard à l'é cran1. M ais la plupart des im plém e ntations perm e tte nt de "rediriger" l'e ntré e
standard ou la sortie s tandard ve rs un fich ie r.

En de h ors de ce s flots prédéfinis 2, l'utilisate ur pe ut définir lui-m ê m e d'autre s flots q u'ilpourra conne cte r à
un fich ie r de s on ch oix.

Si l'on y re garde de plus prè s, on pe ut dire q u'un flot e s t un objet d'une clas s e prédéfinie , à savoir :

1 - Toute fois, cel


a n'e s t pas im pos é par l
e l
angage. On peut trouve r, par e xe m pl
e, des (rares) im pl
é m e ntations dans l
e s q ue l
les l
a s ortie
s tandard corre s pond à une im prim ante.
2 - Nous ve rrons q u'ile n e xis te d'ail
le urs deux autre s : ce rr e t clog.
XVI. Le s flots 275
• ostream pour un flot de sortie ,
• istream pour un flot d'entré e .
Ch acune de ces deux clas s e s s urdé finit les opé rate urs < < e t > > pour les diffé re nts types de bas e . Le ur
e m ploi né ce s s ite l'incorporation du fich ie r e n-tê te iostre am .h 3.

Jus q u'ici, nous nous som m e s conte nté d'exploite r q ue lque s -unes des possibilités des clas s e s istre am e t
ostre am , e n nous lim itant, de plus, aux flots prédéfinis cin e t cout. Ce ch apitre va faire le point sur
l'e ns e m ble des possibilités d'entré e s -sortie s offe rte s par C+ + , te lles q u'e lles s ont pré vues depuis la ve rsion
2.0.

Nous adopte rons la progre s s ion suivante :

• pré s e ntation gé né rale des possibilités de la clas s e ostre am : types de bas e acce pté s , principales fonctions
m e m bre (put, w rite ), e xe m ples de form atage de l'inform ation,
• pré s e ntation gé né rale des possibilités de la clas s e istre am : types de bas e acce pté s , principales fonctions
m e m bre (ge t, ge tline , gcount, re ad...),
• ge s tion de ce q ue l'on nom m e le "statut d'erreur d'un flot",
• possibilités de surdé finition de s opé rate urs < < e t > > pour de s type s (clas s e s ) définis par l'utilisate ur,
• é tude détaillée d e s possibilités de form atage des inform ations, aussi bien en entré e q u'e n sortie ,
• conne xion d'un flot à un fich ie r, e t possibilités d'accè s direct offe rtes dans ce cas,
• possibilités de "lecture ou d'é criture e n m é m oire ", ce q ui pe rm e ttra de re trouve r les facilité s offe rte s par
les fonctions fs canf e t sprintf du langage C.
D 'une m aniè re gé né rale, garde z bie n pré s e nt à l'e s prit, au cours de l'é tude de ce ch apitre , q ue tout ce q ui
s e ra dit dè s le début, à propos des flots, s'appliq ue ra sans re s triction aucune à un flot q ue lconq ue e t, donc, à
un flot conne cté à un fich ie r.

1. PRÉSENTA TIO N GÉNÉRA LE D E LA CLASSE O STREA M

Aprè s avoir pré cis é le rôle de l'opé rate ur < < e t rappe lé les types de bas e pour les q ue ls l'opé rate ur < < e s t
surdéfini, nous ve rrons le rôle des deux fonctions m e m bre put e t w rite . Nous e xam ine rons e nsuite q ue lque s
e xe m ples de form atage de l'inform ation, ce q ui nous perm e ttra d'introduire l'im portante notion de
"m anipulate ur".

1.1 Surdé finition de l


'opé rate ur <<

D ans la clas s e ostre am , l'opé rate ur < < e s t donc surdéfini pour les diffé re nts types de bas e , sous la form e :

ostream & operator << (expression)

Ilre çoit deux opérandes :

• la clas s e l'ayant appe lé (argum e nt im plicite - th is),


• une e xpre s s ion d'un type de bas e q ue lconq ue .

3 - Son e xte nsion dépend de l


'im pl
é m e ntation (h xx, h ...).
276 Program m e r e n langage C+ +
Son rôle consiste à "transm e ttre " la valeur de l'e xpre s s ion au flot conce rné e n la "form atant4" de façon
approprié e . Considérons, par exem ple, l'instruction :

cout << n ;

Si n contie nt la valeur 1234, le travailde l'opé rate ur < < consiste ra à conve rtir la valeur (binaire ) de n dans
le systè m e décim ale t à e nvoye r au flot cout les caractè re s corre s pondant à ch acun de s ch iffre s ainsi obte nus
(soit, ici, les q uatre caractè re s : 1, 2, 3 e t 4). Nous e m ploye rons le m ot "é criture " pour q ualifie r le rôle de
ce t opé rate ur ;sach e z toute fois q ue ce te rm e n'e s t pas unive rs e llem e nt ré pandu : notam m e nt, on re ncontre
parfois "inje ction".

Par ailleurs, ce t opé rate ur < < fournit com m e ré s ultat la ré fé re nce au flot conce rné , aprè s q u'ily a é crit
l'inform ation voulue . Ce la pe rm e t de l'appliq ue r facilem e nt plusieurs fois de suite , com m e dans :

cout << "valeur : " << na << "\n" ;

Tous les types de bas e s ont acce pté s par l'opé rate ur < < 5 (soit par surdéfinition e ffe ctive de l'opé rate ur,
soit par le je u de s conve rsions im plicite s ), y com pris les type s :

• ch ar,
• ch ar *: on obtie nt la ch aî
ne s itué e à l'adre s s e corre s pondante ,
• pointe ur sur un type q ue lconq ue : dans ce cas (du m oins s'ilne s 'agit pas de ch ar *), on obtie nt la valeur
du pointe ur corre s pondant. Si l'on souh aite affich e r la valeur d'un pointe ur de type ch ar *(e t non plus la
ch aî
ne q u'ilré fé re nce ), ilsuffit de le conve rtir e xplicite m e nt e n void *.

1.2 Le s fl
ots pré dé finis

En plus de cout, ile xiste deux autre s flots prédéfinis de clas s e ostre am :

• ce rr : flot de sortie conne cté à la sortie s tandard d'e rre ur (s tde rr e n C), sans "tam pon"6 inte rm édiaire ,
• clog : flot de sortie conne cté é galem e nt à la sortie s tandard d'e rre ur, m ais e n utilisant un "tam pon"7
inte rm édiaire .

1.3 La fonction put

Ile xiste , dans la clas s e ostre am , une fonction m e m bre nom m é e put q ui transm e t au flot corre s pondant le
caractè re re çu e n argum e nt. Ainsi :

cout.put(c) ;

transm e t au flot cout le caractè re conte nu dans c, com m e le fe rait :

cout << c ;

4 - Nous ve rrons q u'ile s t possibl


e d'inte rve nir s ur l
a m aniè re dont e s t e ffe ctué ce form atage. D'autre part, dans certains cas, ilpourra ne
pas y avoir de form atage : c'e s t ce q ui s e produira, par e xe m ple, l ors q ue l
'on util isera l
a fonction w rite .
5 - D u m oins dans l a ve rsion 2.0.
6 - "Buffe r", e n anglais. On parl e parfois e n "frangl ais ", de s ortie "non buffe ris é e ".
7 - O n parle parfois de sortie "buffe ris é e ".
XVI. Le s flots 277
En fait, la fonction put é tait surtout indispensable dans les ve rsions anté rie ure s à la 2.0 pour pallie r l'abs e nce
de surdéfinition de l'opé rate ur pour le type ch ar.

La valeur de re tour de put e s t le flot conce rné , aprè s q u'on y a é crit le caractè re corre s pondant. Ce la pe rm e t
d'écrire , par e xe m ple (c1, c2 e t c3 é tant de type ch ar) :

cout.put(c1).put(c2).put(c3) ;

ce q ui e s t é q uivalent à :

cout.put(c1) ;
cout.put(c2) ;
cout.put(c3) ;

1.4 La fonction w rite

D ans la clas s e ostre am , la fonction m e m bre w rite pe rm e t de transm e ttre au flot de sortie considéré une suite
de caractè re s (octe ts) de longue ur donné e . Par e xe m ple, ave c :

char t[] = "bonjour" ;


...
l'instruction :

cout.write (t, 4) ;

e nve rra sur le flot cout 4 caractè re s cons é cutifs à partir de l'adre s s e t, c'e s t-à -dire les caractè res b, o, n et j.

Ce tte fonction pe ut s e m bler faire double e m ploi ave c la transm ission d'une ch aî ne à l'aide de l'opé rate ur
< < . En fait, ilfaut tout d'abord note r q ue s on com porte m e nt n'e s t pas identiq ue puis q ue w rite ne fait pas
inte rve nir de caractè re de fin de ch aî ne (caractè re nul) ;si un te lcaractè re apparaî t dans la longue ur pré vue ,
ils e ra transm is, com m e les autre s , au flot de sortie . D'autre part, ce tte fonction ne ré alise aucun form atage
(nous ve rrons q u'ave c <<, on peut agir sur le "gabarit" de l'inform ation e ffe ctive m e nt é crite s ur le flot).

En fait, ce tte fonction s'avé re ra indispensable dè s lors q ue l'on souh aite ra transm e ttre une inform ation sous
une form e "brute " (on dit souve nt "binaire "), sans q u'e lle s ubisse la m oindre m odification. Bie n e nte ndu,
ce la n'a gé né ralem e nt guè re d'inté rê t dans le cas d'un écran ;e n re vanch e , ce s e ra la s e ule façon de cré e r un
fich ie r sous form e "binaire " (c'e s t-à -dire dans leq ue lles inform ations –q ue lq ue s oit leur type –sont
e nre gistré e s te lles q u'e lles figure nt e n m é m oire ).

Com m e put, la fonction w rite fournit e n re tour le flot conce rné , aprè s q u'on y a é crit l'inform ation
corre s pondante .

1.5 Q u e l
q ue s pos s ibil
ité s de form atage

Nous étudie rons, dans le paragraph e 5, l'e ns e m ble des possibilités de form atage de la clas s e ostre am , ainsi
d'ailleurs q ue ce lles de la clas s e istre am . Ce pe ndant, dè s m ainte nant, nous vous présentons deux exem ples
courants de form atage de l'inform ation é crite s ur un flot de sortie , ce q ui nous perm e ttra d'introduire la
notion de "m anipulate ur".

a)A ction s ur l
a bas e de num é ration
Lors q ue l'on é crit une valeur e ntiè re s ur un flot de sortie , on pe ut ch oisir de l'e xprim e r dans l'une des bas e s
suivante s :
278 Program m e r e n langage C+ +
• 10 : décim al(ils'agit de la valeur par dé faut),
• 16 : h e xadé cim al,
• 8 : octal.
Voici un e xe m ple de program m e dans leq ue lnous é crivons dans diffé re ntes bas e s la valeur de la m ê m e
variable (n).

___________________________________________________________________________

#include <iostream.h>
main()
{ int n = 12000 ;
cout << "par défaut : " << n << "\n" ;
cout << "en hexadécimal : " << hex << n << "\n" ;
cout << "en décimal : " << dec << n << "\n" ;
cout << "en octal : " << oct << n << "\n" ;
cout << "et en ???? : " << n << "\n" ;
}
_______________________
par défaut : 12000
en hexadécimal : 2ee0
en décimal : 12000
en octal : 27340
et en ???? : 27340
___________________________________________________________________________

Action sur la base de num é ration de s valeurs écrite s s u r cout

Les sym boles h e x, de c e t oct s e nom m e nt des m anipul ateurs. Ils'agit, e n fait, d'opé rate urs prédéfinis, à un
s e ulopé rande de type flot, e t fournissant e n re tour le m ê m e flot, aprè s q u'ils y ont opé ré une ce rtaine action
("m anipulation"). Ici, ce tte action consiste pré cis é m e nt à m odifie r la valeur de la base de num é ration (ce tte
inform ation é tant, e n fait, m é m orisée dans la clas s e ostre am 8). Note z bie n q ue la valeur de la bas e re s te la
m ê m e , tant q u'on ne la m odifie pas (par un m anipulate ur), e t ce la q ue lles q ue s oie nt les inform ations
transm ises au flot (e ntie rs, caractè re s , flottants...).

Nous ve rrons, dans le paragraph e 5, q u'ile xiste beaucoup d'autre s m anipulate urs e t nous e n fe rons une
é tude com plète .

b)A ction s ur l
e gabarit de l
'inform ation é crite

Voye z ce t e xe m ple de program m e q ui m ontre com m e nt agir sur la large ur (gabarit) suivant laq ue lle
l'inform ation e s t é crite :

___________________________________________________________________________

#include <iostream.h>
#include <iomanip.h>
main()

8 - En toute rigue ur, de l


a cl
as s e ios, dont dérive nt l
e s cl
as s e s ostre am e t istre am .
XVI. Le s flots 279
{
int n = 12345 ;
int i ;
for (i=0 ; i<15 ; i++)
cout << setw(2) << i << " : "<< setw(i) << n << "\n" ;
_______________________

0 : 12345
1 : 12345
2 : 12345
3 : 12345
4 : 12345
5 : 12345
6 : 12345
7 : 12345
8 : 12345
9 : 12345
10 : 12345
11 : 12345
12 : 12345
13 : 12345
14 : 12345
___________________________________________________________________________

Action sur le gabarit de l'inform ation écrite s u r cout

Ici e ncore , nous faisons appelà un m anipulate ur (s e tw ). Ce lui-ci e s t ce pe ndant un pe u plus com plexe q ue les
pré cédents (h e x, oct ou de c) puis q u'il com porte un "param è tre " re pré s e ntant, dans ce cas, le gabarit
souh aité . O n parle alors de "m anipulate ur param é triq ue ". Nous ve rrons q u'il e xiste beaucoup d'autre s
m anipulate urs param é triq ue s ;leur e m ploi né ce s s ite absolum e nt l'incorporation du fich ie r e n-tê te iom anip.h .

En ce q ui conce rne s e tw , sach e z q ue ce m anipulate ur dé finit uniq ue m e nt le gabarit de la proch aine


inform ation à é crire. Si l'on ne fait pas à nouve au appe là s e tw pour les inform ations suivante s , ce lles -ci
s e ront é crite s s uivant les conve ntions h abitue lles , à savoir e n utilisant l'e m place m e nt m inim um né ce s s aire
pour les é crire (2 caractè re s pour la valeur 24, 5 caractè re s pour la valeur -2345, 7 caractè re s pour la ch aî ne
"bonjour"...). D'autre part, si la valeur fournie à s e tw e s t insuffisante à l'é criture de la valeur suivante , ce tte
derniè re s e ra é crite s uivant les conve ntions h abitue lles (e lle ne s e ra donc pas tronq ué e ).

2. PRÉSENTA TIO N GÉNÉRA LE D E LA CLASSE ISTREA M

D e m aniè re com parable à ce q ue nous avons fait pour la clas s e ostre am , nous com m e nce rons par pré cis e r le
rôle de l'opé rate ur > > . Nous ve rrons e nsuite le rôle des diffé re nte s fonctions m e m bre de la clas s e istre am
(ge t, ge tline , gcount, re ad...). Nous te rm ine rons sur un e xe m ple de form atage de l'inform ation.
280 Program m e r e n langage C+ +
2.1 Surdé finition de l
'opé rate ur > >

D ans la clas s e istre am , l'opé rate ur > > e s t surdéfini pour tous les types de bas e , y com pris ch ar *9 , sous la
form e :

istream & operator >> ( & type_de_base )

Ilre çoit deux opérandes :

• la clas s e l'ayant appe lé (argum e nt im plicite - th is),


• une "lvalue " d'un type de bas e q ue lconq ue .
Son rôle consiste à "e xtraire " du flot conce rné les caractè re s né ce s s aire s pour form e r une valeur du type de
bas e voulu e n ré alisant une opé ration inve rse du form atage opé ré par l'opé rate ur < < .

Ilfournit com m e ré s ultat la ré fé re nce au flot conce rné , aprè s q u'ile n a e xtrait l'inform ation voulue . Ce la
pe rm e t de l'appliq ue r plusieurs fois de suite , com m e dans :

cin >> n >> p >> x ;

Le s "e s pace s _blancs 10" s e rve nt de délim ite urs. R appe lons q ue l'on range dans ce tte caté gorie les caractè re s
suivants : e s pace , tabulation h orizontale (\t), tabulation ve rticale (\v), fin de ligne (\n), re tour ch ariot (\r) e t
ch ange m e nt de page (\f).

Bie n e nte ndu, les délim ite urs ne peuve nt pas ê tre lus, e n tant q ue caractè re s e ux-m ê m e s . Par e xe m ple, la
ré pé tition de l'instruction (c é tant supposé de type ch ar) :

cin >> c ;

appliq ué e à un flot conte nant ce te xte :

b o
n j

our

conduira à ne pre ndre e n com pte q ue les 7 caractè re s : b, o, n, j, o, u e t r.

Nous ve rrons ci-de s s ous com m e nt procéder (ave c la fonction ge t) pour accéder à tous les caractè res d'un
flot, délim ite urs com pris.

D 'autre part, lors q u'on lit sur un flot une inform ation à destination d'une ch aî
ne de caractè re s (ch ar *) :

• ce s ont, là e ncore , les "e s pace s _blancs" q ui s e rve nt de délim ite urs. Iln'e s t donc pas possible de lire e n
une s e ule fois une ch aîne conte nant, par e xe m ple, un e s pace , te lle q ue :
bonjour mademoiselle

Note z q ue , dans ce cas, ilne s e rt à rie n de la place r e ntre guillem e ts, com m e ce ci :
"bonjour mademoiselle"

En e ffe t, la pre m iè re ch aî
ne lue s e rait alors :
"bonjour

9 - M ais pas, a priori, pour l e s types pointe urs.


10 - D e "w h ite s pace s ", e n angl ais.
XVI. Le s flots 281

Nous ve rrons, un pe u plus loin, com m e nt la fonction ge tline fournit une s olution agré able au problèm e
q ue nous ve nons d'évoq ue r ;
• l'inform ation rangé e e n m é m oire e s t com plété e par un caractè re nulde fin de ch aî
ne (\0). Ainsi, pour lire
une ch aîne de n caractè re s , ilfaut pré voir un e m place m e nt de n+ 1 caractè re s .

2.2 La fonction ge t

La fonction :

istream & get (char &)

pe rm e t d'extraire un caractè re d'un flot d'entré e e t de le range r dans la variable (de type ch ar) q u'on lui
fournit e n argum e nt. Tout com m e put, ce tte fonction fournit e n re tour la ré fé re nce au flot conce rné , aprè s
q u'on e n a e xtrait le caractè re voulu.

Contraire m e nt à l'opé rate ur > > , la fonction ge t pe ut lire n'im porte q ue lcaractè re , délim ite urs com pris.
Ainsi, en l'appliq uant à un flot conte nant ce te xte :

b o
n j

our

e lle conduira à pre ndre e n com pte 16 caractè re s : b, e s pace , o, \n, n, e s pace , e s pace , e s pace , e s pace , j, \n,
\n, o, u, r e t \n.

Ile xiste une autre fonction ge t (ily a donc surdéfinition), de la form e :

int get ()

Ce lle-ci pe rm e t, e lle aussi, d'extraire un caractè re d'un flot d'entré e , m ais, ce tte fois, e lle le fournit, com m e
valeur de re tour, sous form e d'un entier. Elle e s t ainsi en m e s ure de fournir une valeur spéciale EOF (e n
gé né ral-1) lors q ue la fin de fich ie r a é té re ncontré e s ur le flot corre s pondant11.

R e m arque :

Nous ve rrons, dans le paragraph e 3 consacré au "statut d'erreur" d'un flot, q u'il e s t possible de
considérer un flot com m e une "valeur logiq ue " (vrai ou faux) e t, par suite , d'é crire des instructions te lles
q ue :
char c ;
...
while ( cin.get(c) ) // recopie le flot cin
cout.put (c) ; // sur le flot cout
// arrêt quand eof car alors (cin) = 0

Ce lles -ci sont é q uivalente s à :


int c ;
...

11 - C'e s t ce q ui jus tifie q ue s a val


e ur de retour s oit de type int e t non ch ar.
282 Program m e r e n langage C+ +
while ( ( c = cin.get() ) != EOF )
cout.put (c) ;

2.3 Le s fonctions ge tl
ine e t gcount

Ces deux fonctions facilite nt la lecture des ch aî nes de caractè re s ou, plus généralem e nt, la lecture d'une
suite de caractè re s q ue lconq ue s , te rm iné e par un caractè re connu (e t non pré s e nt dans la ch aî
ne e n q ue s tion).

L'e n-tê te de la fonction ge tline s e pré s e nte s ous la form e :

istream & getline (char * ch, int taille, char delim = '\n' )

Ce tte fonction lit des caractè re s s ur le flot l'ayant appe lé e t les place dans l'e m place m e nt d'adre s s e ch . Elle
s'inte rrom pt lors q u'une des deux conditions suivante s e s t satisfaite :

• le caractè re délim ite ur de lim a é té trouvé : dans ce cas, ce caractè re n'e s t pas re copié e n m é m oire .
• taille - 1 caractè re s ont é té lus.
D ans tous les cas, ce tte fonction ajoute un caractè re nulde fin de ch aî
ne , à la suite des caractè re s lus.

Note z q ue le caractè re délim ite ur possè de une valeur par dé faut (\n) bien adapté e à la lecture de lignes de
te xte .

Quant à la fonction gcount, e lle fournit le nom bre de caractè re s e ffe ctive m e nt lus lors du dernier appelde
ge tline . Le caractè re délim ite ur, pas plus q ue ce lui placé à la fin de la ch aî ne ne s ont com pté s ;autre m e nt
dit, gcount fournit la longue ur e ffe ctive de la ch aî ne rangé e e n m é m oire par ge tline .

Voici, à titre d'exem ple, une s é q ue nce classique d'instructions perm e ttant de traite r les diffé re nte s lignes du
flot cin (é ve ntue llem e nt redirigé ve rs un fich ie r) :

const LG_LIG = 120 ; // longueur maxi d'une ligne de texte


...
char ch [LG_LIG+1] ; // pour lire une ligne
int lg ; // longueur courante d'une ligne
...
while ( cin.getline (ch, LG_LIG) )
{ lg = cin.gcount () ;
// traitement d'une ligne de lg caractères
...
}

2.4 La fonction re ad

La fonction re ad pe rm e t de lire s ur le flot d'entré e considéré une suite de caractè re s (octe ts) de longue ur
donné e . Par e xe m ple, ave c :

char t[10] ;

l'instruction :

cin.read (t, 5) ;

lira sur cin 5 caractè re s e t les range ra à partir de l'adre s s e t.


XVI. Le s flots 283
Ici e ncore , ce tte fonction pe ut s e m bler faire double e m ploi soit ave c la lecture d'une ch aî
ne ave c l'opé rate ur
> > , soit ave c la fonction ge tline ;toute fois, re ad ne né ce s s ite ni s é parate ur ni caractè re délim ite ur
particulie r.

En fait, nous ve rrons q ue ce tte fonction s'avé re ra indispensable dè s lors q ue l'on souh aite ra accéder à des
fich ie rs sous form e "binaire ", c'e s t-à -dire e n re copiant e n m é m oire les inform ations te lles q u'e lles figure nt
dans le fich ie r. La fonction re ad joue ra le rôle sym é triq ue de la fonction w rite .

2.5 Q u e l
q ue s autre s fonctions

Ile xiste é galem e nt, dans la clas s e istre am , deux fonctions m e m bre , à caractè re utilitaire :

putback (ch ar c) pour re nvoye r dans le flot conce rné un caractè re donné,
pe e k () q ui fournit le proch ain caractè re disponible s ur le flot conce rné , m ais sans l'e xtraire du flot (il
s e ra donc à nouve au obte nu lors d'une proch aine lecture s ur le flot).

R e m arque :

En toute rigue ur, ile xiste é galem e nt une clas s e iostre am , h é ritant à la fois de istre am e t de ostre am .
Ce lle-ci pe rm e t de ré aliser des entré e s -sortie s "bidire ctionne lles ".

3. STA TUT D 'ERREUR D 'UN FLO T

A ch aq ue flot (d'e ntré e ou de s ortie ) e s t associé un e ns e m ble de bits d'un entie r, form ant ce q ue l'on nom m e
le "statut d'erreur" du flot. Ilpe rm e t de re ndre com pte du bon ou du m auvais déroulem e nt des opérations sur
le flot. Nous allons tout d'abord voir q ue lle e s t pré cis é m e nt la signification de ces diffé re nts bits (au nom bre
de 4). Puis nous appre ndrons com m e nt e n connaî tre la valeur e t, le cas é ch é ant, la m odifie r. Enfin, nous
ve rrons com m e nt la surdéfinition de s opé rate urs () e t ! pe rm e t de sim plifie r l'utilisation d'un flot.

3.1 Le s bits d'e rre ur

La position des diffé re nts bits d'erreur, au sein d'un entie r, e s t définie par de s constantes déclarées dans la
clas s e ios dont dérive nt les deux clas s e s istre am e t ostre am . Ch acune de ce s constante s corre s pond à la
valeur pris e par l'e ntie r e n q ue s tion lors q ue le bit corre s pondant (e t lui s e ul) e s t "activé " (à 1). Ils'agit de :

e ofbit : fin de fich ie r ;ce bit e s t activé s i la fin de fich ie r a é té atte inte , autre m e nt dit si le flot
corre s pondant n'a plus aucun caractè re disponible.
failbit : ce bit e s t activé lors q ue la proch aine opé ration d'e ntré e -sortie ne pe ut aboutir,
badbit : ce bit e s t activé lors q ue le flot e s t dans un état irré cupé rable.
La diffé re nce e ntre badbit e t failbit n'e xiste q ue pour les flots d'entré e ;lors q ue failbit e s t activé , aucune
inform ation n'a é té ré e llem e nt pe rdue s ur le flot ;iln'e n va plus de m ê m e lors q ue badbit e s t activé .

D e plus, ile xiste une constante goodbit (valant, e n fait 0), corre s pondant à la valeur q ue doit avoir le s tatut
d'erreur lors q u'aucun de ses bits n'est activé .
284 Program m e r e n langage C+ +
O n pe ut dire q u'une opé ration d'e ntré e -sortie a ré ussi lors q ue l'un des bits goodbit ou e ofbit e s t activé . De
m ê m e , on pe ut dire q ue la proch aine opé ration d'e ntré e -sortie ne pourra aboutir q ue s i goodbit e s t activé
(m ais iln'e s t pas e ncore 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 (ce q ui va de soi !),


• et q ue le bit d'erreur corrre s pondant n'a pas é té re m is à zé ro : nous allons voir, ci-de s s ous, q u'ile xiste
des fonctions perm e ttant d'agir sur ces bits d'erreur.

3.2 A ction conce rnant l


e s bits d'e rre ur

Ile xiste deux caté gories de fonctions :

• ce lles q ui pe rm e tte nt de connaî


tre le s tatut d'erreur d'un flot, c'e s t-à -dire , e n fait, la valeur de s e s
diffé re nts bits d'erreur,
• ce lles q ui pe rm e tte nt de m odifie r la valeur de ce rtains de ces bits d'erreur.

a)A ccè s aux bits d'e rre ur

D 'une part, ile xiste 5 fonctions m e m bre (de ios 12) :

e of () : fournit la valeur vrai (1) si la fin de fich ie r a é té re ncontré e , c'e s t-à -dire s i le bit e ofbit e s t activé .
bad () : fournit la valeur vrai (1) si le flot e s t alté ré , c'e s t-à -dire s i le bit badbit e s t activé .
fail() : fournit la valeur vrai (1) si le bit failbit e s t activé ,
good () : fournit la valeur vrai (1) si aucune des trois fonctions précédente s n'a la valeur vrai, c'e s t-à -dire
si aucun des bits du statut d'erreur n'est activé .
D 'autre part, la fonction m e m bre 13 rdstate () fournit e n re tour un e ntie r corre s pondant à la valeur du statut
d'erreur.

b)M odification du s tatut d'e rre ur


La fonction m e m bre clear d'en-tê te :

void clear (int i=0)


active les bits d'erreur correspondant à la valeur fournie e n argum e nt. En gé né ral, on dé finit la valeur de ce t
argum e nt e n utilisant les constante s prédéfinies de la clas s e ios.

Par e xe m ple, si fldésigne un flot, l'instruction :

fl.clear (ios::badbit) ;

active ra le bit badbit du statut d'erreur du flot fle t m e ttra tous les autres bits à zé ro.

12 - D onc de istre am e t de ostre am , par h é ritage.


13 - D é s orm ais, nous ne préciserons pl us q u'ils'agit d'un m e m bre de ios, dont h é rite nt istre am e t ostre am .
XVI. Le s flots 285
Si l'on souh aite active r ce bit, sans m odifie r les autre s , ilsuffit de faire appe là rdstate , e n procédant ainsi :

fl.clear (ios::badbit | fl.rdstate () ) ;

R e m arque :

Lors q ue vous surdé finire z les opé rate urs < < e t > > pour vos propre s type s (clas s e s ), ils e ra pratiq ue
de pouvoir active r les bits d'erreur, en com pte re ndu du dé roulem e nt de l'opé ration.

3.3 Surdé finition de s opé rate urs () e t !

Com m e nous l'avons déjà é voq ué dans la re m arq ue du paragraph e 2.2, ile s t possible de "te s te r" un flot e n
le considérant com m e une valeur logiq ue (vrai ou faux). Ce la e s t ré alisé grâ ce à la surdéfinition, dans la
clas s e ios des opérate urs () e t !.

Plus précisém e nt, l'opé rate ur () e s t surdéfini de m aniè re q ue , si fldésigne un flot :

( fl)
• pre nne une valeur non nulle14 (vrai), si aucun des bits d'erreur n'est activé , c'e s t-à -dire s i good () a la
valeur vrai.
• pre nne une valeur nulle (faux), dans le cas contraire , c'e s t-à -dire s i good () a la valeur faux.
Ainsi :

if (fl) ...

pe ut re m place r :

if (fl.good () ) ...

D e m ê m e , l'opé rate ur ! e s t surdéfini, de m aniè re q ue , si fldésigne un flot :

! fl
• pre nne une valeur nulle (faux) si un des bits d'erreur est activé , c'e s t-à -dire s i good () a la valeur faux,
• pre nne une valeur non nulle (vrai) si aucun des bits d'erreur n'est activé , c'e s t-à -dire s i good () a la
valeur vrai.
Ainsi :

if (! flot ) ...

pe ut re m place r :

if (! flot.good () ) ...

14 - Sa val
e ur e xacte n'e s t pas pré cis é e e t e l
le n'a donc pas de signification particul
iè re.
286 Program m e r e n langage C+ +
4. SURD ÉFINITIO N D ES O PÉRA TEURS << ET > >
PO UR LES TYPES D ÉFINIS PAR L'UTILISATEUR

Com m e nous l'avons déjà dit, les opé rate urs < < e t > > pe uve nt ê tre redéfinis par l'utilisate ur pour de s
type s clas s e s q u'ila lui-m ê m e cré é s . Nous allons d'abord e xam ine r la dém arch e à e m ploye r pour ré aliser
ce tte s urdé finition, avant d'en voir un e xe m ple d'application.

4.1 La dé m arch e

Les deux opé rate urs < < e t > > , déjà surdéfinis au s e in de s clas s e s istre am e t ostre am pour les diffé re nts
types de bas e , pe uve nt ê tre s urdé finis pour n'im porte q ue ltype clas s e cré é par l'utilisate ur.

Pour ce faire , ilsuffit de te nir com pte des re m arq ue s s uivante s .

a) Ce s opé rate urs doive nt re ce voir un flot e n pre m ie r argum e nt, ce q ui e m pê ch e d'en faire une fonction
m e m bre de la clas s e conce rné e (note z q u'on ne pe ut plus, com m e dans le cas des types de bas e , e n faire
une fonction m e m bre de la clas s e istre am ou ostre am , dans la m e s ure où l'utilisate ur ne pe ut plus
m odifie r ce s clas s e s q ui lui sont fournie s ave c C+ + ).
Ils'agira donc de fonctions indépendante s ou am ies de la clas s e conce rné e e t ayant un prototype de la
form e :
ostream & operator << (ostream &, expression_de_type_classe)

ou :
istream & operator >> (ostream &, & type_classe)

b) La valeur de re tour s e ra obligatoire m e nt la ré fé re nce au flot conce rné (re çu e n pre m ie r argum e nt).
O n pe ut dire q ue toute s les s urdé finitions d e < < s e fe ront suivant ce "cane vas" :

ostream & operator << (ostream & sortie, type_classe objet15)


{
// Envoi sur le flot sortie des membres de objet en utilisant
// les possibilités classiques de << pour les types de base
// c'est-à-dire des instructions de la forme :
// sortie << ..... ;
return sortie ;
}

D e m ê m e , toute s les s urdé finitions de > > s e fe ront suivant ce "cane vas" :

istream & operator >> (istream & entree, type_classe & objet)
{
// Lecture des informations correspondant aux différents membres de objet
// en utilisant les possibilités classiques de >> pour les types de base
// c'est-à-dire des instructions de la forme :
// entree >> ..... ;
return entree ;
}

15 - Ici, l
a trans m ission peut s e faire par val
e ur ou par ré fé re nce.
XVI. Le s flots 287
R e m arque :

D ans le cas de la surdéfinition de > > (flot d'entré e ), ils e ra souve nt utile de s'assure r q ue l'inform ation
lue ré pond à ce rtaine s e xige nce s e t d'agir e n cons é q ue nce s ur l'é tat du flot. Nous e n ve rrons précisém e nt
un e xe m ple dans le paragraph e s uivant.

4.2 Exe m pl
e

Voici un program m e dans leq ue lnous avons surdé fini les opé rate urs < < e t > > pour le type point q ue
nous avons souve nt re ncontré dans les pré cédents ch apitre s :

class point
{ int x , y ;
.....
;

Nous supposerons q u'une "valeur de type point" s e pré s e nte toujours (aussi bien en lecture q u'e n é criture )
sous la form e :

< e ntie r, e ntie r >


ave c é ve ntue llem e nt des séparate urs "e s pace s _blancs" supplém e ntaire s , de part e t d'autre des valeurs
e ntiè re s .

_______________________________________________________________________________
______

#include <iostream.h>
class point
{ int x, y ;
public :
point (int abs=0, int ord=0)
{ x = abs ; y = ord ; }
int abscisse () { return x ; }
friend ostream & operator << (ostream &, point) ;
friend istream & operator >> (istream &, point &) ;
} ;
ostream & operator << (ostream & sortie, point p)
{
sortie << "<" << p.x << "," << p.y << ">" ;
return sortie ;
}
istream & operator >> (istream & entree, point & p)
{ char c = '\0' ;
float x, y ;
int ok = 1 ;
entree >> c ;
if (c != '<') ok = 0 ;
else
{ entree >> x >> c ;
if (c != ',') ok = 0 ;
else
{ entree >> y >> c ;
if (c != '>') ok = 0 ;
}
288 Program m e r e n langage C+ +
}
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 ;
}

main()
{ char ligne [121] ;
point a(2,3), b ;
cout << "point a : " << a << " point b : " << b << "\n" ;
do
{ cout << "donnez un point : " ;
if (cin >> a) cout << "merci pour le point : " << a << "\n" ;
else { cout << "** information incorrecte \n" ;
cin.clear () ;
cin.getline (ligne, 120, '\n') ;
}
}
while ( a.abscisse () ) ;
}
____________________________

point a : <2,3> point b : <0,0>


donnez un point : 4,5
** information incorrecte
donnez un point : <4,5<
** information incorrecte
donnez un point : <4,5>
merci pour le point : <4,5>
donnez un point : < 8, 9 >
merci pour le point : <8,9>
donnez un point : bof
** information incorrecte
donnez un point : <0,0>
merci pour le point : <0,0>
_______________________________________________________________________________
______

Surdéfinition de l'opérate ur << pour la clas s e point

Voye z com m e nt, dans la surdéfinition de > > , nous avons pris soin de lire tout d'abord toute s les
inform ations re lative s à un point dans des variables locales . Ce n'e s t q ue lors q ue tout s'e s t bien déroulé q ue
nous transfé rons les valeurs ainsi lues dans le point conce rné . Ce la é vite , par e xe m ple e n cas d'inform ation
incom plète , de m odifie r l'une des com posantes du point sans m odifie r l'autre , ou e ncore de m odifie r les
deux com posante s , alors q ue le caractè re > de fin n'a pas é té trouvé .

Si nous ne prenions pas soin d'active r le bit badbit lors q ue l'on ne trouve pas l'un de s caractè re s < ou > , il
s e rait im possible (à l'utilisate ur) de savoir q ue la lecture s 'e s t m aldéroulée .

Note z q ue dans la fonction m ain, e n cas d'erreur sur cin, nous com m e nçons par re m e ttre à zé ro l'é tat du flot
avant d'utiliser ge tline pour "saute r" les inform ations q ui ris q ue nt de ne pas avoir pu ê tre e xploité e s .
XVI. Le s flots 289
5. GESTIO N D U FO RM A TAGE

Nous avons vu q ue lque s possibilités d'action sur le form atage des inform ations, aussi bien pour un flot
d'entré e q ue pour un flot de sortie . Nous allons ici é tudie r e n dé tailla dém arch e adopté e par C+ + pour
gé re r ce form atage .

Ch aq ue flot, c'e s t-à -dire ch aq ue obje t de clas s e istre am ou ostre am , cons e rve e n pe rm ane nce un e ns e m ble
d'inform ations 16 (indicate urs) spécifiant q ue le s t, à un m om e nt donné , son "statut de form atage ". Ce tte
façon de procéder e s t forte m e nt diffé re nte de ce lle e m ployé e par les fonctions C te lles q ue printf ou s canf ;
dans ces derniè re s , e n e ffe t, on fournissait, pour ch aq ue opé ration d'e ntré e -sortie , les indications de
form atage approprié e s (sous form e d'un "form at" com pos é , e ntre autre s , d'une s ucce s s ion de "codes de
form at").

Un de s avantage s les plus é m ine nts de la m é th ode e m ployé e par C+ + e s t q u'e lle pe rm e t é ve ntue llem e nt à
l'utilisate ur d'ignore r totalem e nt ce t aspect form atage , tant q u'ils e conte nte d'un com porte m e nt par dé faut
(ce q ui e s t loin d'ê tre le cas e n C où la m oindre e ntré e -sortie né ce s s ite obligatoire m e nt l'e m ploi d'un
form at).

Un autre avantage de la m é th ode e s t de perm e ttre à ce lui q ui le s ouh aite de définir, une fois pour toute s , un
form at approprié à une application donné e e t de ne plus avoir à s'e n soucie r par la suite .

Com m e nous l'avons fait pour le s tatut d'erreur d'un flot, nous com m e nce rons par é tudie r les diffé re nts
é lém e nts com posant le "statut de form atage " d'un flot avant de voir com m e nt on pe ut le connaî
tre d'une
part, le m odifie r d'autre part.

5.1 Le s tatut de form atage d'un fl


ot

Le s tatut de form atage d'un flot com porte e s s e ntie llem e nt :

• un m ot d'é tat, dans leq ue lch aq ue bit e s t associé à une s ignification particuliè re . O n pe ut dire q u'on y
trouve , e n q ue lque s orte , toute s les indications de form atage de la form e vrai/faux17.
• les valeurs num é riq ue s pré cisant les valeurs courante s s uivante s :
- le "gabarit" : ils'agit de la valeur fournie a s e tw ;rappe lons q u'e lle "re tom be" à zé ro (q ui signifie :
gabarit standard), aprè s le transfe rt (lecture ou é criture ) d'une inform ation.
- la "pré cision" num é riq ue : ils'agit du nom bre de ch iffre s affich é s aprè s le point décim aldans le cas
de notation "flottante " e t du nom bre de ch iffre s s ignificatifs, dans le cas de notation "e xpone ntie lle".
- le caractè re "de re m plissage ", c'e s t-à -dire le caractè re e m ployé pour com pléte r un gabarit, dans le cas
où l'on n'utilise pas le gabarit par dé faut (par dé faut, ce caractè re de re m plissage e s t un e s pace ).

5.2 D e s cription du m ot d'é tat du s tatut de form atage

D e m aniè re com parable à ce q ui s e passait pour le s tatut d'erreur d'un flot, le m ot d'état du statut de
form atage e s t form é d'un entie r, dans leq ue lch aq ue bit e s t re pé ré par une constante prédéfinie dans la clas s e

16 - En toute rigue ur, ce tte inform ation e s t pré vue dans l a clas s e ios dont dérive nt le s cl
as s e s istre am e t ostre am .
17 - O n re trouve l
à le m ê m e m é canis m e q ue pour l 'entie r conte nant l e s tatut d'erreur d'un fl ot. M ais, com m e nous l
e voyons ci-aprè s, l
e
s tatut de form atage d'un fl
ot com porte, quant à l
ui, d'autre s types d'inform ations q ue ce s indications "binaire s ".
29 0 Program m e r e n langage C+ +
ios. Ch acune de ce s constante s corre s pond à la valeur pris e par ce t e ntie r lors q ue le bit corre s pondant (e t lui
s e ul) e s t "activé " (à 1). Ici e ncore , la valeur de ch acune de ce s constante s pe ut s e rvir :

• soit à "ide ntifie r" le bit corre s pondant, au s e in du m ot d'état,


• soit à fabriq ue r dire cte m e nt un m ot d'état.
D e plus, ce rtains "ch am ps de bits" (au nom bre de trois) sont définis au s e in de ce m ê m e m ot ;nous ve rrons
q u'ils facilite nt, dans le cas de ce rtaine s fonctions m e m bre , la m anipulation d'un des bits d'un ch am p (on
pe ut "cite r" le bit à m odifie r dans un ch am p, sans avoir à s e pré occupe r de la valeur des bits des autre s
ch am ps).

Voici la liste des diffé re nte s constante s , accom pagné e s , le cas é ch é ant, du nom du ch am p de bit
corre s pondant.

_______________________________________________________________________________
______
NOM DE CHAMP NOM DU BIT SIGNIFICATION
(s'il existe) (quand activé)
_______________________________________________________________________________
______
ios::skipws saut des "espaces blancs" (en entrée)
_______________________________________________________________________________
______
ios::adjustfield ios::left cadrage à gauche (en sortie)

ios::right cadrage à droite (en sortie)

ios::internal remplissage après signe ou base


_______________________________________________________________________________
______
ios::basefield ios::dec conversion décimale

ios::oct conversion octale

ios::hex conversion hexadécimale


_______________________________________________________________________________
______
ios::showbase affichage indicateur de base (en sortie)

ios::showpoint affichage point décimal (en sortie)

ios::uppercase affichage caractères hexadécimaux en


majuscules
(en sortie)

ios::showpos affichage nombres positifs précédés du


signe +
(en sortie)
_______________________________________________________________________________
______
ios::floatfield ios::scientific notation "scientifique"

ios::fixed notation "point fixe"


_______________________________________________________________________________
______
XVI. Le s flots 29 1
ios::unitbuf vide les tampons après chaque écriture

ios::stdio
vide les tampons après chaque écriture
sur stdout ou stderr
_______________________________________________________________________________
______

Le m ot d'état du statut de form atage

Au sein de ch acun de s trois ch am ps de bits (adjustfie ld, base fie ld, floatfie ld), un s e uldes bits doit ê tre actif.
S'iln'e n va pas ainsi, C+ + lève l'am biguïté e n pré voyant un com porte m e nt par dé faut (righ t, de c,
s cie ntific).

5.3 A ction sur l


e s tatut de form atage

Le s e xe m ples des paragraph e s 1 e t 2 vous ont pré s e nté la notion de m anipulate ur (param é triq ue ou non).
Com m e vous vous e n doute z, ce s m anipulate urs perm e tte nt e ffe ctive m e nt d'agir sur le s tatut de form atage .
M ais ile xiste é galem e nt d'autre s façons d'agir sur ce s tatut, e n utilisant des fonctions m e m bre des clas s e s
istre am ou ostre am . Ces derniè re s s ont gé né ralem e nt redondante s par rapport aux m anipulate urs
param é triq ue s (nous ve rrons toute fois q u'ile xiste des fonctions m e m bre ne com portant aucun é q uivalent
sous form e de m anipulate ur)

Suivant le cas, l'action porte ra sur le m ot d'état ou sur les valeurs num é riq ue s (gabarit, pré cision, caractè re
de re m plissage ). En outre , on pe ut agir globalem e nt sur le m ot d'état. Nous ve rrons q ue ce rtaine s fonctions
m e m bre pe rm e ttront notam m e nt de le "sauve garde r" pour pouvoir le "re s taure r" ulté rie ure m e nt (ce q u'aucun
m anipulate ur ne pe rm e t) ;les valeurs num é riq ue s , q uant à e lles , ne pe uve nt ê tre accé d é e s globalem e nt e t
doive nt donc, le cas é ch é ant, faire l'obje t de sauve garde s individue lles .

a)Le s m anipul
ate urs non param é triq ue s

Ce s ont donc de s opé rate urs q ui s'utilisent ainsi :

flot << manipulateur

pour un flot de sortie , ou ainsi :

flot >> manipulateur

pour un flot d'entré e .

Ils fournis s e nt com m e ré s ultat le flot obte nu aprè s leur action, ce q ui pe rm e t de les traite r de la m ê m e
m aniè re q ue les inform ations à transm e ttre . En particulie r, ils perm e tte nt, e ux aussi, d'appliq ue r plusieurs
fois de suite les opé rate urs < < ou > > .

Voici la liste de ce s m anipulate urs :

_______________________________________________________________________________
______

MANIPULATEUR UTILISATION ACTION


29 2 Program m e r e n langage C+ +
_______________________________________________________________________________
______
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
left/base/internal Sortie Active le bit correspondant
scientific/fixed Sortie Active le bit correspondant
showbase/noshowbase Sortie Active/désactive le bit
correspondant
showpoint/noshowpoint Sortie Active/désactive le bit
correspondant
showpos/noshowpos Sortie Active/désactive le bit
correspondant
skipws/noskipws Entrée Active/désactive le bit
correspondant
uppercase/nouppercase Sortie Active/désactive le bit
correspondant
ws Entrée Active le bit de saut des
caractères
"espaces blancs"
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)
flush Sortie Vide le tampon
_______________________________________________________________________________
______
Le s m anipulate urs non param é trique s

b)Le s m anipul
ate urs param é triq ue s

Ce s ont donc é galem e nt des m anipulate urs, c'e s t-à -dire des opé rate urs agissant sur un flot e t fournissant e n
re tour le flot aprè s m odification. M ais, ce tte fois, ils com porte nt un param è tre q ui leur e s t fourni sous form e
d'un argum e nt e ntre pare nth è s e s . En fait, ce s m anipulate urs param é triq ue s s ont des fonctions dont l'e n-tê te
e s t de la form e :

istream & manipulateur (argument)

ou :

ostream & manipulateur (argument)


XVI. Le s flots 29 3
Ils s'e m ploie nt com m e les m anipulate urs non param é triq ue s , ave c toute fois ce tte diffé re nce q u'ils néce s s ite nt
l'inclusion du fich ie r iom anip.h pp18.

Voici la liste de ce s m anipulate urs param é triq ue s :

_______________________________________________________________________________
______

MANIPULATEUR UTILISATION ROLE


_______________________________________________________________________________
______

setbase (int) Entrée/Sortie Définit la base de conversion

resetiosflags (long) Entrée/Sortie Remet à zéro tous les bits désignés


par
l'argument (sans modifier les autres)

setiosflags (long) Entrée/Sortie Active tous les bits spécifiés par


l'argument (sans modifier les autres)

setfill (int) Entrée/Sortie Définit le caractère de remplissage

setprecision (int) Entrée/Sortie Définit la précision des nombres


flottants

setw (int) Entrée/Sortie Définit le gabarit


_______________________________________________________________________________
______

Le s m anipulate urs param é trique s

Note z bie n q ue les m anipulate urs re s e tiosflags e t s e tiosflags agis s e nt sur tous les bits spé cifié s par leur
argum e nt.

c)Le s fonctions m e m bre


D ans les clas s e s istre am e t ostre am , ile xiste 4 fonctions m e m bre q ue nous n'avons pas encore rencontré e s :
s e tf, fill, pre cision e t w idth .

setf

Ce tte fonction pe rm e t de m odifie r le m ot d'état de form atage . Elle e s t e n fait surdéfinie . Ile xiste deux
ve rsions :

long se tf (long)
Son appe l active les bits spé cifié s par son argum e nt. O n obtie nt, e n re tour, l'ancie nne valeur du m ot
d'état de form atage .

18 - L'exte nsion peut varie r s uivant l


'im pl
é m e ntation (h xx, h ...).
29 4 Program m e r e n langage C+ +
Note z bie n q ue , com m e le m anipulate ur s e tiosflags, ce tte fonction ne m odifie pas les autres bits.
Ainsi, en supposant q ue flot e s t un flot, ave c :
flot.setf (ios::oct)

on active le bit ios::oct, alors q u'un de s autres bits ios::de c ou ios::h e x e s t pe ut ê tre activé . Com m e
nous allons le voir ci-de s s ous, la deuxiè m e form e de s e tf s e ré vè le plus pratiq ue dans ce cas.

long se tf (long, long)


Son appe lactive les bits spé cifié s par le pre m ie r argum e nt, au s e in s e ulem e nt du ch am p de bits défini
par le s e cond argum e nt. Par e xe m ple, si flot désigne un flot :
flot.setf (ios::oct, ios::basefield)

active le bit ios::oct e n dé s activant les autres bits du ch am p ios::base fie ld.

Ce tte ve rsion de s e tf fournit e n re tour l'ancie nne valeur du ch am p de bits conce rné . Ce la pe rm e t
d'éve ntue lles s auve garde s pour de s re s taurations ulté rie ure s . Par e xe m ple, si flot e s t un flot, ave c :
base_a = flot.setf (ios::hex, ios::basefield) ;

vous passez en notation h e xadé cim ale. Pour re ve nir à l'ancie nne notation, q ue lle q u'e lle s oit, ilvous
suffira de procéder ainsi :
flot.setf (base_a, ios::basefield) ;

fil
l

Ce tte fonction pe rm e t d'agir sur le caractè re de re m plissage . Elle e s t é galem e nt surdéfinie . Ile xiste deux
ve rsions :

ch ar fill()
Ce tte ve rsion fournit com m e valeur de re tour l'actue lcaractè re de re m plissage .

ch ar fill(ch ar)
Ce tte ve rsion donne au caractè re de re m plissage la valeur spécifié e par son argum e nt e t fournit e n
re tour l'ancie nne valeur. Si flot e s t un flot de sortie , on pe ut, par e xe m ple, im pos e r te m poraire m e nt le
caractè re * com m e caractè re de re m plissage , puis re trouve r l'ancie n caractè re , q ue lq u'ilsoit, e n
procédant ainsi :
char car_a ;
....
car_a = fill ('*') ; // caractère de remplissage = '*'
....
fill (car_a) ; // retour à l'ancien caractère de remplissage

precision

Ce tte fonction pe rm e t d'agir sur la pré cision num é riq ue . Elle e s t é galem e nt surdéfinie . Ile n e xiste deux
ve rsions.
XVI. Le s flots 29 5

int pre cision ()


Ce tte ve rsion fournit com m e valeur de re tour la valeur actue lle de la pré cision num é riq ue .

int pre cision (int)


Ce tte ve rsion donne à la pré cision num é riq ue , la valeur spécifié e par son argum e nt e t fournit e n
re tour l'ancie nne valeur. Si flot e s t un flot de sortie , on pe ut, par e xe m ple, im pos e r te m poraire m e nt
une ce rtaine pré cision (ici pre c) puis re ve nir à l'ancie nne pré cision, q ue lle q u'e lle s oit, e n procédant
ainsi :
int prec_a, prec ;
.....
prec_a = flot.precision (prec) ; // on impose la précision définie par
prec
.....
flot.precision (prec_a) ; // on revient à l'ancienne précision

w idth

Ce tte fonction pe rm e t d'agir sur le "gabarit". Elle e s t é galem e nt surdéfinie . Ile n e xiste deux ve rsions.

int w idth ()
Ce tte ve rsion fournit com m e valeur de re tour la valeur actue lle du gabarit.

int w idth (int)


Ce tte ve rsion donne au gabarit la valeur spécifié e par son argum e nt e t fournit e n re tour l'ancie nne
valeur. Si flot e s t un flot de sortie , on pe ut par e xe m ple, im pos e r te m poraire m e nt un ce rtain gabarit
(ici gab) puis re ve nir à l'ancie n gabarit, q ue lq u'ilsoit e n procédant ainsi :
int gab_a, gab ;
.....
gab_a = flot.width (gab) ; // on impose un gabarit défini par gab
.....
flot.width (gab_a) ; // on revient à l'ancien gabarit

6. CO NNEXIO N D 'UN FLO T À UN FICH IER

Jus q u'ici, soit nous avons parlé des flots prédéfinis (cin e t cout), soit nous vous avons donné des
inform ations s'appliq uant à un flot q ue lconq ue (paragraph e s 3 e t 5), m ais sans vous dire com m e nt ce flot
pourrait ê tre associé à un fich ie r. Ce paragraph e va d'une part vous m ontre r com m e nt y parve nir, d'autre
part e xam ine r les possibilités d'accè s direct dont on pe ut alors bénéficie r.
29 6 Program m e r e n langage C+ +
6.1 Conne xion d'un fl
ot de s ortie à un fich ie r

Pour associe r un flot de sortie à un fich ie r, ilsuffit e n fait de cré e r un obje t de type ofs tre am , classe dérivant
de ostre am . L'e m ploi de ce tte nouve lle clas s e né ce s s ite d'inclure un fich ie r e n-tê te nom m é fs tre am .h 19 , e n
plus du fich ie r iostre am .h .

Le constructe ur de la clas s e ofs tre am né ce s s ite deux argum e nts :

• le nom du fich ie r conce rné (sous form e d'une ch aî


ne de caractè re s ),
• un m ode d'ouve rture défini par une constante e ntiè re : la clas s e ios com porte , là e ncore , un ce rtain
nom bre de constante s prédéfinie s (nous les pas s e rons toute s e n re vue , dans le paragraph e 7.4).
Voici un e xe m ple de déclaration d'un obje t (nom m é ici sortie ) du type ofs tre am :

ofstream sortie ("truc.dat", ios::out) ;

L'obje t sortie s e ra donc associé au fich ie r nom m é truc.dat, aprè s q u'ila é té ouve rt e n é criture .

Une fois construit un obje t de clas s e ofs tre am , l'é criture dans le fich ie r q ui lui e s t associé pe ut s e faire
com m e pour n'im porte q ue lflot e n faisant appe là toute s les facilités de la clas s e ostre am (dont dérive
ofs tre am ).

Par e xe m ple, aprè s la déclaration pré cédente de sortie , nous pourrons e m ploye r de s instructions te lles q ue :

sortie << .... << .... << .... ;

pour ré aliser des sortie s form até e s , ou e ncore :

sortie.write (.....) ;

pour ré aliser des écritures binaire s . De m ê m e , nous pourrons connaî


tre le s tatut d'erreur du flot
corre s pondant e n e xam inant la valeur de sortie :

if (sortie) ....

Voici un program m e com plet q ui e nre gistre , sous form e binaire , dans un fich ie r de nom fourni par
l'utilisate ur, une s uite de nom bre s e ntie rs q u'illui fournit sur l'e ntré e s tandard.

_______________________________________________________________________________
______

const int LGMAX = 20 ;


#include <stdlib.h> // pour exit
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>

main()
{
char nomfich [LGMAX+1] ;
int n ;
cout << "nom du fichier à créer : " ;
cin >> setw (LGMAX) >> nomfich ;

19 - L'exte nsion peut varie r s uivant l


'im pl
é m e ntation (h xx, h ,..).
XVI. Le s flots 29 7
ofstream sortie (nomfich, ios::out) ;
if (!sortie) { cout << "création impossible \n" ;
exit (1) ;
}
do { cout << "donnez un entier : " ;
cin >> n ;
if (n) sortie.write ((char *)&n, sizeof(int) ) ;
}
while (n && (sortie)) ;
sortie.close () ;
}
_______________________________________________________________________________
______

Création séquentie lle d'un fich ie r d'e ntie rs

Nous nous som m e s s e rvi du m anipulate ur s e tw pour lim ite r la longue ur du nom de fich ie r fourni par
l'utilisate ur. Par ailleurs, nous e xam inons le s tatut d'erreur de sortie com m e nous le fe rions pour un flot
usuel.

R e m arque :

En toute rigue ur, le te rm e "conne xion" (ou ce lui d'association) d'un flot à un fich ie r pourrait lais s e r
e nte ndre :
• soit q u'ile xiste deux types d'obje ts : d'une part un flot, d'autre part un fich ie r.
• soit q ue l'on dé clare tout d'abord un flot q ue l'on associe ulté rie ure m e nt à un fich ie r.
O r, e n fait, iln'e n e s t rie n, puis q ue l'on dé clare e n une s e ule fois un obje t de ofs tre am , e n spécifiant le
fich ie r corre s pondant. O n pourrait d'ailleurs dire qu'un obje t de ce type e s t un fich ie r, si l'on ne craignait
pas de le confondre ave c ce m ê m e te rm e de fich ie r e n langage C (où ildésigne souve nt un nom inte rne
de fich ie r, c'e s t-à -dire un pointe ur sur une s tructure de type FILE).

6.2 Conne xion d'un fl


ot d'e ntré e à un fich ie r

Pour associe r un flot d'entré e à un fich ie r, on e m ploie un m é canism e analogue à ce lui utilisé pour un flot de
sortie . O n cré e , ce tte fois, un obje t de type ifs tre am , classe dérivant de istre am . Ilfaut toujours inclure le
fich ie r e n-tê te fs tre am .h e n plus du fich ie r iostre am .h . Le constructe ur com porte les m ê m e s argum e nts q ue
pré cédem m e nt, c'e s t-à -dire nom de fich ie r e t m ode d'ouve rture .

Par e xe m ple, ave c l'instruction :

ifstream entree ("truc.dat", ios::in)

l'obje t e ntre e s e ra donc associé au fich ie r de nom truc.dat, aprè s q u'ila é té ouve rt e n lecture .

Une fois construit un obje t de clas s e ifs tre am , la lecture dans le fich ie r q ui lui e s t associé pourra s e faire
com m e pour n'im porte q ue lflot d'entré e e n faisant appe là toute s les facilités de la clas s e istre am (dont
dérive ifs tre am ).

Par e xe m ple, aprè s la déclaration pré cédente de e ntre e , nous pourrions e m ploye r de s instructions te lles q ue :

entree >> ... >> ... >> ... ;

pour ré aliser des lecture s form até e s , ou e ncore :


29 8 Program m e r e n langage C+ +
entree.read (.....) ;

pour ré aliser des lectures binaire s .

Voici un program m e com plet q ui pe rm e t de liste r le conte nu d'un fich ie r q ue lconq ue cré é par le program m e
pré cédent.

_______________________________________________________________________________
______

const int LGMAX = 20 ;


#include <stdlib.h> // pour exit
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>
main()
{
char nomfich [LGMAX+1] ;
int n ;
cout << "nom du fichier à lister : " ;
cin >> setw (LGMAX) >> nomfich ;
ifstream entree (nomfich, ios::in) ;
if (!entree) { cout << "ouverture impossible \n" ;
exit (1) ;
}
while ( entree.read ( (char*)&n, sizeof(int) ) )
cout << n << "\n" ;
entree.close () ;
}
_______________________________________________________________________________
______

Le cture s é q u e ntie lle d'un fich ie r d'e ntie rs

R e m arque :

En toute rigue ur, ile xiste é galem e nt une clas s e fs tre am , dérivée des deux clas s e s ifs tre am e t ofs tre am ,
pe rm e ttant d'effe ctue r à la fois des lecture s e t des écriture s ave c un m ê m e fich ie r. Ce la pe ut notam m e nt
s'avé re r fort pratiq ue dans le cas de l'accè s direct q ue nous e xam inons ci-de s s ous. La déclaration d'un
obje t de type fs tre am se déroule com m e pour les type s ifs tre am ou ofs tre am . Par e xe m ple :
fstream fich ("truc.dat", ios::in|ios::out) ;

associe l'obje t fich au fich ie r de nom truc.dat, aprè s l'avoir ouve rt e n lecture e t e n é criture .

6.3 Le s pos s ibil


ité s d'accè s dire ct

Com m e e n langage C, e n C+ + , dè s q u'un flot a é té conne cté à un fich ie r, ile s t possible de ré aliser un
"accè s direct" sur ce fich ie r e n agissant tout sim plem e nt sur un pointe ur dans ce fich ie r, c'e s t-à -dire un
nom bre pré cisant le rang du proch ain octet (caractè re ) à lire ou à é crire . Aprè s ch aq ue opé ration de lecture
ou d'é criture , ce pointe ur e s t incré m e nté du nom bre d'octe ts transfé ré s . Ainsi, lors q ue l'on n'agit pas
e xplicite m e nt sur ce pointe ur, on ré alise un classique accè s s é q ue ntie l;c'e s t ce q ue nous avons fait
pré cédem m e nt.
XVI. Le s flots 29 9
Le s possibilités d'accè s direct s e ré s um e nt donc e n fait aux possibilités d'action sur ce pointe ur ou à la
déte rm ination de s a valeur.

D ans ch acune des deux clas s e s ifs tre am e t ofs tre am , ile xiste une fonction m e m bre nom m é e s e e k g (pour
ifs tre am ) e t s e e k p (pour ofs tre am ) pe rm e ttant de donner une certaine valeur au pointe ur (atte ntion, ch acune
de ces deux clas s e s possè de le s ie n, de s orte q u'ile xiste un pointe ur pour la lecture e t un pointe ur pour
l'é criture ). Plus précisém e nt, ch acune des ces deux fonctions com porte deux argum e nts :

• un e ntie r re pré s e ntant un dé place m e nt du pointe ur, par rapport à une origine pré cis é e par le s e cond
argum e nt,
• une constante e ntiè re ch oisie parm i trois valeurs prédéfinies dans ios :
ios::be g : le déplace m e nt e s t e xprim é par rapport au début du fich ie r,
ios::cur : le déplace m e nt e s t e xprim é par rapport à la position actue lle,
ios::e nd : le déplace m e nt e s t e xprim é par rapport à la fin du fich ie r (par dé faut, ce t argum e nt a la valeur
ios::be g).
Note z q u'on re trouve là les possibilité s offe rte s par la fonction fs e e k du langage C.

Par ailleurs, ile xiste , dans ch acune des clas s e s ifs tre am e t ofs tre am une fonction pe rm e ttant de connaître la
position courante du pointe ur. Ils'agit de te llg (pour ifs tre am ) e t de te llp (pour ofs tre am ). Ce lles -ci offre nt
des possibilité s com parables à la fonction fte lldu langage C.

Voici un e xe m ple de program m e pe rm e ttant d'accéder à n'im porte q ue le ntie r d'un fich ie r du type de ce ux
q ue pouvait cré e r notre program m e du paragraph e 6.1.

_______________________________________________________________________________
______

const int LGMAX_NOM_FICH = 20 ;


#include <stdlib.h> // pour exit
#include <iostream.h>
#include <fstream.h>
#include <iomanip.h>

main()
{
char nomfich [LGMAX_NOM_FICH + 1] ;
int n, num ;
cout << "nom du fichier à consulter : " ;
cin >> setw (LGMAX_NOM_FICH) >> nomfich ;
ifstream entree (nomfich, ios::in) ;
if (!entree) { cout << "Ouverture impossible\n" ;
exit (1) ;
}

do
{ cout << "Numéro de l'entier recherché : " ;
cin >> num ;
if (num)
{ entree.seekg (sizeof(int) * (num-1) , ios::beg ) ;
entree.read ( (char *) &n, sizeof(int) ) ;
if (entree) cout << "-- Valeur : " << n << "\n" ;
else { cout << "-- Erreur\n" ;
300 Program m e r e n langage C+ +
entree.clear () ;
}
}
}
while (num) ;
entree.close () ;
} ____________________________

nom du fichier à consulter : essai.dat


Numéro de l'entier recherché : 4
-- Valeur : 6
Numéro de l'entier recherché : 15
-- Erreur
Numéro de l'entier recherché : 7
-- Valeur : 9
Numéro de l'entier recherché : -3
-- Erreur
Numéro de l'entier recherché : 0
_______________________________________________________________________________
______

Accè s dire ct à un fich ie r d'e ntie rs

6.4 Le s diffé re nts m ode s d'ouve rture d'un fich ie r

Nous avons re ncontré q ue lque s e xe m ples de m odes d'ouve rture d'un fich ie r. Nous allons e xam ine r ici
l'e ns e m ble des possibilité s offe rte s par les clas s e s ifs tre am e t ofs tre am (e t donc aussi de fs tre am ).

Le m ode d'ouve rture e s t défini par un m ot d'état, dans leq ue lch aq ue bit corre s pond à une s ignification
particuliè re . La valeur corre s pondant à ch aq ue bit e s t définie par de s constantes déclarées dans la clas s e ios.
Pour active r plusieurs bits, ilsuffit de faire appe là l'opé rate ur |.

________________________________________________________________________
_________
BIT ACTION
_______________________________________________________________________________
______
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::trunc Si le fichier existe, son contenu est perdu (obligatoire
si
ios::out est activé sans ios::ate ni ios::app)
ios::binary (utile dans certaines implémentations uniquement)
Le fichier est ouvert en mode dit "binaire" ou encore
"non translaté" (voir la remarque ci-après)
_______________________________________________________________________________
______
Les diffé re nts m odes d'ouve rture d'un fich ie r
XVI. Le s flots 301

A titre indicatif, voici les m odes d'ouve rture é q uivalents aux diffé re nts m odes d'ouve rture de la fonction
fope n du C :

________________________________________________________________________
_________
Combinaison de bits Mode correspondant de
fopen
________________________________________________________________________
_________
ios::out w
ios::out ios::app a
ios::out ios::trunc w
ios::in r
ios::in ios::out r+
ios::in ios::out ios::trunc wb+
ios::out ios::binary wb
ios::out ios::app ios::binary ab
ios::out ios::trunc ios::binary wb
ios::in ios::binary rb
ios::in ios::out ios::binary r+b
ios::in ios::out ios::trunc ios::binary w+b
________________________________________________________________________
_________

R e m arque im portante : m ode texte ou m ode binaire

R appe lons q ue ce rtains e nvironne m e nts (e n particulie r, les e nvironne m e nts PC) distinguent l es fich iers
20
de texte des autres (q u'ils appe llent parfois "fich ie rs binaire s ") ;plus précisém e nt, lors de l'ouve rture
du fich ie r, on pe ut spécifie r si l'on souh aite ou non considérer le conte nu du fich ie r com m e du te xte .
Ce tte distinction e s t e n fait principalem e nt m otivé e par le fait q ue le caractè re de fin de ligne (\n)
possè de, sur ces systè m e s , une re pré s e ntation particuliè re obte nue par la succe s s ion de deux caractè re s
(re tour ch ariot \r, suivi de fin de ligne \n). O r, dans ce cas, pour q u'un program m e C puis s e ne "voir"
q u'un s e ulcaractè re de fin de ligne e t q u'ils'agisse bien de \n, ilfaut opé re r un traite m e nt particulie r
consistant à :
• re m place r ch aq ue occurre nce de ce couple de caractè re s par \n, dans le cas d'une lecture ,
• re m place r ch aq ue dem ande d'écriture de \n par l'é criture de ce couple de caractè re s .
Bie n e nte ndu, de te lles s ubstitutions ne doive nt pas ê tre ré alisées sur de s "vrais fich ie rs binaire s ". Ilfaut
donc bie n pouvoir opé re r une distinction au s e in du program m e . Ce tte distinction s e fait au m om e nt de
l'ouve rture du fich ie r, e n activant le bit ios::binary dans le m ode d'ouve rture , dans le cas d'un fich ie r
binaire ;par dé faut, ce bit n'e s t pas activé . O n note ra q ue ce la corre s pond aux m odes d'ouve rture "rb"
ou "w b" du langage C.

7. LES PO SSIBILITÉS D E FO RM A TAGE EN M ÉM O IRE


En langage C :

20 - A l
ors q u'au bout du com pte tout fich ie r e s t binaire !
302 Program m e r e n langage C+ +
• s s canf pe rm e t d'accéder à une inform ation situé e e n m é m oire , de façon com parable à ce q ue fait s canf
sur l'e ntré e s tandard,
• sprintf pe rm e t de fabriq ue r e n m é m oire une ch aî
ne de caractè re s corre s pondant à ce lle q ui s e rait
transm ise à la sortie s tandard par printf.
En C+ + , des facilité s com parables e xiste nt. Elles s ont fournie s par les clas s e s :

• ostrs tre am pour "l'ins e rtion" de caractè res dans un tableau,


• istrs tre am pour "l'e xtraction" de caractè res depuis un tableau.
Le ur utilisation né ce s s ite l'inclusion du fich ie r e n-tê te istrs tre am .h 21.

7.1 La cl
as s e os trs tre am

Un obje t de clas s e ostrs tre am pe ut re ce voir de s caractè re s , au m ê m e titre q u'un flot de sortie . La s e ule
diffé re nce e s t q ue ce s caractè re s ne s ont pas transm is à un pé riph é riq ue ou à un fich ie r, m ais sim plem e nt
cons e rvés dans l'obje t lui-m ê m e , plus précisém e nt dans un tableau m e m bre de la clas s e ostrs tre am ;ce
tableau e s t créé dynam iq ue m e nt e t ne pose donc pas de problèm e de lim itation de taille.

Une fonction m e m bre particuliè re nom m é e s tr pe rm e t d'obte nir l'adresse du tableau e n q ue s tion. Ce lui-ci
pourra alors ê tre m anipulé com m e n'im porte q ue ltableau de caractè re s (re pé ré par un pointe ur de type ch ar
*).

Par e xe m ple, ave c la déclaration :

ostrstream tab

vous pouve z ins é re r de s caractè res dans l'obje t tab par de s instructions te lles q ue :

tab << ..... << ..... << ..... ;

ou :

tab.put (.....) ;

ou e ncore :

tab.write (.....) ;

L'adresse du tableau de caractè re s ainsi constitué pourra ê tre obte nue par :

char * adt = tab.str () ;

A partir de là, vous pourre z agir com m e ilvous plaira sur les caractè re s s itué s à ce tte adre s s e (les consulte r,
m ais é ve ntue llem e nt les m odifie r...).

R e m arques trè s im portantes

1) Lors q ue s tr a é té appe lée pour un obje t, iln'e s t plus possible d'insérer de nouve aux caractè res dans
ce t obje t. O n pe ut dire q ue l'appe lde ce tte fonction "fige " définitive m e nt le tableau de caractè re s
(n'oublie z pas q u'ile s t alloué dynam iq ue m e nt e t q ue s on adre s s e pe ut m ê m e é volue r au fil de
l'ins e rtion de caractè re s !), avant d'en fournir e n re tour une adresse définitive . O n pre ndra donc bie n
soin de n'appe ler s tr q ue lors q ue l'on aura ins é ré dans l'obje t tous les caractè re s voulus.

21 - L'exte nsion peut varie r s uivant l


'im pl
é m e ntation.
XVI. Le s flots 303
2) Si un obje t de clas s e ostrs tre am devie nt h ors de porté e , alors q ue la fonction s tr n'a pas é té appe lée , il
e s t détruit norm alem e nt par appe ld'un de s tructe ur q ui dé truit alors é galem e nt le tableau de caractè re s
corre s pondant. En re vanch e , si s tr a é té appe lée , on considè re q ue le tableau e n q ue s tion e s t
m ainte nant sous la re s ponsabilité du program m e ur e t ilne s e ra donc pas détruit lors q ue l'obje t
devie ndra h ors de porté e (bie n sûr, le re s te de l'obje t le s e ra). Ce s e ra au program m e ur de le faire
lors q u'il le s ouh aite ra, e n procédant com m e pour n'im porte q ue l tableau de caractè re s alloué
dynam iq ue m e nt (par ne w ) c'e s t-à -dire e n faisant appe l à l'opé rate ur de lete . Par e xe m ple,
l'e m place m e nt m é m oire du tableau de l'obje t tab pré cédent, dont l'adre s s e a é té obte nue dans adt
pourra ê tre libéré par :
delete adt ;

7.2 La cl
as s e is trs tre am

Un obje t de clas s e istrs tre am e s t cré é par un appe lde constructe ur, auq ue lon fournit e n argum e nt :

• l'adresse d'un tableau de caractè re s ,


• le nom bre de caractè re s à pre ndre e n com pte .
Ile s t alors possible d'extraire des caractè res de ce t obje t, com m e on le fe rait de n'im porte q ue lflot d'entré e .

Par e xe m ple, ave c les déclarations :

char t[100] ;
istrstream tab ( t, sizeof(t) ) ;

vous pourre z e xtraire des caractè res du tableau t par de s instructions te lles q ue :

tab >> ..... >> ..... >> ..... ;

ou :

tab.get (.....) ;

ou e ncore :

tab.read (.....) ;

Qui plus e s t, vous pourre z agir sur un pointe ur courant dans ce tableau, com m e vous le fe rie z dans un fich ie r
par l'appe lde la fonction s e e k g. Par e xe m ple, ave c l'obje t tab pré cédent, vous pourre z re place r le pointe ur
e n début de tableau par :

tab.seekg (0, ios::beg) ;

Ce la pourrait pe rm e ttre , par e xe m ple, d'e xploite r plusieurs fois une m ê m e inform ation (lue pré alablem e nt
dans un tableau) e n la "lisant" suivant des form ats diffé re nts.

Voici un e xe m ple d'utilisation de la clas s e istrs tre am m ontrant com m e nt ré s oudre les problèm e s e nge ndré s
par la frappe d'un "m auvais" caractè re dans le cas de lecture s s ur l'e ntré e s tandard.

_______________________________________________________________________________
_____

const LGMAX = 122 ; // longueur maxi d'une ligne clavier


#include <iostream.h>
#include <strstream.h>
304 Program m e r e n langage C+ +
main()
{ int n, erreur ;
char c ;
char ligne [LGMAX] ; // pour lire une ligne au clavier
do
{ cout << "donnez un entier et un caractère :\n" ;
cin.getline (ligne, LGMAX) ;
istrstream tampon (ligne, cin.gcount () ) ;
if (tampon >> n >> c) erreur = 0 ;
else erreur = 1 ;
}
while (erreur) ;
cout << "merci pour " << n << " et " << c << "\n" ;
}
____________________________

donnez un entier et un caractère :


bof
donnez un entier et un caractère :
a 125
donnez un entier et un caractère :
12 bonjour
merci pour 12 et b
_______________________________________________________________________________
______

Pour lire e n toute s é curité sur l'e ntré e s tandard

Nous y lisons tout d'abord l'inform ation atte ndue pour toute une ligne , sous form e d'une ch aî ne de
caractè re s (à l'aide de la fonction ge tline ). Nous construisons ensuite , ave c ce tte ch aî ne , un obje t de type
istrs tre am sur leq ue lnous appliq uons nos opérations de lecture (ici lecture form atée d'un e ntie r puis d'un
caractè re ). Com m e vous le constate z, aucun problèm e ne s e pos e plus lors q ue l'utilisate ur fournit un
caractè re invalide (par rapport à l'usage q u'on doit e n faire ), contraire m e nt à ce q ui s e s e rait pas s é e n cas de
lecture directe s ur cin.
XVII. LA GESTIO N
D ES EXCEPTIO NS

D ans sa ve rsion définitive 1, C+ + com porte un m é canism e dit de "ge s tion de s e xce ptions" q ue nous
proposons d'étudie r dans ce ch apitre . O n nom m e e xce ption, une rupture d e s é q ue nce décidé e par program m e
(par l'inte rm édiaire du m ot clé th row ) ;ily a alors débranch e m e nt à une fonction nom m é e ge s tionnaire
d'inte rruption e t dont le nom e s t déte rm iné par la nature de l'inte rruption. Plus précisém e nt, ch aq ue
inte rruption e s t caracté ris é e par un type clas s e e t le ch oix du "bon ge s tionnaire " s e fait e n fonction de la
nature de l'obje t m e ntionné à th row .

1. UN PREM IER EXEM PLE D 'EXCEPTIO N

D ans l'e xe m ple com plet ci-aprè s, nous allons re pre ndre la clas s e ve ct pré s e ntée dans le ch apitre
"surdéfinition de s opé rate urs", c'e s t-à -dire m unie de la surdéfinition de l'opé rate ur []. Ce lui-ci n'é tait alors
pas "proté gé " contre l'utilisation d'indice s s itué s e n de h ors des bornes ;ici, nous allons com pléte r notre
clas s e pour q u'e lle lance une e xce ption dans ce cas. Puis nous ve rrons com m e nt inte rce pte r une te lle
e xce ption e n é crivant un ge s tionnaire d'exception approprié .

1.1 Com m e nt l
ance r une e xce ption : l
'ins truction th row
Nous introduisons donc, au se in de la surdéfinition de [], une vé rification de l'indice ;lors q ue ce lui-ci e s t
incorre ct, nous "lançons 2" une e xce ption, à l'aide de l'instruction th row . D e par sa nature m ê m e , ce tte
derniè re né ce s s ite une e xpre s s ion de type clas s e (e t dont le type s e rt à identifie r l'e xce ption) ;c'e s t la raison
pour laq ue lle nous avons introduit artificie llem e nt, ave c la déclaration de notre clas s e ve ct, une clas s e (sans
aucun m e m bre ici) nom m é e ve ct_lim ite . Son e xiste nce nous perm e t de cré e r un obje t l, de type ve ct_lim ite ,
obje t q ue nous associons à l'instruction th row par l'instruction : th row l;

Voici la définition com plète de notre clas s e ve ct :


_______________________________________________________________________________
______

/* déclaration de la classe vect */


class vect

1 - Plus pré cis é m e nt, ce m é canis m e a é té introduit dans l


a ve rsion 3.
2 - O n e m pl
oie é gal e m e nt l
e te rm e "l
e ve r".
306 Program m e r e n langage C+ +
{ int nelem ;
int * adr ;
public :
vect (int) ;
~vect () ;
int & operator [] (int) ;
} ;
/* déclaration et définition d'une classe vect_limite (vide pour l'instant) */
class vect_limite
{ } ;
/* définition de la classe vect */
vect::vect (int n)
{ adr = new int [nelem = n] ;
}
vect::~vect ()
{ delete adr ;
}
int & vect::operator [] (int i)
{ if (i<0 || i>nelem)
{ vect_limite l ; throw (l) ;
}
return adr [i] ;
}
_______________________________________________________________________________
______

D é finition d'une clas s e provoquant une e xce ption ve ct_lim ite

1.2 Util
is ation d'un ge s tionnaire d'e xce ption

D isposant de notre clas s e ve ct, voyons m ainte nant com m e nt procéder pour pouvoir gé re r conve nablem e nt les
é ve ntue lles e xce ptions de type ve ct_lim ite q ue s on e m ploi pe ut provoq ue r. Pour ce faire , ile s t né ce s s aire de
re s pe cte r de ux conditions :

• inclure dans un bloc particulie r, dit "bloc try", toute s les instructions dans les q ue lles on souh aite pouvoir
lance r une e xce ption ;un te lbloc s e pré s e nte ainsi :
try
{
// instructions
}

• faire s uivre ce bloc de la définition des diffé re nts "ge s tionnaires d'exce ptions" né ce s s aire s (ici, un s e ul
nous suffit). Ch aq ue définition e s t pré cédée d'un en-tê te introduit par le m ot clé catch (com m e s i catch
é tait le nom d'une fonction ge s tionnaire ...). D ans notre cas, voici ce q ue pourrait ê tre notre uniq ue
ge s tionnaire , destiné à inte rce pte r les e xce ptions de type ve ct_lim ite :
catch (vect_limite l) /* nom d'argument superflu ici */
{ cout << "exception limite \n" ;
exit (-1) ;
}
XVII. La ge s tion de s e xce ptions 307
Nous nous conte ntons ici d'affich e r un m e s s age e t d'inte rrom pre l'e xé cution du program m e .

1.3 Ré capitul
atif

A titre indicatif, nous vous fournissons ici la liste com plète de la définition des diffé re nte s clas s e s cone rné e s
e t d'un pe tit program m e d'essai dans leq ue lnous provoq uons volontaire m e nt une e xce ption ve ct_lim ite (par
application de l'opé rate ur [] à un obje t de type ve ct, e n lui indiq uant un indice trop grand).

_______________________________________________________________________________
______
#include <iostream.h>
#include <stdlib.h> /* pour exit */
/* déclaration de la classe vect */
class vect
{ int nelem ;
int * adr ;
public :
vect (int) ;
~vect () ;
int & operator [] (int) ;
} ;
/* déclaration et définition d'une classe vect_limite (vide pour l'instant) */
class vect_limite
{ } ;
/* définition de la classe vect */
vect::vect (int n)
{ adr = new int [nelem = n] ; }
vect::~vect ()
{ delete adr ; }
int & vect::operator [] (int i)
{ if (i<0 || i>nelem)
{ vect_limite l ; throw (l) ;
}
return adr [i] ;
}
/* test interception exception vect_limite */
main ()
{ try
{ vect v(10) ;
v[11] = 5 ; /* indice trop grand */
}
catch (vect_limite l) /* nom d'argument superflu ici */
{ cout << "exception limite \n" ;
exit (-1) ;
}
} ___________________________________

exception limite
_______________________________________________________________________________
______
308 Program m e r e n langage C+ +

Un pre m ie r e xe m ple de ge s tion d'e xce ption

1.4 Com m e ntaire s

a) Ce pre m ie r e xe m ple, destiné à vous présente r le m é canism e de ge s tion de s e xce ptions, é tait re lative m e nt
sim pliste ;notam m e nt :
• ilne com porte q u'un s e ultype d'exception, de s orte q u'ilne m e t pas vraim e nt e n é vidence le
m é canism e de ch oix du bon ge s tionnaire ,
• le ge s tionnaire ne re çoit pas d'inform ation particuliè re (l'argum e nt lé tant ici artificie l).
Nous y revie ndrons pré cis é m e nt dans le proch ain paragraph e .
b) D 'une m aniè re gé né rale, le ge s tionnaire d'une exception e s t défini de façon indé pe ndante des fonctions
q ui sont susce ptibles de leve r ce tte e xce ption. Ainsi, à partir du m om e nt où la définition d'une clas s e e s t
s é paré e d e s on utilisation (ce q ui e s t souve nt le cas e n pratiq ue ), ile s t tout à fait possible de pré voir un
ge s tionnaire d'exception diffé re nt d'une utilisation à une autre d'une m ê m e clas s e . Dans notre pré cédent
e xe m ple, te lutilisate ur pourra vouloir affich e r un m e s s age avant de s'inte rrom pre , te lautre pré fé re ra ne
rie n affich e r ou e ncore te nte r de pré voir une s olution par dé faut...
c) Ici, nous avons prévu une instruction e xit, à l'inté rie ur de notre ge s tionnaire d'exception. Nous ve rrons
plus loin ce q ui s e produirait si te ln'é tait pas le cas.

2. UN SECO ND EXEM PLE

Voyons m ainte nant un e xe m ple un pe u plus ré aliste dans leq ue l on trouve à la fois deux exceptions
diffé re nte s e t où ily a transm ission d'inform ation aux ge s tionnaire s . Nous allons re pre ndre notre clas s e ve ct
pré cédente , e n lui pe rm e ttant de lance r de ux sortes d'exce ptions :

• une e xce ption de type ve ct_lim ite com m e pré cédem m e nt, m ais, ce tte fois, on pré voit de transm e ttre au
ge s tionnaire la valeur de l'indice q ui a provoq ué l'e xce ption,
• une e xce ption ve ct_cre ation lancé e lors q ue l'on transm e t au constructe ur un nom bre d'élém e nts
incorre ct3 (né gatif ou nul) ;là e ncore , on pré voit de transm e ttre ce nom bre au ge s tionnaire .
Ilnous suffit d'appliq ue r le m é canism e pré cédent, e n notant sim plem e nt q ue l'obje t indiq ué à th row e t
ré cupé ré par catch pe ut nous s e rvir à com m uniq ue r toute inform ation de notre ch oix. Ici, nous prévoirons
donc, dans nos nouve lles clas s e s ve ct_lim ite e t ve ct_cre ation, un ch am p public de type e ntie r de s tiné à
re ce voir l'inform ation à transm e ttre au ge s tionnaire .

Voici un e xe m ple com plet (ici, e ncore , la définition e t l'utilisation de s clas s e s figure nt dans le m ê m e
source ;e n pratiq ue , ile n ira rare m e nt ainsi) :

_______________________________________________________________________________
______

#include <iostream.h>
#include <stdlib.h> // pour exit
/* déclaration de la classe vect */
class vect
{ int nelem ;
int * adr ;

3 - D ans un cas ré e l
, on pourrait é gal
e m e nt l
ance r ce tte m ê m e inte rrruption e n cas de m anq ue de m é m oire.
XVII. La ge s tion de s e xce ptions 309
public :
vect (int) ;
~vect () ;
int & operator [] (int) ;
} ;

/* déclaration - définition des deux classes exception */


class vect_limite
{ public :
int hors ; // valeur indice hors limites (public)
vect_limite (int i) // constructeur
{ hors = i ; }
} ;
class vect_creation
{ public :
int nb ; // nombre elements demandes (public)
vect_creation (int i) // constructeur
{ nb = i ; }
} ;

/* définition de la classe vect */


vect::vect (int n)
{ if (n <= 0)
{ vect_creation c(n) ; // anomalie
throw (c) ;
}
adr = new int [nelem = n] ; // construction normale
}
vect::~vect ()
{ delete adr ;
}

int & vect::operator [] (int i)


{ if (i<0 || i>nelem)
{ vect_limite l(i) ; // anomalie
throw (l) ;
}
return adr [i] ; // fonctionnement normal
}

/* test exception */
main ()
{
try
{ vect v(-3) ; // provoque l'exception vect_creation
v[11] = 5 ; // provoquerait l'exception vect_limite
}
catch (vect_limite l)
{ cout << "exception indice " << l.hors << " hors limites \n" ;
exit (-1) ;
}
catch (vect_creation c)
{ cout << "exception création vect nb elem = " << c.nb << "\n" ;
exit (-1) ;
}
310 Program m e r e n langage C+ +

}
___________________________________

exception création vect nb elem = -3


_______________________________________________________________________________
______

Exe m ple de ge s tion de de ux e xce ptions , ave c trans m ission d'inform ation au ge s tionnaire

Bie n e nte ndu, la pre m iè re e xce ption (dé clench é e par ve ct v(-3)) ayant provoq ué l'arrê t de l'e xé cution, nous
n'avons ici aucune ch ance de m e ttre e n é vidence celle q u'aurait provoq ué v[11] = 5 ;si la cré ation de v
avait é té corre cte , ce tte derniè re instruction aurait e ntraîné l'affich age du m e s s age :

exception indice 11 hors limites

R e m arques :

1) D ans un exem ple ré e l, on pourrait avoir inté rê t à transm e ttre , dans ve ct_lim ite , non s e ulem e nt la
valeur de l'indice , m ais é galem e nt les lim ite s pré vue s ;il suffirait d'introduire les m e m bre s
corre s pondants dans la clas s e ve ct_lim ite .
2) Ici, nos clas s e s ve ct_lim ite e t ve ct_cre ation sont indé pe ndantes de la clas s e ve ct. M ais ils e rait tout à
fait possible d'en faire des clas s e s m e m bre de la clas s e ve ct.
3) Ici, ch aq ue type d'exception n'e s t lancé q u'e n un s e ule ndroit ;m ais, bie n e nte ndu, n'im porte q ue lle
fonction (pas néce s s aire m e nt m e m bre de la clas s e ve ct !) disposant de la définition des deux clas s e s
(ve ct_lim ite e t ve ct_cre ation) pe ut lance r ce s e xce ptions.
4) D e par sa nature m ê m e , le m é canism e de ge s tion de s e xce ptions, te lq u'ila é té pré vu par C+ + , fait
obligatoire m e nt appe là un obje t de type clas s e (ou, com m e nous le ve rrons un pe u plus loin, à un
pointe ur sur un obje t de type clas s e ).

3. LES EXCEPTIO NS D 'UNE M A NIÈRE GÉNÉRA LE

3.1 Aprè s l
'e xé cution du ge s tionnaire d'e xce ption

D ans tous nos exem ples pré cédents, le ge s tionnaire d'inte rruption inte rrom pait l'e xé cution par un appe lde
e xit (nous aurions pu égalem e nt utiliser la fonction standard abort). Si te ln'avait pas é té le cas, ilfaut savoir
q u'alors, aprè s l'e xé cution de s intructions du gestionnaire conce rné , on e xé cute , si elles e xiste nt, les
instructions (du bloc try) suivant ce lles du dernier gestionnaire . Si aucune instruction d'arrê t d'exécution ne
figure parm i ces derniè re s , on s e trouve dans la situation classique de retour de la fonction corre s pondante .

Voye z ce t e xe m ple (ilutilise les m ê m e s clas s e s ve ct, ve ct_lim ite e t ve ct_cre ation q ue pré cédem m e nt) dans
leq ue lnous avons artificie llem e nt appe lé, depuis m ain, une fonction f, dans laq ue lle on acce pte de gé re r les
e xce ptions (afin de m ontre r q u'aprè s e xé cution d'un ge s tionnaire d'exception ilpe ut y avoir re tour dans la
fonction appe lant f, à savoir ici m ain) :

_______________________________________________________________________________
______

// déclaration et définition des classes vect, vect_limite, vect_creation


XVII. La ge s tion de s e xce ptions 311
// comme dans le paragraphe 2
// .....
main()
{ void f() ;
f() ;
cout << "après appel de f \n" ;
}
void f()
{ try
{ vect v(-3) ; // nombre éléments incorrect
// ...
}
catch (vect_limite l)
{ cout << "exception indice " << l.hors << " hors limites \n" ; }
catch (vect_creation c)
{ cout << "exception création vect nb elem = " << c.nb << "\n" ;
}
// traitement commun aux exceptions n'ayant pas appelé exit
cout << "traitement commun \n" ;
}
_______________________

exception création vect nb elem = -3


traitement commun
après appel de f
_______________________________________________________________________________
______

Lors q u e l'on "pas s e à trave rs " un ge s tionnaire d'e xce ption

3.2 A l
gorith m e de ch oix du ge s tionnaire d'inte rruption

Le ch oix du "bon ge s tionnaire " se bas e s ur le type de l'e xpre s s ion m e ntionné dans l'instruction th row . Plus
pré cis é m e nt, on ch e rch e un ge s tionnaire corre s pondant à l'un de s type s s uivants :

• type e xact m e ntionné dans th row ,


• type corre s pondant à une classe de base du type m e ntionné dans th row ;ce tte possibilité e s t pré cie us e
pour re groupe r plusieurs exceptions q u'on pe ut traite r plus ou m oins "fine m e nt"...,
• type corre s pondant à un pointe ur sur une classe dérivée du type m e ntionné dans th row (lors q ue ce type
e s t lui-m ê m e un pointe ur),
• le type m e ntionné dans catch corre s pond à un type indé te rm iné , noté par de s points de suspension.
D è s q u'un ge s tionnaire corre s pond, on l'e xé cute , sans s e pré ocupe r de l'e xiste nce d'autre s ge s tionnaire s .
Ainsi, ave c :

catch (truc) // gestionnaire 1


{ // }
catch (...) // gestionnaire 2
{ // }
catch (chose) // gestionnaire 3
{ // }
312 Program m e r e n langage C+ +
le ge s tionnaire 3 n'a aucune ch ance d'ê tre e xé cuté , puis q ue le ge s tionnaire 2 inte rce pte ra toute s les
e xce ptions non inte rce pté e s par le ge s tionnaire 1.

3.3 Le ch e m ine m e nt de s e xce ptions

Quand une e xce ption e s t levé e par une fonction, on ch e rch e tout d'abord un ge s tionnaire dans l'é ve ntue lbloc
try associé à ce tte fonction ;si l'on n'e n trouve pas (ou si aucun bloc try n'e s t associé ), on poursuit la
re ch e rch e dans un éve ntue lbloc try associé à une fonction appe lante e t ainsi de suite . Voye z ce t e xe m ple
(utilisant toujours les m ê m e s clas s e s q ue pré cédem m e nt) :

/* test exception */
main ()
{ try
{ void f1 () ;
f1 () ;
}
catch (vect_limite l)
{ cout << "dans main : exception indice \n" ;
exit (-1) ;
}
}
void f1 ()
{
try
{ vect v(10) ; v[12] = 0 ; // provoque affichage de : dans main : exception
ndice
vect v1 (-1) ; // provoque affichage de : dans f1 : exception
création
// (à condition que l'instruction précédente
n'ait
// pas déjà provoqué une exception)
}
catch (vect_creation v)
{ cout << "dans f1 : exception création \n" ;
}
}

Si aucun ge s tionnaire d'exception n'e s t trouvé , on appe lle la fonction term inate. Par défaut, ce tte derniè re
appe lle la fonction abort (ave c Turbo/Borland C+ + , e lle fournit le m e s s age "Abnorm al program
te rm ination"). Ile s t possible de dem ande r q ue s oit appe lée une fonction de votre ch oix dont vous fournis s e z
l'adre s s e à s e t_te rm inate (de façon com parable à ce q ue vous faite s ave c s e t_ne w _h andler).

3.4 Spé cification d'inte rface

Une fonction (y com pris m ain) pe ut spécifie r les e xce ptions q u'e lle e s t susce ptible de provoq ue r (e lle-m ê m e ,
ou dans les fonctions q u'e lle appe lle à son tour). Elle le fait à l'aide du m ot clé th row , suivi, e ntre
pare nth è s e s , de la liste d e s e xce ptions conce rné e s . Dans ce cas, toute e xce ption non pré vue e t levé e à
l'inté rie ur de la fonction (ou d'une fonction appe lée ) e ntraî ne l'appe ld'une fonction particuliè re nom m é e
une xpe cte d. Par défaut, ce tte fonction appe lle la fonction te rm inate (ou la fonction indiq ué e à s e t_te rm inate ).
M ais vous pouve z é galem e nt fournir votre propre fonction, e n re m place m e nt de une xpe cte d, e n l'indiq uant
par s e t_une xpe cte d.
XVII. La ge s tion de s e xce ptions 313
Voici un e xe m ple q ui utilise, ici encore, les clas s e s ve ct, ve ct_lim ite e t ve ct_cre ation définies dans le
paragraph e 3 :

#include <iostream.h>
#include <stdlib.h> // pour exit
#include <except.h> // pour set_unexpected
// définition et déclaration des classes vect, vect_limite, vect_creation
// comme dans le paragraphe 3
// .....

/* test exception */
main () throw (vect_limite)
{ try
{ void autre_except () ; // pour gérer les exception non attendues
set_unexpected (autre_except) ;
vect v(-3) ; // nombre éléments incorrect
v[11] = 5 ;
}
catch (vect_limite l)
{ cout << "exception indice " << l.hors << " hors limites \n" ;
exit (-1) ;
}
}
void autre_except ()
{ cout << "exception non attendue \n" ; }

Son e xé cution fournit tout d'abord le m e s s age e xce ption non atte ndue , puis Abnorm alte rm ination.

Note z q ue nous obtie ndrions e xacte m e nt la m ê m e ch os e ave c ce cane vas (les clas s e s ve ct, ve ct_lim ite e t
ve ct_cre ation é tant toujours les m ê m e s ) :

main ()
{ try
{ void f1 () throw (vect_limite) ;
void autre_except () ; // pour gérer les exception non attendues
set_unexpected (autre_except) ;
f1 () ;
}
catch (vect_limite l)
{ cout << "exception indice " << l.hors << " hors limites \n" ;
exit (-1) ;
}
}
void f1 () throw (vect_limite)
{ vect v1 (-1) ;
}
void autre_except ()
{ cout << "exception non attendue \n" ;
}

4. LES EXCEPTIO NS STANDARD

La biblioth è q ue s tandard com porte q ue lque s clas s e s corre s pondants à des exce ptions spé cifiq ue s q ui pe uve nt
é ve ntue llem e nt ê tre utilisées dans un program m e . Le urs déclarations figure nt, notam m e nt, dans s tde xce pt.
314 Program m e r e n langage C+ +
La plupart ont une s ignification é vidente : dom ain_e rror, invalid_argum e nt, length _e rror, out_of_range ,
range _e rror, ove rflow _e rror, unde rflow _e rror, bad_alloc. Le urs constructe urs disposent d'un argum e nt de
type s tring corre s pondant au m e s s age à affich e r. Le type s tring ne s e ra é tudié q ue dans le ch apitre XXI m ais
sach e z, dè s m ainte nant, q u'une ch aîne usuelle pe ut trè s bien faire l'affaire .

Par ailleurs, on y trouve é galem e nt les e xce ptions bad_type _id e t bad_cast dont la signification s e ra plus
com pré h e nsible aprè s e xam e n de l'anne xe C.
XVIII. GÉNÉRALITÉS CO NCERNANT LA
BIBLIO TH ÈQUE STANDARD

Com m e ce lle du C, la norm e du C+ + com pre nd la définition d'une biblioth è q ue s tandard. Bie n e nte ndu, on
y trouve toute s les fonctions prévues dans les ve rsions C+ + d'avant la norm e , q u'ils'agisse des flots décrits
pré cédem m e nt ou de s fonctions de la biblioth è q ue s tandard du C. M ais, on y dé couvre s urtout bon nom bre
de nouve auté s originales . La plupart d'entre e lles s ont constitué e s d e patrons de clas s e s e t de
fonctions prove nant e n m ajorité d'une biblioth è q ue du dom aine public, nom m é e Standard Te m plate Library
(e n abré gé STL) e t déve loppé e ch e z H e w lett Pack ard.

L'obje ctif de ce ch apitre e s t de vous fam iliaris e r ave c les notions de bas e conce rnant l'utilisation de s
principaux com posants de ce tte biblioth è q ue , à savoir : les conte ne urs, les ité rate urs, les algorith m e s , les
gé né rate urs d'opérate urs, les prédicats e t l'utilisation d'une re lation d'ordre .

1. NO TIO NS D E CO NTENEUR, D 'ITERA TEUR ET D 'ALGO RITH M E

Ce s trois notions sont é troite m e nt lié e s e t, la plupart du te m ps, e lles inte rvie nne nt sim ultané m e nt dans un
program m e utilisant des conte ne urs.

1.1 Notion de conte ne ur

La biblioth è q ue s tandard fournit un e ns e m ble de classes dite s conte ne urs, pe rm e ttant de re pré s e nte r les
structures de données les plus ré pandue s te lles q ue les ve cte urs, les liste s , les e ns e m bles ou les tableaux
associatifs. Ils'agit de patrons de clas s e s param é tré s tout nature llem e nt par le type de leurs é lém e nts. Par
e xe m ple, on pourra construire une liste d'entie rs, un ve cte ur de flottants ou une liste de points (point é tant
une clas s e ) par les déclarations suivante s :

list <int> li ; /* liste vide dont les éléments seront de type int
*/
vector <double> ld ; /* vecteur vide dont les éléments seront de type
double */
list <point> lp ; /* liste vide dont les éléments seront de type point
*/
316 Program m e r e n langage C+ +
Ch acune de ce s clas s e s conte ne ur dispose de fonctionnalité s appropriées dont on pourrait pe ns e r, a priori,
q u'e lles s ont trè s diffé re ntes d'un conte ne ur à l'autre . En ré alité , les conce pte urs de STL ont fait un gros
e ffort d'h om ogé né isation e t beaucoup de fonctions m e m bre s ont com m une s à diffé re nts conte ne urs. O n pe ut
dire q ue , dè s q u'une action donné e e s t ré alisable ave c deux conte ne urs diffé re nts, e lle s e program m e de la
m ê m e m aniè re .

R e m arque im portante

En toute rigue ur, les patrons de conte ne urs sont param é tré s à la fois par le type de leurs é lém e nts e t par
une fonction dite allocate ur utilisée pour les allocations e t les libérations de m é m oire . Ce s e cond
param è tre possè de une valeur par dé faut q ui e s t gé né ralem e nt satisfaisante . Ce pe ndant, ce rtaine s
im plém e ntations n'acce pte nt pas e ncore les param è tre s par dé faut dans les patrons de clas s e s e t, dans ce
cas, ile s t né ce s s aire de pré cis e r l'allocate ur à utiliser, m ê m e s 'ils'agit de ce lui par dé faut. Ilfaut alors
savoir q ue ce dernie r e s t une fonction patron, de nom allocator, param é tré e par le type d e s é lém e nts
conce rné s . Voici ce q ue devie ndraie nt les déclarations précédentes dans un te lcas :
list <int, allocator<int> > li ; /* attention à laisser un espace entre >
et > */
vector <double, allocator<double> > ld ; /* sinon , >> serait interprété
comme */
list <point, allocator<point> > lp ; /* l'opérateur >>
*/

1.2 Notion d'ité rate ur

C'e s t dans ce s ouci d'h om ogé né isation de s actions sur un conte ne ur q u'a é té introduite la notion d'ité rate ur.
Un ité rate ur e s t un obje t défini gé né ralem e nt par la clas s e conte ne ur conce rné e q ui gé né ralise la notion de
pointe ur :

• à un instant donné , un ité rate ur possè de une valeur q ui dé s igne un é lém e nt donné d'un conte ne ur ;on
dira souve nt q u'un ité rate ur pointe s ur un é lém e nt d'un conte ne ur ;
• un ité rate ur pe ut ê tre incré m e nté par l'opé rate ur + + , de m aniè re à pointe r sur l'é lém e nt suivant du
m ê m e conte ne ur ;on note ra q ue ce ci n'e s t possible q ue , com m e on le ve rra plus loin, parce q ue les
conte ne urs sont toujours ordonné s s uivant une ce rtaine s é q ue nce ;
• un ité rate ur pe ut ê tre déré fé re ncé , com m e un pointe ur, e n utilisant l'opé rate ur *;par e xe m ple, si it e s t
un ité rate ur sur une liste de points, *it désigne un point de ce tte liste ;
• deux ité rate urs sur un m ê m e conte ne ur pe uve nt ê tre com paré s par é galité ou iné galité .
Tous les conte ne urs fournis s e nt un ité rate ur portant le nom ite rator e t possédant au m inim um les proprié té s
q ue nous ve nons d'énum é re r q ui corre s ponde nt à ce q u'on nom m e un ité rate ur unidire ctionne l. Ce rtains
ité rate urs pourront posséder de s proprié té s s upplém e ntaire s , e n particulie r :

• décré m e ntation par l'opé rate ur -- ;com m e ce tte possibilité s 'ajoute alors à ce lle q ui e s t offe rte par + + ,
l'ité rate ur e s t alors dit bidire ctionne l;
• accè s direct ;dans ce cas, si it e s t un te lité rate ur, l'e xpre s s ion it+ i a un s e ns ;souve nt, l'opé rate ur [] e s t
alors défini, de m aniè re q ue it[i] soit é q uivalent à *(it+ i) ;e n outre , un te lité rate ur pe ut ê tre com paré
par iné galité .
XVIII. Généralité s conce rnant la biblioth è q u e s tandard 317
R e m arque :

Ici, nous avons é voq ué trois caté gories d'ité rate ur : unidire ctionne l, bidire ctionne le t accè s direct. Dans
le ch apitre XXI, nous ve rrons q u'ile xiste deux autre s caté gorie s (e ntré e e t sortie ) q ui sont d'un usage
plus lim ité . De m ê m e , on ve rra q u'il e xiste ce q u'on appe lle des adaptate urs d'ité rate ur, les q ue ls
pe rm e tte nt d'en m odifie r les proprié té s ;les plus im portants s e ront l'ité rate ur de flux e t l'ité rate ur
d'insertion.

1.3 Parcours d'un conte ne ur ave c un ité rate ur

a) Parcours dire ct
Tous les conte ne urs fournis s e nt des valeurs particuliè res de type ite rator, sous form e des fonctions m e m bre
be gin() e t e nd(), de sorte q ue , q ue lq ue s oit le conte ne ur, le cane vas suivant, pré s e nté ici sur une liste de
points, e s t toujours utilisable pour parcourir s é q ue ntie llem e nt un conte ne ur de s on début jus q u'à sa fin :

list<point> lp ;
.....
list<point>::iterator il ; /* itérateur sur une liste de points */
for (il = lp.begin() ; il != lp.end() ; il++)
{
/* ici *il désigne l'élément courant de la liste de points lp */
}

O n note ra la particularité des valeurs des ité rate urs de fin q ui consiste à pointe r, non pas sur le dernie r
é lém e nt d'un conte ne ur, m ais juste aprè s. D'ailleurs, lors q u'un conte ne ur e s t vide, be gin() possè de la m ê m e
valeur q ue e nd(), de sorte q ue le cane vas précédent fonctionne toujours conve nablem e nt.

R e m arque

Atte ntion, on ne pe ut pas utiliser com m e condition d'arrê t de la boucle for, une e xpre s s ion te lle q ue il<
lp.e nd, car l'opé rate ur < ne pe ut s'appliq ue r q u'à des ité rate urs à accè s direct.

b)Parcours inve rs e
Toute s les clas s e s conte ne ur pour les q ue lles ite rator e s t au m oins bidirectionne l(on pe ut donc lui appliq ue r
+ + e t --) disposent d'un second ité rate ur noté re ve rs e _ite rator. Construit à partir du pre m ie r, ilpe rm e t
d'explore r le conte ne ur suivant l'ordre inve rs e . Dans ce cas, la signification de + + e t --, appliq ué s à ce t
ité rate ur, e s t alors adapté e e n cons é q ue nce ;e n outre , ile xiste é galem e nt des valeurs particuliè res de type
re ve rs e _ite rator fournie s par les fonctions m e m bre rbe gin() e t re nd() ;on pe ut dire q ue rbe gin() pointe s ur le
dernie r é lém e nt du conte ne ur, tandis q ue re nd() pointe juste avant le pre m ie r. Voici com m e nt parcourir une
liste de points dans l'ordre inve rs e :

list<point> lp ;
.....
list<point>::reverse_iterator ril ; /* itérateur inverse sur une liste de
points */
for (ril = lp.rbegin() ; ril != lp.rend() ; ril++)
{
/* ici *ril désigne l'élément courant de la liste de points lp */
}
318 Program m e r e n langage C+ +
1.4 Inte rval
le d'ité rate ur

Com m e nous l'avons déjà fait re m arq ue r, tous les conte ne urs sont ordonné s , de sorte q u'on pe ut toujours les
parcourir d'un début jus q u'à une fin. Plus généralem e nt, on pe ut définir ce q u'on nom m e un inte rvalle
d'ité rate ur e n pré cisant les bornes sous form e de deux valeurs d'ité rate ur. Supposons que l'on ait déclaré :

vector<point>::iterator ip1, ip2 ; /* ip1 et ip2 sont des itérateurs sur un


*/
/* vecteur de points
*/

Supposons, de plus, q ue ip1 e t ip2 possè dent des valeurs te lles q ue ip2 soit "acce s s ible" depuis ip1,
autre m e nt dit q ue , aprè s un ce rtain nom bre d'incré m e ntations de ip1 par + + , on obtie nne la valeur de ip2.
D ans ce s conditions, le couple de valeurs ip1, ip2 définit un inte rvalle d'un conte ne ur du type
ve ctor< point> s'é te ndant de l'é lém e nt pointé par ip1 jus q u'à (m ais non com pris) ce lui pointé par ip2. Ce t
inte rvalle s e note s ouve nt [ip1, ip2). O n dit é galem e nt q ue les é lém e nts désignés par ce t inte rvalle form e nt
une s é q ue nce .

Ce tte notion d'inte rvalle d'ité rate ur s e ra trè s utilisée par les algorith m e s e t par ce rtaine s fonctions m e m bre .

1.5 Notion d'al


gorith m e

La notion d'algorith m e e s t tout aussi originale q ue les deux pré cédente s . Elle s e fonde sur le fait q ue , par le
biais d'un ité rate ur, be aucoup d'opé rations peuve nt ê tre appliq ué e s à un conte ne ur, q ue ls q ue s oie nt sa
nature e t le type d e s e s é lém e nts. Par e xe m ple, on pourra trouve r le pre m ie r é lém e nt ayant une valeur
donné e aussi bien dans une liste , un ve cte ur ou e ns e m ble ;ilfaudra ce pe ndant q ue l'é galité de deux élém e nts
soit conve nablem e nt définie , soit par dé faut, soit par surdéfinition de l'opé rate ur ==. De m ê m e , on pourra
trie r un conte ne ur d'obje ts de type T, pour pe u q ue ce conte ne ur dispose d'un ité rate ur à accè s direct e t q ue
l'on ait défini une re lation d'ordre s ur le type T, par e xe m ple e n surdéfinissant l'opé rate ur < .

Les diffé re nts algorith m e s s ont fournis sous form e de patrons de fonctions, param é tré s par le type des
ité rate urs q ui leurs sont fournis e n argum e nt. Là e ncore , ce la conduit à des program m e s trè s h om ogè ne s
puis q ue les m ê m e s fonctions pourront ê tre appliq ué e s à des conte ne urs diffé re nts. Par e xe m ple, pour
com pte r le nom bre d'élém e nts é gaux à un dans un ve cte ur dé claré par :

vector<int> v ; /* vecteur d'entiers */

on pourra procéder ainsi :

n = count (v.begin(), v.end(), 1) ; /* compte le nombre d'éléments de valeur


1 */
/* dans la séquence [v.begin(), v.end())
*/
/* autrement dit, dans tout le conteneur
v */

Pour com pte r le nom bre d'élém e nts é gaux à un dans une liste déclaré e :

list<int> l ; /* liste d'entiers */

on procédera de façon sim ilaire (e n s e conte ntant de re m place r v par l) :

n = count (l.begin(), l.end(), 1) ; /* compte le nombre d'éléments de valeur


1 */
XVIII. Généralité s conce rnant la biblioth è q u e s tandard 319
/* dans la séquence [l.begin(), l.end())
*/
/* autrement dit, dans tout le conteneur
l */

D 'une m aniè re gé né rale, com m e le lais s e nt e nte ndre ces deux e xe m ples , les algorith m e s s 'appliq ue nt, non
pas à un conte ne ur, m ais à une s é q ue nce définie par un inte rvalle d'ité rate ur ;ici, ce tte s é q ue nce
corre s pondait à l'inté gralité du conte ne ur.

Ce rtains algorith m e s pe rm e ttront facilem e nt de re copie r de s inform ations d'un conte ne ur d'un type donné
ve rs un conte ne ur d'un autre type , pour pe u q ue s e s é lém e nts soie nt du m ê m e type q ue ce ux du pre m ie r
conte ne ur. Voici, par e xe m ple, com m e nt re copie r un ve cte ur d'e ntie rs dans une liste d'entie rs :

vector<int> v ; /* vecteur d'entiers */


list<int> l ; /* liste d'entiers */
.....
copy (v.begin(), v.end(), l.begin() ) ; /* recopie l'inter [v.begin(), v.end())
*/
/* à partir de l'emplacement pointé par
*/
/* l.begin()
*/

Note z q ue , si l'on fournit l'inte rvalle de départ, on ne m e ntionne q ue le début de ce lui d'arrivé e .

R e m arque

O n pourra parfois ê tre gê né par le fait q ue l'h om ogé né isation é voq ué e n'e s t pas absolue . Ainsi, on ve rra
q u'ile xiste un algorith m e de re ch e rch e d'une valeur donné e nom m é find, alors m ê m e q u'un conte ne ur
com m e list dispose d'une fonction m e m bre com parable. La justification ré s idera dans des considérations
d'efficacité .

1.6 Ité rate urs e t pointe urs

La m aniè re dont les algorith m e s ou les fonctions m e m bre utilisent un ité rate ur fait q ue tout obje t ou toute
variable possédant les proprié té s atte ndue s (déréfé re nciation, incré m e ntation...) pe ut ê tre utilisé à la place
d'un obje t te lq ue ite rator.

O r, les pointe urs usuels possè dent tout nature llem e nt les proprié tés d'un ité rate ur à accè s direct. Ce la leur
pe rm e t d'ê tre e m ployés dans bon nom bre d'algorith m e s . Ce tte possibilité e s t fré q ue m m e nt utilisée pour la
re copie d e s é lém e nts d'un tableau ordinaire dans un conte ne ur :

int t[6] = { 2, 9, 1, 8, 2, 11 } ;
list<int> l ;
.....
copy (t, t+6, l.begin()) ; /* copie de l'intervalle [t, t+6) dans la liste
l */

Bie n e nte ndu, ici, iln'e s t pas q ue s tion d'utiliser une notation te lle q ue t.be gin() q ui n'aurait aucun s e ns, t
n'é tant pas un obje t.

R e m arque

Par souci de s im plicité , nous parlerons e ncore d e s é q ue nce d'élém e nts (m ais plus d e s é q ue nce de
conte ne ur) pour dé s igne r les é lém e nts ainsi définis par un inte rvalle de pointe urs.
320 Program m e r e n langage C+ +

2. LES D IFFERENTES SO RTES D E CO NTENEURS

2.1 Conte ne urs e t s tructure s de donné e s cl


as s iq ue s

O n dit souve nt q ue les conte ne urs corre s ponde nt à des structures de données usuelles . M ais, à partir du
m om e nt où ce s conte ne urs sont des clas s e s q ui e ncapsulent conve nablem e nt leurs données, leurs
caracté ristiq ues doive nt ê tre indé pe ndantes de leur im plém e ntation. D ans ce s conditions, les diffé re nts
conte ne urs devraie nt se distingue r les uns des autre s uniq ue m e nt par leurs fonctionnalité s e t e n aucun cas par
les s tructures de données sous-jace nte s . Be aucoup de conte ne urs posséderaie nt alors des fonctionnalité s
voisines, voire identiq ue s .

En ré alité , les diffé re nts conte ne urs s e caracté ris e nt, outre leurs fonctionnalité s , par l'e fficacité de ce rtaine s
opé rations. Par e xe m ple, on ve rra q u'un ve cte ur pe rm e t des insertions d'élém e nts e n n'im porte q ue lpoint
m ais ce lles -ci sont m oins e fficace s q u'ave c une liste . En re vanch e , on pe ut accéder plus rapide m e nt à un
é lém e nt e xistant dans le cas d'un ve cte ur q ue dans ce lui d'une liste . Ainsi, bien q ue la norm e n'im pos e pas
l'im plém e ntation de s conte ne urs, e lle introduit des contraintes d'efficacité q ui la conditionne ront large m e nt.

En dé finitive , on pe ut dire q ue le nom ch oisi pour un conte ne ur é voq ue la structure de donnée classique qui
e n e s t proch e s ur le plan de s fonctionnalité s , sans pour autant coïncide r ave c e lle. Dans ces conditions, un
bon usage des diffé re nts conte ne urs passe par un apprentissage de leurs possibilité s , com m e s 'ils'agissait bel
e t bien de classes diffé re nte s .

2.2 Le s diffé re nte s caté gorie s de conte ne urs

La norm e clas s e les diffé re nts conte ne urs e n de ux caté gorie s :

- les conte ne urs e n s é q ue nce (ou conte ne urs s é q ue ntie ls),


- les conte ne urs associatifs.
La notion de conte ne ur e n s é q ue nce corre s pond à des élém e nts q ui sont ordonné s com m e ce ux d'un ve cte ur
ou d'une liste . O n pe ut parcourir le conte ne ur suivant ce t ordre . Quand on insè re ou q u'on supprim e un
é lém e nt, on le fait e n un e ndroit q u'on a e xplicite m e nt ch oisi.

La notion de conte ne ur associatif pe ut ê tre illustré e par un ré pe rtoire té léph oniq ue . Dans ce cas, on associe
une valeur (num é ro de té léph one , adre s s e ...) à ce q u'on nom m e une clé (ici le nom ). A partir de la clé, on
accè de à la valeur associé e . Pour ins é re r un nouve lé lém e nt dans ce conte ne ur, ilne s e ra th é oriq ue m e nt plus
utile de pré cis e r un e m place m e nt.

Il s e m ble donc q u'un conte ne ur associatif ne s oit plus ordonné . En fait, pour d'é vidente s q ue s tions
d'efficacité , un te lconte ne ur de vra ê tre ordonné m ais, ce tte fois, de façon intrinsè q ue , c’ e s t-à -dire s uivant
un ordre q ui n'e s t plus défini par le program m e . La principale cons é q ue nce e s t q u'ilre s te ra toujours possible
de parcourir s é q ue ntie llem e nt les é lém e nts d'un te lconte ne ur q ui disposera toujours au m oins d'un ité rate ur
nom m é ite rator e t des valeurs be gin() e t e nd(). Ce t aspect pe ut d'ailleurs prê te r à confusion, dans la m e s ure
où ce rtaine s opé rations prévue s pour de s conte ne urs s é q ue ntie ls pourront s'appliq ue r à des conte ne urs
associatifs, tandis q ue d'autre s pos e ront problèm e . Par e xe m ple, il n'y aura aucun ris q ue à e xam ine r
s é q ue ntie llem e nt ch acun de s é lém e nts d'un conte ne ur associatif ;ily en aura m anife s te m e nt, e n re vanch e , si
l'on ch e rch e à m odifie r s é q ue ntie llem e nt les valeurs d'élém e nts e xistants, puis q u'alors, on ris q ue de
pe rturbe r l'ordre intrinsè q ue du conte ne ur. Nous y revie ndrons le m om e nt ve nu.
XVIII. Généralité s conce rnant la biblioth è q u e s tandard 321
3. LES GENERA TEURS D 'O PERA TEURS

Le m é canism e de surdé finition d'opé rate urs utilisé par C+ + fait q ue l'on pe ut th é oriq ue m e nt définir, pour
une classe donnée, à la fois l'opé rate ur == e t l'opé rate ur !=, de m aniè re totalem e nt indé pe ndante , voir
incoh é re nte . Ile n va de m ê m e pour les opé rate urs < , <=, > e t > =.

M ais la biblioth è q ue s tandard dispose de patrons de fonctions perm e ttant de définir :

• l'opé rate ur !=, à partir de l'opé rate ur ==


• les opé rate urs > , <= e t > =, à partir de l'opé rate ur < .
Com m e on pe ut s'y atte ndre , si a e t b sont d'un type clas s e pour laq ue lle on a dé fini ==, != s e ra dé fini
par :

a != b si !(a == b)
D e la m ê m e m aniè re , les opé rate urs < =, > e t > = pe uve nt ê tre déduits de < par les définitions
suivante s :

a > b si b < a
a <= b si ! (a > b)
a > = b si ! (a < b)
D ans ce s conditions, on voit q u'ilsuffit de m unir une classe des opé rate urs == e t < pour q u'e lle dispose
autom atiq ue m e nt des autre s .

Bie n e nte ndu, ilre s te toujours possible de donner sa propre définition de l'un q ue lconq ue de ce s q uatre
opé rate urs. Elle s e ra alors utilisée, en tant q ue s pé cialisation d'une fonction patron.

Ile s t trè s im portant de note r q u'iln'e xiste aucun lie n e ntre la définition autom atiq ue d e < = e t ce lle de
==. Ainsi, rie n n'im pos e , h orm is le bon sens, que a==b im pliq ue a<=b, com m e le m ontre ce pe tit
e xe m ple d'école, dans leq ue lnous définissons l'opé rate ur < d'une m aniè re artificie lle e t incoh é re nte ave c la
définition de == :

_________________________________________________________________________________

#include <iostream.h>
#include <utility> // pour les générateurs d'opérateurs
using namespace std ; // indispensable pour utility

class point
{ int x, y ;
public :
point(int abs=0, int ord=0) { x=abs ; y=ord ; }
friend int operator== (point, point) ;
friend int operator< (point, point) ;
} ;
int operator== (point a, point b)
{ return ( (a.x == b.x) && (a.y == b.y) ) ;
}
int operator<(point a, point b)
{ return ( (a.x < b.x) && (a.y < b.y) ) ;
}
main()
322 Program m e r e n langage C+ +
{ point a(1, 2), b(3, 1) ;
cout << "a == b : " << (a==b) << " a != b : " << (a!=b) << "\n" ;
cout << "a < b : " << (a<b) << " a <= b : " << (a<=b) << "\n" ;
char c ; cin >> c ;
}
_______________________

a == b : 0 a != b : 1
a < b : 0 a <= b : 1
________________________________________________________________________
_________

Exe m ple de génération non s atisfais ante de s opérate urs !=, > , <= e t > =

R e m arque

Le m anq ue de coh é re nce e ntre les définitions des opérate urs == e t < e s t ici sans cons é q ue nce . En
re vanch e , on ve rra q ue l'opé rate ur < pe ut inte rve nir, par e xe m ple, pour ordonne r un conte ne ur
associatif ou pour trie r un conte ne ur de type list lors q u'on utilise la fonction m e m bre sort. Dans ce cas,
sa définition de vra re s pe cte r un ce rtain nom bre de contrainte s com m e nous le ve rrons dans le paragraph e
7.

4. LES CO NTENEURS D O NT LES ELEM ENTS SO NT D ES O BJETS

Le patron de classe définissant un conte ne ur pe ut ê tre appliq ué à n'im porte q ue ltype e t donc, e n particulie r
à des élém e nts de type clas s e . Dans ce cas, ilne faut pas perdre de vue q ue bon nom bre de m anipulations de
ce s é lém e nts vont e ntraî
ne r de s appe ls autom atiq ues de ce rtaine s fonctions m e m bre .

4.1 Cons truction e t copie d'obje ts

Toute construction d'un conte ne ur, non vide, dont les é lém e nts sont des obje ts, e ntraî
ne :

• soit l'appe ld'un constructe ur ;ilpe ut s'agir d'un constructe ur par dé faut lors q u'aucun argum e nt n'e s t
né ce s s aire ,
• soit l'appe ld'un constructe ur par re copie .
Par e xe m ple, on ve rra q ue la déclaration suivante (point é tant une clas s e ) construit un ve cte ur de trois
é lém e nts de type point :

vector<point> v(3) ; /* construction d'un vecteur de 3 points */

Pour ch acun de s trois é lém e nts, ily aura appe ld'un constructe ur sans argum e nt de point. Si l'on construit un
autre ve cte ur, à partir de v :

vector<point> w (v) ; /* ou vector v = w ; */

ily aura appe ldu constructe ur par re copie de la clas s e ve ctor< point> , leq ue l, tout nature llem e nt, appe llera
le constructe ur par re copie de la clas s e point pour ch acun de s trois é lém e nts de type point à re copie r.

O n pourrait s'atte ndre à des ch os e s com parables ave c l'opé rate ur d'affe ctation dan un cas te lq ue :

w = v ; /* le vecteur v est affecté à w */


XVIII. Généralité s conce rnant la biblioth è q u e s tandard 323
Ce pe ndant, ici, les ch os e s s ont un pe u m oins sim ples . En e ffe t, gé né ralem e nt, si la taille de w e s t suffisante ,
on s e conte nte ra e ffe ctive m e nt d'appe ler l'opé rate ur d'affe ctation pour tous les é lém e nts de v (on appe llera
le destructe ur pour les é lém e nts e xcédentaires de w ). En re vanch e , si la taille de w e s t insuffisante , ily aura
destruction de tous s e s é lém e nts e t cré ation d'un nouve au ve cte ur par appe ldu constructe ur par re copie ,
leq ue lappe llera tout nature llem e nt le constructe ur par re copie de la clas s e point pour tous les é lém e nts de v.

Bie n e nte ndu, pour les obje ts ne possédant pas de partie dynam iq ue , les fonctions m e m bre pré vue s par
défaut s e ront satisfaisante s . Dans le cas contraire , ilfaudra pré voir les fonctions approprié e s , ce q ui s e ra
bien sûr le cas si la clas s e conce rné e re s pe cte le s ch é m a de clas s e canoniq ue proposé dans le ch apitre IX.

R e m arque

D ans les descriptions des diffé re nts conte ne urs ou algorith m e s , nous ne rappellerons pas ces diffé re nts
points, dans la m e s ure où ils conce rne nt systé m atiq ue m e nt tous les obje ts.

4.2 Autre s opé rations

Ile xiste d'autre s opé rations q ue les constructions ou re copies de conte ne ur q ui pe uve nt e ntraî
ne r de s appe ls
autom atiq ues de ce rtaine s fonctions m e m bre .

L'un de s e xe m ples les plus é vidents e s t ce lui de la re ch e rch e d'un élém e nt de valeur donné e , com m e le fait
la fonction m e m bre find du conte ne ur list. Dans ce cas, la clas s e conce rné e d e vra m anife s te m e nt disposer de
l'opé rate ur ==, leq ue l, ce tte fois, ne possè de plus de ve rsion par dé faut.

Un autre e xe m ple ré s ide dans les possibilités dites de "com paraisons lexicograph iq ue s " q ue nous
e xam ine rons dans le ch apitre XIX ;nous ve rrons q ue ce lles -ci s e fonde nt sur la com paraison, par l'un de s
opé rate urs < , > , <= ou > = des diffé re nts é lém e nts du conte ne ur. M anife s te m e nt, là e ncore , ilfaudra
définir au m oins l'opé rate ur < pour la clas s e conce rné e : les possibilités de gé né ration autom atiq ue
pré s e nté e s ci-de s s us pourront é vite r les définitions des trois autre s .

D 'une m aniè re gé né rale, ce tte fois, com pte te nu de l'aspect é pisodiq ue de ce type de besoin, nous le
pré cis e rons ch aq ue fois q ue ce s e ra né ce s s aire .

5. EFFICACITE D ES O PERA TIO NS SUR D ES CO NTENEURS

Pour juge r de l'e fficacité d'une fonction m e m bre d'un conte ne ur ou d'un algorith m e appliq ué à un
conte ne ur, on ch oisit gé né ralem e nt la notation dite "de Landau" (O (...)) q ui se définit ainsi :

Le te m ps t d'une opé ration e s t dit O (x) s 'ile xis te une cons tante k te lle q ue , dans tous les cas , on ait : t
< = k x.
Com m e on pe ut s'y atte ndre , le nom bre N d'élém e nts d'un conte ne ur (ou d'une s é q ue nce de conte ne ur)
pourra inte rve nir. C'e s t ainsi qu'on rencontre ra typiq ue m e nt :

• des opérations e n O (1), c’ e s t-à -dire pour les q ue lles le te m ps e s t constant (plutôt borné par une constante ,
indé pe ndante du nom bre d'élém e nts de la s é q ue nce ) ;on ve rra q ue ce s e ra le cas des insertions dans une
liste ou de s ins e rtions e n fin de ve cte ur ;
• des opérations e n O (N), c’ e s t-à -dire pour les q ue lles le te m ps e s t proportionne lau nom bre d'élém e nts de
la s é q ue nce ;on ve rra q ue ce s e ra le cas des insertions e n un point q ue lconq ue d'un ve cte ur ;
• des opérations e n O (LogN)...
324 Program m e r e n langage C+ +
D 'une m aniè re gé né rale, on ne pe rdra pas de vue q u'une te lle inform ation n'a q u'un caractè re re lative m e nt
indicatif ;pour ê tre pré cis, ilfaudrait indiq ue r s'ils'agit d'un m axim um ou d'une m oyenne et m e ntionne r la
nature des opé rations conce rné e s . C'e s t d'ailleurs ce q ue nous fe rons dans l'anne xe C décrivant l'e ns e m ble
des algorith m e s s tandard.

6. FO NCTIO NS, PRED ICA TS ET CLASSES FO NCTIO N

6.1 Fonction unaire

Be aucoup d'algorith m e s e t q ue lque s fonctions m e m bre pe rm e tte nt d'appliq ue r une fonction donné e aux
diffé re nts é lém e nts d'une séquence (définie par un inte rvalle d'ité rate ur). Ce tte fonction e s t alors passée
sim plem e nt e n argum e nt de l'algorith m e , com m e dans :

for_each(it1, it2, f) ; /* applique la fonction f à chacun des éléments de


*/
/* la séquence [it1, it2)
*/

Bie n e nte ndu, la fonction f doit posséder un argum e nt du type d e s é lém e nts corre s pondants (dans le cas
contraire , on obtie ndrait une e rre ur de com pilation). Iln'e s t pas inte rdit q u'une te lle fonction possè de une
valeur de re tour m ais, q uoi q u'ile n soit, e lle ne s e ra pas utilisée.

Voici un e xe m ple m ontrant com m e nt utiliser cette te ch niq ue pour affich e r tous les é lém e nts d'une liste :

main()
{ list<float> lf ;
void affiche (float) ;
.....
for_each (lf.begin(), lf.end(), affiche) ; cout << "\n" ;
.....
}
void affiche (float x) { cout << x << " " ; }

Bie n e nte ndu, on obtie ndrait le m ê m e ré s ultat e n procédant sim plem e nt ainsi :

main()
{ list<float> lf ;
void affiche (list<float>) ;
.....
lf.affiche() ;
.....
}
void affiche (list<float> l)
{ list<float>::iterator il ;
for (il=l.begin() ; il!=l.end() ; il++) cout << (*il) << " " ;
cout << "\n" ;
}
XVIII. Généralité s conce rnant la biblioth è q u e s tandard 325
6.2 Pré dicats

O n parle de prédicat pour caracté ris e r une fonction q ui re nvoie une valeur de type bool. Com pte te nu de s
conve rsions im plicite s q ui sont m ises en place autom atiq ue m e nt, ce tte valeur pe ut é ve ntue llem e nt ê tre
e ntiè re , sach ant q u'alors 0 corre s pondra à false e t q ue tout autre valeur corre s pondra à true .

O n re ncontre ra de s prédicats unaire s , c’e s t-à -dire disposant d'un seulargum e nt e t des prédicats binaire s ,
c’e s t-à -dire disposant de deux argum e nts de m ê m e type .

Là e ncore , ce rtains algorith m e s e t ce rtaine s fonctions m e m bre né ce s s ite ront q u'on leur fournis s e un prédicat
e n argum e nt. Par e xe m ple, l'algorith m e find_if pe rm e t de trouve r le pre m ie r é lém e nt d'une s é q ue nce
vé rifiant un prédicat pas s é e n argum e nt :

main()
{ list<int> l ;
list<int>::iterator il ;
bool impair (int) ;
.....
il = find_if (l.begin(), l.end(), impair) ; /* il désigne le premier élément
de */
..... /* l vérifiant le prédicat
impair */
}
bool impair (int n) /* définition du prédicat unaire impair */
{ return n%2 ; }

6.3 Cl
as s e s e t obje ts fonction

a)Util
is ation d'obje ts fonction com m e fonction de rappe l
Nous ve nons de voir q ue ce rtains algorith m e s ou fonctions m e m bre né ce s s itaie nt un prédicat e n argum e nt.
D 'une m aniè re gé né rale, ils peuve nt né ce s s ite r une fonction q ue lconq ue e t l'on parle s ouve nt de "fonction de
rappe l" pour é voq ue r un te lm é canism e dans leq ue lune fonction e s t am e né e à appe ler une autre fonction
q u'on lui a transm ise en argum e nt.

La plupart du te m ps, ce tte fonction de rappe le s t pré vue dans la définition du patron corre s pondant, non pas
sous form e d'une fonction, m ais bele t bien sous form e d'un obje t de type q ue lconq ue . Le s clas s e s e t les
obje ts fonction ont é té pré s e ntés dans le paragraph e 9 e t nous e n avions alors donné un exem ple s im ple
d'utilisation. En voici un autre q ui m ontre l'inté rê t q u'ils présente nt dans le cas de patrons de fonctions. Ici,
le patron de fonction e s s ai définit une fam ille de fonctions re ce vant e n argum e nt une fonction de rappe lsous
form e d'un obje t fonction f de type q ue lconq ue . Le s e xe m ples d'appe ls de la fonction e s s ai m ontre nt q u'on
pe ut lui fournir, indiffé re m m e nt com m e fonction de rappe l, soit une fonction usuelle, soit un obje t fonction.

________________________________________________________________________
_________

#include <iostream.h>
class cl_fonc /* definition d'une classe fonction */
{ int coef ;
public :
cl_fonc(int n) {coef = n ;}
int operator () (int p) {return coef*p ; }
} ;
int fct (int n) /* definition d'une fonction usuelle */
326 Program m e r e n langage C+ +
{ return 5*n ;
}
template <class T>void essai (T f) // definition d'essai qui reçoit en
argument
{ cout << "f(1) : " << f(1) << "\n" ; // un objet de type quelconque
cout << "f(4) : " << f(4) << "\n" ; // et qui l'utilise comme une fonction
}
main()
{ essai (fct) ; // appel essai en lui fournissant une fonction de rappel
usuelle
essai (cl_fonc(3)) ; // appel essai en lui fournissant une fonction de rappel
objet
essai (cl_fonc(7)) ; // idem
}
_______________________

f(1) : 5
f(4) : 20
f(1) : 3
f(4) : 12
f(1) : 7
f(4) : 28
________________________________________________________________________
_________

Exe m ple d'utilisation d'obje ts fonction

O n voit q u'un algorith m e atte ndant un obje t fonction pe ut re ce voir une fonction usuelle. En re vanch e , on
note ra q ue la ré ciproq ue e s t faus s e . C'e s t pourq uoi, tous les algorith m e s ont pré vu leurs fonctions de rappe l
sous form e d'obje ts fonction.

b)Cl
as s e s fonction pré dé finie s
D ans < functional> , il e xiste un ce rtain nom bre de patrons de clas s e s fonction corre s pondant à des
prédicats binaires de com paraison de deux élém e nts de m ê m e type . Par e xe m ple, les s < int> instancie une
fonction patron corre s pondant à la com paraison par < (les s ) de deux élém e nts de type int. Com m e on pe ut
s'y atte ndre , les s < point> instancie ra une fonction patron corre s pondant à la com paraison de deux obje ts de
type point par l'opé rate ur < , q ui de vra alors ê tre conve nablem e nt défini dans la clas s e point.

Voici les diffé re nts nom s de patrons e xistants e t les opé rate urs corre s pondants : e q ual_to (==),
not_e q ual_to (!=), gre ate r (> ), les s (<), gre ate r_e q ual(> =), les s _e q ual(<=).

Toute s ce s clas s e s fonction disposent d'un constructe ur sans argum e nt, ce q ui leur pe rm e t d'ê tre cité e s
com m e fonction de rappe l. D'autre part, e lles s e ront é galem e nt utilisées com m e argum e nt de type dans la
construction de ce rtaine s clas s e s .

R e m arque

Ile xiste é galem e nt des clas s e s fonction corre s pondant aux opé rations binaire s usuelles , par e xe m ple
plus<int> pour la som m e de deux int. Voici les diffé re nts nom s des autre s patrons e xistants e t les
opé rate urs corre s pondants : m odulus (%), m inus (-), tim e s (*), divide s (/). O n trouve é galem e nt les
prédicats corre s pondant aux opé rations logiq ue s : logical_and (& & ), logical_or (||), logical_not (!). Ce s
clas s e s s ont ce pe ndant d'un usage m oins fré q ue nt q ue ce lles q ui ont é té é tudié e s pré cédem m e nt.
XVIII. Généralité s conce rnant la biblioth è q u e s tandard 327

7. CO NTENEURS, A LGO RITH M ES ET RELA TIO N D 'O RD RE

7.1 Introduction

Un ce rtain nom bre de situations néce s s ite ront la connaissance d'une relation pe rm e ttant d'ordonne r les
diffé re nts é lém e nts d'un conte ne ur. Citons-e n q ue lque s e xe m ples :

• pour de s q ue s tions d'efficacité , com m e ila déjà é té dit, les é lém e nts d'un conte ne ur associatif s e ront
ordonné s e n pe rm ane nce ;
• un conte ne ur list disposera d'une fonction m e m bre sort, pe rm e ttant de ré arrange r s e s é lém e nts suivant un
ce rtain ordre ;
• ile xiste beaucoup d'algorith m es de tri q ui, e ux aussi, réorganisent les é lém e nts d'un conte ne ur suivant
un ce rtain ordre .
Bie n e nte ndu, tant q ue les é lém e nts du conte ne ur conce rné s ont d'un type s calaire ou s tring, pour leq ue lil
e xiste une re lation nature lle (<) pe rm e ttant d'ordonne r les é lém e nts, on pe ut s e pe rm e ttre d'appliq ue r ce s
diffé re nte s opé rations d'ordonnance m e nt, sans trop s e pos e r de q ue s tions.

En re vanch e , si les é lém e nts conce rné s s ont d'un type clas s e q ui ne dispose pas par défaut de l'opé rate ur < ,
ilfaudra surdéfinir conve nablem e nt ce t opé rate ur. D ans ce cas, e t com m e on pe ut s'y atte ndre , ce t opé rate ur
devra re s pe cte r un ce rtain nom bre de proprié té s , né ce s s aire s au bon fonctionne m e nt de la fonction ou de
l'algorith m e utilisé.

Par ailleurs, e t q ue lq ue s oit le type d e s é lém e nts (clas s e , type de bas e ...), on pe ut ch oisir d'utiliser une
re lation autre q ue ce lle q ui corre s pond à l'opé rate ur < (par dé faut ou surdéfini) :

• soit e n ch oisissant un autre opé rate ur (par dé faut ou surdéfini),


• soit e n fournissant e xplicite m e nt une fonction de com paraison de deux élém e nts.
Là e ncore , ce t opé rate ur ou ce tte fonction de vra re s pe cte r les proprié té s é voq ué e s q ue nous allons e xam ine r
m ainte nant.

7.2 Proprié té s à re s pe cte r

Pour sim plifie r les notations, nous note rons toujours R , la re lation binaire e n q ue s tion, q u'e lle s oit définie
par un opé rate ur ou par une fonction. La norm e pré cis e q ue R doit ê tre une re lation d'ordre faible s trict,
laq ue lle s e d é finit ainsi :

• ∀ a, !(a R a)
e s t-à -dire q ue ∀ a, b, c, te ls q ue : a R b et b R c, alors a R c ;
• R e s t transitive , c’
• ∀ a, b, c, te ls q ue : !(a R b) e t !(b R c), alors !(a R c).
O n note ra q ue l'é galité n'a pas besoin d'ê tre définie pour q ue R re s pe cte les proprié té s re q uis e s .

Bie n e nte ndu, on pe ut sans problèm e utiliser les opé rate urs < e t > pour les type s num é riq ue s ;on pre ndra
garde , ce pe ndant, à ne pas utiliser <= ou > = q ui ne ré ponde nt pas à la définition.

O n pe ut m ontre r q ue ce s contraintes définis s e nt une re lation d'ordre total, non pas sur l'e ns e m ble des
é lém e nts conce rné s , m ais sim plem e nt sur les classes d'équivalence induite s par la re lation R , une clas s e
d'équivalence é tant te lle q ue a e t b appartie nne nt à la m ê m e clas s e s i l'on a à la fois !(a R b) e t !(b R a). A
328 Program m e r e n langage C+ +
titre d'exem ple, considérons des élém e nts d'un type clas s e (point), possédant deux coordonné e s x e t y ;
supposons q u'on y dé finis s e la re lation R par :

p1(x1, y1) R p2(x2, y2) si x1 < x2


O n pe ut m ontre r q ue R satisfait les contrainte s re q uis e s e t q ue les classes d'équivalence s ont form ées des
points ayant la m ê m e abscis s e .

D ans ce s conditions, si l'on utilise R pour trie r un conte ne ur de points, ce ux-ci apparaî tront ordonné s s uivant
la pre m iè re coordonné e . Ce la n'e s t pas trè s grave car, dans une te lle opé ration de tri, tous les points s e ront
cons e rvé s . En re vanch e , si l'on utilise ce tte m ê m e re lation R pour ordonne r intrinsè q ue m e nt un conte ne ur
associatif de type m ap (dont on ve rra q ue deux é lém e nts ne peuve nt avoir de clés é q uivalente s ), deux points
de m ê m e abscis s e apparaî tront com m e "ide ntiq ue s " e t un s e uls e ra cons e rvé dans le conte ne ur.

Ainsi, lors q u'on s e ra am e né à définir sa propre re lation d'ordre , ilfaudra bie n ê tre e n m e s ure d'en prévoir
corre cte m e nt les cons é q ue nce s au nive au de s opé rations q ui e n dé pe ndront. Notam m e nt, dans ce rtains cas, il
faudra savoir si l'é galité de deux élém e nts s e fonde s ur l'opé rate ur == (surdéfini ou non), ou sur les clas s e s
d'équivalence induite s par une re lation d'ordre (par dé faut, ils'agira alors de <, surdéfini ou non). Par
e xe m ple, l'algorith m e find s e fonde s ur ==, tandis q ue la fonction m e m bre find d'un conte ne ur associatif s e
fonde s ur l'ordre intrinsè q ue du conte ne ur. Bie n e nte ndu, aucune diffé re nce n'apparaî tra ave c des élém e nts
de type num é riq ue ou s tring, tant q u'on s e lim ite ra à l'ordre induit par < puis q u'alors les clas s e s
d'équivalence e n q ue s tion s e ront réduite s à un s e ulé lém e nt.

Bie n e nte ndu, nous attire rons à nouve au votre atte ntion sur ce point au m om e nt voulu.
XIX. LES CO NTENEURS SÉQUENTIELS

Nous avons vu, dans le pré cédent ch apitre , q ue les conte ne urs pouvaie nt s e clas s e r e n de ux caté gorie s trè s
diffé re nte s : les conte ne urs s é q ue ntie ls e t les conte ne urs associatifs ;les pre m ie rs sont ordonné s suivant un
ordre im pos é e xplicite m e nt par le program m e lui-m ê m e , tandis q ue les s e conds le s ont de m aniè re
intrinsè q ue . Le s trois conte ne urs s é q ue ntie ls principaux sont les clas s e s ve ctor, list e t de q ue . La clas s e ve ctor
gé né ralise la notion de tableau, tandis q ue la clas s e list corre s pond à la notion de liste doublem e nt ch aî né e .
Com m e on pe ut s'y atte ndre , ve ctor disposera d'un ité rate ur à accè s direct, tandis q ue list ne disposera que
d'un ité rate ur bidire ctionne l. Quant à la clas s e de q ue , on ve rra q u'ils'agit d'une clas s e inte rm édiaire e ntre
les deux pré cédentes dont la pré s e nce ne s e justifie q ue pour de s q ue s tions d'efficacité .

Nous com m e nce rons par é tudie r les fonctionnalité s com m une s à ce s trois conte ne urs : construction,
affe ctation globale, initialisation par un autre conte ne ur, ins e rtion e t suppre s s ion d'é lém e nts,
com paraisons... Puis nous exam ine rons e n dé tailles fonctionnalité s s pé cifiq ue s à ch acun de s conte ne urs
ve ctor, de q ue e t list. Nous te rm ine rons par une brè ve description de s trois adaptate urs de conte ne urs q ue
sont s tack , que ue e t priority_que ue .

1. FO NCTIO NNA LITES CO M M UNES AUX CO NTENEURS VECTO R, LIST ET


D EQUE

Com m e tous les conte ne urs, ve ctor, list e t de q ue sont de taille dynam iq ue , c’
e s t-à -dire s usce ptibles de varie r
au filde l'e xé cution. M algré leur diffé re nce de nature , ce s trois conte ne urs possè dent des fonctionnalité s
com m une s q ue nous allons é tudie r ici. Elles conce rne nt :

• leur construction,
• l'affe ctation globale,
• leur com paraison,
• l'ins e rtion de nouve aux é lém e nts ou la suppre s s ion d'é lém e nts e xistants.

1.1 Cons truction

Le s trois clas s e s ve ctor, list e t de q ue disposent de diffé re nts constructe urs : conte ne ur vide, ave c nom bre
d'élém e nts donné, à partir d'un autre conte ne ur.

Construction d'un conteneur vide


330 Program m e r e n langage C+ +
L'appe ld'un constructe ur sans argum e nt construit un conte ne ur vide, c’
e s t-à -dire ne com portant aucun
é lém e nt :

list<float> lf ; /* la liste lf est construite vide ; lf.size() vaudra 0 ;


*/
/* et lf.begin() == lf.end()
*/

Construction avec un nom bre donné d 'é l


é m ents

D e façon com parable à ce q ui s e pas s e ave c la déclaration d'un tableau classique, l'appe ld'un constructe ur
ave c un s e ul argum e nt e ntie r n construit un conte ne ur com pre nant n é lém e nts. En ce q ui conce rne
l'initialisation de ce s é lém e nts, e lle e s t ré gie par les rè gles h abitue lles dans le cas d'élém e nts de type
standard (0 pour la clas s e s tatiq ue , indé te rm iné s inon). Lors q u'ils'agit d'élém e nts de type clas s e , ils sont
tout nature llem e nt initialisés par appe ld'un constructe ur sans argum e nt.

list<float> lf(5) ; /* lf est construite avec 5 éléments de type float */


/* lf.size() vaut 5 */
vector<point> vp(5) ; /* vp est construit avec 5 éléments de type point */
/* initialisés par appel du constructeur sans argument */

Construction avec un nom bre donné d 'é l


é m ents initial
isés à une val
eur im posé e

Le pre m ie r argum e nt du constructe ur fournit le nom bre d'élém e nts, le s e cond argum e nt e n fournit la valeur :

list<int> li(5, 999) ; /* li est construite avec 5 éléments de type int


*/
/* ayant tous la valeur 999
*/
point a(3, 8) ; /* on suppose que point est une classe...
*/
list<point> lp (10, a) ; /* lp est construite avec 10 points ayant tous
*/
/* la valeur de a : il y a appel du constructeur par
*/
/* recopie (éventuellement par défaut) de point
*/

Construction à partir d'une séquence

O n pe ut construire un conte ne ur à partir d'une s é q ue nce d'élém e nts de m ê m e type . Dans ce cas, on fournit
sim plem e nt au constructe ur de ux argum e nts re pré s e ntant les bornes de l'inte rvalle corre s pondant. Voici de s
e xe m ples utilisant d e s s é q ue nces de conte ne ur de type list< point> :

list<point> lp(6) ; /* liste de 6 points */


.....
vector<point> vp (lp.begin(), lp.end()) ; /* construit un vecteur de points
*/
/* en recopiant les points de la liste lp ; le constructeur
*/
/* par recopie de point sera appelé pour chacun des points
*/
list<point> lpi (lp.rbegin(), lp.rend()) ; /* construit une liste obtenue en
*/
/* inversant l'ordre des points de la liste lp
*/
XIX. Le s conte ne urs séquentie ls 331

Ici, les s é q ue nce s corre s pondaie nt à l'e ns e m ble du conte ne ur ;ils'agit de la situation la plus usuelle, m ais
rie n n'e m pê ch e rait d'utiliser des inte rvalles d'ité rate urs q ue lconq ue s , pour pe u q ue la s e conde borne soit
acce s s ible à partir de la pre m iè re .

Voici un autre e xe m ple de construction de conte ne urs, à partir de s é q ue nces de valeurs issues d'un tableau
classique, utilisant des inte rvalles définis par de s pointe urs :

int t[6] = { 2, 9, 1, 8, 2, 11 } ;
vector<int> vi(t, t+6) ; /* construit un vecteur formé des 6 valeurs du
tableau t */
vector<int> vi2(t+1, t+5) ; /* construit un vecteur formé des valeurs t[1] à
t[5] */

D ans le pre m ie r cas, si l'on souh aite une form ulation indé pe ndante de la taille e ffe ctive de t, on pourra
procéder ainsi :

int t[] = { ..... } ; /* nombre quelconque de valeurs


*/
vector<int> vi(t, t + sizeof(t)/sizeof(int)) ; /* qui seront recopiées dans vi
*/

Construction à partir d'un autre conteneur de m ê m e type

Ils'agit d'un classique constructe ur par re copie q ui, com m e on pe ut s'y atte ndre , appe lle le constructe ur de
re copie d e s é lém e nts conce rné s lors q u'ils'agit d'obje ts.

vector<int> vi1 ; /* vecteur d'entiers */


.....
vector<int> vi2(vi1) ; /* ou encore vector<int> vi2 = vi1 ; */

1.2 M odifications gl
obal
es

Le s trois clas s e s ve ctor, de q ue e t list définis s e nt conve nablem e nt l'opé rate ur d'affe ctation ;de plus, e lles
propos e nt une fonction m e m bre assign, com portant plusieurs définitions, ainsi qu'une fonction clear.

a)O pé rate ur d'affe ctation


O n pe ut affe cte r un conte ne ur d'un type donné à un autre conte ne ur de m ê m e type , c’ e s t-à -dire ayant le
m ê m e nom de patron e t le m ê m e type d'élém e nts. Bie n e nte ndu, iln'e s t nullem e nt né ce s s aire q ue le nom bre
d'élém e nts de ch acun de s conte ne urs soit le m ê m e . Voici q ue lque s e xe m ples :

vector<int> vi1 (...), vi2 (...) ;


vector<float> vf (...) ;
.....
vi1 = vi2 ; /* correct, quel que soit le nombre d'éléments de vi1 et de vi2
*/
/* le contenu de vi1 est remplacé par celui de vi2 qui reste
inchangé */
vf = vi1 ; /* incorrect (refusé en compilation) : les éléments de vf et de vi1
*/
/* ne sont pas du même type
*/

Voici un autre e xe m ple ave c un conte ne ur dont les é lém e nts sont des obje ts :
332 Program m e r e n langage C+ +
vector<point> vp1 (....), vp2 (...) ;
.....
vp1 = vp2 ;

D ans ce cas, com m e nous l'avons déjà fait re m arq ue r dans le paragraph e 4.1 du pré cédent ch apitre , ile xiste
deux façons de parve nir au ré s ultat e s com pté , suivant les tailles re latives des ve cte urs vp1 e t vp2, à savoir,
soit l'utilisation du constructe ur par re copie de la clas s e point, soit l'utilisation de l'opé rate ur d'affe ctation
de la clas s e point.

b)La fonction m e m bre as s ign


Alors q ue l'affe ctation n'e s t possible q u'e ntre conte ne urs de m ê m e type , la fonction assign pe rm e t
d'affe cte r, à un conte ne ur e xistant, les é lém e nts d'une séquence définie par un inte rvalle [de but, fin), à
condition q ue les é lém e nts désignés soient du type voulu (e t pas s e ulem e nt d'un type com patible par
affe ctation) :

assign (début, fin) /*fin doit ê tre acce s s ible depuis début */
Ile xiste é galem e nt une autre ve rsion pe rm e ttant d'affe cte r à un conte ne ur, un nom bre donné d'élém e nts
ayant une valeur im pos é e :

assign (nb_fois, valeur)


D ans les deux cas, les é lém e nts e xistants s e ront re m placé s par les é lém e nts voulus, com m e s 'ily avait e u
affe ctation.

point a (...) ;
list<point> lp (...) ;
vector<point> vp (...) ;
.....
lp.assign (vp.begin(), vp.end()) ; /* on a maintenant : lp.size() =
vp.size() */
vp.assign (10, a) ; /* on a maintenant : vp.size()=10
*/

char t[] = {"hello"} ;


list<char> lc(7, 'x') ; /* la liste contient : x, x, x, x, x, x,
x */
.....
lc.assign(t, t+4) ; /* la liste contient maintenant : h, e, l, l, o
*/
lc.assign(3, 'z') ; /* la liste contient maintenant : z, z, z
*/

c)La fonction cl
e ar
La fonction clear() vide le conte ne ur de son conte nu.

vector<point> vp(10) ; /* vp.size() = 0 */


.....
vp.clear () ; /* appel du destructeur de chacun des points de vp */
/* maintenant vp.size() = 0 */
XIX. Le s conte ne urs séquentie ls 333
d)La fonction s w ap
La fonction m e m bre s w ap (conte ne ur) pe rm e t d'éch ange r le conte nu de deux conte ne urs de m ê m e type . Par
e xe m ple :

vector<int> v1, v2 ;
.....
v1.swap(v2) ; /* ou : v2.swap(v1) ; */

L'affe ctation pré cédente s e ra plus e fficace q ue la dém arch e traditionne lle :

vector<int> v3=v1 ;
v1=v2 ;
v2=v3 ;

R e m arque

Com m e on pe ut le constate r, les possibilités de m odifications globales d'un conte ne ur sont sim ilaire s à
ce lles q ui sont offe rte s au m om e nt de la construction, la s e ule possibilité absente é tant l'affe ctation d'un
nom bre d'élém e nts donnés, éve ntue llem e nt non initialisés.

1.3 Com parais on de conte ne urs

Le s trois conte ne urs ve ctor, de q ue e t list disposent des opérate urs == e t < ;par le biais des générations
autom atiq ues d'opérate urs, ils disposent donc é galem e nt de !=, <=, > e t > =. Le rôle de == corre s pond
à ce q u'on atte nd d'un te lopé rate ur, tandis q ue ce lui de < s 'appuie s ur ce q ue l'on nom m e parfois une
com paraison lexicograph iq ue , analogue à ce lle q ui pe rm e t de clas s e r de s m ots par ordre alph abétiq ue .

a)L'opé rate ur ==
Il ne pré s e nte pas de difficulté s particuliè re s . Si c1 e t c2 sont deux conte ne urs de m ê m e type , leur
com paraison par == s e ra vraie s 'ils ont la m ê m e taille e t si les é lém e nts de m ê m e rang sont é gaux.

O n note ra ce pe ndant q ue s i les é lém e nts conce rné s s ont de type clas s e , ils e ra né ce s s aire q ue ce tte derniè re
dispose elle-m ê m e de l'opé rate ur ==.

b)L'opé rate ur <


Ile ffe ctue une com paraison lexicograph iq ue d e s é lém e nts des deux conte ne urs. Pour ce faire , ilcom pare les
é lém e nts de m ê m e rang, par l'opé rate ur < , e n com m e nçant par les pre m ie rs, s'ils e xiste nt. Ils'inte rrom pt
dè s q ue l'une des conditions suivante s e s t ré alisée :

• fin de l'un de s conte ne urs atte inte ;le ré s ultat de la com paraison est vrai,
• com paraison de deux élém e nts faus s e ;le ré s ultat de la com paraison des conte ne urs e s t alors faux.
Si un s e uldes deux conte ne urs e s t vide, ilapparaît com m e < à l'autre . Si les deux conte ne urs sont vides,
aucun n'e s t infé rie ur à l'autre (ils sont é gaux).

O n note ra, là e ncore , q ue s i les é lém e nts conce rné s s ont de type clas s e , ils e ra né ce s s aire q ue ce tte derniè re
dispose elle-m ê m e d'un opé rate ur < approprié .

c)Exe m pl
es
Ave c ces déclarations :
334 Program m e r e n langage C+ +
int t1[] = {2, 5, 2, 4, 8 } ;
int t2[] = {2, 5, 2, 8 } ;
vector<int> v1 (t1, t1+5) ; /* v1 contient : 2 5 2 4 8 */
vector<int> v2 (t2, t2+4) ; /* v2 contient : 2 5 2 8 */
vector<int> v3 (t2, t2+3) ; /* v3 contient : 2 5 2 */
vector<int> v4 (v3) ; /* v4 contient : 2 5 2 */
vector<int> v5 ; /* v5 est vide */

Voici q ue lque s com paraisons possibles e t la valeur corre s pondante :

v2 < v1 /* faux */ v3 < v2 /* vrai */ v3 < v4 /* faux */


v4 < v3 /* faux */ v3 == v4 /* vrai */ v4 > v5 /* vrai */
v5 > v5 /* faux */ v5 < v5 /* faux */

1.4 Ins e rtion ou suppre s s ion d'é l


é m e nts

Ch acun de s trois conte ne urs ve ctor, de q ue e t list dispose nature llem e nt de possibilités d'accè s à un é lém e nt
e xistant, soit pour e n connaî tre la valeur, soit pour la m odifie r. Com m e ce s possibilité s varie nt q ue lque pe u
d'un conte ne ur à l'autre , e lles s e ront décrites dans les paragraph e s ulté rie urs. Par ailleurs, ce s trois
conte ne urs (com m e tous les conte ne urs) pe rm e tte nt des m odifications dynam iq ue s fondé e s s ur de s ins e rtions
de nouve aux é lém e nts ou des suppressions d'élém e nts e xistants. O n note ra q ue de te lles possibilité s
n'e xistaie nt pas dans le cas d'un tableau classique, alors q u'e lles e xiste nt pour le conte ne ur ve ctor, m ê m e s i,
m anife s te m e nt, e lles s ont davantage utilisées dans le cas d'une liste .

R appe lons toute fois q ue , bie n q u'e n th é orie , les trois conte ne urs offre nt les m ê m e s possibilités d'insertions
e t de suppressions, leur e fficacité s e ra diffé re nte d'un conte ne ur à un autre . Nous ve rrons dans les
paragraph e s s uivants q ue , dans une liste , e lles s e ront toujours e n O (1), tandis q ue dans les conte ne urs ve ctor
e t de q ue , e lles s e ront e n O (N), e xce pté lors q u'e lles auront lie u e n fin de ve ctor ou e n début ou e n fin de
de q ue où e lles s e fe ront e n O (1) ;dans ces dernie rs cas, on ve rra d'ailleurs q u'ile xiste des fonctions m e m bre
spécialisées.

a)Ins e rtion
La fonction inse rt pe rm e t d'insérer :

• une valeur avant une position donné e :


inse rt (position, valeur) /*insè re valeur avant l'é lém e nt pointé par position */
/*fournit un ité rate ur sur l'é lém e nt ins é ré */
• n fois une valeur donné e , avant une position donné e :
inse rt (position, nb_fois, valeur) /*insè re nb_fois valeur, avant l'é lém e nt */
/* pointé par position */
/*fournit un ité rate ur sur l'é lém e nt ins é ré */
• les é lém e nts d'un inte rvalle, à partir d'une position donné e :
inse rt (de but, fin, position) /*insè re les valeurs de l'inte rvalle [de but, fin) , */
/*avant l'é lém e nt pointé par position */
En voici q ue lque s e xe m ples :
list<double> ld ;
list<double>::iterator il ;
..... /* on suppose que il pointe correctement dans la liste ld */
XIX. Le s conte ne urs séquentie ls 335
ld.insert (il, 2.5) ; /* insère 2.5 dans ld, avant l'élément pointé par
il */
ld.insert (ld.begin(), 6.7) ; /* insère 6.7 au début de ld
*/
ld.insert (ld.end(), 3.2) ; /* insère 3.2 en fin de ld
*/
.....
ld.insert(il, 10, -1) ; /* insère 10 fois -1, avant l'élément pointé par
il */
.....
vector<double> vd (...) ;
ld.insert(ld.begin(), vd.begin(), vd.end()) ; /* insère tous les éléments de
vd */
/* en début de la liste ld
*/

b)Suppre s s ion
La fonction e ras e pe rm e t de supprim e r :

• un é lém e nt de position donné e :


e ras e (position) /*supprim e l'é lém e nt désigné par position - fournit un ité rate ur */
/*sur l'é lém e nt suivant ou sur la fin de la s é q ue nce */
• les é lém e nts d'un inte rvalle :
e ras e (début, fin) /*supprim e les valeurs de l'inte rvalle [début, fin) - fournit un */
/*ité rate ur sur l'é lém e nt suivant ou sur la fin de la s é q ue nce */
En voici q ue lque s e xe m ples :
list<double> ld ;
list<double>::iterator il1, il2 ;
..... /* on suppose que il1 et il2 pointent correctement dans */
/* la liste ld et que il2 est accessible à partir de il1*/
ld.erase(il1, il2) ; /* supprime les éléments de l'intervalle [il1, il2) */
ld.erase(ld.begin()) ; /* supprime l'élément de début de ld */

R e m arques

1) Les deux fonctions e ras e re nvoie nt la valeur de l'ité rate ur suivant le dernie r é lém e nt supprim é s 'ile n
e xiste un ou sinon, la valeur e nd(). Voye z par e xe m ple, la construction suivante , dans laq ue lle ile s t un
ité rate ur, de valeur conve nable, sur une liste d'entie rs ld :
while (il = ld.erase(il) != ld.end()) ;

Elle e s t é q uivalente à :
erase (il, ld.end()) ;

2) Le s conte ne urs s é q ue ntie ls ne sont pas adapté s à la re ch e rch e de valeurs données ou à leur suppre s s ion. Il
n'e xiste ra d'ailleurs aucune fonction m e m bre à ce t e ffe t, contraire m e nt à ce q ui s e produira ave c les
conte ne urs associatifs. Iln'e n re s te pas m oins q u'une te lle re ch e rch e pe ut toujours s e faire à l'aide d'un
algorith m e s tandard te lq ue find ou find_if, m ais au prix d'une e fficacité m édiocre (en O(N)).
336 Program m e r e n langage C+ +
c)Cas de s ins e rtions /s uppre s s ions e n fin : pop_back e t pus h _back
Si l'on s'e n tie nt aux possibilité s gé né rales pré s e nté e s ci-de s s us, on constate q ue s 'il e s t possible de
supprim e r le pre m ie r é lém e nt d'un conte ne ur e n appliq uant e ras e à la position be gin(), iln'e s t pas possible
de supprim e r le dernie r é lém e nt d'un conte ne ur, e n appliq uant e ras e à la position e nd(). Un te lré s ultat pe ut
toute fois s'obte nir e n appliq uant e ras e à la position rbe gin(). Quoi q u'ile n soit, com m e l'e fficacité de ce tte
suppre s s ion e s t e n O (1) pour les trois conte ne urs, ile xiste une fonction m e m bre s pé cialisée pop_back () q ui
ré alise ce tte opé ration ;si c e s t un conte ne ur, c.pop_back () e s t é q uivalente à c.e ras e (c.rbe gin()).

D 'une m aniè re s e m blable, e t bien q ue ce ne s oit guè re indispensable, ile xiste une fonction spécialisée
d'insertion e n fin push _back . Si c e s t un conte ne ur, c.pus h _back (valeur) e s t é q uivalent à c.ins e rt (c.e nd(),
valeur).

2. LE CO NTENEUR VECTO R

Ilre pre nd la notion usuelle de tableau e n autorisant un accè s direct à un é lém e nt q ue lconq ue ave c une
e fficacité e n O (1), c’e s t-à -dire indé pe ndante du nom bre d e s e s é lém e nts. Ce t accè s peut s e faire s oit par le
biais d'un ité rate ur à accè s direct, soit de façon plus classique, par l'opé rate ur [ ] ou par la fonction m e m bre
at. M ais iloffre un cadre plus généralq ue le tableau puis q ue :

• la taille, c’e s t-à -dire le nom bre d'élém e nts, pe ut varie r au filde l'e xé cution (com m e ce lle de tous les
conte ne urs) ;
• on pe ut e ffe ctue r toute s les opé rations de construction, d'affe ctation e t de com paraisons décrite s aux
paragraph e s 1.1, 1.2 e t 1.3 ;
• on dispose des possibilité s gé né rales d'insertion ou de s uppre s s ions décrite s au paragraph e 1.4 (ave c,
ce pe ndant, une e fficacité e n O (N) dans le cas général).
Ici, nous nous conte nte rons d'exam ine r les fonctionnalité s s pé cifiq ues de la clas s e ve ctor, q ui vie nne nt donc
e n com plém e nt de ce lles q ui sont e xam inées dans le paragraph e 1.

2.1 A ccè s aux é l


é m e nt e xis tants

O n accè de aux diffé re nts é lém e nts d'un ve cte ur, aussi bien pour en connaî tre la valeur q ue pour la m odifie r,
de diffé re nte s m aniè re s : par ité rate ur (ite rator ou re ve rs e _ite rator) ou par indice (opé rate ur [ ] ou fonction
m e m bre at). En outre , l'accè s au de rnie r é lém e nt pe ut s e faire par une fonction m e m bre approprié e back .
D ans tous les cas, l'e fficacité de ce t accè s e s t e n O (1), ce q ui constitue m anife s te m e nt le point fort de ce
type de conte ne ur.

A ccè s par ité rate ur


Le s ité rate urs ite rator e t re ve rs e _ite rator d'un conte ne ur de type ve ctor sont à accè s direct. Si, par e xe m ple,
iv e s t une variable de type ve ctor< int> ::ite rator, une e xpre s s ion te lle q ue iv+ i a alors un sens : e lle
désigne l'é lém e nt du ve cte ur v, situé i é lém e nts plus loin q ue ce lui q ui e s t désigné par iv, à condition q ue la
valeur de i soit com patible ave c le nom bre d'élém e nts de v.

L'ité rate ur iv pe ut, bie n sûr, com m e tout ité rate ur bidire ctionne l, ê tre incré m e nté ou dé cré m e nté par + + ou
--. M ais, com m e ile s t à accè s direct, ilpe ut é galem e nt ê tre incré m e nté ou dé cré m e nté d'une quantité
q ue lconq ue , com m e dans :

iv += n ; iv -= p ;
XIX. Le s conte ne urs séquentie ls 337

Voici un pe tit e xe m ple d'école

vector<int> vi(10) ; /* vecteur de 10 éléments


*/
vector<int>::iterator iv = v.begin() ; /* iv pointe sur le premier élément de
v */
.....
iv = vi.begin() ; *iv=0 ; /* place la valeur 0 dans le premier élément de vi
*/
iv+=3 ; *iv=30 ; /* place la valeur 30 dans le quatrième élément de
vi */
iv = vi.end()-2 ; *iv=70 ; /* place la valeur 90 dans le huitième élément de
vi */

A ccè s par indice


L'opé rate ur [ ] e s t, e n fait, utilisable de façon nature lle. Si v e s t de type ve ctor, l'e xpre s s ion v[i] e s t une
ré fé re nce à l'é lém e nt de rang i, de sorte q ue les deux instructions suivante s s ont é q uivalente s :

v[i] = ... ; *(v.begin()+i) = ... ;

M ais ile xiste é galem e nt une fonction m e m bre at te lle q ue v.at(i) soit é q uivalente à v[i]. Sa s e ule raison
d'ê tre e s t de générer une exception out_of_range e n cas d'indice incorre ct, ce q ue l'opé rate ur [ ] ne fait
th é oriq ue m e nt pas. Bie n e nte ndu, e n contre partie , at e s t légè re m e nt m oins rapide q ue l'opé rate ur [ ].

L'e xe m ple d'école pré cédent pe ut m anife s te m e nt s'é crire plus sim plem e nt :

vi[0] = 0 ; /* ou : vi.at(0) = 0 ; */
vi[3] = 30 ; /* ou : vi.at(3) = 30 ; */
vi[7] = 70 ; /* ou : vi[vi.size()-2] = 70 ; ou : vi.at(7) = 70 ; */

Ile s t gé né ralem e nt pré fé rable d'utiliser les indice s plutôt q ue les ité rate urs dont le principalavantage ré s ide
dans l'h om ogé né ïsation de notation ave c les autre s conte ne urs.

Cas de l
'accè s au de rnie r é l
é m e nt
Com m e le ve cte ur e s t particuliè re m e nt adapté aux ins e rtions ou aux suppre s s ions e n fin, ile xiste une
fonction m e m bre back q ui pe rm e t d'accéder dire cte m e nt au de rnie r é lém e nt.

vector<int> v(10) ;
.....
v.back() = 25 ; /* équivalent, quand v est de taille 10, à : v[9] = 25 ;
*/
/* équivalent, dans tous les cas, à : v[v.size()-1] = 25
*/

O n note ra bie n q ue ce tte fonction s e conte nte de fournir une ré fé re nce à un é lém e nt e xistant. Elle ne pe rm e t
e n aucun cas des insertions ou des suppressions en fin, les q ue lles s ont é tudié e s ci-de s s ous.

2.2 Ins e rtions e t suppre s s ions

Le conte ne ur ve ctor dispose des possibilité s gé né rales d'insertion e t de suppression décrite s au paragraph e
1.4. Toute fois, leur e fficacité e s t m édiocre, puisq u'e n O (N), alors q ue , dans le cas des liste s , e lle s e ra e n
338 Program m e r e n langage C+ +
O (1). C'e s t là le prix à paye r pour disposer d'accè s aux é lém e nts e xistant e n O (1). En re vanch e , nous avons
vu q ue , com m e les deux autre s conte ne urs, ve ctor disposait de fonctions m e m bre d'insertion ou de
suppre s s ion du de rnie r é lém e nt, dont l'e fficacité e s t e n O (1) :

• la fonction push _back (valeur) pour ins é re r un nouve lé lém e nt e n fin,


• la fonction pop_back () pour supprim e r le dernie r é lém e nt.
Voici un pe tit e xe m ple d'école :
vector<int> v(5, 99) ; _ /* vecteur de 5 éléments de valeur 99 v.size()
= 5 */
v.push_back(10) ; /* ajoute un élément de valeur 10 : v.size() = 6 et v[5] =
10 */
/* ici, v[6] n'existe pas
*/
v.push_back(20) ; /* ajoute un élément de valeur 20 : v.size() = 7 et v[6] =
20 */
v.pop_back() ; /* supprime le dernier élément : v.size() = 6
*/

2.3 Ge s tion de l
'e m pl
ace m e nt m é m oire

a) Introduction
La norm e n'im pos e pas e xplicite m e nt la m aniè re dont une im plém e ntation doit gé re r l'e m place m e nt alloué à
un ve cte ur. Ce pe ndant, com m e nous l'avons vu, e lle im pose des contraintes d'efficacité à ce rtaine s
opé rations, ce q ui, com m e on s'e n doute , lim ite s é vè re m e nt la m arge de m anœuvre de l'im plém e ntation.

Par ailleurs, la clas s e ve ctor dispose d'outils fournissant des inform ations re lative s à la ge s tion de s
e m place m e nts m é m oire e t pe rm e ttant, é ve ntue llem e nt, d'inte rve nir dans leur allocation. Bie n e nte ndu, le
rôle de te ls outils e s t plus facile à appré h e nde r lors q ue l'on connaî t la m aniè re e xacte dont une
im plém e ntation gè re un ve cte ur.

Enfin, la norm e pré voit q ue , suite à ce rtaine s opé rations, des réfé re nce s ou de s valeurs d'ité rate urs peuve nt
deve nir invalides, c’ e s t-à -dire inutilisables pour accéder aux é lém e nts corre s pondants. Là e ncore , ile s t plus
facile de com pre ndre les rè gles im pos é e s s i l'on connaî t la m aniè re dont l'im plém e ntation gè re les
e m place m e nts m é m oire .

O r, pré cis é m e nt, les im plém e ntations actue lles alloue nt toujours l'e m place m e nt d'un ve cte ur e n un s e ul
bloc. M ê m e s i ce n'e s t pas la s e ule s olution e nvisage able, c'e s t ce rtaine m e nt la plus plausible.

b)Inval
idation d'ité rate urs ou de ré fé re nce s
Un ce rtain nom bre d'opérations sur un ve cte ur e ntraî ne nt l'invalidation de s ité rate urs ou des réfé re nce s s ur
ce rtains des élém e nts de ce ve cte ur. Le s é lém e nts conce rné s s ont e xacte m e nt ce ux auxq ue ls on pe ut
s'atte ndre dans le cas où l'e m place m e nt m é m oire e s t gé ré e n un s e ulbloc, à savoir :

• tous les é lém e nts, e n cas d'augm e ntation de la taille ;e n e ffe t, ils e pe ut q u'une re copie de l'e ns e m ble du
ve cte ur ait é té né ce s s aire ;on ve rra toute fois q u'ile s t possible d'évite r ce rtaine s re copie s e n ré s e rvant
plus d'em place m e nts q ue né ce s s aire ;
• tous les é lém e nts, e n cas d'insertion d'un é lém e nt ;la raison en est la m ê m e ;
• les é lém e nts situé s à la suite d'un élém e nt supprim é , ainsi que l'é lém e nt supprim é (ce q ui va de soi !) ;
ici, on voit q ue s e uls les é lém e nts situé s à la suite de l'é lém e nt supprim é ont dû ê tre déplacé s .
XIX. Le s conte ne urs séquentie ls 339

c)O util
s de ge s tion de l
'e m pl
ace m e nt m é m oire d'un ve cte ur
La norm e propos e un ce rtain nom bre d'outils fournissant des inform ations conce rnant l'e m place m e nt
m é m oire alloué à un ve cte ur e t pe rm e ttant, é ve ntue llem e nt, d'inte rve nir dans son allocation. Com m e on l'a
dit e n introduction, le rôle de ce s outils e s t plus facile à appré h e nde r si l'on fait l'h ypoth è s e q ue
l'e m place m e nt d'un ve cte ur e s t toujours alloué s ous form e d'un bloc uniq ue .

O n a dé jà vu q ue la fonction size () pe rm e ttait de connaî tre le nom bre d'élém e nts d'un ve cte ur. M ais ile xiste
une fonction voisine, capacity(), q ui fournit la taille pote ntie lle du ve cte ur, c’ e s t-à -dire le nom bre
d'élém e nts q u'ilpourra acce pte r, sans avoir à e ffe ctue r de nouve lle allocation. D ans le cas usueloù le
ve cte ur e s t alloué s ous form e d'un seulbloc, ce tte fonction e n fournit sim plem e nt la taille (l'unité utilisée
re s tant l'é lém e nt du ve cte ur). Bie n e nte ndu, à tout instant, on a toujours capacity() > = size (). La diffé re nce
capacity()-size () pe rm e t de connaî tre le nom bre d'élém e nts q u'on pourra ins é re r dans un ve cte ur sans q u'une
ré allocation de m é m oire s oit né ce s s aire .

M ais une te lle inform ation ne s e rait guè re inté re s s ante s i l'on ne pouvait pas agir sur ce tte allocation. O r, la
fonction m e m bre re s e rve (taille) pe rm e t pré cis é m e nt d'im pos e r la taille m inim ale de l'e m place m e nt alloué à
un ve cte ur à un m om e nt donné . Bie n e nte ndu, l'appe lde ce tte fonction pe ut trè s bien am e ne r à une re copie
de tous les é lém e nts du ve cte ur e n un autre e m place m e nt. Ce pe ndant, une fois ce travailaccom pli, tant q ue
la taille du ve cte ur ne dépas s e ra pas la lim ite alloué e , on e s t assuré de lim ite r au m axim um les re copie s
d'élém e nts e n cas d'insertion ou de s uppre s s ion. En particulie r, e n cas d'insertion d'un nouve lé lém e nt, les
é lém e nts situé s avant ne s e ront pas déplacé s e t les ré fé re nce s ou ité rate urs corre s pondants re s te ront valides.

Par ailleurs, la fonction m ax_size () pe rm e t de connaî


tre la taille m axim ale q u'on pe ut alloue r au ve cte ur, à
un instant donné .

Enfin, ile xiste une fonction re s ize (taille), pe u usité e , q ui pe rm e t de m odifie r la taille e ffe ctive du ve cte ur,
aussi bien dans le s e ns de l'accrois s e m e nt q ue dans ce lui de la réduction. Atte ntion, ilne s 'agit plus, ici,
com m e ave c re s e rve , d'agir sur la taille de l'e m place m e nt alloué , m ais, bel e t bien, sur le nom bre
d'élém e nts du ve cte ur. Si l'appe lde re s ize conduit à augm e nte r la taille du ve cte ur, on lui insè re , e n fin, de
nouve aux é lém e nts. Si, e n re vanch e , l'appe lconduit à dim inue r la taille du ve cte ur, on supprim e , e n fin, le
nom bre d'élém e nts voulus ave c, nature llem e nt, appe lde leur de s tructe ur, s'ils'agit d'obje ts.

2.4 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant les principales fonctionnalités de la clas s e ve ctor q ue
nous ve nons d'exam ine r dans ce paragraph e e t dans le pré cédent. Nous y avons adjoint une re ch e rch e de
valeur par l'algorith m e find q ui ne s e ra pré s e nté q u'ulté rie ure m e nt, m ais dont la signification e s t as s e z
é vidente : re ch e rch e r une valeur donné e .

_______________________________________________________________________________
__

#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
int i ;
int t[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } ;
vector<int> v1(4, 99) ; // vecteur de 4 entiers egaux à 99
vector<int> v2(7, 0) ; // vecteur de 7 entiers
vector<int> v3(t, t+6) ; // vecteur construit a partir de t
340 Program m e r e n langage C+ +
cout << "V1 init = " ; affiche(v1) ;
for (i=0 ; i<v2.size() ; i++) v2[i] = i*i ;
v3 = v2 ;
cout << "V2 = " ; affiche(v2) ;
cout << "V3 = " ; affiche(v3) ;
v1.assign (t+1, t+6) ; cout << "v1 apres assign : " ; affiche(v1) ;
cout << "dernier element de v1 : " << v1.back() << "\n" ;
v1.push_back(99) ; cout << "v1 apres push_back : " ; affiche(v1) ;
v2.pop_back() ; cout << "v2 apres pop_back : " ; affiche(v2) ;
cout << "v1.size() : " << v1.size() << " v1.capacity() : "
<< v1.capacity() << " V1.max_size() : " << v1.max_size() << "\n" ;
vector<int>::iterator iv ;
iv = find (v1.begin(), v1.end(), 16) ; // recherche de 16 dans v1
if (iv != v1.end()) v1.insert (iv, v2.begin(), v2.end()) ;
// attention, ici iv n'est plus utilisable
cout << "v1 apres insert : " ; affiche(v1) ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++) cout << v[i] << " " ;
cout << "\n" ;
} _______________________

V1 init = 99 99 99 99
V2 = 0 1 4 9 16 25 36
V3 = 0 1 4 9 16 25 36
v1 apres assign : 2 3 4 5 6
dernier element de v1 : 6
v1 apres push_back : 2 3 4 5 6 99
v2 apres pop_back : 0 1 4 9 16 25
v1.size() : 6 v1.capacity() : 10 V1.max_size() : 1073741823
v1 apres insert : 2 3 4 5 6 99
________________________________________________________________________
_________

Exe m ple d'utilisation de la clas s e ve ctor

2.5 Cas particul


ie r de s ve cte urs de bool
é ns

La norm e pré voit l'e xiste nce d'une spécialisation du patron ve ctor, lors q ue s on argum e nt e s t de type bool.
L'obje ctif principal e s t de perm e ttre à l'im plém e ntation d'optim iser le s tock age s ur un s e ul bit des
inform ations corre s pondant à ch aq ue é lém e nt. Le s fonctionnalités de la clas s e ve ctor<bool> sont donc
ce lles q ue nous avons é tudié e s pré cédem m e nt. Ilfaut ce pe ndant lui adjoindre une fonction m e m bre flip
destiné e à inve rs e r tous les bits d'un te lve cte ur.

3. LE CO NTENEUR D EQUE

3.1 Pré s e ntation gé né ral


e

Le conte ne ur de q ue offre des fonctionnalité s as s e z voisines de ce lles d'un ve cte ur. En particulie r, ilpe rm e t
toujours l'accè s direct e n O (1) à un é lém e nt q ue lconq ue , tandis q ue les s uppre s s ions e t ins e rtions e n un point
q ue lconq ue re s te nt e n O (N). En re vanch e , iloffre , e n plus de l'ins e rtion ou suppre s s ion e n fin, une ins e rtion
XIX. Le s conte ne urs séquentie ls 341
ou suppre s s ion e n début, é galem e nt e n O (1), ce q ue ne pe rm e ttait pas le ve cte ur. En fait, ilne faut pas e n
conclure pour autant q ue de q ue e s t plus e fficace q ue ve ctor car ce tte possibilité s upplém e ntaire s e paye à
diffé re nts nive aux :

• une opé ration e n O (1) sur un conte ne ur de type de q ue s e ra m oins rapide q ue la m ê m e opé ration, toujours
e n O (1) sur un conte ne ur de type ve ctor ;
• ce rtains outils de gestion de l'e m place m e nt m é m oire d'un conte ne ur de type ve ctor, n'e xiste nt plus pour
un conte ne ur de type de q ue ;plus précisém e nt, on disposera bien de size () e t de m ax_size (), m ais plus de
capacity e t de re s e rve .
Là e ncore e t com m e nous l'avons fait re m arq ue r au paragraph e 2.3, la norm e n'im pos e pas e xplicite m e nt
la m aniè re de gé re r l'e m place m e nt m é m oire d'un conte ne ur de type de q ue ;né anm oins, les ch os e s
devie nne nt beaucoup plus com pré h e nsibles s i l'on adm e t q ue , pour satisfaire aux contrainte s im pos é e s , il
n'e s t pas raisonnable d'alloue r un de q ue e n un s e ulbloc m ais plutôt sous form e de plusieurs blocs conte nant
ch acun un ou, gé né ralem e nt, plusieurs élém e nts. Dans ces conditions, on voit bien q ue l'ins e rtion ou la
suppre s s ion e n début de conte ne ur ne né ce s s ite ra plus le déplace m e nt de l'e ns e m ble des autre s é lém e nts,
com m e c'é tait le cas ave c un ve cte ur, m ais s e ulem e nt d e q ue lque s -uns d'entre e ux. En re vanch e , plus la
taille des blocs s e ra pe tite , plus la rapidité de l'accè s direct (bie n q ue toujours e n O (1)) dim inue ra. Au
contraire , les ins e rtions e t les s uppre s s ions, bie n q u'ayant une e fficacité e n O (N), s e ront d'autant plus
pe rform ante s q ue les blocs s e ront pe tits.

Si l'on fait abstraction de ces diffé re nces de pe rform ance s , les fonctionnalités de de q ue sont ce lles de ve ctor,
auxq ue lles ilfaut, tout nature llem e nt, ajoute r les fonctions spé cialisées conce rnant le pre m ie r é lém e nt :

• front(), pour accéder au pre m ie r é lém e nt ;e lle com plète la fonction back pe rm e ttant l'accè s au de rnie r
é lém e nt ;
• push _front(valeur), pour ins é re r un nouve lé lém e nt e n début ;e lle com plète la fonction push _back () ;
• pop_front(), pour supprim e r le pre m ie r é lém e nt ;e lle com plète la fonction pop_back ().
Le s rè gles d'invalidation de s ité rate urs e t des ré fé re nce s re s te nt e xacte m e nt les m ê m e s q ue ce lles de la clas s e
ve ctor, m ê m e s i, dans ce rtains cas, e lles pe uve nt apparaî tre trè s contraignante s . Par e xe m ple, si un
conte ne ur de type de q ue e s t im plém e nté s ous form e de 5 blocs diffé re nts, ile s t ce rtain q ue l'ins e rtion e n
début, n'invalidera q ue les ité rate urs sur de s é lém e nts du prem ie r bloc q ui s e ra le s e ulsoum is à une re copie ;
m ais, e n pratiq ue , on ne pourra jam ais profite r de ce tte re m arq ue ;d'ailleurs, on ne connaî tra m ê m e pas la
taille des blocs !

D 'une m aniè re gé né rale, le conte ne ur de q ue e s t beaucoup m oins utilisé que les conte ne urs ve ctor e t list q ui
possè dent des fonctionnalités bien distincte s . Ilpe ut s'avé re r inté re s s ant dans des situations de pile de type
FIFO (Firs t In, Firs t Out) où ile s t né ce s s aire d'introduire des inform ations à une e xtré m ité , e t de les
re cue illir à l'autre . En fait, dans ce cas, si l'on n'a plus besoin d'accéder directe m e nt aux diffé re nts
é lém e nts, ile s t pré fé rable d'utiliser l'adaptate ur de conte ne ur que ue dont nous parlerons au paragraph e 5.

3.2 Exe m pl
e

Voici un pe tit e xe m ple d'école illustrant q ue lque s -unes des fonctionnalités du conte ne ur de q ue :

_______________________________________________________________________________
__

#include <iostream.h>
#include <deque>
using namespace std ;
main()
{
342 Program m e r e n langage C+ +
void affiche (deque<char>) ;
char mot[] = {"xyz"} ;
deque<char> pile(mot, mot+3) ; affiche(pile) ;
pile.push_front('a') ; affiche(pile) ;
pile[2] = '+' ;
pile.push_front('b') ;
pile.pop_back() ; affiche(pile) ;
deque<char>::iterator ip ;
ip = find (pile.begin(), pile.end(), 'x') ;
pile.erase(pile.begin(), ip) ; affiche(pile)
;
}
void affiche (deque<char> p)
{ int i ;
for (i=0 ; i<p.size() ; i++) cout << p[i] << " " ;
cout << "\n" ;
} _______________________

x y z
a x y z
b a x +
x +
________________________________________________________________________
_________

Exe m ple d'utilisation de la clas s e deque

4. LE CO NTENEUR LIST

Le conte ne ur list corre s pond au conce pt de liste doublem e nt ch aî né e , ce q ui signifie q u'on y disposera d'un
ité rate ur bidire ctionne lpe rm e ttant de parcourir la liste à l'e ndroit ou à l'e nve rs. Ce tte fois, les ins e rtions ou
suppre s s ions vont s e faire ave c une e fficacité e n O (1), q ue lle q ue s oit leur position, ce q ui constitue l'atout
m aje ur de ce conte ne ur par rapport aux de ux clas s e s pré cédente s ve ctor e t de q ue . En contre partie , le
conte ne ur list ne dispose plus d'un ité rate ur à accè s direct. R appe lons q ue toute s les possibilité s e xpos é e s
dans le paragraph e 1 s'appliq ue nt aux liste s ;nous ne les re pre ndrons donc pas ici.

4.1 A ccè s aux é l


é m e nts e xis tants

Le s conte ne urs ve ctor e t de q ue pe rm e ttaie nt d'accéder aux é lém e nts e xistants de deux m aniè re s : par
ité rate ur ou par indice ;e n fait, ile xistait un lie n e ntre ces deux possibilité s parce q ue les ité rate urs de ce s
clas s e s é taie nt à accè s direct. Le conte ne ur list offre toujours les ité rate urs ite rator e t re ve rs e _ite rator m ais,
ce tte fois, ils sont s e ulem e nt bidire ctionne ls. Si it désigne un te lité rate ur, on pourra toujours consulte r
l'é lém e nt pointé par la valeur de l'e xpre s s ion *it, ou le m odifie r par une affe ctation de la form e :

*it = ... ;

L'ité rate ur it pourra ê tre incré m e nté par + + ou --, m ais ilne s e ra plus possible de l'incré m e nte r d'une
q uantité q ue lconq ue . Ainsi, pour accéder une pre m iè re fois à un é lém e nt d'une liste , il aura fallu
obligatoire m e nt la parcourir de puis son début ou de puis sa fin, é lém e nt par é lém e nt, jus q u'à l'é lém e nt
conce rné e t ce ci, q ue lq ue s oit l'inté rê t q u'on pe ut attach e r aux é lém e nts inte rm édiaire s .

La clas s e list dispose des fonctions front() e t back (), ave c la m ê m e s ignification q ue pour la clas s e de q ue : la
pre m iè re e s t une ré fé re nce au pre m ie r é lém e nt, la s e conde e s t une ré fé re nce au de rnie r é lém e nt :
XIX. Le s conte ne urs séquentie ls 343
list<int> l () ;
.....
if (l.front()=99) l.front=0 ; /* si le premier élément vaut 99, */
/* on lui donne la valeur 0 */

O n ne confondra pas la m odification de l'un de ce s é lém e nts, opé ration q ui ne m odifie pas le nom bre
d'élém e nts de la liste , ave c l'ins e rtion e n début ou e n fin de liste q ui m odifie le nom bre d'élém e nts de la
liste .

4.2 Ins e rtions e t suppre s s ions

Le conte ne ur list dispose des possibilité s gé né rales d'insertion e t de suppression procurées par les fonctions
inse rt e t e ras e e t décrite s au paragraph e 1.4. M ais, ce tte fois, leur e fficacité e s t toujours e n O (1), ce q ui
n'é tait pas le cas, e n gé né ral, des conte ne urs ve ctor e t de q ue . O n dispose égalem e nt des fonctions
spécialisées d'insertion e n début push _front(valeur) ou e n fin push _back (valeur) ou de s uppre s s ion e n début
pop_front() ou e n fin pop_back (), re ncontrées dans les clas s e s ve ctor e t de q ue .

En outre , la clas s e list dispose de fonctions de suppressions conditionne lles q ue ne possédaie nt pas les
conte ne urs précédents :

• suppre s s ion de tous les é lém e nts ayant une valeur donné e ,
• suppre s s ion de s é lém e nts satisfaisant à une condition donné e .

a)Suppre s s ion de s é l
é m e nts de val
e ur donné e
re m ove (valeur) /*supprim e tous é lém e nts é gaux à valeur */
Com m e on pe ut s'y atte ndre , ce tte fonction s e fonde s ur l'opé rate ur == q ui doit donc ê tre défini dans le cas
où les é lém e nts conce rné s s ont des obje ts :

int t[] = {1, 3, 1, 6, 4, 1, 5, 2, 1 }


list<int> li(t, t+9) ; /* li contient : 1, 3, 1, 6, 4, 1, 5, 2, 1
*/
li.remove (1) ; /* li contient maintenant : 3, 6, 4, 5, 2
*/

b)Suppre s s ions de s é l
é m e nts ré pondant à une condition
re m ove _if (prédicat) /*supprim e tous les é lém e nts ré pondant au prédicat */
Ce tte fonction supprim e tous les é lém e nts pour les q ue ls le prédicat unaire fourni e n argum e nt e s t vrai. La
notion de prédicat a é té abordée dans le paragraph e 6 du ch apitre XVIII. Voici un e xe m ple utilisant le
prédicat pair défini ainsi :

bool pair(int n) /* ne pas oublier : #include <functional>


{ return (n%2) ;
}

int t[] = {1, 6, 3, 9, 11, 18, 5 } ;


list<int> li(t, t+7) ; /* li contient : 1, 6, 3, 9, 11, 18, 5 */
li.remove_if(pair) ; /* li contient maintenant : 1, 3, 9, 11, 5 */
344 Program m e r e n langage C+ +
R e m arques

1) La fonction m e m bre re m ove ne fournit aucun ré s ultat, de sorte q u'iln'e s t pas possible de savoir s'il
e xistait des élém e nts ré pondant aux conditions spé cifié e s . Ile s t toujours possible de re courir auparavant à
un algorith m e te lq ue count pour obte nir ce tte inform ation.
2) Il e xiste une fonction m e m bre unique dont la vocation e s t é galem e nt la suppre s s ion d'é lém e nts ;
ce pe ndant, nous vous la pré s e nte rons dans le paragraph e s uivant, consacré à la fonction de tri (sort) car
e lle e s t souve nt utilisée conjointe m e nt ave c la fonction unique .

4.3 O pé rations gl
obal
es

En plus des possibilité s gé né rales offe rte s par l'affe ctation e t la fonction m e m bre assign, décrite s au
paragraph e 1.2, la clas s e list e n offre d'autre s , as s e z originales : tri de s e s é lém e nts ave c suppre s s ion
é ve ntue lle des occurre nce s m ultiples , fusion de deux liste s pré alablem e nt ordonné e s , transfe rt de tout ou
partie d'une liste dans une autre liste de m ê m e type .

a)Tri d'une l
is te
Ile xiste des algorith m es de tri de s é lém e nts d'un conte ne ur, m ais la plupart né ce s s ite nt des ité rate urs à accè s
dire ct. En fait, la clas s e list dispose de sa propre fonction sort, é crite s pé cifiq ue m e nt pour ce type de
conte ne ur e t re lative m e nt e fficace , puis q u'e n O (Log N).

Com m e tout ce q ui touch e à l'ordonnance m e nt d'un conte ne ur, la fonction sort s'appuie s ur une re lation
d'ordre faible s trict, te lle q u'e lle a é té pré s e ntée dans le ch apitre pré cédent. O n pourra utiliser par défaut
l'opé rate ur < , y com pris pour un type clas s e , pour pe u q ue ce tte derniè re l'ait conve nablem e nt défini. O n
aura la possibilité , dans tous les cas, d'im pos e r une re lation de s on ch oix par le biais d'un prédicat binaire
prédéfini ou non.

sort () /*trie la liste conce rné e , e n s'appuyant sur l'opé rate ur < */
list<int> li(...) ; /* on suppose que li contient : 1, 6, 3, 9, 11, 18,
5 */
li.sort () ; /* maintenenant li contient : 1, 3, 5, 6, 9, 11,
18 */

sort (prédicat) /*trie la liste conce rné e , e n s'appuyant sur le prédicat binaire prédicat */
list<int> li(...) ; /* on suppose que li contient : 1, 6, 3, 9, 11, 18,
5 */
li.sort(greater<int>) ; /* maintenenant li contient : 18, 11, 9, 6, 5, 3,
1 */

b)Suppre s s ion de s é l
é m e nts e n doubl
e
La fonction unique pe rm e t d'élim ine r les é lém e nts e n double, à condition de la faire porte r sur une liste
pré alablem e nt trié e . Dans le cas contraire , e lle pe ut fonctionne r m ais, alors, e lle s e conte nte de re m place r
par un s e ulé lém e nt, les s é q ue nces de valeurs cons é cutive s identiq ue s , ce q ui signifie q ue , e n dé finitive , la
liste pourra e ncore conte nir de s valeurs identiq ue s , m ais non consé cutive s .

Com m e on pe ut s'y atte ndre , ce tte fonction s e fonde par dé faut sur l'opé rate ur == pour dé cide r de l'é galité
de deux élém e nts, ce t opé rate ur de vant bien sûr ê tre défini conve nablem e nt e n cas d'élém e nts de type clas s e .
M ais on pourra aussi, dans tous les cas, im pos e r une re lation de com paraison de son ch oix, par le biais d'un
prédicat binaire , prédéfini ou non.
XIX. Le s conte ne urs séquentie ls 345
O n note ra bie n q ue s i l'on appliq ue unique à une liste triée d'é lém e nts de type clas s e , ils e ra pré fé rable
d'assure r la com patibilité e ntre la re lation d'ordre utilisée pour le tri (m ê m e s 'ils'agit de l'opé rate ur < ) e t
le prédicat binaire d'égalité (m ê m e s 'ils'agit de ==). Plus précisém e nt, pour obte nir un fonctionne m e nt
logiq ue de l'algorith m e , ilfaudra q ue les classes d'équivalence induite s par la re lation == soient les m ê m e s
q ue ce lles q ui sont induite s par la re lation d'ordre du tri :

unique () /*ne cons e rve q ue le pre m ie r é lém e nt de valeurs cons é cutive s é gales (==) */
unique (prédicat) /*ne cons e rve q ue le pre m ie r é lém e nt de valeurs cons é cutive s */
/*satisfaisant au prédicat binaire prédicat */
Voici un e xe m ple q ui m ontre claire m e nt la diffé re nce d'effe t obte nu, suivant q ue la liste e s t trié e ou non.

int t[] = {1, 6, 6, 4, 6, 5, 5, 4, 2 } ;


list<int> li1(t, t+9) ; /* li1 contient : 1 6 6 4 6 5 5 4 2 */
list<int> li2=li1 ; /* li2 contient : 1 6 6 4 6 5 5 4 2 */
li1.unique() ; /* li1 contient maintenant : 1 6 4 6 5 4 2 */
li2.sort() ; /* li2 contient maintenant : 1 2 4 4 5 5 6 6 6 */
li2.unique() /* li2 contient maintenant : 1 2 4 5 6 */

c) Fus ion de de ux l
is te s
Bie n q u'ile xiste un algorith m e gé né ralde fusion pouvant s'appliq ue r à deux conte ne urs conve nablem e nt
trié s , la clas s e list dispose d'une fonction m e m bre s pé cialisée généralem e nt légè re m e nt plus perform ante ,
m ê m e s i, dans les deux cas, l'e fficacité e s t e n O (N1+ N2), N1 e t N2 dé s ignant le nom bre d'élém e nts de
ch acune des liste s conce rné e s .

La fonction m e m bre m e rge pe rm e t de ve nir fusionne r une autre liste de m ê m e type ave c la liste conce rné e .
La liste fusionné e e s t vidée de son conte nu. Com m e on pe ut s'y atte ndre , la fonction m e rge s'appuie , com m e
sort, sur une re lation d'ordre faible s trict ;par dé faut, ils'agira de l'opé rate ur < .

m e rge (liste ) /*fusionne liste ave c la liste conce rné e , e n s'appuyant sur l'opé rate ur < */
/*à la fin : liste e s t vide */
m e rge (liste , prédicat) /*fusionne liste ave c la liste conce rné e , e n s'appuyant sur le */
/*prédicat binaire prédicat */
O n note ra q u'e n th é orie , aucune contrainte ne pè s e s ur l'ordonnance m e nt des deux liste s conce rné e s .
Ce pe ndant, la fonction m e rge suppose que les deux liste s s ont trié e s s uivant la m ê m e re lation d'ordre q ue
ce lle q ui e s t utilisée par la fusion. Voici un pre m ie r e xe m ple, dans leq ue lnous avons préalablem e nt trié les
deux liste s :

int t1[] = {1, 6, 3, 9, 11, 18, 5 } ;


int t2[] = {12, 4, 9, 8} ;
list<int> li1(t1, t1+7) ;
list<int> li2(t2, t2+4) ;
li1.sort() ; /* li1 contient : 1 3 5 6 9 11 18
*/
li2.sort() ; /* li2 contient : 4 8 9 12
*/
li1.merge(li2) ; /* li1 contient maintenant : 1 3 4 5 6 8 9 9 11 12 18
*/
/* et li2 est vide
*/

A sim ple titre indicatif, voici le m ê m e e xe m ple, sans tri pré alable des deux liste s :
346 Program m e r e n langage C+ +
int t1[] = {1, 6, 3, 9, 11, 18, 5 } ;
int t2[] = {12, 4, 9, 8} ;
list<int> li1(t1, t1+7) ; /* li1 contient : 1 6 3 9 11 18 5
*/
list<int> li2(t2, t2+4) ; /* li2 contient : 12 4 9 8
*/
li1.merge(li2) ; /* li1 contient maintenant : 1 6 3 9 11 12 4 9 8
18 5 */
/* et li2 est vide
*/

d)Trans fe rt d'une partie de l


is te dans une autre
La fonction splice pe rm e t de déplace r de s é lém e nts d'une autre liste dans la liste conce rné e . O n note ra bie n,
com m e ave c m e rge , les é lém e nts déplacé s s ont supprim és de la liste d'origine e t pas s e ulem e nt copié s .

splice (position, liste _or) /*déplace les é lém e nts de liste _or à l'e m place m e nt position */
char t1[] = {"xyz"}, t2[] = {"abcdef"} ;
list<char> li1(t1, t1+3) ; /* li1 contient : x y z */
list<char> li2(t2, t2+6) ; /* li2 contient : a b c d e f */
list<char>::iterator il ;
il = li1.begin() ; il++ ; /* il pointe sur le deuxième élément de li1 */
li1.splice(il, li2) ; /* li1 contient : x a b c d e f y z */
/* li2 est vide */

splice (position, liste _or, position_or)


/*déplace l'é lém e nt de liste _or pointé par position_or à l'e m place m e nt position */
char t1[] = {"xyz"}, t2[] = {"abcdef"} ;
list<char> li1(t1, t1+3) ; /* li1 contient : x y z */
list<char> li2(t2, t2+6) ; /* li2 contient : a b c d e f */
list<char>::iterator il1=li1.begin() ;
list<char>::iterator il2=li2.end() ; il2-- ; /* pointe sur avant dernier */
li1.splice(il1, li2, il2) ; /* li1 contient : f x y z */
/* li2 contient : a b c d e */

splice (position, liste _or, de but_or, fin_or)


/*déplace l'inte rvalle [de but_or, fin_or) de la liste liste _or à l'e m place m e nt position */
char t1[] = {"xyz"}, t2[] = {"abcdef"} ;
list<char> li1(t1, t1+3) ; /* li1 contient : x y z
*/
list<char> li2(t2, t2+6) ; /* li2 contient : a b c d e f
*/
list<char>::iterator il1=li1.begin() ;
list<char>::iterator il2=li2.begin() ; il2++ ;
li1.splice(il1, li2, il2, li2.end()) ; /* li1 contient : b c d e f x y z
*/
/* li2 contient : a
*/

4.4 Ge s tion de l
'e m pl
ace m e nt m é m oire

La norm e n'im pos e pas e xplicite m e nt la m aniè re de gé re r les e m place m e nts m é m oire alloué s à une liste , pas
plus q u'e lle ne le fait pour les autre s conte ne urs. Ce pe ndant, e lle im pos e à la fois des contraintes d'efficacité
XIX. Le s conte ne urs séquentie ls 347
e t des rè gles d'invalidation de s ité rate urs e t des ré fé re nce s s ur de s é lém e nts d'une liste . Notam m e nt, e lle
pré cis e q u'e n cas d'insertions ou de suppressions d'élém e nts dans une liste , s e uls les ité rate urs ou ré fé re nce s
conce rnant les é lém e nts insérés ou supprim és devie nne nt invalides. Ce la signifie donc q ue les autre s n'ont
pas dû ch ange r de place . Ainsi, indire cte m e nt, la norm e im pos e q ue ch aq ue é lém e nt dispose de son propre
bloc de m é m oire .

D ans ce s conditions, si le conte ne ur list dispose toujours des fonctions d'inform ation size () e t m ax_size (), on
n'y re trouve e n re vanch e aucune fonction pe rm e ttant d'agir sur les allocations, e t e n particulie r capacity e t
re s e rve .

4.5 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant bon nom bre des fonctionnalités de la clas s e list q ue nous
avons e xam inées dans ce paragraph e , ainsi que dans le paragraph e 1.

________________________________________________________________________
_________

#include <iostream.h>
#include <list>
using namespace std ;
main()
{ void affiche(list<char>) ;
char mot[] = {"anticonstitutionnellement"} ;
list<char> lc1 (mot, mot+sizeof(mot)-1) ;
list<char> lc2 ;
cout << "lc1 init : " ; affiche(lc1) ;
cout << "lc2 init : " ; affiche(lc2) ;

list<char>::iterator il1, il2 ;


il2 = lc2.begin() ;
for (il1=lc1.begin() ; il1!=lc1.end() ; il1++)
if (*il1!='t') lc2.push_back(*il1) ; /* equivaut a : lc2=lc1 ;
lc2.remove('t'); */
cout << "lc2 apres : " ; affiche(lc2) ;

lc1.remove('t') ;
cout << "lc1 remove : " ; affiche(lc1) ;
if (lc1==lc2) cout << "les deux listes sont egales\n" ;

lc1.sort() ;
cout << "lc1 sort : " ; affiche(lc1) ;
lc1.unique() ;
cout << "lc1 unique : " ; affiche(lc1) ;
}
void affiche(list<char> lc)
{ list<char>::iterator il ;
for (il=lc.begin() ; il!=lc.end() ; il++) cout << (*il) << " " ;
cout << "\n" ;
} _______________________

lc1 init : a n t i c o n s t i t u t i o n n e l l e m e n t
lc2 init :
lc2 apres : a n i c o n s i u i o n n e l l e m e n
348 Program m e r e n langage C+ +
lc1 remove : a n i c o n s i u i o n n e l l e m e n
les deux listes sont egales
lc1 sort : a c e e e i i i l l m n n n n n o o s u
lc1 unique : a c e i l m n o s u
________________________________________________________________________
_________

Exe m ple d'utilisation de la clas s e list

5. LES A D A PTA TEURS D E CO NTENEUR : QUEUE, STACK ET PRIO RITY_QUEUE

La biblioth è q ue s tandard dispose de trois patrons particulie rs s tack , que ue e t priority_que ue , dits adaptate urs
de conte ne urs. Ils'agit de clas s e s patrons construite s s ur un conte ne ur d'un type donné qui en m odifie nt
l'inte rface , à la fois e n la re s tre ignant e t e n l'adaptant à des fonctionnalités données. Ils disposent tous d'un
constructe ur sans argum e nt.

5.1 L'adaptate ur s tack

Le patron s tack e s t destiné à la ge s tion de piles de type LIFO (Last In, First O ut) ;ilpe ut ê tre construit à
partir de l'un de s trois conte ne urs s é q ue ntie ls ve ctor, de q ue ou list, com m e dans ces déclarations :

stack <int, vector<int> > s1 ; /* pile de int, utilisant un conteneur vector


*/
stack <int, deque<int> > s2 ; /* pile de int, utilisant un conteneur deque
*/
stack <int, list<int> > s3 ; /* pile de int, utilisant un conteneur list
*/

D ans un te lconte ne ur, on ne pe ut q u'introduire (push ) des inform ations q u'on e m pile les une s s ur les autre s
e t q u'on re cue ille, à raison d'une s e ule à la fois, e n e xtrayant la derniè re introduite . O n y trouve uniq ue m e nt
les fonctions m e m bre s uivante s :

• e m pty() : fournit true si la pile e s t vide,


• size () : fournit le nom bre d'élém e nts de la pile,
• top() : accè s à l'inform ation situé e au som m e t de la pile q u'on pe ut connaî
tre ou m odifie r (sans la
supprim e r),
• push (valeur) : place valeur sur la pile,
• pop() : supprim e l'é lém e nt situé au som m e t e n le s upprim ant de la pile.
Voici un pe tit e xe m ple de program m e utilisant une pile :
________________________________________________________________________
_________

#include <iostream.h>
#include <stack>
#include <vector>
using namespace std ;
main()
{
int i ;
XIX. Le s conte ne urs séquentie ls 349
stack<int, vector<int> > q ;
cout << "taille initiale : " << q.size() << "\n" ;
for (i=0 ; i<10 ; i++) q.push(i*i) ;
cout << "taille apres for : " << q.size() << "\n" ;
cout << "sommet de la pile : " << q.top() << "\n" ;
q.top() = 99 ; /* on modifie le sommet de la pile */
cout << "on depile : " ;
for (i=0 ; i<10 ; i++) { cout << q.top() << " " ; q.pop() ; }
}
_______________________
taille initiale : 0
taille apres for : 10
sommet de la pile : 81
on depile : 99 64 49 36 25 16 9 4 1 0
________________________________________________________________________
_________

Exe m ple d'utilisation de l'adaptate ur de conte ne ur s tack

5.2 L'adaptate ur q ue ue

Le patron que ue e s t destiné à la ge s tion de files d'atte nte s , dite s aussi queues, ou encore piles de type FIFO
(First In, First O ut). O n y place des inform ations q u'on introduit e n fin e t q u'on re cue ille e n tê te , dans
l'ordre inve rse de leur introduction. Un te lconte ne ur pe ut ê tre construit à partir de l'un des deux conte ne urs
s é q ue ntie ls de q ue ou list (le conte ne ur ve ctor ne s e rait pas approprié puis q u'ilne dispose pas d'insertions
e fficace s e n début), com m e dans ces déclarations :

queue <int, deque<int> > q1 ; /* queue de int, utilisant un conteneur deque


*/
queue <int, list<int> > q2 ; /* queue de int, utilisant un conteneur list
*/

O n y trouve uniq ue m e nt les fonctions m e m bre s uivante s :

• e m pty() : fournit true si la q ue ue e s t vide,


• size () : fournit le nom bre d'élém e nts de la q ue ue ,
• front() : accè s à l'inform ation situé e e n tê te de la q ue ue , q u'on pe ut ainsi connaî
tre ou m odifie r, sans la
supprim e r,
• back () : accè s à l'inform ation situé e e n fin de la q ue ue , q u'on pe ut ainsi connaî
tre ou m odifie r, sans la
supprim e r,
• push (valeur) : place valeur dans la q ue ue ,
• pop() : fournit l'é lém e nt situé e n tê te de la q ue ue e n le s upprim ant.
Voici un pe tit e xe m ple de program m e utilisant une q ue ue :
________________________________________________________________________
_________

#include <iostream.h>
#include <queue>
#include <deque>
350 Program m e r e n langage C+ +
using namespace std ;
main()
{ int i ;
queue<int, deque<int> > q ;
for (i=0 ; i<10 ; i++) q.push(i*i) ;
cout << "tete de la queue : " << q.front() << "\n" ;
cout << "fin de la queue : " << q.back() << "\n" ;
q.front() = 99 ; /* on modifie la tete de la queue */
q.back() = -99 ; /* on modifie la fin de la queue */
cout << "on depile la queue : " ;
for (i=0 ; i<10 ; i++)
{ cout << q.front() << " " ; q.pop() ;
}
} _______________________

tete de la queue : 0
fin de la queue : 81
on depile la queue : 99 1 4 9 16 25 36 49 64 -99
________________________________________________________________________
_________

Exe m ple d'utilisation de l'adaptate ur de conte ne ur s tack

5.3 L'adaptate ur priority_q ue ue

Un te lconte ne ur re s s e m ble à une file d'atte nte , dans laq ue lle on introduit toujours des élém e nts e n fin ;e n
re vanch e , l'e m place m e nt des élém e nts dans la q ue ue e s t m odifié à ch aq ue introduction, de m aniè re à
re s pe cte r une ce rtaine priorité définie par une re lation d'ordre q u'on pe ut fournir sous form e d'un prédicat
binaire . O n parle parfois de file d'atte nte ave c priorité s . Un te lconte ne ur ne pe ut ê tre construit q u'à partir
d'un conte ne ur de q ue , com m e dans ces déclarations :

priority_queue <int, deque<int> > q1 ;


priority_queue <int, deque<int>, greater<int> > q2 ;

En re vanch e , ici, on pe ut le construire classiquem e nt à partir d'une s é q ue nce .

O n y trouve uniq ue m e nt les fonctions m e m bre s uivante s :

• e m pty() : fournit true si la q ue ue e s t vide ;


• size () : fournit le nom bre d'élém e nts de la q ue ue ;
• push (valeur) : place valeur dans la q ue ue ;
• top() : accè s à l'inform ation situé e e n tê te de la q ue ue q u'on pe ut connaî tre ou, th é oriq ue m e nt m odifie r
(sans la supprim e r) ;actue llem e nt, nous re com m andons de ne pas utiliser la possibilité de m odification
q ui, dans ce rtaine s im plém e ntations, n'assure plus le re s pe ct de l'ordre d e s é lém e nts de la q ue ue ;
• pop() : fournit l'é lém e nt situé e n tê te de la q ue ue e n le s upprim ant.
Voici un pe tit e xe m ple de program m e utilisant une file d'atte nte ave c priorité s :

________________________________________________________________________
_________

#include <iostream.h>
#include <queue>
XIX. Le s conte ne urs séquentie ls 351
#include <deque>

using namespace std ;


main()
{ int i ;
priority_queue <int, deque<int>, greater<int> > q ;
q.push (10) ; q.push(5) ; q.push(12) ; q.push(8) ;
cout << "tete de la queue : " << q.top() << "\n" ;
cout << "on depile : " ;
for (i=0 ; i<4 ; i++) { cout << q.top() << " " ; q.pop() ;
}
} _______________________

tete de la queue : 5
on depile : 5 8 10 12
________________________________________________________________________
_________

Exe m ple d'utilisation de l'adaptate ur de conte ne ur priority_q ue ue


XX. LES CO NTENEURS ASSO CIA TIFS

Com m e ila é té dit dans le ch apitre XVIII, les conte ne urs s e clas s e nt e n de ux caté gorie s : les conte ne urs
s é q ue ntie ls e t les conte ne urs associatifs. Le s conte ne urs s é q ue ntie ls, q ue nous avons é tudiés dans le
pré cédent ch apitre , sont ordonné s s uivant un ordre im pos é e xplicite m e nt par le program m e lui-m ê m e ;on
accè de à un de leurs é lém e nts e n te nant com pte de ce t ordre , q ue l'on utilise un indice ou un ité rate ur.

Le s conte ne urs associatifs ont pour principale vocation de re trouve r une inform ation, non plus e n fonction de
sa place dans le conte ne ur, m ais e n fonction de s a valeur ou d'une partie de sa valeur nom m é e clé. Nous
avons déjà cité l'e xe m ple du répertoire té léph oniq ue , dans leq ue lon re trouve le num é ro de té léph one à partir
d'une clé form ée du nom de la pe rsonne conce rné e . M algré tout, pour de s im ples q ue s tions d'efficacité , un
conte ne ur associatif s e trouve ordonné intrinsè q ue m e nt e n pe rm ane nce , e n s e fondant sur une re lation (par
défaut < ) ch oisie à la construction.

Les deux conte ne urs associatifs les plus im portants sont m ap e t m ultim ap. Ils corre s ponde nt pleine m e nt au
conce pt de conte ne ur associatif, e n associant une clé e t une valeur. M ais, alors q ue m ap im pos e l'unicité des
clés , autre m e nt dit l'abs e nce de deux élém e nts ayant la m ê m e clé, m ultim ap ne l'im pos e pas e t on pourra y
trouve r plusieurs élém e nts de m ê m e clé q ui apparaî tront alors cons é cutive m e nt. Si l'on re pre nd notre
e xe m ple de ré pe rtoire té léph oniq ue , on pe ut dire q ue m ultim ap autoris e la pré s e nce de plusieurs personnes
de m ê m e nom (ave c des num é ros associés diffé re nts ou non), tandis q ue m ap ne l'autoris e pas. Ce tte
distinction pe rm e t pré cis é m e nt de redéfinir l'opé rate ur [ ] sur un conte ne ur de type m ap. Par e xe m ple, ave c
un conte ne ur nom m é annuaire , dans leq ue lles clés s ont des ch aî ne s , on pourra utiliser l'e xpre s s ion annuaire
["Dupont"] pour dé s igne r l'é lém e nt corre s pondant à la clé "Dupont" ; ce tte possibilité n'e xiste ra
nature llem e nt plus ave c m ultim ap.

Ile xiste deux autre s conte ne urs q ui corre s ponde nt à des cas particulie rs de m ap e t m ultim ap, dans le cas où
la valeur associé e à la clé n'e xiste plus, ce q ui re vie nt à dire q ue les é lém e nts s e lim ite nt à la s e ule clé. Dans
ce s conditions, la notion d'association e ntre une clé e t une valeur disparaî t e t ilne re s te plus q ue la notion
d'apparte nance . Ce s conte ne urs s e nom m e nt s e t e t m ultise t e t l'on ve rra q u'e ffe ctive m e nt ils perm e ttront de
re pré s e nte r de s e ns e m bles au s e ns m ath é m atiq ue , à condition toute fois de disposer, com m e pour tout
conte ne ur associatif, d'une re lation d'ordre approprié e s ur les é lém e nts, ce q ui n'e s t pas néce s s aire e n
m ath é m atiq ue s ;e n outre m ultise t autoris e ra la pré s e nce de plusieurs élém e nts identiq ue s , ce q ui n'e s t
m anife s te m e nt pas le cas d'un ensem ble usuel.
XX. Le s conte ne urs associatifs 353
1. LE CO NTENEUR M A P

Le conte ne ur m ap e s t donc form é d'élém e nts com posés de deux partie s : une clé e t une valeur. Pour
re pré s e nte r de te ls é lém e nts, ile xiste un patron de clas s e approprié , nom m é pair, param é tré par le type de la
clé e t par ce lui de la valeur. Un conte ne ur m ap pe rm e t d'accéder rapide m e nt à la valeur associé e à une clé
e n utilisant l'opé rate ur [] ;l'e fficacité de l'opé ration e s t e n O (N Log N). Com m e un te lconte ne ur e s t
ordonné e n pe rm ane nce , ce la suppose le re cours à une re lation d'ordre q ui, com m e à l'accoutum é e , doit
posséder les proprié tés d'une relation d'ordre faible s trict, te lles q u'e lles ont é té pré s e nté e s au ch apitre
XVIII.

Com m e la notion de tableau associatif e s t m oins connue q ue ce lle de tableau, de ve cte ur ou m ê m e q ue ce lle
de liste , nous com m e nce rons par un e xe m ple introductif d'utilisation d'un conte ne ur de type m ap avant d'en
é tudie r les proprié té s e n dé tail.

1.1 Exe m pl
e introductif

Une déclaration te lle q ue :

map<char, int> m ;

cré e un conte ne ur de type m ap, dans leq ue lles clés s ont de type ch ar e t les valeurs associé e s d e type int.
Pour l'instant, ce conte ne ur e s t vide : m .size () vaut 0.

Une instruction te lle q ue :

m['S'] = 5 ;

insè re , dans le conte ne ur m , un é lém e nt form é de l'association de la clé 'S' e t de la valeur 5. O n voit déjà là
une diffé re nce fondam e ntale e ntre un ve cte ur e t un conte ne ur de type m ap : dans un ve cte ur, on ne pe ut
accéder par l'opé rate ur [ ] q u'aux é lém e nts e xistants e t, e n aucun cas, e n ins é re r de nouve aux.

Qui plus e s t, si l'on ch e rch e à utiliser une valeur associé e à une clé ine xistante , com m e dans :

cout << "valeur associée a la clé 'X' : ", m['X'] ;

le s im ple fait de ch e rch e r à consulte r m ['X'] cré e ra l'é lém e nt corre s pondant, e n initialisant la valeur associé e
à 0.

Pour affich e r tous les é lém e nts d'un m ap te lq ue m , on pourra le parcourir ave c un ité rate ur bidire ctionne l
classique ite rator fourni par la clas s e m ap. Ce ci n'e s t possible q ue parce q ue , com m e nous l'avons dit à
plusieurs reprises, les conte ne urs associatifs sont ordonné s intrinsè q ue m e nt. O n pourra classiquem e nt
parcourir tous les é lém e nts de m par l'un des deux sch é m as suivants :

map<char, int> ::iterator im ; /* itérateur sur un map<char,int> */


.....
for (im=m.begin() ; im!=m.end() ; im++) /* im parcourt tout le map m */
{ /* ici *im désigne l'élément courant de m */
}

map<char, int> ::reverse_iterator im ; /* itérateur inverse sur un


map<char,int> */
.....
for (im=m.rbegin() ; im!=m.rend() ; im++) /* im parcourt tout le map m */
354 Program m e r e n langage C+ +
{ /* ici *im désigne l'élément courant de m */
}

Ce pe ndant, on constate q u'une pe tite difficulté apparaî t : *im désigne bien l'é lém e nt courant de m , m ais, la
plupart du te m ps, on aura be s oin d'accéder s é paré m e nt à la clé e t à la valeur corre s pondante . En fait, les
é lém e nts d'un conte ne ur m ap sont d'un type clas s e particulie r, nom m é pair, q ui dispose de deux m e m bre s
publics :

• firs t corre s pondant à la clé,


• s e cond corre s pondant à la valeur associé e .
En dé finitive , voici, par e xe m ple, com m e nt affich e r, suivant l'ordre nature l, toute s les valeurs de m sous la
form e (clé, valeur) :

for (im=m.begin() ; im!=m.end() ; im++)


cout << "(" << (*im).first << "," << (*im).second << ") " ;

Voici un pe tit program m e com plet re pre nant les diffé re nts points q ue nous ve nons d'exam ine r (atte ntion, la
position re lative de la clé 'c' pe ut dépendre de l'im plém e ntation) :

________________________________________________________________________
_________
#include <iostream.h>
#include <map>
using namespace std ;
main()
{ void affiche (map<char, int>) ;
map<char, int> m ;
cout << "map initial : " ; affiche(m) ;
m['S'] = 5 ; /* la cle S n'existe pas encore, l'element est cree */
m['C'] = 12 ; /* idem */
cout << "map SC : " ; affiche(m) ;
cout << "valeur associee a la cle 'S' : " << m['S'] << "\n" ;
cout << "valeur associee a la cle 'X' : " << m['X'] << "\n" ;
cout << "map X : " ; affiche(m) ;
m['S'] = m['c'] ; /* on a utilise m['c'] au lieu de m['C'] ; */
/* la cle 'c' est creee */
cout << "map final : " ; affiche(m) ;
}
void affiche (map<char, int> m)
{ map<char, int> ::iterator im ;
for (im=m.begin() ; im!=m.end() ; im++)
cout << "(" << (*im).first << "," << (*im).second << ") " ;
cout << "\n" ;
} _______________________

map initial :
map SC : (C,12) (S,5)
valeur associee a la cle 'S' : 5
valeur associee a la cle 'X' : 0
map X : (C,12) (S,5) (X,0)
map final : (C,12) (S,0) (X,0) (c,0)
________________________________________________________________________
_________

Exe m ple introductif d'utilisation d'un conte ne ur m ap


XX. Le s conte ne urs associatifs 355

1.2 Le patron de cl
as s e s pair

Com m e nous ve nons de le voir, ile xiste un patron de clas s e pair, com portant deux param è tres de type e t
pe rm e ttant de re groupe r dans un obje t deux valeurs. O n y trouve un constructe ur à deux argum e nts :

pair <int, float> p(3, 1.25) ; /* crée une paire formée d'un int de valeur 3
*/
/* et d'un float de valeur 1.25
*/

Pour affe cte r de s valeurs données à une te lle paire , on pe ut th é oriq ue m e nt procéder com m e dans :

p = pair<int,float> (4, 3.35) ; /* ici, les arguments peuvent être d'un type
*/
/* compatible par affectation avec celui
attendu */

M ais les ch os e s s ont un pe u plus sim ples s i l'on fait appe là une fonction standard m ak e _pair :

p = make_pair (4, 3.35f) ; /* attention : 3.35f car le type des arguments


*/
/* sert à instancier la fonction patron make_pair
*/

Com m e on l'a vu dans notre e xe m ple introductif, la clas s e pair dispose de deux m e m bre s publics nom m é s
firs t e t s e cond. Ainsi, l'instruction pré cédente pourrait é galem e nt s'é crire :

p.first = 4 ; p.second = 3.35 ; /* ici 3.35 de type double sera converti en


float */

La clas s e pair dispose des deux opérate urs == e t < . Le s e cond corre s pond à une com paraison
lexicograph iq ue , c’e s t-à -dire q u'ilappliq ue d'abord < à la clé, puis à la valeur. Bie n e nte ndu, dans le cas
où l'un de s é lém e nts au m oins de la paire e s t de type clas s e , ce s opé rate urs doive nt ê tre conve nablem e nt
surdéfinis.

1.3 Cons truction d'un conte ne ur de type m ap

Le s possibilités de construction d'un te lconte ne ur sont beaucoup plus re s tre inte s q ue pour les conte ne urs
s é q ue ntie ls ;e lles s e lim ite nt à trois possibilité s :

• construction d'un conte ne ur vide (com m e dans notre e xe m ple du paragraph e 1.1) ;
• construction à partir d'un autre conte ne ur de m ê m e type ;
• construction à partir d'une s é q ue nce .
En outre , ile s t possible de ch oisir la re lation d'ordre q ui s e ra utilisée pour ordonner intrinsè q ue m e nt le
conte ne ur. Pour plus de clarté , nous e xam ine rons ce point à part.
356 Program m e r e n langage C+ +
a)Cons tructions util
is ant l
a re l
ation d'ordre par dé faut
Construction d'un conteneur vide

O n s e conte nte de pré cis e r les type s voulus pour la clé e t pour la valeur, com m e dans ce s e xe m ples (on
suppose que point e s t un type clas s e ) :

map <int, long> m1 ; /* clés de type int, valeurs associées de type


long */
map <char, point> m2 ; /* clés de type char, valeurs associées de type
point */
map <string, long> repert ; /* clés de type string, valeurs associées de type
long */

Construction à partir d'un autre conteneur de m ê m e type

Ils'agit d'un classique constructe ur par re copie q ui, com m e on pe ut s'y atte ndre , appe lle le constructe ur par
re copie d e s é lém e nts conce rné s lors q u'ils'agit d'obje ts.

map <int, long> m1 ;


.....
map <int, long> m2(m1) ; /* ou encore : map <int, long> m2 = m1 ; */

Construction à partir d'une séquence

Ils'agit d'une possibilité déjà re ncontré e pour les conte ne urs s é q ue ntie ls, ave c ce pe ndant une diffé re nce
im portante : les é lém e nts conce rnés doive nt ê tre de type pair< type _de s _clés , type _de s _valeurs> . Par
e xe m ple, s'ile xiste une liste lr, construite ainsi :

list<pair<char, long> > lr (...) ;

e t conve nablem e nt re m plie , on pourra l'utiliser en partie ou e n totalité pour construire :

map <char, long> repert (lr.begin(), lr.end() ) ;

En pratiq ue , ce type de construction e s t pe u utilisé.

b)Ch oix de l
'ordre intrins è q ue du conte ne ur
Com m e on l'a dé jà dit, les conte ne urs sont intrinsè q ue m e nt ordonné s e n faisant appe là une re lation d'ordre
faible s trict pour ordonne r conve nablem e nt les clés . Par défaut, on utilise la re lation < , q u'ils'agisse de la
re lation prédéfinie pour les type s s calaire s ou s tring, ou d'une s urdé finition de l'opé rate ur > lors q ue les clés
sont des obje ts.

Ile s t possible d'im pos e r à un conte ne ur d'ê tre ordonné e n utilisant une autre re lation q ue l'on fournit sous
form e d'un prédicat binaire prédéfini (com m e les s < int> ) ou non. D ans ce dernie r cas, il e s t alors
né ce s s aire de fournir un type e t non pas un nom de fonction, ce q ui signifie q u'ile s t né ce s s aire de re courir à
une clas s e fonction (dont nous avons parlé au ch apitre XVII). Voici q ue lque s e xe m ples :

map <char, long, greater<char> > m1 ; /* les clés seront ordonnées par
valeurs */
/* décroissantes - attention > > et non
>> */
map <char, long, greater<char> > m2(m1) ; /* si m2 n'est pas ordonné par la
même */
XX. Le s conte ne urs associatifs 357
/* relation à erreur de compilation
*/

class mon_ordre
{ .....
public :
bool operator () (int n, int p) { ..... } /* ordre faible strict */
} ;
map <int, float, mon_ordre> m_perso ; /* clés ordonnées par le prédicat
mon_ordre */
/* qui doit être une classe fonction
*/

R e m arque

Ce rtaine s im plém e ntations peuve nt ne pas acce pte r le ch oix d'une valeur par dé faut pour la re lation
d'ordre des clés . Dans ce cas, ilfaut toujours préciser les s < type > com m e troisiè m e argum e nt, type
corre s pondant au type des clés pour instancie r conve nablem e nt le conte ne ur. La lourde ur de s notations
q ui e n dé coule pe ut parfois incite r à re courir à l'instruction type de f.

c)Pour connaî
tre l
a re l
ation d'ordre util
is é e par un conte ne ur
Le s clas s e s m ap disposent d'une fonction m e m bre k e y_com p() fournissant la fonction utilisée pour ordonner
les clés . Par e xe m ple, ave c le conte ne ur de notre e xe m ple introductif :

map<char, int> m ;

on pe ut, ce rte s , com pare r de ux clés de type ch ar de façon dire cte , com m e dans :

if ('a' < 'c') .....

m ais, on obtie ndra le m ê m e ré s ultat ave c :

if m.key_comp() ('a', 'c') ..... /* notez bien key_comp() (....) */

Ce rte s , tant q ue l'on s e conte nte d'ordonne r de te ls conte ne urs e n utilisant la re lation d'ordre par dé faut, ce ci
ne pré s e nte guè re d'inté rê t ;dans le cas contraire , ce la pe ut é vite r d'avoir à se dem ande r, à ch aq ue fois
q u'on com pare des clés , q ue lle re lation d'ordre a é té utilisée lors de la construction.

D 'une m aniè re s im ilaire , la clas s e m ap dispose d'une fonction m e m bre value _com p() fournissant la fonction
utilisable pour com pare r de ux é lém e nts, toujours s e lon la valeur de s clés . L'inté rê t de ce tte fonction e s t de
pe rm e ttre de com pare r de ux é lém e nts (donc, de ux paire s ), suivant l'ordre des clés , sans avoir à e n e xtraire
les m e m bre s firs t. O n note ra bie n q ue , contraire m e nt à k e y_com p, ce tte fonction n'e s t jam ais ch oisie
libre m e nt, e lle e s t sim plem e nt déduite de k e y_com p. Par e xe m ple, ave c :

map <char, int> m ;


map <char, int>::iterator im1, im2 ;

on pourra com pare r les clés re lative s aux é lém e nts pointé s par im 1 e t im 2 de ce tte m aniè re :

if ( value_comp() (*im1, *im2) ) .....

Ave c k e y_com p, ilaurait fallu procéder ainsi :

if ( key_comp() ( (*im1).first, (*im2).first) ) .....


358 Program m e r e n langage C+ +
d)Cons é q ue nce s du ch oix de l
'ordre d'un conte ne ur
Tant q ue l'on utilise des clés de type s calaire ou s tring e t q u'on s e lim ite à la re lation par dé faut (<), aucun
problèm e particulie r ne s e pos e . Iln'e n va plus néce s s aire m e nt de m ê m e dans les autre s cas.

Par e xe m ple, on dit gé né ralem e nt q ue , dans un conte ne ur de type m ap, les clés s ont uniq ue s . En fait, pour
ê tre plus précis, ilfaudrait dire q u'un nouve lé lém e nt n'e s t introduit dans un te lconte ne ur q ue s 'iln'e xiste
pas d'autre é lém e nt possédant une clé é q uivalente ;l'é q uivalence é tant ce lle q ui e s t induite par la re lation
d'ordre , te lq u'ila é té e xpliq ué dans le paragraph e 7.2 du ch apitre XVIII. Par e xe m ple, considérons un m ap
utilisant com m e clé des obje ts de type point e t supposons q ue la re lation < ait é té définie dans la clas s e
point e n s'appuyant uniq ue m e nt sur les abscisses des points ;dans ce s conditions, les clés corre s pondant à
des points de m ê m e abscis s e apparaî tront com m e é q uivalente s .

D e plus, com m e on aura l'occasion de le voir plus loin, la re ch e rch e d'un élém e nt de clé donnée se fonde ra,
non pas sur une h ypoth é tiq ue re lation d'é galité , m ais bele t bien sur la re lation d'ordre utilisée pour
ordonne r le conte ne ur. Autre m e nt dit, toujours ave c notre e xe m ple de points utilisés en guise de clés , on
pourra re ch e rch e r la clé (1, 9 ) e t trouve r la clé (1, 5).

1.4 A ccè s aux é l


é m e nts

Com m e tout conte ne ur, m ap pe rm e t th é oriq ue m e nt d'accéder aux é lém e nts e xistants, soit pour e n connaître
la valeur, soit pour la m odifie r. Ce pe ndant, par rapport aux conte ne urs s é q ue ntie ls, ce s opé rations prennent
un tour un pe u particulie r lié à la nature m ê m e des conte ne urs associatifs. En e ffe t, d'une part, une te ntative
d'accè s à une clé ine xistante am è ne à la cré ation d'un nouve lé lém e nt, d'autre part, com m e on le ve rra un
pe u plus loin, une te ntative de m odification globale (clé + valeur) d'un é lém e nt e xistant s e ra forte m e nt
décons e illée .

a)A ccè s par l


'opé rate ur [ ]
Le paragraph e 1 a dé jà m ontré e n q uoi ce t accè s par l'opé rate ur e s t am bigu puisq u'ilpe ut conduire à la
cré ation d'un nouve l é lém e nt, dè s lors q u'on l'appliq ue à une clé ine xistante e t ce la, aussi bien en
consultation q u'e n m odification. Par e xe m ple :

map<char, int> m ;
.....
m ['S'] = 2 ; /* si la clé 'S' n'existe pas, on crée l'élément make_pair ('S',
2) */
/* si la clé existe, on modifie la valeur de l'élément qui ne change pas de
place */
... = m['T'] ; /* si la clé 'T' n'existe pas, on crée l'élément make_pair ('T',
0) */

b)A ccè s par ité rate ur


Com m e on pe ut s'y atte ndre e t com m e on l'a dé jà fait dans les e xe m ples pré cédents, si it e s t un ité rate ur
valide sur un conte ne ur de type m ap, l'e xpre s s ion *it désigne l'é lém e nt corre s pondant ;rappe lons q u'ils'agit
d'une paire form é e d e la clé (*it).firs t e t de la valeur associé e (*it).s e cond ;e n gé né ral, d'ailleurs, on s e ra
plutôt am e né à s'inté re s s e r à ces deux de rniè re s valeurs (ou à l'une d'entre e lles ) plutôt q u'à la paire
com plète *it.

En th é orie , iln'e s t pas inte rdit de m odifie r la valeur de l'é lém e nt désigné par it ;par e xe m ple, pour un
conte ne ur de type m ap< ch ar, int> , on pourrait é crire :
XX. Le s conte ne urs associatifs 359
*it = make_pair ('R', 5) ; /* remplace théoriquement l'élément désigné par
ip */
/* fortement déconseillé en pratique
*/

M ais le rôle e xact d'un te lle opé ration n'e s t actue llem e nt pas totalem e nt spécifié par la norm e . O r, ce rtaine s
am biguïté s apparais s e nt. En e ffe t, d'une part, com m e une te lle opé ration m odifie la valeur de la clé, le
nouve lé lém e nt ris q ue de ne plus ê tre à sa place ;ildevrait donc ê tre déplacé ;d'autre part, q ue doit-ils e
pas s e r si la clé 'R ' e xiste déjà ? La s e ule dém arch e raisonnable nous s e m ble ê tre de dire qu'une te lle
m odification de vrait ê tre é q uivalente à une destruction de l'é lém e nt désigné par it, suivie d'une insertion du
nouve lé lém e nt. En pratiq ue , ce n'e s t pas ce q ue l'on constate dans toute s les im plém e ntations actue lles .
D ans ce s conditions :

Ilest fortem ent d é conseil


lé d e m odifier l
a val
eur d'un él
é m ent d'un m ap, par l
e biais d'un itérateur.

c)Re ch e rch e par l


a fonction m e m bre find
La fonction m e m bre

find (clé)
a un rôle nature l: fournir un ité rate ur sur un é lém e nt ayant une clé donnée (ou une clé é q uivalente au s e ns
de la re lation d'ordre utilisée par le conte ne ur). Si aucun é lém e nt n'e s t trouvé , ce tte fonction fournit la
valeur e nd().

R e m arque

Atte ntion, la fonction find ne se bas e pas sur l'opé rate ur == ;ce tte re m arq ue e s t surtout s e nsible lors q ue
l'on a affaire à des élém e nts de type clas s e , classe dans laq ue lle on a surdéfini l'opé rate ur == de
m aniè re incom patible ave c le prédicat binaire utilisé pour ordonne r le conte ne ur. Le s ré s ultats peuve nt
alors ê tre déconce rtants.

1.5 Ins e rtions e t suppre s s ions

Com m e on pe ut s'y atte ndre , le conte ne ur m ap offre des possibilités de m odifications dynam iq ue s fondé e s
sur des insertions e t des suppressions, analogue s à ce lles q ui sont offe rte s par les conte ne urs s é q ue ntie ls.
Toute fois, si la notion de s uppre s s ion d'un é lém e nt désigné par un ité rate ur cons e rve la m ê m e s ignification,
ce lle d'insertion à un e m place m e nt donné n'a plus guè re de raison d'ê tre puis q u'on ne pe ut plus agir sur la
m aniè re dont sont intrinsè q ue m e nt ordonné s les é lém e nts d'un conte ne ur associatif. O n ve rra q u'ile xiste
q uand m ê m e une fonction d'inse rtion re ce vant un te largum e nt m ais q ue ce dernie r a e n fait un rôle un pe u
particulie r.

En outre , alors q u'une ins e rtion dans un conte ne ur s é q ue ntie laboutissait toujours, dans le cas d'un conte ne ur
de type m ap, e lle n'aboutit q ue s 'iln'e xiste pas d'élém e nt de clé é q uivalente .

D 'une m aniè re gé né rale, l'e fficacité de ce s opé rations e s t e n O (Log N). Nous apporte rons q ue lque s
pré cisions par la suite pour ch acune des opé rations.

a)Ins e rtions
La fonction m e m bre inse rt pe rm e t d'insérer :

• un é lém e nt de valeur donné e :


360 Program m e r e n langage C+ +
inse rt (é lém e nt) /*insè re la paire é lém e nt */
• les é lém e nts d'un inte rvalle :
inse rt (début, fin) /*insè re les paires de la s é q ue nce [début, fin) */
O n note ra bie n, dans les deux cas, q ue les é lém e nts conce rnés doive nt ê tre des paires d'un type approprié .

L'e fficacité de la pre m iè re fonction e s t e n O (Log N) ;ce lle de la s e conde e s t e n O (Log(N+ M )), M
désignant le nom bre d'élém e nts de l'inte rvalle. Toute fois, si ce t inte rvalle e s t trié s uivant l'ordre voulu,
l'e fficacité e s t e n O (M ).

Voici q ue lque s e xe m ples :

map<int, float> m1, m2 ;


map<int, float>::iterator im1 ;
.....
m1.insert (make_pair(5, 6.25f)) ; /* tentative d'insertion d'un élément
*/
m1.insert (m2.begin(), m2.end()) ; /* tentative d'insertion d'une séquence
*/

R e m arques

1) En toute rigue ur, ile xiste une troisiè m e ve rsion de inse rt, de la form e :
inse rt (paire , position)
L'ité rate ur position e s t une s ugge s tion q ui e s t faite pour facilite r la re ch e rch e de l'e m place m e nt e xact
d'insertion. Si la valeur fournie corre s pond e xacte m e nt au point d'insertion, on obtie nt alors une
e fficacité e n O (1), ce q ui s'e xpliq ue par le fait q ue la fonction n'a be s oin q ue de com pare r de ux valeurs
cons é cutive s .
2) Les deux fonctions d'insertion d'un é lém e nt fournis s e nt une valeur de re tour q ui e s t une paire de la form e
pair(position, indic), dans laq ue lle le boolée n indic pré cis e s i l'ins e rtion a e u lie u e t position e s t
l'ité rate ur corre s pondant ;on note ra q ue s on utilisation e s t as s e z laborie us e ;voici, par e xe m ple,
com m e nt adapte r notre pré cédent e xe m ple dans ce s e ns :
if(m1.insert(make_pair(5, 6.25f)).second) cout << "insertion effectuée\n"
;
else cout << "élément existant\n" ;

Et e ncore , ici, nous n'avons pas ch e rch é à place r la valeur de re tour dans une variable. Si nous avions
voulu le faire , ilaurait fallu dé clare r une variable, par e xe m ple re s ul, d'un type pair approprié ;de plus,
com m e pair ne dispose pas de constructe ur par dé faut, ilaurait fallu pré cis e r de s argum e nts fictifs ;voici
une déclaration possible :
pair<map<int,float>::iterator, bool> resul(m1.end(),false) ;

D ans les im plém e ntations q ui n'acce pte nt pas la valeur les s < type > par dé faut, les ch os e s s e raie nt
e ncore un pe u plus com plexe s e t ils e rait probablem e nt plus sage de re courir à des définitions de type s
synonym e s (type de f ) pour allége r q ue lque pe u l'é criture .

b)Suppre s s ions
La fonction e ras e pe rm e t de supprim e r :

• un é lém e nt de position donné e :


XX. Le s conte ne urs associatifs 361
e ras e (position) /*supprim e l'é lém e nt désigné par position */
• les é lém e nts d'un inte rvalle :
e ras e (début, fin) /*supprim e les paires de l'inte rvalle [début, fin) */
• l'é lém e nt de clé donnée :
e ras e (clé) /*supprim e les é lém e nts 1 de clé é q uivalente à clé */
En voici q ue lque s e xe m ples :
map<int, float> m ;
map<int, float>::iterator im1, im2 ;
.....
m.erase (5) ; /* supprime l'élément de clé 5 s'il existe
*/
m.erase (im1) ; /* supprime l'élément désigné par im1
*/
m.erase (im2, m.end()) ; /* supprime tous les éléments de celui désigné par
im2 */
/* jusqu'à la fin du conteneur m
*/

Enfin, de façon fort classique, la fonction clear() vide le conte ne ur de tout son conte nu.

R e m arque

Ilpe ut arrive r q ue l'on souh aite s upprim e r tous les é lém e nts dont la clé appartie nt à un inte rvalle donné.
D ans ce cas, on pourra avoir re cours aux fonctions low e r_bound e t uppe r_bound pré s e ntées dans le
paragraph e 2.

1.6 Ge s tion m é m oire

Contraire m e nt à ce q ui s e pas s e pour ce rtains conte ne urs s é q ue ntie ls, les opé rations sur les conte ne urs
associatifs, donc, e n particulie r, sur m ap, n'e ntraî ne nt jam ais d'invalidation de s ré fé re nce s e t des ité rate urs,
e xce pté , bie n e nte ndu, pour les é lém e nts supprim é s q ui ne s ont plus acce s s ibles aprè s leur de s truction.

Toute fois, com m e on l'a indiq ué dans le paragraph e 1.4, ile s t th é oriq ue m e nt possible, bie n q ue forte m e nt
décons e illé, de m odifie r globalem e nt un é lém e nt de position donné e ;par e xe m ple (iv désignant un ité rate ur
valide sur un conte ne ur de type m ap< ch ar, int> ) :

*iv = make_pair ('S', 45) ;

Que la clé 'S' soit pré s e nte ou non, on court, outre les ris q ues déjà é voq ué s , ce lui q ue l'ité rate ur iv devie nne
invalide.

1.7 Autre s pos s ibil


ité s

Le s m anipulations globales des conte ne urs m ap s e lim ite nt à la s e ule affe ctation e t à la fonction s w ap
pe rm e ttant d'éch ange r les conte nus de deux conte ne urs de m ê m e type . Iln'e xiste pas de fonction assign, ni
de possibilités de com paraisons lexicograph iq ue s auxq ue lles ils e rait difficile de donner une signification ;e n
e ffe t, d'une part, les é lém e nts sont des paire s , d'autre part, un te lconte ne ur e s t ordonné intrinsè q ue m e nt e t
son organisation é volue e n pe rm ane nce .

1 - Pour m ap, ily en aura un au pl


us ;pour m ultim ap, on pourra e n trouve r pl
usieurs.
362 Program m e r e n langage C+ +
En th é orie , ile xiste des fonctions m e m bre low e r_bound, uppe r_bound, e q ual_range e t count q ui sont
utilisables aussi bien ave c des conte ne urs de type m ap q u'ave c des conte ne urs de type m ultim ap. C'e s t
ce pe ndant dans ce dernie r cas q u'e lles pré s e nte nt le plus d'inté rê t ;e lles s e ront é tudiées dans le paragraph e
2.

1.8 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant les principales fonctionnalités de la clas s e m ap q ue nous
ve nons d'exam ine r.

_______________________________________________________________________________
__

#include <iostream.h>
#include <map>
using namespace std ;
main()
{ void affiche(map<char, int>) ;
map<char, int> m ;
map<char, int>::iterator im ;
m['c'] = 10 ; m['f'] = 20 ; m['x'] = 30 ; m['p'] = 40 ;
cout << "map initial : " ; affiche(m) ;
im = m.find ('f') ; /* ici, on ne verifie pas que im est !=
m.end() */
cout << "cle 'f' avant insert : " << (*im).first << "\n" ;
m.insert (make_pair('a', 5)) ; /* on insere un element avant 'f' */
m.insert (make_pair('t', 7)) ; /* et un element apres 'f' */
cout << "map apres insert : " ; affiche(m) ;
cout << "cle 'f' apres insert : " << (*im).first << "\n" ; /* im à 'f' */
m.erase('c') ;
cout << "map apres erase 'c' : " ; affiche(m) ;
im = m.find('p') ; if (im != m.end()) m.erase(im, m.end()) ;
cout << "map apres erase int : " ; affiche(m) ;
}
void affiche(map<char, int> m)
{ map<char, int>::iterator im ;
for (im=m.begin() ; im!=m.end() ; im++)
cout << "(" << (*im).first << "," << (*im).second << ") " ;
cout << "\n" ;
} _______________________

map initial : (c,10) (f,20) (p,40) (x,30)


cle 'f' avant insert : f
map apres insert : (a,5) (c,10) (f,20) (p,40) (t,7) (x,30)
cle 'f' apres insert : f
map apres erase 'c' : (a,5) (f,20) (p,40) (t,7) (x,30)
map apres erase int : (a,5) (f,20)
________________________________________________________________________
_________

Exe m ple d'utilisation de la clas s e m ap


XX. Le s conte ne urs associatifs 363
2. LE CO NTENEUR M ULTIM A P

2.1 Pré s e ntation gé né ral


e

Com m e nous l'avons déjà dit, dans un conte ne ur de type m ultim ap, une m ê m e clé pe ut apparaî tre plusieurs
fois ou, plus généralem e nt, on pe ut trouve r plusieurs clés é q uivalente s . Bie n e nte ndu, les é lém e nts
corre s pondants apparais s e nt alors cons é cutifs. Com m e on pe ut s'y atte ndre , l'opé rate ur [ ] n'e s t plus
applicable à un te lconte ne ur, com pte te nu de l'am biguïté q u'induirait la non-unicité des clés . H orm is ce tte
re s triction, les possibilités des conte ne urs m ap s e gé né ralisent sans difficulté s aux conte ne urs m ultim ap q ui
possè dent les m ê m e s fonctions m e m bre , ave c q ue lque s nuance s q ui vont de soi :

• s'ile xiste plusieurs clés é q uivalente s , la fonction m e m bre find fournit un ité rate ur sur un de s é lém e nts
ayant la clé voulue ;atte ntion, on ne pré cis e pas q u'ils'agit du pre m ie r ;ce lui-ci pe ut ce pe ndant ê tre
connu e n re courant à la fonction low e r_bound e xam iné e un pe u plus loin ;
• la fonction m e m bre e ras e (clé) pe ut supprim e r plusieurs élém e nts tandis q u'ave c un conte ne ur m ap, e lle
n'e n supprim ait q u'un s e ulau m axim um .
D 'autre part, com m e nous l'avons déjà fait re m arq ue r, un ce rtain nom bre de fonctions m e m bre de la clas s e
m ap, pre nne nt tout leur inté rê t lors q u'on les appliq ue à un conte ne ur m ultim ap. O n pe ut, e n e ffe t :

• connaî
tre le nom bre d'élém e nts ayant une clé é q uivalente à une clé donnée, à l'aide de count (clé) ;
• obte nir de s inform ations conce rnant l'inte rvalle d'élém e nts ayant une clé é q uivalente à une clé donnée, à
savoir :
low e r_bound (clé) /*fournit un ité rate ur sur le pre m ie r é lém e nt ayant une clé */
/*é q uivalente à clé */
uppe r__bound (clé) /*fournit un ité rate ur sur le dernie r é lém e nt ayant une clé */
/*é q uivalente à clé */
e q ual_range (clé) /*fournit une paire form é e d e s valeurs des deux ité rate urs */
/*pré cédents, low e r_bound (clé) e t uppe r_bound (clé) */
O n note ra q u'on a la re lation :
m .e q ual.range (clé) = m ak e _pair (m .low e r_bound (clé), m .uppe r_bound (clé) )
Voici un pe tit e xe m ple :

multimap<char, int> m ;
.....
m.erase(m.lower_bound('c'), m.upper_bound('c')); /* équivalent tout simplement
à : */
/* erase('c') ;
*/
m.erase(m.lower_bound('e'), m.upper_bound('g')); /* supprime toutes les clés
*/
/* allant de 'e' à 'g'
*/
/* aucun équivalent simple
*/

R e m arque

Le deuxiè m e appe lde e ras e de notre pré cédent e xe m ple pe ut pré s e nte r un inté rê t dans le cas d'un
conte ne ur de type m ap ;e n e ffe t, m algré l'unicité des clés dans ce cas, iln'e s t pas ce rtain q u'un appe lte l
q ue :
364 Program m e r e n langage C+ +
m.erase (m.find('e'), m.find('g')) ;

convie nne puis q u'on court le ris q ue q ue l'une au m oins des clés 'e ' ou 'g' n'e xiste pas.

2.2 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant les principales fonctionnalités de la clas s e m ultim ap q ue
nous ve nons d'exam ine r :

________________________________________________________________________
_________

#include <iostream.h>
#include <map>
using namespace std ;
main()
{
void affiche(multimap<char, int>) ;
multimap<char, int> m, m_bis ;
multimap<char, int>::iterator im ;
m.insert(make_pair('c', 10)) ; m.insert(make_pair('f', 20)) ;
m.insert(make_pair('x', 30)) ; m.insert(make_pair('p', 40)) ;
m.insert(make_pair('y', 40)) ; m.insert(make_pair('p', 35)) ;
cout << "map initial : " ; affiche(m) ;
m.insert(make_pair('f', 25)) ; m.insert(make_pair('f', 20)) ;
m.insert(make_pair('x', 2)) ;
cout << "map avec fff et xx : " ; affiche(m) ;
im=m.find('x') ; /* on ne verifie pas que im != m.end() */
m_bis = m ; /* on fait une copie de m dans m_bis */
m.erase(im) ;
cout << "map apres erase(find('x')) : " ; affiche(m) ;
m.erase('f') ;
cout << "map apres erase('f') : " ; affiche(m) ;
m.swap(m_bis) ;
cout << "map apres swap : " ; affiche(m) ;
cout << "il y a " << m.count('f') << " fois la cle 'f'\n" ;
m.erase(m.upper_bound('f')) ; /* supprime derniere cle 'f' - ici pas
de test*/
cout << "map apres erase (u_b('f')) : " ; affiche(m) ;
m.erase(m.lower_bound('f')) ;
cout << "map apres erase (l_b('f')) : " ; affiche(m) ;
m.erase(m.upper_bound('g')) ;
cout << "map apres erase (u_b('g')) : " ; affiche(m) ;
m.erase(m.lower_bound('g')) ;
cout << "map apres erase (l_b('d')) : " ; affiche(m) ;
m.erase(m.lower_bound('d'), m.upper_bound('x')) ;
cout << "map apres erase (l_b('d'), u_b('x')) : " ; affiche(m) ;
}
void affiche(multimap<char, int> m)
{ map<char, int>::iterator im ;
for (im=m.begin() ; im!=m.end() ; im++)
cout << "(" << (*im).first << "," << (*im).second << ")" ;
cout << "\n" ;
} _______________________
XX. Le s conte ne urs associatifs 365

map initial : (c,10)(f,20)(p,40)(p,35)(x,30)(y,40)


map avec fff et xx :
(c,10)(f,20)(f,25)(f,20)(p,40)(p,35)(x,30)(x,2)(y,40)
map apres erase(find('x')) :
(c,10)(f,20)(f,25)(f,20)(p,40)(p,35)(x,2)(y,40)
map apres erase('f') : (c,10)(p,40)(p,35)(x,2)(y,40)
map apres swap :
(c,10)(f,20)(f,25)(f,20)(p,40)(p,35)(x,30)(x,2)(y,40)
il y a 3 fois la cle 'f'
map apres erase (u_b('f')) :
(c,10)(f,20)(f,25)(f,20)(p,35)(x,30)(x,2)(y,40)
map apres erase (l_b('f')) : (c,10)(f,25)(f,20)(p,35)(x,30)(x,2)(y,40)
map apres erase (u_b('g')) : (c,10)(f,25)(f,20)(x,30)(x,2)(y,40)
map apres erase (l_b('d')) : (c,10)(f,25)(f,20)(x,2)(y,40)
map apres erase (l_b('d'), u_b('x')) : (c,10)(y,40)
________________________________________________________________________
_________

Exe m ple d'utilisation de m ultim ap

3. LE CO NTENEUR SET

3.1 Pré s e ntation gé né ral


e

Com m e ila é té dit e n introduction, le conte ne ur s e t e s t un cas particulie r du conte ne ur m ap, dans leq ue l
aucune valeur n'e s t associé e à la clé. Le s é lém e nts d'un conte ne ur s e t ne s ont donc plus des paire s , ce q ui e n
facilite nature llem e nt la m anipulation. Une autre diffé re nce e ntre les conte ne urs s e t e t les conte ne urs m ap e s t
q u'un é lém e nt d'un conte ne ur s e t e s t une constante ;on ne pe ut pas e n m odifie r la valeur :

set<int> e(...) /* ensemble d'entiers */


set<int>::iterator ie ; /* itérateur sur un ensemble d'entiers */
.....
cout << *ie ; /* correct */
*ie = ... ; /* interdit */

En de h ors de ce tte contrainte , les possibilités d'un conte ne ur s e t se déduisent tout nature llem e nt de ce lles
d'un conte ne ur m ap, aussi bien pour sa construction q ue pour l'ins e rtion ou la suppre s s ion d'é lém e nts q ui,
q uant à e lle, re s te toujours possible, aussi bien à partir d'une position q ue d'une valeur.

3.2 Exe m pl
e

Voici un e xe m ple com plet de program m e illustrant les principales fonctionnalités de la clas s e s e t (atte ntion,
le caractè re "e s pace " n'e s t pas trè s visible dans les ré s ultats !) :

________________________________________________________________________
_________

#include <iostream.h>
#include <set>
#include <string>
using namespace std ;
366 Program m e r e n langage C+ +
main()
{ char t[] = "je me figure ce zouave qui joue du xylophone" ;
char v[] = "aeiouy" ;
void affiche (set<char> ) ;
set<char> let(t, t+sizeof(t)-1), let_bis ;
set<char> > voy(v, v+sizeof(v)-1) ;

cout << "lettres presentes : " ; affiche (let) ;


cout << "il y a " << let.size() << " lettres differentes\n" ;
if (let.count('z')) cout << "la lettre z est presente\n" ;
if (!let.count('b')) cout << "la lettre b n'est pas presente\n" ;

let_bis = let ;
set<char, less<char> >:: iterator iv ;
for (iv=voy.begin() ; iv!=voy.end() ; iv++)
let.erase(*iv) ;
cout << "lettres sans voyelles : " ; affiche (let) ;
let.insert(voy.begin(), voy.end()) ;
cout << "lettres + toutes voyelles : " ; affiche (let) ;
}
void affiche (set<char> e )
{ set<char>::iterator ie ;
for (ie=e.begin() ; ie!=e.end() ; ie++)
cout << *ie << " " ;
cout << "\n" ;
} _______________________

lettres presentes : a c d e f g h i j l m n o p q r u v x y z
il y a 22 lettres differentes
la lettre z est presente
la lettre b n'est pas presente
lettres sans voyelles : c d f g h j l m n p q r v x z
lettres + toutes voyelles : a c d e f g h i j l m n o p q r u v x y z
________________________________________________________________________
_________

Exe m ple d'utilisation du conte ne ur s e t

3.3 Le conte ne ur s e t e t l
'e ns e m bl
e m ath é m atiq ue

Un conte ne ur de type s e t e s t obligatoire m e nt ordonné , tandis q u'un e ns e m ble m ath é m atiq ue ne l'e s t pas
né ce s s aire m e nt. Ilfaudra te nir com pte de ce tte re m arq ue dè s q ue l'on s e ra am e né à cré e r un e ns e m ble
d'obje ts puisq u'ilfaudra alors m unir la clas s e corre s pondante d'une relation d'ordre faible s trict. En outre , il
ne faudra pas perdre de vue q ue c'e s t ce tte re lation q ui s e ra utilisée pour définir l'é galité de deux élém e nts e t
non une é ve ntue lle s urdé finition de l'opé rate ur ==.

Par ailleurs, dans la clas s e s e t, iln'e xiste pas de fonction m e m bre pe rm e ttant de ré aliser les opé rations
e ns e m bliste s classiques (inte rs e ction, ré union...). Ce pe ndant, nous ve rrons, dans le ch apitre XXI, q u'il
e xiste des algorith m e s gé né raux, utilisables ave c n'im porte q ue lle s é q ue nce ordonné e . Le ur application au
cas particulie r de s e ns e m bles pe rm e ttra de ré aliser les opé rations e n q ue s tion.
XX. Le s conte ne urs associatifs 367

4. LE CO NTENEUR M ULTISET

D e m ê m e q ue le conte ne ur m ultim ap e s t un conte ne ur m ap, dans leq ue l on autoris e plusieurs clés


é q uivalente s , le conte ne ur m ultise t e s t un conte ne ur s e t, dans leq ue l on autoris e plusieurs élém e nts
é q uivalents à apparaî tre . Bie n e nte ndu, ce tte notion n'a alors plus grand-ch os e à voir ave c la notion
m ath é m atiq ue corre s pondante . Ce la n'e m pê ch e ra pas les algorith m e s gé né raux d'inte rs e ction ou de ré union,
é voq ué s ci-de s s us, de fonctionne r e ncore dans le cas des conte ne urs m ultise t.

Voici un e xe m ple com plet de program m e illustrant les principales fonctionnalités de la clas s e m ultise t
(atte ntion, le caractè re "e s pace " n'e s t pas trè s visible dans les ré s ultats !) :

________________________________________________________________________
________

#include <iostream.h>
#include <set>
using namespace std ;
main()
{ char t[] = "je me figure ce zouave qui joue du xylophone" ;
char v[] = "aeiouy" ;
void affiche (multiset<char> ) ;
multiset<char> let(t, t+sizeof(t)-1), let_bis ;
multiset<char> > voy(v, v+sizeof(v)-1) ;
cout << "lettres presentes : " ; affiche (let) ;
cout << "il y a " << let.size() << " lettres en tout\n" ;
cout << "la lettre e est presente " << let.count('e') << " fois\n" ;
cout << "la lettre b est presente " << let.count('b') << " fois\n" ;
let_bis = let ;
multiset<char>:: iterator iv ;
for (iv=voy.begin() ; iv!=voy.end() ; iv++)
let.erase(*iv) ;
cout << "lettres sans voyelles : " ; affiche (let) ;
}
void affiche (multiset<char> e )
{ multiset<char>::iterator ie ;
for (ie=e.begin() ; ie!=e.end() ; ie++)
cout << *ie ;
cout << "\n" ;
} _______________________

lettres presentes : acdeeeeeeefghiijjlmnoooopqruuuuuvxyz


il y a 44 lettres en tout
la lettre e est presente 7 fois
la lettre b est presente 0 fois
lettres sans voyelles : cdfghjjlmnpqrvxz
________________________________________________________________________
_________

Exe m ple d'utilisation du conte ne ur m ultiset


368 Program m e r e n langage C+ +
5. CO NTENEURS ASSO CIA TIFS ET A LGO RITH M ES

Ile s t gé né ralem e nt difficile d'appliq ue r ce rtains algorith m e s gé né raux aux conte ne urs associatifs. Ily a
plusieurs raisons à ce la.

Tout d'abord, un conte ne ur de type m ap ou m ultim ap e s t form é d'élém e nts de pair, q ui s e prê te nt as s e z
difficilem e nt aux algorith m e s usuels. Par e xe m ple, une re ch e rch e par find devrait s e faire s ur la paire (clé,
valeur), ce q ui ne pré s e nte gé né ralem e nt guè re d'inté rê t ;on pré fé re ra utiliser la fonction m e m bre find
travaillant sur une clé donnée.

D e m ê m e , vouloir trie r un conte ne ur associatif déjà ordonné de façon intrinsè q ue n'e s t guè re ré aliste : soit
on ch e rch e à trie r suivant l'ordre inte rne , ce q ui n'a aucun inté rê t, soit on ch e rch e à trie r suivant un autre
ordre , e t alors apparais s e nt des conflits e ntre les deux ordre s .

Né anm oins, ilre s te possible d'appliq ue r tout algorith m e q ui ne m odifie pas les valeurs du conte ne ur.

D 'une m aniè re gé né rale, dans le ch apitre XXI consacré aux algorith m e s , nous indiq ue rons ce ux q ui sont
utilisables ave c des conte ne urs associatifs.
XXI. LES A LGO RITH M ES STANDARD

La notion d'algorith m e a déjà é té pré s e ntée dans le ch apitre XVIII, e t nous avons e u l'occasion d'en utiliser
q ue lque s -uns dans ce rtains de nos précédents e xe m ples . Le pré s e nt ch apitre e xpos e les diffé re nte s
possibilité s offe rte s par les algorith m es de la biblioth è q ue s tandard. Auparavant, ilpré s e nte ou rappe lle un
ce rtain nom bre de notions générales q ui inte rvie nne nt dans leur utilisation, e n particulie r : les caté gorie s
d'ité rate ur, la notion de s é q ue nce , les ité rate urs de flot e t les ité rate urs d'insertion.

O n note ra bie n q ue ce ch apitre vise avant tout à faire com pre ndre le rôle des diffé re nts algorith m e s e t à
illustre r les plus im portants par de s e xe m ples de program m e s . O n trouve ra dans l'anne xe C, une ré fé re nce
com plète du rôle pré cis, de l'e fficacité e t de la syntaxe e xacte de l'appe l de ch acun de s algorith m e s
e xistants.

1. NO TIO NS GENERA LES

1.1 A l
gorith m e s e t ité rate urs

Le s algorith m e s s tandard s e pré s e nte nt sous form e de patrons de fonctions. Le ur code e s t é crit, sans
connaissance pré cise des élém e nts q u'ils s e ront am e né s à m anipuler. Ce pe ndant, ce tte m anipulation ne s e
fait jam ais directe m e nt, m ais toujours par l'inte rm édiaire d'un ité rate ur q ui, q uant à lui, possè de un type
donné , à partir duq ue lse déduit le type d e s é lém e nts e ffe ctive m e nt m anipulés . Par e xe m ple, lors q u'un
algorith m e contie nt une instruction de la form e :

*it = ...

le code s ource du program m e ne connaî t e ffe ctive m e nt pas le type de l'é lém e nt q ui s e ra ainsi m anipulé m ais
ce type s e ra parfaite m e nt défini à la com pilation, lors de l'instanciation de la fonction patron corre s pondant
à l'algorith m e e n q ue s tion.

1.2 Le s caté gorie s d'ité rate urs

Jus q u'ici, nous avons surtout m anipulé d e s é lém e nts de conte ne urs e t les ité rate urs associé s q ui s e
ré partissaie nt alors e n trois caté gorie s : unidire ctionne l, bidire ctionne le t à accè s direct. En fait, ile xiste
deux autre s caté gories d'ité rate urs, disposant de proprié té s plus re s trictive s q ue les ité rate urs
unidire ctionne ls ;ils'agit des ité rate urs e n e ntré e e t des ité rate urs e n sortie . Bie n q u'ils ne soient fournis par
aucun de s conte ne urs, ils présente nt un inté rê t au nive au de s ité rate urs de flot q ui, com m e nous le ve rrons un
pe u plus loin, pe rm e tte nt d'accéder à un flot com m e à une s é q ue nce .
370 Program m e r e n langage C+ +

a)Ité rate ur e n e ntré e


Un ité rate ur e n e ntré e possè de les m ê m e s proprié té s q u'un ité rate ur unidire ctionne l, ave c ce tte diffé re nce
q u'iln'autoris e q ue la consultation de la valeur corre s pondante e t plus sa m odification ;si it e s t un te l
ité rate ur :

... = *it ; /* correct si it est un itérateur en entrée */


*it = ... ; /* impossible si it est un itérateur en entrée */

En outre , un ité rate ur e n e ntré e n'autoris e q u'un s e ulpassage (on dit aussi une seule pas s e ) sur les é lém e nts
q u'ilpe rm e t de décrire . Autre m e nt dit, si, à un m om e nt donné , it1==it2, it1+ + e t it2+ + ne désignent
pas néce s s aire m e nt la m ê m e valeur. Ce tte re s triction n'e xistait pas dans le cas des ité rate urs
unidire ctionne ls. Ici, e lle s e justifie dè s lors q u'on sait q ue l'ité rate ur e n e ntré e e s t destiné à la lecture d'une
suite de valeurs de m ê m e type s ur un flot, d'une façon analogue à la lecture des inform ations d'une
s é q ue nce . O r, m anife s te m e nt, iln'e s t pas possible de lire deux fois une m ê m e valeur sur ce rtains flots te ls
q ue l'unité d'entré e s tandard.

b)Ité rate ur e n s ortie


D e façon concom itante , un ité rate ur e n sortie possè de les m ê m e s proprié té s q u'un ité rate ur unidire ctionne l,
ave c ce tte diffé re nce q u'iln'autoris e q ue la m odification e t e n aucun cas la consultation. Par e xe m ple, si it
e s t un te lité rate ur :

*it = ... ; /* correct si it est un itérateur en sortie */


... = *it ; /* impossible si it est un itérateur en sortie */

Com m e l'ité rate ur e n e ntré e , l'ité rate ur e n sortie ne pe rm e ttra q u'un s e ulpassage ;si, à un m om e nt donné ,
on a it1==it2, les affe ctations succe s s ive s :

*it1++ = ... ;
*it2++ = ... ;

e ntraîne ront la cré ation de deux valeurs distincte s . Là e ncore , pour m ie ux com pre ndre ce s re s trictions, il
faut voir q ue la principale justification de l'ité rate ur e n sortie e s t de perm e ttre d'écrire une s uite de valeur de
m ê m e type s ur un flot, de la m ê m e façon q u'on pe ut introduire des inform ations dans une séquence . O r,
m anife s te m e nt, iln'e s t pas possible d'écrire deux fois e n un m ê m e e ndroit de ce rtains flots te ls q ue l'unité
standard de s ortie .

c)H ié rarch ie de s caté gorie s d'ité rate urs


O n pe ut m ontre r q ue les proprié tés des cinq caté gories d'ité rate urs perm e tte nt de les range r s e lon une
h ié rarch ie dans laq ue lle toute caté gorie possè de au m oins les proprié tés de la caté gorie pré cédente :

itérateur en entrée itérateur en sortie


|___________________________|
|
itérateur unidirectionnel
|
itérateur bidirectionnel
|
itérateur à accès direct

Le s ité rate urs e n e ntré e e t e n sortie s e ront fré q ue m m e nt utilisés pour associer un ité rate ur à un flot, e n
faisant appe là un adaptate ur particulie r d'ité rate ur dit ité rate ur de flot ;nous y revie ndrons au paragraph e
XXI. Le s algorith m e s s tandard 371
1.5. En de h ors de ce la, ils présente nt un inté rê t indire ct à propos de l'inform ation q u'on pe ut déduire au vu
de la caté gorie d'ité rate ur atte ndu par un algorith m e ;par e xe m ple, si un algorith m e acce pte un ité rate ur e n
e ntré e , c'e s t q ue , d'une part, ilne m odifie pas la s é q ue nce corre s pondante e t q ue , d'autre part, iln'e ffe ctue
q u'une s e ule pas s e s ur ce tte s é q ue nce .

1.3 A l
gorith m e s e t s é q ue nce s
Be aucoup d'algorith m e s s 'appliq ue nt à une s é q ue nce définie par un inte rvalle d'ité rate ur de la form e [début,
fin) ;dans ce cas, on lui com m uniq ue ra sim plem e nt e n argum e nt les deux valeurs début e t fin, les q ue lles
devront nature llem e nt ê tre du m ê m e type , sous peine d'erreur de com pilation.

Tant q ue l'algorith m e ne m odifie pas les é lém e nts de ce tte s é q ue nce , ce tte derniè re pe ut apparte nir à un
conte ne ur de n'im porte q ue ltype , y com pris les conte ne urs associatifs pour les q ue ls, rappe lons-le, la notion
d e s é q ue nce a bien un sens, com pte te nu de leur ordre inte rne . Ce pe ndant, dans le cas des type s m ap ou
m ultim ap, on s e ra gé né ralem e nt gê né par le fait q ue leurs é lém e nts sont des paire s .

En re vanch e , si l'algorith m e m odifie les é lém e nts de la s é q ue nce , iln'e s t plus possible q u'e lle appartie nne à
un conte ne ur de type s e t e t m ultise t, puis q ue les é lém e nts n'en sont plus m odifiables . Bie n q u'iln'e xiste pas
d'inte rdiction form e lle, il n'e s t guè re raisonnable q u'e lle appartie nne à un conte ne ur de type m ap ou
m ultim ap, com pte te nu de s ris q ues d'incom patibilité q ui apparais s e nt alors e ntre l'organisation inte rne e t
ce lle q u'on ch e rch e rait à lui im pos e r...

Ce rtains algorith m e s s 'appliq ue nt à deux séquences de m ê m e taille. C'e s t par e xe m ple le cas de la re copie
d'une s é q ue nce dans une autre ayant des élém e nts de m ê m e type . Dans ce cas, tous ce s algorith m e s
procè dent de la m ê m e façon, à savoir :

• deux argum e nts définis s e nt classiquem e nt un pre m ie r inte rvalle, corre s pondant à la pre m iè re s é q ue nce ,
• un troisiè m e argum e nt fournit la valeur d'un ité rate ur dé s ignant le début de la s e conde s é q ue nce .
O n note ra bie n q ue ce tte façon de procéder pré s e nte m anife s te m e nt le ris q ue q ue la s é q ue nce cible s oit trop
pe tite . Dans ce cas, le com porte m e nt du program m e e s t indé te rm iné com m e ilpouvait l'ê tre e n cas de
débordem e nt d'un tableau classique ;d'ailleurs, rie n n'inte rdit de fournir à un algorith m e un ité rate ur q ui
soit un pointe ur...

Enfin, q ue lque s rare s algorith m e s fournis s e nt com m e valeur de re tour, les lim ites d'un inte rvalle, sous form e
de deux ité rate urs ;dans ce cas, ce lles -ci s e ront re groupé e s au s e in d'une s tructure de type pair.

1.4 Ité rate ur d'ins e rtion


Be aucoup d'algorith m e s s ont pré vus pour m odifie r les valeurs des élém e nts d'une séquence ;c'e s t par
e xe m ple le cas de copy :

copy (v.begin(), v.end(), l.begin());/* recopie l'intervalle [v.begin(),


v.end() ) */
/* à partir de la position l.begin()
*/

D e te lles opé rations im pos e nt nature llem e nt un ce rtain nom bre de contrainte s :

• les e m place m e nts néce s s aire s à la copie doive nt déjà e xiste r,


• leur m odification doit ê tre autoris é e , ce q ui n'e s t pas le cas pour de s conte ne urs de type s e t ou m ultise t,
• la copie ne doit pas s e faire à l'inté rie ur d'un conte ne ur associatif de type m ap ou m ultim ap, com pte te nu
de l'incom patibilité q ui ré s ulte rait e ntre l'ordre s é q ue ntie lim pos é e t l'ordre inte rne du conte ne ur.
En fait, ile xiste un m é canism e particulie r pe rm e ttant de transform e r une s ucce s s ion d'opé rations de copie à
partir d'une position donné e e n une s ucce s s ion d'inse rtions à partir de ce tte position. Pour ce faire , on fait
372 Program m e r e n langage C+ +
appe là ce q u'on nom m e un ité rate ur d'inse rtion ;ils'agit d'un patron de clas s e s nom m é inse rt_ite rator e t
param é tré par un type de conte ne ur. Par e xe m ple :

insert_iterator <list<int> > ins ; /* ins est un itérateur d'insertion dans


*/
/* un conteneur de type list<int>
*/

Pour affe cte r une valeur à un te lité rate ur, on s e s e rt du patron de fonction inse rte r ;e n voici un e xe m ple
dans leq ue lon suppose que c e s t un conte ne ur e t it e s t une valeur particuliè re d'ité rate ur sur ce conte ne ur :

ins = inserter(c, it) ;/* valeur initiale d'un itérateur d'insertion permettant
*/
/* d'insérer à partir de la position it dans le
conteneur c */

D ans ce s conditions, l'utilisation de ins, e n lie u e t place d'une valeur initiale d'ité rate ur, fe ra q u'une
instruction te lle q ue *ins = ... ins é re ra un nouve lé lém e nt e n position it. De plus, toute incré m e ntation de
ins, suivie d'une nouve lle affe ctation *ins=... provoq ue ra une nouve lle ins e rtion à la suite de l'é lém e nt
pré cédent.

D 'une m aniè re gé né rale, ile xiste trois fonctions perm e ttant de définir une valeur initiale d'un ité rate ur
d'insertion, à savoir :

• front_inse rte r (conte ne ur) : pour une ins e rtion e n début du conte ne ur ;le conte ne ur doit disposer de la
fonction m e m bre push _front ;
• back _inse rte r (conte ne ur) : pour une ins e rtion e n fin du conte ne ur ;le conte ne ur doit disposer de la
fonction m e m bre push _back ;
• inse rte r (conte ne ur, position) : pour une ins e rtion à partir de position dans le conte ne ur ;le conte ne ur
doit disposer de la fonction m e m bre inse rt(valeur, position).
Voici un e xe m ple de program m e utilisant un te lm é canism e pour transform e r une copie dans des élém e nts
e xistant e n une ins e rtion ;auparavant, on a te nté une copie usuelle dans un conte ne ur trop pe tit pour m ontre r
q u'e lle s e d é roulait m al;e n pratiq ue , nous décons e illons ce ge nre de procé d é q ui pe ut trè s bien am e ne r à un
plantage du program m e :

________________________________________________________________________
_________
#include <iostream.h>
#include <list>
using namespace std ;
main()
{ void affiche (list<char>) ;
char t[] = {"essai insert_iterator"} ;
list<char> l1(t, t+sizeof(t)-1) ;
list<char> l2 (4, 'x') ;
list<char> l3 ;
cout << "l1 initiale : " ; affiche(l1) ;
cout << "l2 initiale : " ; affiche(l2) ;
/* copie avec liste l2 de taille insuffisante - deconseille en pratique */
copy (l1.begin(), l1.end(), l2.begin()) ;
cout << "l2 apres copie usuelle : " ; affiche(l2) ;
/* insertion dans liste non vide ; pourrait utiliser aussi
front_inserter(l2) */
copy (l1.begin(), l1.end(), inserter(l2, l2.begin())) ;
XXI. Le s algorith m e s s tandard 373
cout << "l2 apres copie inser : " ; affiche(l2) ;
/* insertion dans liste vide ; on pourrait utiliser aussi */
/* front_inserter(l3) ou back_inserter(l3) */
copy (l1.begin(), l1.end(), inserter(l3, l3.begin())) ;
cout << "l3 apres copie inser : " ; affiche(l3) ;
}
void affiche (list<char> l)
{ void af_car (char) ;
for_each (l.begin(), l.end(), af_car) ; /* appelle af_car pour chaque
element */
cout << "\n" ;
}
void af_car (char c)
{ cout << c << " " ;
} _______________________

l1 initiale : e s s a i i n s e r t _ i t e r a t o r
l2 initiale : x x x x
l2 apres copie usuelle : r r a t
l2 apres copie inser : e s s a i i n s e r t _ i t e r a t o r r r a t
l3 apres copie inser : e s s a i i n s e r t _ i t e r a t o r
________________________________________________________________________
_________

Exe m ple d'utilisation d'un ité rate ur d'inse rtion

R e m arque

Si l'on tie nt à m e ttre e n é vidence l'e xiste nce d'une clas s e inse rt_ite rator, la sim ple instruction du
pré cédent program m e :
copy (l1.begin(), l1.end(), inserter(l2, l2.begin())) ;

pe ut se décom pos e r ainsi :


insert_iterator<list<char> > ins = inserter(l2, l2.begin()) ;
copy (l1.begin(), l1.end(), ins ) ;

1.5 Ité rate ur de fl


ot

a) Ité rate ur de fl
ot de s ortie
Lors q u'on lit, par e xe m ple, sur l'e ntré e s tandard, une s uite d'inform ations de m ê m e type , on pe ut considérer
q u'on parcourt une s é q ue nce . Effe ctive m e nt, ile s t possible de définir un ité rate ur sur une te lle s é q ue nce ne
disposant q ue des proprié tés d'un ité rate ur d'e ntré e te lles q u'e lles ont é té définie s pré cédem m e nt. Pour ce
faire , ile xiste un patron de clas s e s , nom m é ostre am _ite rator, param é tré par le type d e s é lém e nts conce rné s ;
par e xe m ple :

ostream_iterator<char> /* type itérateur sur un flot d'entrée de caractères


*/

Ce tte classe dispose d'un constructe ur re ce vant e n argum e nt un flot e xistant. C'e s t ainsi que :

ostream_iterator<char> flcar(cout) ; /* flcar est un itérateur sur un flot


de */
374 Program m e r e n langage C+ +
/* caractères connecté à cout
*/

D ans ce s conditions, une instruction te lle q ue :

*flcar = 'x' ;

e nvoie le caractè re x sur le flot cout.

O n note ra q u'ile s t th é oriq ue m e nt possible d'incré m e nte r l'ité rate ur flcar e n é crivant flcar+ + ;ce pe ndant,
une te lle opé ration e s t sans e ffe t car sans signification à ce nive au. Son e xiste nce e s t ce pe ndant pré cie us e
puis q u'e lle pe rm e ttra d'utiliser un te lité rate ur ave c ce rtains algorith m e s s tandard, te ls q ue copy.

Voici un e xe m ple ré s um ant ce q ue nous ve nons de dire :

________________________________________________________________________
_________

#include <iostream.h>
#include <list>
using namespace std ;
main()
{ char t[] = {"essai iterateur de flot"} ;
list<char> l(t, t+sizeof(t)-1) ;
ostream_iterator<char> flcar(cout) ;
*flcar = 'x' ; *flcar = '-' ;
flcar++ ; flcar++ ; /* pour montrer que l'incrementation est inoperante
ici */
*flcar = ':' ;
copy (l.begin(), l.end(), flcar) ;
}
_______________________

x-:essai iterateur de flot


________________________________________________________________________
_________

Exe m ple d'utilisation d'un ité rate ur de flot de s ortie

R e m arque

Ici, notre e xe m ple s 'appliq uait à la sortie s tandard ;dans ce s conditions, l'utilisation d'inform ations de
type autre q ue ch ar pos e rait le problèm e de leur s é paration à l'affich age ou dans le fich ie r te xte
corre s pondant. En re vanch e , l'application à un fich ie r binaire q ue lconq ue ne pos e rait plus aucun
problèm e .

b)Ité rate ur de fl
ot d'e ntré e
D e m ê m e q u'on pe ut définir de s ité rate urs de flot de sortie , on pe ut définir de s ité rate urs de flot d'entré e ,
suivant un procédé trè s voisin. Par e xe m ple, ave c :

istream_iterator<int> flint(cin) ;
XXI. Le s algorith m e s s tandard 375
on dé finit un ité rate ur nom m é flint, sur un flot d'entrée d'e ntie rs, conne cté à cin. De la m ê m e m aniè re ,
ave c :

ifstream fich("essai", ios::in) ;


istream_iterator<int> flint(fich) ;

on dé finit un ité rate ur, nom m é flint, sur un flot d'entrée d'e ntie rs, conne cté au flot fich , supposé
conve nablem e nt ouve rt.

Le s ité rate urs de flot d'entré e né ce s s ite nt ce pe ndant la possibilité d'en déte cte r la fin. Pour ce faire , ile xiste
une conve ntion pe rm e ttant de construire un ité rate ur e n re pré s e ntant la fin, à savoir, l'utilisation d'un
constructe ur sans argum e nt ;par e xe m ple, ave c :

istream_iterator<int> fin ; /* fin est un itérateur représentant une fin de */


/* fichier sur un itérateur de flot d'entiers */

Voici, par e xe m ple, com m e nt utiliser un ité rate ur de flot d'entré e pour re copie r les inform ations d'un fich ie r
dans une liste ;ici, nous cré ons une liste vide et nous utilisons un ité rate ur d'inse rtion pour y introduire le
ré s ultat de la copie :

list<int> l ;
ifstream fich("essai", ios::in) ;
istream_iterator<int, ptrdiff_t> flint(fich), fin ;
copy (flint, fin, inserter(l, l.begin())) ;

2. A LGO RITH M ES D 'INITIA LISATIO N D E SEQUENCES EXISTANTES


Tous ce s algorith m e s pe rm e tte nt de donner des valeurs à des élém e nts e xistant d'une s é q ue nce , dont la
valeur e s t donc re m placé e . De par leur nature m ê m e , ils ne sont pas adapté s aux conte ne urs associatifs, à
m oins d'utiliser un ité rate ur d'inse rtion e t de te nir com pte de la nature de type pair de leurs é lém e nts.

2.1 Copie d'une s é q ue nce dans une autre

Com m e on l'a dé jà vu à plusieurs reprises, on peut re copie r une s é q ue nce dans une autre , pour pe u q ue les
types des élém e nts soie nt les m ê m e s . Par e xe m ple, si le s t une liste d'entie rs e t v un ve cte ur d'e ntie rs :

copy (l.begin(), l.end(), v.begin()) ; /* recopie les éléments de la liste l


dans */
/* le vecteur v, à partir de son début
*/

Le s e ns de la copie e s t im pos é , à savoir q u'on com m e nce bien par recopier l.be gin() e n v.be gin(). La s e ule
contrainte (logiq ue ) q ui soit im pos é e aux valeurs des ité rate urs e s t q ue la position de la pre m iè re copie
n'appartie nne pas à l'inte rvalle à copie r. En re vanch e , rie n n'inte rdirait, par e xe m ple :

copy (v.begin()+1, v.begin()+10, v.begin()); /* recopie v[1] dans v[0]


*/
/* v[2] dans v[1]... v[9] dans
v[8] */

Ile xiste é galem e nt un algorith m e copy_back w ard q ui procè de à la copie dans l'ordre inve rse de copy, c’
e s t-
à -dire e n com m e nçant par le dernie r é lém e nt. Dans ce cas, com m e on pe ut s'y atte ndre , les ité rate urs
corre s pondants doive nt ê tre bidirectionne ls.
376 Program m e r e n langage C+ +
Voici un e xe m ple de program m e utilisant copy pour ré aliser des copie s usuelles , ainsi que des insertions, par
le biais d'un ité rate ur d'inse rtion :

________________________________________________________________________
_________

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std ;
main()
{ int t[5] = { 1, 2, 3, 4, 5 } ;
vector<int> v(t, t+5) ; /* v contient : 1, 2, 3, 4, 5 */
list<int> l(8, 0) ; /* liste de 8 elements egaux a 0*/
void affiche(vector<int>) ;
void affiche(list<int>) ;
cout << "liste initiale : " ; affiche(l) ;
copy (v.begin(), v.end(), l.begin()) ;
cout << "liste apres copie 1 : " ; affiche(l) ;
l.assign (3, 0) ; /* l contient maintenant 3 elements égaux
à 0 */
copy (v.begin(), v.end(), l.begin()) ; /* sequence trop courte :
deconseille */
cout << "liste apres copie 2 : " ; affiche(l) ;
l.erase(l.begin(), l.end()) ; /* l est maintenant vide
*/
copy (v.begin(), v.end(), inserter(l, l.begin())) ; /* on y insere les elem
de v */
cout << "liste apres copie 3 : " ; affiche(l) ;
}
void affiche(list<int> l)
{ list<int>::iterator il ;
for (il=l.begin() ; il!=l.end() ; il++) cout << *il << " " ;
cout << "\n" ;
} _______________________

liste initiale : 0 0 0 0 0 0 0 0
liste apres copie 1 : 1 2 3 4 5 0 0 0
liste apres copie 2 : 5 2 3
liste apres copie 3 : 1 2 3 4 5
________________________________________________________________________
_________

Exe m ple de copie s u s u e lles e t de copie s ave c ins e rtion

2.2 Gé né ration de val


e urs par une fonction
Il e s t fré q ue nt q u'on ait besoin d'initialiser un conte ne ur par de s valeurs ré s ultant d'un calcul. La
biblioth è q ue s tandard offre un outil as s e z gé né ral à ce t e ffe t, à savoir ce q u'on nom m e s ouve nt un
algorith m e gé né rate ur. O n lui fournit e n argum e nt, un obje t fonction (ilpe ut donc s'agir d'une fonction
ordinaire ) q u'ilappe llera pour dé te rm ine r la valeur à attribue r à ch aq ue é lém e nt d'un inte rvalle. Une te lle
fonction ne re çoit aucun argum e nt. Par e xe m ple, l'appe l:

generate (v.begin(), v.end(), suite) ;


XXI. Le s algorith m e s s tandard 377
utilisera la fonction suite pour donne r une valeur à ch acun de s é lém e nts de la s é q ue nce définie par
l'inte rvalle [v.be gin(), v.e nd()).

Voici un pre m ie r e xe m ple faisant appe là une fonction ordinaire :

________________________________________________________________________
_________
#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ int n = 10 ;
vector<int> v(n, 0) ; /* vecteur de n elements initialises a 0 */
int suite() ; /* fonction utilisee pour la generation d'entiers */
void affiche(vector<int>) ;
cout << "vecteur initial : " ; affiche(v) ;
generate (v.begin(), v.end(), suite) ;
cout << "vecteur genere : " ; affiche(v) ;
}
int suite()
{ static int n = 0 ;
return n++ ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur initial : 0 0 0 0 0 0 0 0 0 0
vecteur genere : 0 1 2 3 4 5 6 7 8 9
________________________________________________________________________
_________
Génération de valeurs par une fonction ordinaire

O n constate q u'ile s t difficile d'im pos e r une valeur initiale à la suite de nom bre s , autre m e nt q u'e n la fixant
dans la fonction e lle-m ê m e ;e n particulie r, il n'e s t pas possible de la ch oisir en argum e nt. C'e s t là
pré cis é m e nt q ue la notion de clas s e fonction s'avè re inté re s s ante com m e le m ontre l'e xe m ple s uivant :

________________________________________________________________________
_________

#include <iostream.h>
#include <vector>
using namespace std ;
class sequence /* classe fonction utilisee pour la generation d'entiers
*/
{ public :
sequence (int i) { n = i ;} /* constructeur */
int operator() () { return n++ ; } /* ne pas oublier () */
private :
int n ; /* valeur courante generee */
} ;
378 Program m e r e n langage C+ +
main()
{ int n = 10 ;
vector<int> v(n, 0) ; /* vecteur de n elements initialises a 0 */
void affiche(vector<int>) ;
cout << "vecteur initial : " ; affiche(v) ;
generate (v.begin(), v.end(), sequence(0)) ;
cout << "vecteur genere 1 : " ; affiche(v) ;
generate (v.begin(), v.end(), sequence(4)) ;
cout << "vecteur genere 2 : " ; affiche(v) ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
}
_______________________

vecteur initial : 0 0 0 0 0 0 0 0 0 0
vecteur genere 1 : 0 1 2 3 4 5 6 7 8 9
vecteur genere 2 : 4 5 6 7 8 9 10 11 12 13
________________________________________________________________________
_________

Génération de valeurs par une clas s e fonction

R e m arques

1) Si l'on com pare les deux appe ls suivants, l'un du pre m ie r e xe m ple, l'autre du second :
generate (v.begin(), v.end(), suite) ;
generate (v.begin(), v.end(), sequence(0)) ;

on constate q ue , dans le pre m ie r cas, suite e s t la ré fé re nce à une fonction, tandis q ue dans le s e cond,
s e q u e nce (0) e s t la ré fé re nce à un obje t de type s e q u e nce . M ais, com m e ce dernie r a conve nablem e nt
surdéfini l'opé rate ur (), l'algorith m e ge ne rate n'a pas à te nir com pte de ce tte diffé re nce .
2) Ile xiste un autre algorith m e , ge ne rate _n, com parable à ge ne rate , q ui gé nè re un nom bre de valeurs
pré vue s e n argum e nt. D'autre part, l'algorith m e fill pe rm e t d'affe cte r une valeur donné e à tous les
é lém e nts d'une séquence ou à un nom bre donné d'élém e nts :
fill(début, fin, valeur)
fill(position, NbFois, valeur)

3. A LGO RITH M ES D E RECH ERCH E

Ce s algorith m e s ne m odifie nt pas la s é q ue nce s ur laq ue lle ils travaillent. O n distingue :

• les algorith m e s fondé s s ur une é galité ou sur un prédicat unaire ,


• les algorith m e s fondé s s ur une re lation d'ordre pe rm e ttant de trouve r le plus grand ou le plus petit
é lém e nt.
XXI. Le s algorith m e s s tandard 379
3.1 A l
gorith m e s fondé s s ur une é gal
ité ou un pré dicat unaire

Ce s algorith m e s pe rm e tte nt de re ch e rch e r la pre m iè re occurre nce de valeurs ou de séries de valeurs q ui


sont :

• soit im pos é e s e xplicite m e nt ;ce la signifie e n fait q u'on s e fonde s ur la re lation d'é galité induite par
l'opé rate ur ==, q u'ilsoit surdéfini ou non ;
• soit par une condition fournie s ous form e d'un prédicat unaire .
Ils fournis s e nt tous un ité rate ur sur l'é lém e nt re ch e rch é , s'ile xiste , e t l'ité rate ur sur la fin de la s é q ue nce ,
sinon ;dans ce dernie r cas, ce tte valeur n'e s t é gale à e nd() q ue s i la s é q ue nce conce rné e appartie nt à un
conte ne ur e t s'é te nd jus q u'à sa fin. Sinon, on pe ut obte nir un ité rate ur valide sur un élém e nt n'ayant rie n à
voir ave c la re ch e rch e e n q ue s tion. D ans le cas où les ité rate urs utilisés sont des pointe urs, on pe ut obte nir
un pointe ur sur une valeur situé e au-de là de la s é q ue nce e xam iné e . Ilfaudra te nir com pte de ce s re m arq ue s
dans le te s t de la valeur de re tour, q ui constitue le s e ulm oye n de s avoir si la re ch e rch e a abouti.

L'algorith m e find pe rm e t de re ch e rch e r une valeur donné e , tandis q ue find_firs t_of pe rm e t de re ch e rch e r une
valeur parm i plusieurs. L'algorith m e find_if (début, fin, prédicat) autoris e la re ch e rch e de la pre m iè re valeur
satisfaisant au prédicat unaire fourni e n argum e nt.

O n pe ut re ch e rch e r, dans une séquence [début_1, fin_1), la pre m iè re apparition com plète d'une autre
s é q ue nce [début_2, fin_2) par s e arch (début_1, fin_1, début_2, fin_2). De m ê m e , s e arch _n (début, fin,
NbFois, valeur) pe rm e t de re ch e rch e r une s uite de NbFois une m ê m e valeur. Là e ncore , on se bas e s ur
l'opé rate ur ==, surdéfini ou non.

O n pe ut re ch e rch e r les "doublons", c’ e s t-à -dire les valeurs apparaissant deux fois de suite , par adjace nt_find
(début, fin). Atte ntion, ce n'e s t pas un cas particulie r de s e arch _n, dans la m e s ure où l'on n'im pos e pas la
valeur dupliq ué e . Pour ch e rch e r les autres doublons, on pe ut soit supprim e r l'une des valeurs trouvé e s , soit
sim plem e nt re com m e nce r la re ch e rch e , au-de là de l'e m place m e nt où s e trouve le doublon pré cédent.

Voici un e xe m ple de program m e illustrant la plupart de ce s possibilité s (par souci de s im plification, nous
supposons q ue les valeurs re ch e rch é e s e xiste nt toujours) :

________________________________________________________________________
_________
#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ char *ch1 = "anticonstitutionnellement" ;
char *ch2 = "uoie" ;
char *ch3 = "tion" ;
vector<char> v1 (ch1, ch1+strlen(ch1)) ;
vector<char> v2 (ch2, ch2+strlen(ch2)) ;
vector<char>::iterator iv ;
iv = find_first_of (v1.begin(), v1.end(), v2.begin(), v2.end()) ;
cout << "\npremier de uoie en : " ; for ( ; iv!=v1.end() ; iv++) cout << *iv
;
iv = find_first_of (v1.begin(), v1.end(), v2.begin(), v2.begin()+2) ;
cout << "\npremier de uo en : " ; for ( ; iv!=v1.end() ; iv++) cout << *iv
;
v2.assign (ch3, ch3+strlen(ch3)) ;
iv = search (v1.begin(), v1.end(), v2.begin(), v2.end()) ;
cout << "\ntion en : " ; for ( ; iv!=v1.end() ; iv++) cout <<
*iv ;
iv = search_n(v1.begin(), v1.end(), 2, 'l' ) ;
380 Program m e r e n langage C+ +
cout << "\n'l' 2 fois en : " ; for ( ; iv!=v1.end() ; iv++) cout <<
*iv ;
iv = adjacent_find(v1.begin(), v1.end()) ;
cout << "\npremier doublon en : " ; for ( ; iv!=v1.end() ; iv++) cout <<
*iv ;
} _______________________

premier de uoie en : iconstitutionnellement


premier de uo en : onstitutionnellement
tion en : tionnellement
'l' 2 fois en : llement
premier doublon en : nnellement
________________________________________________________________________
_________

Exe m ple d'utilisation de s algorith m e s de re ch e rch e

3.2 A l
gorith m e s de re ch e rch e de m axim um ou de m inim um

Les deux algorith m e s m ax_e lem e nt e t m in_e lem e nt pe rm e tte nt de déte rm ine r le plus grand ou le plus petit
é lém e nt d'une s é q ue nce . Ils s'appuie nt par dé faut sur la re lation induite par l'opé rate ur < , m ais ile s t
é galem e nt possible d'im pos e r sa propre re lation, sous form e d'un prédicat binaire . Com m e les algorith m e s
pré cédents, ils fournis s e nt e n re tour soit un ité rate ur sur l'é lém e nt corre s pondant ou sur le pre m ie r d'e ntre
e ux s'ile n e xiste plusieurs, soit un ité rate ur sur la fin de la s é q ue nce , s'iln'e n e xiste aucun. M ais ce tte
derniè re s ituation ne pe ut s e produire ici q u'ave c une s é q ue nce vide ou lors q u'on ch oisit son propre prédicat,
de sorte q ue l'e xam e n de la valeur de re tour e s t alors m oins cruciale.

Voici un e xe m ple dans leq ue l nous appliq uons ce s algorith m e s à un tableau usuel (par souci de
sim plification, nous supposons que les valeurs re ch e rch é e s e xiste nt toujours) :

________________________________________________________________________
_________

#include <iostream.h>
#include <algorithm> // utile car aucun en-tete de conteneur
using namespace std ;
main()
{ int t[] = {5, 4, 1, 8, 3, 9, 2, 9, 1, 8} ;
int * ad ;
ad = max_element(t, t+sizeof(t)/sizeof(t[0])) ;
cout << "plus grand elem de t en position " << ad-t
<< " valeur " << *ad << "\n" ;
ad = min_element(t, t+sizeof(t)/sizeof(t[0])) ;
cout << "plus petit elem de t en position " << ad-t
<< " valeur " << *ad << "\n" ;
ad = max_element(t, t+sizeof(t)/sizeof(t[0]), greater<int>()) ;
cout << "plus grand elem avec greater<int> en position " << ad-t
<< " valeur " << *ad << "\n" ;
}
_______________________

plus grand elem de t en position 5 valeur 9


plus petit elem de t en position 2 valeur 1
plus grand elem avec greater<int> en position 2 valeur 1
XXI. Le s algorith m e s s tandard 381
________________________________________________________________________
_________

Exe m ple d'utilisation de m ax_e lem e nt e t de m in_e lem e nt

4. A LGO RITH M ES D E TRANSFO RM A TIO N D 'UNE SEQUENCE

Ils'agit des algorith m e s q ui m odifie nt les valeurs d'une séquence ou leur ordre , sans e n m odifie r le nom bre
d'élém e nts. Ils ne sont pas applicables aux conte ne urs associatifs, pour les q ue ls l'ordre e s t im posé de façon
intrinsè q ue .

O n pe ut distingue r trois caté gories d'algorith m e s :

• re m place m e nt de valeurs,
• pe rm utation de valeurs,
• partition.
Be aucoup de ce s algorith m es disposent d'une ve rsion suffixé e par _copy ;dans ce cas, la ve rsion xxxx_copy
ré alise le m ê m e traite m e nt q ue xxxx, ave c ce tte diffé re nce im portante q u'e lle ne m odifie plus la s é q ue nce
d'origine e t q u'e lle copie le ré s ultat obte nu dans une autre s é q ue nce dont les é lém e nts doive nt alors e xiste r,
com m e ave c copy. Ce s algorith m es de la form e xxxx_copy pe uve nt, q uant à e ux, s'appliq ue r à des
conte ne urs associatifs, à condition toute fois, d'utiliser un ité rate ur d'inse rtion e t de te nir com pte de la nature
de type pair de leurs é lém e nts.

Par ailleurs, ile xiste un algorith m e nom m é trans form q ui, contraire m e nt à ce q ue s on nom pourrait lais s e r
e nte ndre , initialise une séquence en appliq uant une fonction de transform ation à une s é q ue nce ou à deux
s é q ue nces de m ê m e taille, ces derniè re s n'é tant alors pas m odifié e s .

4.1 Re m pl
ace m e nt de val
e urs

O n pe ut re m place r toute s les occurre nces d'une valeur donné e par une autre valeur, e n s e fondant sur
l'opé rate ur == ;par e xe m ple :

replace (l.begin(), l.end(), 0, -1) ; /* remplace toutes les occurrences */


/* de 0 par -1 */

O n pe ut é galem e nt re m place r toute s les occurre nces d'une valeur satisfaisant à une condition ;par e xe m ple :

replace_if (l.begin(), l.end(), impair, 0) ; /* remplace par 0 toutes les


valeurs */
/* satisfaisant au prédicat
unaire */
/* impair qu'il faut fournir
*/

4.2 Pe rm utations d e val


e urs

a)Rotation
L'algorith m e rotate pe rm e t d'effe ctue r une pe rm utation circulaire des valeurs d'une séquence. On note ra
q u'on ne dispose que des possibilités de pe rm utation circulaire inve rs e com pte te nu de la m aniè re dont on
382 Program m e r e n langage C+ +
pré cis e l'am pleur de la pe rm utation, à savoir, non pas par un nom bre , m ais e n indiq uant q ue lé lém e nt doit
ve nir e n pre m iè re position. En voici un e xe m ple :
________________________________________________________________________
_________
#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
int t[] = {1, 2, 3, 4, 5, 6, 7, 8} ;
int decal = 3 ;
vector<int> v(t, t+8) ;
cout << "vecteur initial : " ; affiche(v) ;
rotate (v.begin(), v.begin()+decal, v.end()) ;
cout << "vecteur decale de 3 : " ; affiche(v) ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur initial : 1 2 3 4 5 6 7 8
vecteur decale de 3 : 4 5 6 7 8 1 2 3
________________________________________________________________________
_________
Exe m ple d'utilisation de rotate

b)Gé né ration de pe rm utations


D è s lors q u'une s é q ue nce e s t ordonné e par une re lation d'ordre R , ile s t possible d'ordonne r les diffé re nte s
pe rm utations possibles des valeurs de ce tte s é q ue nce . Par e xe m ple, si l'on considè re les trois valeurs 1, 4, 8
e t la re lation d'ordre < , voici la liste ordonné e d e toute s les pe rm utations possibles :

148
184
418
481
814
841
D ans ce s conditions, ile s t possible de parler de la pe rm utation suivante ou pré cédente d'une séquence de
valeurs données. Dans l'e xe m ple ci-de s s us, la pe rm utation pré cédente de la s é q ue nce 4, 1, 8 s e rait la
s é q ue nce 1, 8, 4 tandis q ue la pe rm utation suivante s e rait 4, 8, 1. Pour é vite r tout problèm e , on considè re
q ue la pe rm utation suivant la derniè re e s t la pre m iè re , e t q ue la pe rm utation pré cédent la derniè re e s t la
pre m iè re .

Le s algorith m e s ne xt_pe rm utation e t pre v_pe rm utation pe rm e tte nt de re m place r une s é q ue nce donnée
re s pe ctive m e nt par la pe rm utation suivante ou par la pe rm utation pré cédente . O n pe ut utiliser soit, par
défaut, l'opé rate ur < , soit une re lation im pos é e s ous form e d'un prédicat binaire . Actue llem e nt, iln'e xiste
pas de variante s _copy de ce s algorith m e s .

Voici un e xe m ple (la valeur de re tour true ou false des algorith m e s pe rm e t de savoir si l'on a e ffe ctué un
bouclage dans la liste des pe rm utations) :
XXI. Le s algorith m e s s tandard 383
________________________________________________________________________
_________

#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
int t[] = {2, 1, 3} ;
int i ;
vector<int> v(t, t+3) ;
cout << "vecteur initial : " ; affiche(v) ;
for (i=0 ; i<=10 ; i++)
{ bool res = next_permutation (v.begin(), v.end()) ;
cout << "permutation " << res << " : " ; affiche(v) ;
}
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur initial : 2 1 3
permutation 1 : 2 3 1
permutation 1 : 3 1 2
permutation 1 : 3 2 1
permutation 0 : 1 2 3
permutation 1 : 1 3 2
permutation 1 : 2 1 3
permutation 1 : 2 3 1
permutation 1 : 3 1 2
permutation 1 : 3 2 1
permutation 0 : 1 2 3
permutation 1 : 1 3 2
________________________________________________________________________
_________

Exe m ple d'utilisation de ne xt_pe rm utation e t de pre v_pe rm utation

c)Pe rm utations al
é atoire s
L'algorith m e random _sh uffle pe rm e t d'effe ctue r une pe rm utation aléatoire des valeurs d'une séquence. En
voici un e xe m ple :
_______________________________________________________________________________
__
#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
int t[] = {2, 1, 3} ;
int i ;
384 Program m e r e n langage C+ +
vector<int> v(t, t+3) ;
cout << "vecteur initial : " ; affiche(v) ;
for (i=0 ; i<=10 ; i++)
{ random_shuffle (v.begin(), v.end()) ;
cout << "vecteur hasard : " ; affiche(v) ;
}
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur initial : 2 1 3
vecteur hasard : 3 2 1
vecteur hasard : 2 3 1
vecteur hasard : 1 2 3
vecteur hasard : 1 3 2
vecteur hasard : 3 1 2
vecteur hasard : 3 2 1
vecteur hasard : 3 1 2
vecteur hasard : 3 2 1
vecteur hasard : 2 3 1
vecteur hasard : 2 3 1
vecteur hasard : 2 3 1
________________________________________________________________________
_________

Exe m ple d'utilisation de random _s h uffle

R e m arque

Ile xiste une ve rsion de random _sh uffle pe rm e ttant d'im pos e r son gé né rate ur de nom bre s aléatoire s .

4.3 Partitions

O n nom m e partition d'une s é q ue nce s uivant un prédicat unaire donné, un réarrangem e nt de ce tte s é q ue nce
défini par un ité rate ur dé s ignant un é lém e nt te lq ue tous les é lém e nts le pré cédant vé rifie nt la dite condition.
Par e xe m ple, ave c la s é q ue nce :

1 3 4 11 2 7 8
e t le prédicat im pair (supposé vrai pour un nom bre im pair e t faux sinon), voici de s partitions possibles (dans
tous les cas, l'ité rate ur dé s igne ra le q uatriè m e é lém e nt) :

1 3 11 7 4 2 8 /*l'ité rate ur dé s igne ra ici le 4 */


1 3 11 7 2 8 4 /*l'ité rate ur dé s igne ra ici le 2 */
3 1 7 11 2 4 8 /*l'ité rate ur dé s igne ra ici le 2 */
O n dit q ue la partition obte nue e s t stable s i l'ordre re latif des élém e nts satisfaisant au prédicat e s t cons e rvé .
D ans notre e xe m ple, s e ules les deux pre m iè re s pe rm utations sont stables .

Le s algorith m e s partition e t s table_partition pe rm e tte nt de déte rm ine r une te lle partition à partir d'un
prédicat unaire fourni e n argum e nt.
XXI. Le s algorith m e s s tandard 385

5. A LGO RITH M ES D ITS "D E SUPPRESSIO N"

Ce s algorith m e s pe rm e tte nt d'élim ine r d'une s é q ue nce les é lém e nts ré pondant à un ce rtain critè re . M ais,
as s e z curie us e m e nt, ils ne supprim e nt pas les é lém e nts corre s pondants ;ils s e conte nte nt de re groupe r e n
début d e s é q ue nce les é lém e nts non conce rné s par la condition d'é lim ination e t de fournir e n re tour un
ité rate ur sur le pre m ie r é lém e nt non cons e rvé . En fait, ilfaut voir q u'aucun algorith m e ne pe ut supprim e r
des élém e nts d'une séquence pour la bonne e t sim ple raison q u'ilris q ue d'ê tre appliq ué à une s tructure autre
q u'un conte ne ur (ne s e rait-ce q u'un tableau usuel) pour laq ue lle la notion de s uppre s s ion n'e xiste pas 1.
D 'autre part, contraire m e nt à toute atte nte , iln'e s t pas du tout ce rtain q ue les valeurs apparaissant e n fin de
conte ne ur soient ce lles q ui ont é té é lim inées du début.

Bie n e nte ndu, rie n n'e m pê ch e d'effe ctue r, aprè s avoir appe lé un te lalgorith m e , une s uppre s s ion e ffe ctive
des élém e nts conce rné s e n utilisant une fonction m e m bre te lle q ue re m ove , dans le cas où l'on a affaire à une
s é q ue nce d'un conte ne ur.

L'algorith m e re m ove (début, fin, valeur) pe rm e t d'élim ine r tous les é lém e nts ayant la valeur indiq ué e , e n s e
basant sur l'opé rate ur ==. Ile xiste une ve rsion re m ove _if, q ui s e fonde s ur un prédicat binaire donné. Se ul
le pre m ie r algorith m e e s t stable, c’
e s t-à -dire q u'ilcons e rve l'ordre re latif des valeurs non é lim iné e s .

L'algorith m e unique pe rm e t de ne cons e rve r q ue la pre m iè re valeur d'une s é rie de valeurs é gales (au s e ns de
==) ou ré pondant à un prédicat binaire donné. Iln'im pos e nullem e nt q ue la s é q ue nce s oit ordonné e s uivant
un ce rtain ordre .

Ce s algorith m es disposent d'une ve rsion ave c _copy q ui ne m odifie pas la s é q ue nce d'origine e t q ui range
dans une autre s é q ue nce les s e ules valeurs non é lim iné e s . Utilisés conjointe m e nt ave c un ité rate ur
d'insertion, ils peuve nt pe rm e ttre de cré e r une nouve lle s é q ue nce .

Voici un e xe m ple de program m e m ontrant les principales possibilité s é voq ué e s , y com pris des insertions
dans une séquence ave c re m ove _copy_if (dont on re m arq ue claire m e nt d'ailleurs q u'iln'e s t pas stable) :

_______________________________________________________________________________
__

#include <iostream.h>
#include <list>
using namespace std ;
main()
{ void affiche(list<int>) ;
bool pair (int) ;
int t[] = { 4, 3, 5, 4, 4, 4, 9, 4, 6, 6, 3, 3, 2 } ;
list<int> l (t, t+sizeof(t)/sizeof(int)) ;
list<int> l_bis=l ;
list<int> l2 ; /* liste vide */
list<int>::iterator il ;
cout << "liste initiale : " ; affiche(l) ;

il = remove(l.begin(), l.end(), 4) ; /* different de l.remove(4) */


cout << "liste apres remove(4) : " ; affiche(l) ;
cout << "element places en fin : " ;
for (; il!=l.end() ; il++) cout << *il << " " ; cout << "\n" ;

1 - Un al
gorith m e ne pe ut pas davantage ins é re r un é l
é m e nt dans une séquence ;on pe ut toute fois y parve nir, dans l
e cas d'un conte ne ur,
e n re courant à un ité rate ur d'insertion.
386 Program m e r e n langage C+ +
l = l_bis ;
il = unique (l.begin(), l.end()) ;
cout << "liste apres unique : " ; affiche(l) ;
cout << "elements places en fin : " ;
for (; il!=l.end() ; il++) cout << *il << " " ; cout << "\n" ;

l = l_bis ;
il = remove_if(l.begin(), l.end(), pair) ;
cout << "liste apres remove pair : " ; affiche(l) ;
cout << "elements places en fin : " ;
for (; il!=l.end() ; il++) cout << *il << " " ; cout << "\n" ;

/* elimination de valeurs par copie dans liste vide l2 par iterateur


d'insertion */
l = l_bis ;
remove_copy_if(l.begin(), l.end(), front_inserter(l2), pair) ;
cout << "liste avec remove_copy_if pair : " ; affiche(l2) ;
}
void affiche(list<int> l)
{ list<int>::iterator il ;
for (il=l.begin() ; il!=l.end() ; il++) cout << (*il) << " " ;
cout << "\n" ;
}
bool pair (int n)
{ return !(n%2) ;
} _______________________

liste initiale : 4 3 5 4 4 4 9 4 6 6 3 3 2
liste apres remove(4) : 3 5 9 6 6 3 3 2 6 6 3 3 2
element places en fin : 6 6 3 3 2
liste apres unique : 4 3 5 4 9 4 6 3 2 6 3 3 2
elements places en fin : 6 3 3 2
liste apres remove pair : 3 5 9 3 3 4 9 4 6 6 3 3 2
elements places en fin : 4 9 4 6 6 3 3 2
liste avec remove_copy_if pair : 3 3 9 5 3
________________________________________________________________________
_________

Exe m ple d'utilisation de s algorith m e s de suppression

6. A LGO RITH M ES D E TRIS

Ce s algorith m e s s 'appliq ue nt à d e s s é q ue nce s ordonnables , c’ e s t-à -dire pour les q ue lles ila é té défini une
re lation d'ordre faible s trict, soit par l'opé rate ur < , soit par un prédicat binaire donné. Ils ne peuve nt pas
s'appliq ue r à un conte ne ur associatif, com pte te nu du conflit q ui apparaî trait alors e ntre leur ordre inte rne e t
ce lui q u'on voudrait leur im pos e r. Pour d'é vidente s q ue s tions d'efficacité , la plupart de ce s algorith m e s
né ce s s ite nt des ité rate urs à accè s direct, de sorte q u'ils ne sont pas applicables à des liste s (m ais le conte ne ur
list dispose de sa fonction m e m bre sort).
XXI. Le s algorith m e s s tandard 387
O n pe ut ré aliser des tris com plets d'une séquence. Dans ce cas, on peut ch oisir entre un algorith m e s table
s table_sort ou un algorith m e non stable, plus rapide . O n pe ut e ffe ctue r é galem e nt, ave c partial_sort, des tris
partie ls, c’ e s t-à -dire q ui s e conte nte nt de n'ordonne r q u'un ce rtain nom bre d'élém e nts. Dans ce cas, l'appe l
s e pré s e nte s ous la form e partial_sort (début, m ilie u, fin) e t l'am plitude du tri e s t définie par l'ité rate ur
m ilie u désignant le pre m ie r é lém e nt non trié . Enfin, ave c nth _e lem e nt, il e s t possible de déte rm ine r
s e ulem e nt le niè m e é lém e nt, c’ e s t-à -dire de place r dans ce tte position l'é lém e nt q ui s'y trouve rait si l'on
avait trié toute la s é q ue nce ;là e ncore , l'appe ls e pré s e nte s ous la form e nth _e lem e nt (début, m ilie u, fin) e t
m ilie u désigne l'é lém e nt e n q ue s tion.

Voici un e xe m ple m ontrant l'utilisation de s principaux algorith m es de tri :

________________________________________________________________________
_________

#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
bool comp (int, int) ;
int t[] = {2, 1, 3, 9, 2, 7, 5, 8} ;
int i ;
vector<int> v(t, t+8), v_bis=v ;
cout << "vecteur initial : " ; affiche(v) ;
sort (v.begin(), v.end()) ;
cout << "apres sort : " ; affiche(v) ;
v = v_bis ;
partial_sort (v.begin(), v.begin()+5, v.end()) ;
cout << "apres partial_sort (5) : " ; affiche(v) ;
v = v_bis ;
nth_element (v.begin(), v.begin()+ 5, v.end()) ;
cout << "apres nth_element 6 : " ; affiche(v) ;
nth_element (v.begin(), v.begin()+ 2, v.end()) ;
cout << "apres nth_element 3 : " ; affiche(v) ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur initial : 2 1 3 9 2 7 5 8
apres sort : 1 2 2 3 5 7 8 9
apres partial_sort (5) : 1 2 2 3 5 9 7 8
apres nth_element 6 : 2 1 3 5 2 7 8 9
apres nth_element 3 : 2 1 2 3 5 7 8 9
________________________________________________________________________
_________

Exe m ple d'utilisation de s algorith m e s de tri


388 Program m e r e n langage C+ +
7. A LGO RITH M ES D E RECH ERCH E ET D E FUSIO N SUR D ES SEQUENCES
O RD O NNEES

Ce s algorith m e s s 'appliq ue nt à d e s s é q ue nce s s uppos é e s ordonné e s par une re lation d'ordre faible s trict.

7.1 A l
gorith m e s de re ch e rch e binaire

Le s algorith m es de re ch e rch e pré s e ntés dans le paragraph e 3 s'appliq uaie nt à d e s s é q ue nce s non
né ce s s aire m e nt ordonné e s . Le s algorith m e s pré s e nté s ici supposent q ue la s é q ue nce conce rné e s oit
conve nablem e nt ordonné e s uivant la re lation d'ordre faible s trict q ui s e ra utilisée, qu'ils'agis s e par dé faut
de l'opé rate ur < ou d'un prédicat fourni e xplicite m e nt. C'e s t ce q ui leur pe rm e t d'utiliser des m é th odes de
re ch e rch e dich otom iq ue (ou binaire ) plus perform ante s q ue de sim ples re ch e rch e s s é q ue ntie lles .

Com m e on pe ut s'y atte ndre , ce s algorith m e s ne m odifie nt pas la s é q ue nce conce rné e e t ils peuve nt donc, e n
th é orie , s'appliq ue r à des conte ne urs de type s e t ou m ultise t. En re vanch e , leur application à des type s m ap
e t m ultim ap n'e s t guè re e nvisage able puis q ue , e n gé né ral, ce ne s ont pas leurs é lém e nts q ui sont ordonné s ,
m ais s e ulem e nt les clés ... Quoi q u'ile n soit, les conte ne urs associatifs disposent déjà de fonctions m e m bre
é q uivalant aux algorith m e s e xam iné s ici, e xce pté pour binary_se arch .

L'algorith m e binary_s e arch pe rm e t de savoir s'ile xiste dans la s é q ue nce une valeur é q uivalente (au s e ns de
l'é q uivalence induite par la re lation d'ordre conce rné e ). Par ailleurs, on pe ut localiser l'e m place m e nt
possible pour une valeur donné e , com pte te nu d'un ce rtain ordre : low e r_bound fournit la pre m iè re position
possible tandis q ue uppe r_bound fournit la derniè re position possible ;e q ual_range fournit les deux
inform ations précédente s s ous form e d'une paire.

7.2 A l
gorith m e s de fus ion

La fusion de deux séquences ordonnées consiste à les ré unir e n une troisiè m e s é q ue nce ordonné e s uivant le
m ê m e ordre . Là e ncore , ils peuve nt s'appliq ue r à des conte ne urs de type s e t ou m ultise t ;e n re vanch e , leur
application à des conte ne urs de type m ap ou m ultim ap n'e s t guè re ré aliste , com pte te nu de ce q ue ce s
dernie rs sont ordonné s uniq ue m e nt suivant les clés . Ile xiste deux algorith m e s :

• m e rge q ui pe rm e t la cré ation d'une troisiè m e s é q ue nce par fusion de deux autre s ;
• inplace _m e rge q ui pe rm e t la fusion de deux séquences consécutive s e n une s e ule q ui vie nt pre ndre la
place des deux séquence s originales .
Voici un e xe m ple d'utilisation de ce s algorith m e s :
________________________________________________________________________
_________
#include <iostream.h>
#include <vector>
using namespace std ;
main()
{ void affiche (vector<int>) ;
int t1[8] = {2, 1, 3, 12, 2, 18, 5, 8} ;
int t2[5] = {5, 4, 15, 9, 11} ;
vector<int> v1(t1, t1+8), v2(t2, t2+6), v ;
cout << "vecteur 1 initial : " ; affiche(v1) ;
sort (v1.begin(), v1.end()) ;
cout << "vecteur 1 trie : " ; affiche(v1) ;
cout << "vecteur 2 initial : " ; affiche(v2) ;
sort (v2.begin(), v2.end()) ;
cout << "vecteur 2 trie : " ; affiche(v2) ;
XXI. Le s algorith m e s s tandard 389
merge (v1.begin(), v1.end(), v2.begin(), v2.end(), back_inserter(v)) ;
cout << "fusion des deux : " ; affiche(v) ;
random_shuffle (v.begin(), v.end()) ; /* v n'est plus ordonne */
cout << "vecteur v desordonne : " ; affiche(v) ;
sort (v.begin(), v.begin()+6) ; /* tri des premiers elements de v */
sort (v.begin()+6, v.end()) ; /* tri des derniers elements de v */
cout << "vecteur v trie par parties : " ; affiche(v) ;
inplace_merge (v.begin(), v.begin()+6, v.end()) ; /* fusion interne */
cout << "vecteur v apres fusion : " ; affiche(v) ;
}
void affiche (vector<int> v)
{ unsigned int i ;
for (i=0 ; i<v.size() ; i++)
cout << v[i] << " " ;
cout << "\n" ;
} _______________________

vecteur 1 initial : 2 1 3 12 2 18 5 8
vecteur 1 trie : 1 2 2 3 5 8 12 18
vecteur 2 initial : 5 4 15 9 11 2
vecteur 2 trie : 2 4 5 9 11 15
fusion des deux : 1 2 2 2 3 4 5 5 8 9 11 12 15 18
vecteur v desordonne : 5 12 9 2 2 15 2 5 1 18 3 8 11 4
vecteur v trie par parties : 2 2 5 9 12 15 1 2 3 4 5 8 11 18
vecteur v apres fusion : 1 2 2 2 3 4 5 5 8 9 11 12 15 18
________________________________________________________________________
_________
Exe m ple d'utilisation de s algorith m e s de fusion

8. A LGO RITH M ES A CARACTERE NUM ERIQUE

Nous avons classé dans ce tte rubriq ue les algorith m e s q ui e ffe ctue nt, sur les é lém e nts d'une séquence, des
opé rations num é riq ue s fondé e s s ur les opé rate urs + , - ou *. Plutôt destiné s , a priori, à des élém e nts d'un
type e ffe ctive m e nt num é riq ue , ils peuve nt né anm oins s'appliq ue r à des élém e nts de type clas s e pour pe u q ue
ce tte derniè re ait conve nablem e nt surdéfini les opé rate urs voulus ou q u'e lle fournis s e une fonction binaire
approprié e .

Com m e on pe ut s'y atte ndre , l'algorith m e accum ulate fait la som m e d e s é lém e nts d'une séquence tandis q ue
inne r_product e ffe ctue le produit scalaire de deux séquences de m ê m e taille. O n pre ndra garde au fait q ue
ces deux algorith m e s ajoute nt le ré s ultat à une valeur initiale fournie e n argum e nt (e n gé né ral, on ch oisit 0).

L'algorith m e partial_sum cré e , à partir d'une s é q ue nce , une nouve lle s é q ue nce de m ê m e taille form é e d e s
cum uls partie ls des valeurs de la pre m iè re : le pre m ie r é lém e nt e s t inch angé , le s e cond e s t la som m e du
pre m ie r e t du second, e tc. Enfin, l'algorith m e adjace nt_diffe re nce cré e , à partir d'une s é q ue nce , une
s é q ue nce de m ê m e taille form ée des diffé re nces de deux élém e nts cons é cutifs (le pre m ie r é lém e nt re s tant
inch angé ).

Voici un e xe m ple d'utilisation de ces diffé re nts algorith m e s :

________________________________________________________________________
_________

#include <iostream.h>
#include <numeric> // pour les algorithmes numeriques
using namespace std ;
39 0 Program m e r e n langage C+ +
main()
{ void affiche (int *) ;
int v1[5] = { 1, 3, -1, 4, 1} ;
int v2[5] = { 2, 5, 1, -3, 2} ;
int v3[5] ;
cout << "vecteur v1 : " ; affiche(v1) ;
cout << "vecteur v2 : " ; affiche(v2) ;
cout << "somme des elements de v1 : "
<< accumulate (v1, v1+3, 0) << "\n" ; /* ne pas oublier 0 */
cout << "produit scalaire v1.v2 : "
<< inner_product (v1, v1+3, v2, 0) << "\n" ; /* ne pas oublier 0 */
partial_sum (v1, v1+5, v3) ;
cout << "sommes partielles de v 1 : " ; affiche(v3) ;
adjacent_difference (v1, v1+5, v3) ;
cout << "differences ajdacentes de v1 : " ; affiche(v3) ;
}
void affiche (int * v)
{ int i ; for (i=0 ; i<5 ; i++) cout << v[i] << " " ; cout << "\n" ;
} _______________________

vecteur v1 : 1 3 -1 4 1
vecteur v2 : 2 5 1 -3 2
somme des elements de v1 : 3
produit scalaire v1.v2 : 16
sommes partielles de v 1 : 1 4 3 7 8
differences ajdacentes de v1 : 1 2 -4 5 -3
________________________________________________________________________
_________

Exe m ple d'utilisation d'algorith m e s num é rique s

9 . A LGO RITH M ES A CARACTERE ENSEM BLISTE

Com m e on a pu le constate r dans le ch apitre pré cédent, les conte ne urs s e t e t m ultise t ne disposent d'aucune
fonction m e m bre pe rm e ttant de ré aliser les opé rations e ns e m bliste s classiques. En revanch e , ile xiste des
algorith m e s gé né raux q ui, q uant à e ux, pe uve nt e n th é orie s 'appliq ue r à d e s s é q ue nce s q ue lconq ue s ;ilfaut
ce pe ndant q u'e lles s oie nt conve nablem e nt ordonné e s , ce q ui constitue une pre m iè re diffé re nce par rapport
aux notions m ath é m atiq ue s usuelles , dont l'ordre e s t m anife s te m e nt absent. De plus, ce s notions
e ns e m bliste s ont dû ê tre q ue lque pe u am é nagé e s , de m aniè re à acce pte r la pré s e nce de plusieurs élém e nts de
m ê m e valeur.

L'é galité e ntre deux é lém e nts s e fonde s ur l'opé rate ur == ou, é ve ntue llem e nt, sur un prédicat binaire
fourni e xplicite m e nt. Pour q ue les algorith m e s fonctionne nt conve nablem e nt, ile s t alors néce s s aire q ue ce tte
re lation d'é galité s oit com patible ave c la re lation ayant s e rvi à ordonne r les s é q ue nce s corre s pondante s ;plus
pré cis é m e nt, ile s t né ce s s aire q ue les classes d'équivalence induite par la re lation d'ordre faible s trict
coïncide nt ave c ce lles q ui sont induite s par l'é galité .

Par ailleurs, les algorith m e s cré ant une nouve lle s é q ue nce le font, com m e toujours, dans des élém e nts
e xistants, ce q ui pos e m anife s te m e nt un problèm e ave c des conte ne urs de type s e t ou m ultise t q ui
n'autoris e nt pas la m odification de s valeurs de leurs é lém e nts m ais s e ulem e nt les s uppre s s ions ou les
ins e rtions. Dans ce cas, ilfaudra donc re courir à un ité rate ur d'inse rtion pour la s é q ue nce à cré e r. D e plus,
com m e ni s e t ni m ultise t ne disposent d'insertion e n début ou e n fin, ce t ité rate ur d'inse rtion ne pourra ê tre
q ue inse rte r.
XXI. Le s algorith m e s s tandard 39 1
Voici un e xe m ple corre s pondant à l'usage le plus courant des algorith m e s , à savoir leur application à des
conte ne urs de type s e t.

________________________________________________________________________
_________

#include <iostream.h>
#include <set>
using namespace std ;
main()
{ char t1[] = "je me figure ce zouave qui joue du xylophone" ;
char t2[] = "en buvant du whisky" ;
void affiche (set<char> ) ;
set<char> e1(t1, t1+sizeof(t1)-1) ;
set<char> e2(t2, t2+sizeof(t2)-1) ;
set<char> u, i, d, ds ;
cout << "ensemble 1 : " ; affiche (e1) ;
cout << "ensemble 2 : " ; affiche (e2) ;
set_union (e1.begin(), e1.end(), e2.begin(), e2.end(),
inserter(u, u.begin())) ;
cout << "union des deux : " ; affiche (u) ;
set_intersection (e1.begin(), e1.end(), e2.begin(), e2.end(),
inserter(i, i.begin())) ;
cout << "intersecton des deux : " ; affiche (i) ;
set_difference (e1.begin(), e1.end(), e2.begin(), e2.end(),
inserter(d, d.begin())) ;
cout << "difference des deux : " ; affiche (d) ;
set_symmetric_difference (e1.begin(), e1.end(), e2.begin(), e2.end(),
inserter(ds, ds.begin())) ;
cout << "difference_symetrique des deux : " ; affiche (ds) ;
}
void affiche (set<char> e )
{ set<char>::iterator ie ;
for (ie=e.begin() ; ie!=e.end() ; ie++) cout << *ie << " " ; cout << "\n" ;
} _______________________

ensemble 1 : a c d e f g h i j l m n o p q r u v x y z
ensemble 2 : a b d e h i k n s t u v w y
union des deux : a b c d e f g h i j k l m n o p q r s t u v w x y z
intersecton des deux : a d e h i n u v y
difference des deux : c f g j l m o p q r x z
difference_symetrique des deux : b c f g j k l m o p q r s t w x z
________________________________________________________________________
_________

Exe m ple d'utilisation d'algorith m e s à caractè re e ns e m bliste ave c un conte ne ur de type s e t


XXII. LA CLASSE STRING

Si l'on ch e rch e à m anipuler de s ch aînes de caractè re s e n s e fondant uniq ue m e nt sur les instructions de bas e
du langage C+ + , les ch os e s ne s ont pas plus satisfaisante s q u'e n C ;e n particulie r on n'y dispose pas d'un
type ch aîne à part e ntiè re e t m ê m e une opé ration aussi banale q ue l'affe ctation n'e xiste pas ;q uant aux
possibilités de ge s tion dynam iq ue , on ne pe ut y accéder q u'e n gé rant soi m ê m e les ch os e s ...

La biblioth è q ue s tandard dispose d'un patron de clas s e s pe rm e ttant de m anipuler de s ch aî ne s gé né ralisées,


c’ e s t-à -dire des suites de valeurs de type q ue lconq ue donc, en particulie r, de type ch ar. Ils'agit du patron
basic_string param é tré par le type d e s é lém e nts. M ais ile xiste une clas s e s pé cialisée nom m é e s tring q ui e s t
définie com m e basic_string< ch ar> . Ici, nous nous lim ite rons à l'e xam e n de s proprié tés de ce tte clas s e q ui
e s t de loin la plus utilisée ;la gé né ralisation à basic_string ne pré s e nte , de toute s façons, aucune difficulté .

La clas s e s tring propos e un cadre trè s souple de m anipulation de ch aî nes de caractè re s e n offrant les
fonctionnalité s traditionne lles q u'on pe ut atte ndre d'un te l type : ge s tion dynam iq ue transpare nte des
e m place m e nts corre s pondants, affe ctation, concaté nation, re ch e rch e de sous-ch aî ne s , ins e rtions ou
suppre s s ion de s ous-ch aî ne s ... O n ve rra q u'e lle possè de non seulem e nt beaucoup de s fonctionnalités de la
clas s e ve ctor (plus précisém e nt ve ctor< ch ar> pour s tring), m ais é galem e nt bien d'autre s . D'une m aniè re
gé né rale, ce s fonctionnalité s s e m e tte nt e n œuvre de façon trè s nature lle, ce q ui nous perm e ttra de les
pré s e nte r as s e z briè ve m e nt. Ilfaut ce pe ndant note r une pe tite difficulté lié e à la pré s e nce de ce rtaine s
possibilité s redondante s , les une s faisant appe là des ité rate urs usuels, les autre s à des valeurs d'indice s .

1. GENERA LITES

Un obje t de type s tring contie nt, à un instant donné , une s uite form ée d'un nom bre q ue lconq ue de caractè re s
q ue lconq ue s . Sa taille pe ut é volue r dynam iq ue m e nt au filde l'e xé cution du program m e . Contraire m e nt aux
conve ntions utilisées pour les (ps e udo) ch aî nes du C, la notion de caractè re de fin de ch aî ne n'e xiste plus e t
ce caractè re de code nulpe ut apparaî tre au s e in de la ch aîne , é ve ntue llem e nt à plusieurs reprises. Un te l
obje t re s s e m ble donc à un conte ne ur de type ve ctor< ch ar> e t ilpossè de d'ailleurs un ce rtain nom bre de
fonctionnalité s com m une s :

• l'accè s aux é lém e nts e xistants peut s e faire ave c l'opé rate ur [] ou ave c la fonction m e m bre at ;com m e
ave c les ve cte urs ou les tableaux usuels, le pre m ie r caractè re corre s pond à l'indice 0 ;
• ilpossè de une taille courante fournie par la fonction m e m bre size () ;
• son em place m e nt e s t ré s e rvé s ous form e d'un seulbloc de m é m oire (ou, du m oins, tout s e pas s e com m e
si ce la é tait le cas) ;la fonction capacity fournit le nom bre m axim alde caractè re s q u'on pourra y
introduire , sans q u'ilsoit besoin de procéder à une nouve lle allocation m é m oire ;on pe ut re courir aux
fonctions re s e rve e t re s ize ;
XXII. La clas s e s tring 39 3
• on dispose des ité rate urs à accè s direct ite rator e t re ve rs e _ite rator, ainsi que des valeurs particuliè re s
be gin(), e nd(), rbe gin(), re nd().

2. CO NSTRUCTIO N

La clas s e s tring dispose de beaucoup de constructe urs ;ce rtains corre s ponde nt aux constructe urs d'un
ve cte ur :

string ch1 ; /* construction d'une chaîne vide : ch1.size() == 0


*/
string ch2 (10, '*') ; /* construction d'une chaîne de 10 caractères égaux à
'*' */
/* ch2.size() == 10
*/
string ch3 (5, '\0') ; /* construction d'une chaîne de 5 caractères de code nul
*/
/* ch2.size() == 5
*/

D 'autre s pe rm e tte nt d'initialiser une ch aî


ne lors de sa construction, à partir de ch aî
ne s usuelles , constante s
ou non :

string mess1 ("bonjour") ; /* construction d'une chaîne de 7 caractères :


bonjour */
char * adr = "salut" ;
string mess2 (adr) ; /* construction d'une chaîne de 5 caractères : salut
*/

Bie n e nte ndu, on dispose d'un constructe ur par re copie usuel:

string s1 ;
.....
string s2(s1) /* ou string s2 = s1 ; construction de s2 par recopie de s1
*/
/* s2.size() == s1.size()
*/

Bie n q ue d'un inté rê t lim ité , on pe ut é galem e nt construire une ch aî


ne à partir d'une s é q ue nce de caractè re s ,
par e xe m ple, si le s t de type list< ch ar> :

string chl (l.begin(), l.end()) ; /* construction d'une chaîne en y recopiant


*/
/* les caractères de la liste l
*/

3. O PERA TIO NS GLO BA LES

O n dispose tout nature llem e nt des opérations globales déjà re ncontré e s pour les ve cte urs, à savoir
l'affe ctation, les fonctions assign e t s w ap, ainsi que des com paraisons lexicograph iq ue s .
39 4 Program m e r e n langage C+ +
En outre , les opé rate urs < < e t > > sont conve nablem e nt surdéfinis pour de s obje ts de type s tring ;ile n va
de m ê m e de la fonction ge tline , re ncontrée dans le paragraph e 2.3 du ch apitre XVI dans le cas de ch aî ne s
usuelles .

4. CO NCA TENA TIO N

L'opé rate ur + a é té s urdé fini de m aniè re à pe rm e ttre la concaté nation :

• de deux obje ts de type s tring,


• d'un obje t de type s tring ave c une ch aî
ne usuelle ou ave c un caractè re , e t ce ci dans n'im porte q ue lordre ,
L'opé rate ur + = e s t défini de façon concom itante .

Voici q ue lque s e xe m ples :

string ch1 ("bon") ; /* ch1.size() == 3 */


string ch2 ("jour") ; /* ch2.size() == 4 */
string ch3 ; /* ch3.size() == 0 */
ch3 = ch1 + ch2 ; /* ch3.size() == 7 ; ch3 contient la chaîne "bonjour"
*/
ch3 = ch1 + ' ' ; /* ch3.size() == 4 */
ch3 += ch2 ; /* ch3.size() == 8 ; ch3 contient la chaîne "bon jour"
*/
ch3 += " monsieur" /* ch3 contient la chaîne "bon jour monsieur"
*/

O n note ra ce pe ndant q u'iln'e s t pas possible de concaté ne r de ux ch aî


ne s usuelles ou une ch aî
ne usuelle e t un
caractè re :

char c1, c2 ;
ch3 = ch1 + c1 + ch2 + c2 ; /* correct */
ch3 = ch1 + c1 + c2 ; /* incorrect ; mais on peut toujours faire :
*/
/* ch3 = ch1 + c1 ; ch3 += c2 ;
*/

5. RECH ERCH E D A NS UNE CH A INE

Ce s fonctions perm e tte nt de re trouve r la pre m iè re ou la derniè re occurre nce d'une ch aî


ne ou d'un caractè re
donné s , d'un caractè re apparte nant à une s uite de caractè res donnés, d'un caractè re n'apparte nant pas à une
suite de caractè res donnés.

Lors q u'une te lle ch aî ne ou un te lcaractè re a é té localisé, on obtie nt e n re tour l'indice corre s pondant au
pre m ie r caractè re conce rné ;si la re ch e rch e n'aboutit pas, on obtie nt une valeur d'indice e n de h ors des
lim ite s pe rm ises pour la ch aî
ne , ce q ui re nd q ue lque pe u difficile l'e xam e n de s a valeur.

5.1 Re ch e rch e d'une ch aî


ne ou d'un caractè re

La fonction m e m bre find pe rm e t de re ch e rch e r, dans une ch aî


ne donnée, la pre m iè re occurre nce :

• d'une autre ch aî
ne (on parle s ouve nt de sous-ch aî
ne ) fournie s oit par un obje t de type s tring, soit par une
ch aî
ne usuelle,
XXII. La clas s e s tring 39 5
• d'un caractè re donné.
Par défaut, la re ch e rch e com m e nce au début de la ch aî
ne , m ais on pe ut la faire débute r à un caractè re de
rang donné .

Voici q ue lque s e xe m ples :


string ch = "anticonstitutionnellement" ;
string mot ("on");
char * ad = "ti" ;
int i ;
i = ch.find ("elle") ; /* i == 17 */
i = ch.find ("elles") ; /* i <0 ou i > ch.size() */
i = ch.find (mot) ; /* i == 5 */
i = ch.find (ad) ; /* i == 2 */
i = ch.find ('n') ; /* i == 1 */
i = ch.find ('n', 5) ; /* i == 6 , car ici, la recherche débute à ch[5] */
i = ch.find ('p') ; /* i <0 ou i > ch.size() */

D e m aniè re s e m blable, la fonction rfind pe rm e t de re ch e rch e r la derniè re occurre nce d'une autre ch aî
ne ou
d'un caractè re .

string ch = "anticonstitutionnellement" ;
string mot ("on");
char * ad = "ti" ;
int i ;
i = ch.rfind ("elle") ; /* i == 17 */
i = ch.rfind ("elles") ; /* i <0 ou i > ch.size() */
i = ch.rfind (mot) ; /* i == 14 */
i = ch.rfind (ad) ; /* i == 12 */
i = ch.rfind ('n') ; /* i == 23 */
i = ch.rfind ('n', 18) ; /* i == 16 */

5.2 Re ch e rch e d'un caractè re pré s e nt ou abs e nt d'une s uite

La fonction find_firs t_of re ch e rch e la pre m iè re occurre nce de l'un de s caractè res d'une autre ch aîne (s tring
ou usuelle), tandis q ue find_last_of e n re ch e rch e la derniè re occurre nce . La fonction find_firs t_not_of
re ch e rch e la pre m iè re occurre nce d'un caractè re n'apparte nant pas à une autre ch aî ne , tandis q ue
find_last_not_of e n re ch e rch e la derniè re . Voici q ue lque s e xe m ples :

string ch = "anticonstitutionnellement" ;
char * ad = "oie" ;
int i ;
i = ch.find_first_of ("aeiou") ; /* i == 0 */
i = ch.find_first_not_of ("aeiou") ; /* i == 1 */
i = ch.find_first_of ("aeiou", 6) ; /* i == 9 */
i = ch.find_first_not_of ("aeiou", 6) /* i == 6 */
i = ch.find_first_of (ad) ; /* i == 3 */
i = ch.find_last_of ("aeiou") ; /* i == 22 */
i = ch.find_last_not_of ("aeiou") ; /* i == 24 */
i = ch.find_last_of ("aeiou", 6) ; /* i == 5 */
i = ch.find_last_not_of ("aeiou", 6) /* i == 6 */
i = ch.find_last_of (ad) ; /* i == 22 */
39 6 Program m e r e n langage C+ +
6. INSERTIO NS, SUPPRESSIO NS ET REM PLACEM ENTS

Ce s possibilité s s ont re lative m e nt classiques, m ais e lles s e re coupe nt partie llem e nt, dans la m e s ure où l'on
pe ut :

- d'une part utiliser, non seulem e nt des obje ts de type s tring, m ais aussi des ch aî
ne s usuelles (ch ar *) ou
des caractè re s ,
- d'autre part définir une s ous-ch aî ne , soit par indice , soit par ité rate ur, ce tte derniè re possibilité n'é tant
ce pe ndant pas offe rte systé m atiq ue m e nt.

6.1 Ins e rtions

La fonction inse rt pe rm e t d'insérer :

• à une position donné e , définie par un indice :


- une autre ch aî ne (obje t de type s tring) ou une partie de ch aî
ne définie par un indice de début e t une
é ve ntue lle longue ur,
- une ch aî
ne usuelle (type ch ar *) ou une partie de ch aî
ne usuelle définie par une longue ur,
- une ou plusieurs fois un caractè re donné ;
• à une position donné e d é finie par un ité rate ur :
- une s é q ue nce d'élém e nts de type ch ar, définie par un ité rate ur de début e t un ité rate ur de fin,
- une ou plusieurs fois un caractè re donné.
Voici q ue lque s e xe m ples :

________________________________________________________________________
_________

#include <iostream.h>
#include <string>
#include <list>
using namespace std ;
main()
{ string ch ("0123456") ;
string voy ("aeiou") ;
char t[] = {"778899"} ;
/* insere le caractere a en ch.begin()+1 */
ch.insert (ch.begin()+1, 'a') ; cout << ch << "\n" ;
/* insere le caractere b en position d'indice 4 */
ch.insert (4, 'b') ; cout << ch << "\n" ;
/* insere 3 fois le caractere x en fin de ch */
ch.insert (ch.end(), 3, 'x') ; cout << ch << "\n" ;
/* insere 3 fois le caractere x en position d'indice 6 */
ch.insert (6, 3, 'x') ; cout << ch << "\n" ;
/* insere la chaine voy en position 0 */
ch.insert (0, voy) ; cout << ch << "\n" ;
/* insere, en position 3, la chaine voy, a partir de position
d'indice 2 */
ch.insert (3, voy, 2) ; cout << ch << "\n" ;
/* insere en debut, la chaine voy, a partir de position d'indice 1,
longueur 3 */
XXII. La clas s e s tring 39 7
ch.insert (0, voy, 1, 3) ; cout << ch << "\n" ;
/* insertion d'une sequence */
ch.insert (ch.begin()+2, t, t+6) ; cout << ch << "\n" ;
}
_______________________

0a123456
0a12b3456
0a12b3456xxx
0a12b3xxx456xxx
aeiou0a12b3xxx456xxx
aeiiouou0a12b3xxx456xxx
eioaeiiouou0a12b3xxx456xxx
ei778899oaeiiouou0a12b3xxx456xxx
________________________________________________________________________
_________

Exe m ple d'inse rtions dans une ch aî


ne

6.2 Suppre s s ions

La fonction re m ove pe rm e t de supprim e r :

• une partie d'une ch aîne , définie s oit par un ité rate ur de début e t un ité rate ur de fin, soit par un indice de
début e t une longue ur ;
• un caractè re donné défini par un ité rate ur de début.
Voici q ue lque s e xe m ples :

________________________________________________________________________
_________

#include <iostream.h>
#include <string>
#include <list>
using namespace std ;
main()
{ string ch ("0123456789"), ch_bis=ch ;
/* supprime, a partir de position d'indice 3, pour une longueur de 2 */
ch.remove (3, 2) ; cout << "A : " << ch << "\n" ;
ch = ch_bis ;
/* supprime, de begin()+3 à begin()+6 */
ch.remove (ch.begin()+3, ch.begin()+6) ; cout << "B : " << ch << "\n" ;
/* supprime, a partir de position d'indice 3 */
ch.remove (3) ; cout << "C : " << ch << "\n" ;
ch = ch_bis ;
/* supprime le caractere de position begin()+4 */
ch.remove (ch.begin()+4) ; cout << "D : "<< ch << "\n" ;
}
_______________________

A : 01256789
39 8 Program m e r e n langage C+ +
B : 0126789
C : 012
D : 012356789

________________________________________________________________________
_________

Exe m ples de suppressions dans une ch aî


ne

6.3 Re m pl
ace m e nts

La fonction re place pe rm e t de re m place r une partie d'une ch aî


ne définie , soit par un indice e t une longue ur,
soit par un inte rvalle d'ité rate ur, par :

• une autre ch aî
ne (obje t de type s tring),
• une partie d'une autre ch aî
ne définie par un indice de début e t, é ve ntue llem e nt, une longue ur,
• une ch aî
ne usuelle (type ch ar *) ou une partie de longue ur donné e ,
• un ce rtain nom bre de fois un caractè re donné.
En outre , on pe ut re m place r une partie d'une ch aî ne définie par un inte rvalle par une autre s é q ue nce
d'élém e nts de type ch ar, définie par un ité rate ur de début e t un ité rate ur de fin.

Voici q ue lque s e xe m ples :


________________________________________________________________________
_________

#include <iostream.h>
#include <string>
using namespace std ;
main()
{ string ch ("0123456") ;
string voy ("aeiou") ;
char t[] = {"+*-/=<>"} ;
char * message = "hello" ;
/* remplace, a partir de indice 2, sur longueur 3, par voy */
ch.replace (2, 3, voy) ; cout << ch <<
"\n" ;
/* remplace, a partir de indice 0 sur longueur 1, par voy, */
/* a partir de indice 2, longueur 3 */
ch.replace (0, 1, voy, 1, 2) ; cout << ch
<< "\n" ;
/* remplace, a partir de indice 1 sur longueur 2, par 8 fois '*' */
ch.replace (1, 2, 8, '*') ; cout << ch
<< "\n" ;
/* remplace, a partir de indice 1 sur longueur 2, par 5 fois '#' */
ch.replace (1, 2, 5, '#') ; cout << ch
<< "\n" ;
/* remplace, a partir de indice 2, sur longueur 4, par "xxxxxx" */
ch.replace (2, 4, "xxxxxx" ) ; cout << ch
<< "\n" ;
/* remplace les 7 derniers caracteres par les 3 premiers de message
*/
XXII. La clas s e s tring 39 9
ch.replace (ch.size()-7, ch.size(), message, 3) ; cout << ch
<< "\n" ;
/* remplace tous les caracteres, sauf le dernier, par (t, t+5) */
ch.replace (ch.begin(), ch.begin()+ch.size()-1, t, t+5) ; cout << ch
<< "\n" ;
}
_______________________

01aeiou56
ei1aeiou56
e********aeiou56
e#####******aeiou56
e#xxxxxx******aeiou56
e#xxxxxx******hel
+*-/=l
________________________________________________________________________
_________

Exe m ples d e re m place m e nts dans une ch aî


ne
XXIII. LES O UTILS NUM ÉRIQUES

La biblioth è q ue s tandard offre q ue lque s patrons de classe destiné s à facilite r les opé rations m ath é m atiq ue s
usuelles s ur les nom bre s com plexe s e t sur les ve cte urs, de m aniè re à m unir C+ + de possibilité s voisines de
ce lles de Fortran 9 0 e t à favoris e r son utilisation sur des calculate urs ve ctorie ls ou parallèles . Ils'agit
e s s e ntie llem e nt :

• de la clas s e com plex


• de la clas s e val_array e t de clas s e s assim ilée s .

1. LA CLASSE CO M PLEX

Le patron de clas s e com plexe offre de trè s rich e s outils de m anipulation de s nom bre s com plexe s . Ilpe ut ê tre
param é tré par n'im porte q ue ltype flottant, float, double ou long double. Ilcom porte :

• les opé rations arith m é tiq ue s usuelles : + , -, *, /,


• l'affe ctation (ordinaire ou com pos é e com m e + =, -=...),
• les fonctions de bas e : abs, arg, norm , re al, im ag,
• les fonctions "transce ndante s " :
- cos , sin, tan,
- acos , asin, atan,
- cos h , sinh , tanh ,
- e xp, log.
Voici un e xe m ple d'utilisation :

________________________________________________________________________
_________

#include <complex>
using namespace std ;
main()
{ complex<float> z1(1, 2), z2(2, 5), z, zr ;
cout << "z1 : " << z1 << " z2 : " << z2 << "\n" ;
cout << "Re(z1) : " << real(z1) << " Im(z1) : " << imag(z1) << "\n" ;
cout << "z1 + z2 : " << (z1+z2) << " z1*z2 : " << (z1*z2)
<< " z1/z2 : " << (z1/z2) << "\n" ;
complex<double> i(0, 1) ; // on definit la constante i
z = 1+i ;
XXIII. Le s outils num é rique s 401
zr = exp(z) ;
cout << "exp(1+i) : " << zr << " exp(i) : " << exp(i) << "\n" ;
zr = log(i) ;
cout << "log(i) : " << zr << "\n" ;
double rho, theta, norme ;
rho = abs(z) ; theta = arg(z) ; norme = norm(z) ;
cout << "abs(1+i) : " << rho << " arg(1+i) : " << theta
<< " norm(1+i) : " << norme << "\n" ;
double pi = 3.1415926535 ;
cout << "cos(i) : " << cos(i) << " sinh(pi*i): " << sinh(pi*i)
<< " cosh(pi*i) : " << cosh(pi*i) << "\n" ;
}
_______________________

z1 : (1,2) z2 : (2,5)
Re(z1) : 1 Im(z1) : 2
z1 + z2 : (3,7) z1*z2 : (-8,9) z1/z2 : (0.413793,-0.0344828)
exp(1+i) : (1.46869,2.28736) exp(i) : (0.540302,0.841471)
log(i) : (0,1.5708)
abs(1+i) : 1.41421 arg(1+i) : 0.785398 norm(1+i) : 2
cos(i) : (1.54308,0) sinh(pi*i): (0,8.97932e-11) cosh(pi*i) : (-1,0)
________________________________________________________________________
_________

Exe m ples d'utilisation de nom bre s com plexe s

2. LA CLASSE VA LARRAY

Ces diffé re nte s clas s e s s ont indé pe ndantes des conte ne urs décrits dans les ch apitre s pré cédents. Par ailleurs,
e lles ne s ont actue llem e nt pas connue s par toute s les im plém e ntations de C+ + ;nous n'en donnerons q u'un
bre f ape rçu.

La clas s e valarray e s t particuliè re m e nt adapté e aux tableaux num é riq ue s , c'e s t-à -dire dont les é lém e nts sont
d'un type de bas e . Voici q ue lque s e xe m ples de construction :

valarray<int> vi (10) ; /* tableau de 10 int */


valarray<float> vf (0.1, 20) ; /* tableau de 20 float initialisés à 0.1 */
double t [] = { 1.25, 3.5, 0, 1.5 } ;
valarray<double> vd (t, t+4) ; /* tableau de 4 double, initialisé avec les */
/* valeurs de t */

La clas s e valarray pe rm e t d'effe ctue r de s opé rations usuelles de calculve ctorie le n gé né ralisant le rôle de
tous les opé rate urs e t fonctions num é riq ue s : un opé rate ur unaire appliq ué à un tableau fournit e n ré s ultat le
tableau obte nu e n appliq uant ce t opé rate ur à ch acun de s e s é lém e nts ;un opé rate ur binaire appliq ué à deux
tableaux de m ê m e taille fournit e n ré s ultat le tableau obte nu e n appliq uant ce t opé rate ur à ch acun de s
é lém e nts de m ê m e rang. Par e xe m ple :

valarray<float> v1(5), v2(5), v3(5) ;


.....
v3 = -v1 ; /* v3[i] = -v1[i] pour i de 0 à 4 */
v3 = cos(v1) ; /* v3[i] = cos(v1[i]) pour i de 0 à 4 */
v3 = v1 + v2 ; /* v3[i] = v2[i] + v1[i] pour i de 0 à 4 */
v3 = v1*v2 + exp(v1) ; /* v3[i] = v1[i]*v2[i] + exp(v1[i]) pour i de 0 à 4 */
402 Program m e r e n langage C+ +
Elle com porte é galem e nt des opérate urs de com paraison (==, !=, <, <=...) q ui s'appliq ue nt à deux
opé rande s (de type valarray) de m ê m e nom bre d'élém e nts e t q ui fournis s e nt e n ré s ultat un tableau de
boolée ns :

int dim = ... ;


valarray<float> v1(dim), v2(dim) ;
valarray<bool> egal(dim), inf(dim) ;
.....
egal = (v1 == v2) ; /* egal[i] = (v1[i] == v2[i]) pour i de 0 à dim-1 */
inf = (v1 < v2) ; /* inf[i] = (v1[i] < v2[i]) pour i de 0 à dim-1 */

La clas s e m ask _array pe rm e t de définir de s "m as q ue s " (tableaux de boolée ns) utilisables dans la plupart des
opé rations appliq ué e s aux tableaux1.

Enfin, ile s t possible de définir des "s e ctions" de tableaux ;on nom m e ainsi un sous-e ns e m ble d e s é lém e nts
d'un tableau sur leq ue lon pe ut travailler com m e s 'ils'agissait d'un tableau. La clas s e s lice _array pe rm e t de
définir de s s e ctions ré guliè re s , dans les q ue lles on considè re d e s é lém e nts ré partis de façon ré guliè re ;e lles
sont caracté ris é e s par un indice de début, un pas e t un nom bre d'élém e nts. La clas s e indire ct_array pe rm e t
de définir de s s e ctions irré guliè re s caracté ris é e s par de s ve cte urs d'indice s , c’ e s t-à -dire q u'on pré cis e
l'e m place m e nt de ch aq ue é lém e nt. De plus, la clas s e gslice _array pe rm e t de définir de s s e ctions à plusieurs
nive aux facilitant la m anipulation de tableaux à plusieurs indices.

1 - O n trouve des possibil


ité s s e m bl
abl
e s e n Fortran 9 0, ave c l
'instruction w h e re .
ANNEXE A :
RÈGLES D E M ISE EN
CO RRESPO ND A NCE D 'ARGUM ENTS

Voici l'e ns e m ble des rè gles pré s idant à la m ise en corre s pondance d'argum e nts lors de l'appe l d'une
fonction surdéfinie ou d'un opé rate ur.

Nous décrivons tout d'abord la dém arch e e m ployé e pour les fonctions à un s e ulargum e nt avant de voir
com m e nt e lle s e gé né ralise aux fonctions à plusieurs argum e nts.

Note z bie n q ue , com m e nous l'avons signalé dans les ch apitre s corre s pondants, ce s rè gles ne s 'appliq ue nt
pas inté gralem e nt à l'instanciation d'une fonction patron.

1. CAS DES FO NCTIO NS À UN ARGUM ENT

1.1 Re ch e rch e d'une corre s pondance e xacte

D ans la re ch e rch e d'une correspondance exacte :

• O n distingue bien les diffé re nts type s e ntie rs (ch ar, s h ort, int e t long) ave c leur attribut de signe ainsi que
les diffé re nts type s flottants (float, double e t long double). Note z q ue , as s e z curie us e m e nt, ch ar e s t à la
fois diffé re nt de signe d ch ar e t de unsigne d ch ar (alors q ue , dans une im plém e ntation donné e 1, ch ar e s t
é q uivalent à l'un de ces deux type s !).
• O n ne tie nt pas com pte d e s é ve ntue ls q ualificatifs volatile e t cons t, ave c ce pe ndant deux exceptions pour
cons t :
- D e puis la ve rsion 2.0, on distingue un pointe ur de type t *( t é tant un type q ue lconq ue ) d'un pointe ur
de type cons t t *, c'e s t-à -dire un pointe ur sur une valeur constante de type t.
Plus précisém e nt, ilpe ut e xiste r de ux fonctions, l'une pour le type t *, l'autre pour le type cons t t *.
La pré s e nce ou l'abs e nce du qualificatif cons t pe rm e ttra de ch oisir la "bonne " fonction.
S'iln'e xiste q u'une s e ule de ces deux fonctions corre s pondant au type cons t t *, t *constitue q uand
m ê m e une corre s pondance e xacte pour cons t t *(là e ncore , ce ci s e justifie par le fait q ue le traite m e nt
pré vu pour q ue lque ch ose de constant pe ut s'appliq ue r à q ue lque ch ose de non constant). En
re vanch e , s'iln'e xiste q u'une fonction corre s pondant au type t *, cons t t * ne constitue pas une
corre s pondance e xacte pour ce type t *(ce q ui signifie q u'on ne pourra pas appliq ue r à q ue lque ch os e
de constant le traite m e nt pré vu pour q ue lque ch ose de non constant).

1 - D u m oins, pour des options de com pil


ation données.
404 Program m e r e n langage C+ +
- D e puis la ve rsion 3, on distingue le type t & (t é tant un type q ue lconq ue e t & désignant un transfe rt
par ré fé re nce ) du type cons t t & . Le raisonne m e nt pré cédent s'appliq ue e n re m plaçant sim plem e nt t *
par t & 2.
Si une fonction ré alise une correspondance exacte , la re ch e rch e s 'arrê te là e t la fonction trouvé e e s t appe lée .
Note z q u'à ce nive au ce tte fonction e s t obligatoire m e nt uniq ue ;e n e ffe t, dans le cas contraire , les
déclarations des diffé re nte s fonctions auraie nt é té re je té e s lors de leur com pilation (par e xe m ple, vous ne
pourre z jam ais définir f(int) e t f(cons t int)).

1.2 Prom otions num é riq ue s 3

Si la re ch e rch e pré cédente n'a pas abouti, on e ffe ctue alors une nouve lle re ch e rch e , e n faisant inte rve nir les
conve rsions suivante s :

ch ar, signe d ch ar, unsigne d ch ar, s h ort -> int


unsigne d sh ort -> int ou unsigne d int4
e num -> int
float -> double
Ici e ncore , si une fonction e s t trouvé e , e lle ne pe ut ê tre q u'uniq ue .

1.3 Conve rs ions s tandard

Si la re ch e rch e n'a toujours pas abouti, on fait alors inte rve nir les conve rsions standard suivante s :

• type num é riq ue e n un autre type num é riq ue (y com pris des conve rsions "dégradante s "5 : ainsi, un float
convie ndra là où un int e s t atte ndu),
• e num e n un autre type num é riq ue ,
• 0 -> num é riq ue .
• 0 -> pointe ur q ue lconq ue ,
• pointe ur q ue lconq ue -> void *6,
• pointe ur sur une classe dérivé e -> pointe ur sur une classe de bas e .
Ce tte fois, ile s t possible q ue plusieurs fonctions convie nne nt. Ily a alors am biguïté , e xce pté q ue lque s
situations :

• la conve rsion d'un pointe ur sur une classe dérivé e e n un pointe ur sur une classe de bas e e s t pré fé ré e à la
conve rsion en void *,
• si C dérive de B e t q ue B dérive de A, la conve rsion C *e n B *e s t pré fé ré e à la conve rsion en A * ;il
e n va de m ê m e pour la conve rsion C & e n B & q ui e s t pré fé ré e à la conve rsion en A & .

2 - En toute rigue ur, on distingue é gal e m e nt vol


atile t*de t*e t vol atile t & de t & .
3 - Elle s n'e xis taie nt pas dans le s ve rsions anté rie ure s à l
a ve rsion 2.0.
4 - Suivant q ue, dans l 'im pl
é m e ntation conce rnée, un int s uffit ou ne s uffit pas à accue il
lir un unsigne d sh ort (ilne l
e pe ut pas l
ors q ue s h ort
e t int corre s ponde nt au m ê m e nom bre de bits ).
5 - Dans l e s ve rsions anté rie ure s à l
a 2.0, on s e l
im itait aux conve rsions "non dégradante s ".
6 - La conve rsion inve rs e n'e s t pas pré vue. Ceci est coh é re nt ave c l e fait q u'e n C+ + , contraire m e nt à ce q ui s e pas s e e n C ANSI, un
pointe ur de type void *ne pe ut pas ê tre affe cté à un pointe ur q ue l
conq ue.
Anne xe A : rè gles d e "m ise en correspondance d'argum e nts " 405

1.4 Conve rs ions dé finie s par l


'util
is ate ur

Si aucune fonction ne convie nt, on fe ra inte rve nir les "conve rsions définie s par l'utilisate ur" (C.D .U.).

Une s e ule C.D .U. pourra inte rve nir ;e n re vanch e , e lle pourra ê tre associé e à d'autre s conve rsions.
Toute fois, lors q u'une ch aî ne de conve rsions peut ê tre s im plifié e e n une ch aî ne plus courte , s e ule ce tte
derniè re e s t considérée ;par e xe m ple, dans ch ar -> int -> float e t ch ar -> float , on ne considè re q ue
ch ar -> float. Ici e ncore , si plusieurs com binaisons de conve rsions existe nt (aprè s les é ve ntue lles
sim plifications é voq ué e s ), le com pilate ur re fus e ra l'appe là cause de son am biguïté .

1.5 Fonctions à argum e nts variabl


es

Lors q u'une fonction a pré vu de s argum e nts de type s q ue lconq ue s (notation "..."), n'im porte q ue ltype
d'argum e nt e ffe ctif convie nt.

Note z bie n q ue ce tte possibilité n'e s t e xam iné e q u'e n de rnie r. Ce tte re m arq ue pre ndra tout son inté rê t dans
le cas de fonctions à plusieurs argum e nts.

1.6 Exce ption

Lors q u'une fonction possè de un argum e nt m ue t q ui e s t une ré fé re nce (autre m e nt dit q u'ile s t du type T& ), la
corre s pondance d'argum e nt doit pe rm e ttre à la fonction de travailler "dire cte m e nt" ave c la variable
conce rné e , donc é ve ntue llem e nt de la m odifie r. Ce la im pliq ue obligatoire m e nt des re s trictions sur le type de
l'argum e nt e ffe ctif corre s pondant : ildoit s'agir d'une lvalue de type T.

Une s e ule e xce ption a lie u lors q ue l'argum e nt m ue t possè de l'attribut cons t car, dans ce cas, on pe ut m e ttre
à disposition de la fonction la ré fé re nce à une valeur te m poraire obte nue à partir de la valeur de l'argum e nt
e ffe ctif (ave c d'éve ntue lles conve rsions).

2. CAS DES FO NCTIO NS À PLUSIEURS ARGUM ENTS

Le com pilate ur re ch e rch e une fonction "m e illeure " q ue toute s les autre s . Pour ce faire , ilappliq ue les rè gles
de re ch e rch e pré cédente s à ch acun de s argum e nts. Ce la l'am è ne à s é lectionne r, pour ch aq ue argum e nt, une
ou plusieurs fonctions ré alisant la m e illeure corre s pondance ;ce tte fois, ilpe ut y en avoir plusieurs car la
déte rm ination finale de la "bonne fonction" n'e s t pas e ncore faite (toute fois, si aucune fonction n'e s t
s é lectionné e pour un argum e nt donné , on e s t déjà sûr q u'aucune fonction ne convie ndra). Ensuite d e q uoi, le
com pilate ur dé te rm ine , pour toute s les fonctions ainsi sélectionné e s , ce lle, si elle e xiste e t si elle e s t uniq ue ,
q ui ré alise la m e illeure corre s pondance , c'e s t-à -dire ce lle pour laq ue lle la corre s pondance de ch aq ue
argum e nt e s t é gale ou supérieure à ce lle des autre s 7.

R e m arque :

7 - En fait, ce l
a re vie nt à dire, en te rm e e ns e m bl
istes, qu'on considè re l
'inte rs e ction des diffé re nts e ns e m bl
e s form és des fonctions
ré al
isant l
a m e il
le ure corre s pondance pour ch aq ue argum e nt. Ce tte inte rs e ction doit com porte r e xacte m e nt un é l
é m e nt.
406 Program m e r e n langage C+ +
Le s fonctions com portant un ou plusieurs argum e nts par dé faut sont traité e s com m e s i plusieurs fonctions
diffé re nte s avaie nt é té définie s ave c un nom bre croissant d'argum e nts.

3. CAS DES FO NCTIO NS M EM BRE

Un appe lde fonction m e m bre (non statiq ue 8) pe ut ê tre considéré com m e un appe ld'une fonction ordinaire ,
auq ue ls'ajoute un argum e nt e ffe ctif ayant le type de l'obje t ayant e ffe ctué l'appe l. Toute fois, ce t argum e nt
n'e s t pas du tout soum is aux rè gl es de correspondance dont nous parlons ici ;e n e ffe t, c'e s t son type q ui
déte rm ine la fonction m e m bre à appe ler (ave c é ve ntue llem e nt pris e e n com pte d'un m é canism e d'h é ritage ).

Le s s e ules "nuance s " q ui puis s e nt inte rve nir conce rne nt les attribut cons t e t volatile. En e ffe t, ile s t possible
de distingue r une fonction m e m bre agissant sur des obje ts constants d'une fonction m e m bre agissant sur des
obje ts non constants. Une fonction m e m bre constante pe ut toujours agir sur des obje ts non constants ;la
ré ciproq ue e s t bien sûr faus s e . La m ê m e re m arq ue s 'appliq ue à l'attribut volatile.

8 - Une fonction m e m bre statiq ue ne com porte aucun argum e nt im pl


icite de type cl
asse.
ANNEXE B :
LES INCO M PA TIBILITÉS
ENTRE C ET C+ +

Nous ré capitulons ici l'e ns e m ble des incom patiblité s e xistant e ntre le C ANSI e t le C+ + (dans ce s e ns),
c'e s t-à -dire les diffé re nts points acce pté s par le C ANSI e t re fus é s par le C+ + . Note z q ue les cinq pre m ie rs
points ont é té e xpos é s e n dé taildans le ch apitre II, le dernie r l'a é té dans le ch apitre IV. Le s autre s
corre s ponde nt à des usage s as s e z pe u fré q ue nts.

1. Prototype s

En C+ + , toute fonction non dé finie pré alablem e nt dans un fich ie r source où e lle e s t utilisée doit faire
l'obje t d'une déclaration sous form e d'un prototype .

2. Fonctions s ans argum e nts

En C+ + , une fonction sans argum e nts se définit (e n-tê te ) e t se déclare (prototype ) e n fournissant une "liste
vide" d'argum e nts com m e dans :

float fct () ;

3. 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 ) obl
igatoirem ent à
l'aide du m ot void com m e dans :

void fct (int, double) ;

4. Le q ual
ificatif cons t

En C+ + , un sym bole accom pagné , dans sa déclaration, du q ualificatif cons t a une porté e lim ité e au fich ie r
source conce rné , alors q u'e n C ANSI ile s t considéré com m e un sym bole e xte rne . De plus, e n C+ + , un te l
sym bole pe ut inte rve nir dans une expression constante (ilne s 'agit toute fois plus d'une incom patibilité m ais
d'une liberté offe rte par C+ + ).
408 Program m e r e n langage C+ +

5. Le s pointe urs d e type void *

En C+ + , un pointe ur de type void *ne pe ut pas ê tre conve rti im plicite m e nt e n un pointe ur d'un autre type .

6. M ots cl
és

C+ + possè de, par rapport à C, les m ots clés s upplém e ntaire s suivants 1 :

1 - Le m ot cl
é ove rload a e xis té dans l
e s ve rsions anté rie ure s à l
a 2.0. S'ilre s te re connu de ce rtaine s im pl
é m e ntations, en étant al
ors s ans
e ffe t, ilne figure ce pe ndant pas dans l
a norm e.
bool
catch
class
cons t_cas t
de lete
dynam ic_cas t
e xplicit
false
frie nd
inline
m utable
nam e space
ne w
ope rator
private
prote cte d
public
re inte rpre t_cas t
s tatic_cas t
te m plate
th is
true
th row
try
type id
type nam e
using
virtual
Voici la liste com plète des m ots clés de C+ + ;ce ux q ui e xiste nt déjà e n C sont é crits e n rom ain tandis q ue
ce ux q ui sont propre s à C+ + sont é crits e n italiq ue ;à sim ple titre indicatif, les m ots clés introduits
tardive m e nt par la norm e ANSI sont é crits e n gras (e t e n italiq ue ).
asm virtual
auto void
bool volatile
bre ak w ch ar_t
cas e w h ile
catch
ch ar
class
const
const_cast
continue
default
de lete
do
double
dynam ic_cast
e lse
e num
explicit
e xte rn
false
float
for
frie nd
goto
if
inline
int
long
m utable
nam espace
ne w
ope rator
private
prote cte d
public
re giste r
reinterpret_cast
re turn
sh ort
signed
sizeof
static
static_cast
struct
sw itch
te m plate
th is
th row
true
try
typedef
typeid
typenam e
union
unsigned
using
7. Le s cons tante s de type caractè re

En C+ + (depuis la ve rsion 2.0), une constante caractè re te lle q ue 'a', 'z' ou '\n' e s t de type ch ar, alors
q u'e lle e s t im plicite m e nt conve rtie e n nt e n C ANSI (e t dans les ve rsions de C+ + anté rie ure s à la 2.0).
Ce la pe rm e t notam m e nt de distingue r, par e xe m ple, les deux fonctions suivante s :

fct (char) ;

fct (int) ;

C'e s t ainsi que l'opé rate ur < < d e la clas s e ostre am pe ut fonctionne r corre cte m e nt ave c des caractè re s (dans
les ve rsions anté rie ure s à la 2.0, on obtie nt le code num é riq ue du caractè re ).

Note z bie n q u'une e xpre s s ion te lle q ue :

sizeof ('a')

vaut 1 e n C+ + (depuis la ve rsion 2.0), alors q u'e lle vaut davantage (gé né ralem e nt 2 ou 4) e n C ou dans les
ve rsions de C+ + anté rie ure s à la 2.0.

8. Le s dé finitions m ul
tipl
es

En C ANSI, ile s t pe rm is de trouve r plusieurs déclarations d'une m ê m e variable dans un fich ie r source . Par
e xe m ple, ave c :

int n ;
.....
int n ;

C considè re q ue la pre m iè re instruction e s t une s im ple déclaration, tandis q ue la s e conde e s t une définition ;
c'e s t ce tte derniè re q ui provoq ue la ré s e rvation de l'e m place m e nt m é m oire pour n.

En C+ + , cel a est interdit. La raison principale vie nt de ce q ue , dans le cas où de te lles déclarations
porte raie nt sur des obje ts, par e xe m ple dans :

point a ;
.....
point a ;
.....

ilfaudrait q ue le com pilate ur distingue déclaration e t définition de l'obje t point e t q u'ilpré voie de n'appe ler
le constructe ur q ue dans le s e cond cas. Ce la aurait é té particuliè re m e nt dange re ux, d'où l'inte rdiction
adopté e .

9 . L'ins truction goto

En C+ + , une instruction goto ne pe ut pas faire s aute r une déclaration com portant un "initialiseur" (par
e xe m ple int n = 2 ), sauf si ce tte déclaration figure dans un bloc e t q ue ce bloc e s t sauté com plète m e nt.
Anne xe B : les incom patibilité s e ntre C e t C+ + 413
10. Le s é num é rations

En C+ + , les é lém e nts d'une énum é ration (m ot clé e num ) ont une porté e lim ité e à l'e s pace de visibilité dans
leq ue lils sont définis. Par e xe m ple, ave c :

struct chose
{ enum (rouge = 1, bleu, vert) ;
.....
} ;

les sym boles rouge , bleu e t ve rt ne pe uve nt pas ê tre e m ployé s e n de h ors d'un obje t de type ch ose . Ils
pe uve nt é ve ntue llem e nt ê tre redéfinis ave c une s ignification diffé re nte . En C, ces sym boles s ont acce s s ibles
de toute la partie du fich ie r source s uivant leur dé claration e t iln'e s t alors plus possible de les redéfinir.

11. Initial
is ation de tabl
e aux de caractè re s

En C+ + , l'initialisation de tableaux de caractè re s par une ch aî


ne de m ê m e longue ur n'e s t pas possible. Par
e xe m ple, l'instruction :

char t[5] = "hello" ;

provoq ue ra une e rre ur, due à ce q ue t n'a pas une dim e nsion suffisante pour re ce voir le caractè re (\0) de fin
de ch aî
ne .

En C ANSI, ce tte m ê m e déclaration s e rait acce pté e e t le tableau t s e ve rrait sim plem e nt initialisé ave c les 5
caractè re s h , e , l, le t o (sans caractè re de fin de ch aî
ne ).

Note z q ue l'instruction :

char t[] = "hello" ;

convie nt indiffé re m m e nt e n C e t e n C+ + e t q u'e lle ré s e rve dans les deux cas un tableau de 6 caractè re s : h ,
e , l, l, o e t \0.

12. Le s nom s d e fonctions

En C+ + , depuis la ve rsion 2.0, le com pilate ur attribue à toute s les fonctions un "nom e xte rne " basé d'une
façon dé te rm iniste :

• sur son nom "inte rne ",


• sur la nature de ses argum e nts.
Si l'on ve ut obte nir les m ê m e s nom s de fonction q u'e n C, on pe ut faire appe lau m ot clé e xte rn. Pour plus de
détails, voye z le paragraph e 5.3 du ch apitre IV.
ANNEXE C :
O PÉRA TEURS D E CAST ET
ID ENTIFICA TIO N D E TYPE À
L'ÉXÉCUTIO N

Ce tte anne xe pré s e nte q ue lque s points q ui ont é té introduits as s e z tardive m e nt dans la norm e ANSI e t q ui
ris q ue nt de ne pas existe r dans ce rtaine s im plém e ntations. Ils'agit e s s e ntie llem e nt :

• de possibilités d'identification dynam iq ue du type des obje ts au m om e nt de l'e xé cution,


• de nouve aux opé rate urs de "cast",
• de possibilités de "cast" dynam iq ue s ,

1. ID ENTIFICA TIO N D E TYPE À L'EXÉCUTIO N

La norm e ANSI pré voit dans C+ + un m é canism e pe rm e ttant de connaî tre (ide ntifie r e t com pare r), lors de
l'e xé cution du program m e , le type d'une variable, d'une e xpre s s ion ou d'un obje t.

Bie n e nte ndu, ce la ne pré s e nte guè re d'inté rê t si un te ltype e s t défini lors de la com pilation. Ainsi, ave c :

int n ;
float x ;

ilne s e ra guè re inté re s s ant de savoir q ue le type de n ou ce lui de x pe uve nt ê tre connus ou encore que n e t x
sont d'un type diffé re nt. La m ê m e re m arq ue s 'appliq ue rait à des obje ts d'un type clas s e .

En fait, ce tte possibilité a é té e s s e ntie llem e nt introduite pour ê tre utilisée dans les s ituations de
polym orph ism e , com m e nous l'avons décrit dans le ch apitre re latif aux fonctions virtue lles .

Plus précisém e nt, ile s t possible, lors de l'e xé cution, de connaî


tre le véritabl
e type d'un objet désigné par
un pointeur ou par une référence.

Pour ce faire , ile xiste un opé rate ur nom m é type id à un opé rande fournissant e n ré s ultat un obje t de type
prédéfini Type _info. Ce tte clas s e contie nt la fonction m e m bre nam e (), laq ue lle fournit une ch aî ne de
caractè re s re pré s e ntant le nom du type ;ce nom n'e s t pas im pos é par la norm e ;ilpe ut donc dé pe ndre de
l'im plém e ntation m ais on est sûr q ue deux types diffé re nts n'auront jam ais le m ê m e nom .
Anne xe C : les apports du C+ + ANSI 415
D e plus, la classe dispose de deux opérate urs binaire s == e t != q ui pe rm e tte nt de com pare r de ux type s .

1.1 Util
is ation du ch am p nam e de Type _info

Voici un pre m ie r e xe m ple inspiré du program m e utilisé pour illustre r le m é canism e des fonctions virtue lles
(paragraph e 2 du ch apitre XV) ;ilm ontre l'inté rê t q ue pré s e nte type id lors q u'on l'appliq ue dans un conte xte
de polym orph ism e .

_______________________________________________________________________________
______

#include <iostream.h>
#include <typeinfo.h> // pour typeid
class point
{ public :
virtual void affiche ()
{ } // ici vide - utile pour le polymorphisme
} ;

class pointcol : public point


{ public :
void affiche ()
{ } // ici vide
} ;
main()
{ point p ; pointcol pc ;
point * adp ;
adp = &p ;
cout << "type de adp : " << typeid (adp).name() << "\n" ;
cout << "type de *adp : " << typeid (*adp).name() << "\n" ;
adp = &pc ;
cout << "type de adp : " << typeid (adp).name() << "\n" ;
cout << "type de *adp : " << typeid (*adp).name() << "\n" ;
}
_______________________

type de adp : point *


type de *adp : point
type de adp : point *
type de *adp : pointcol
_______________________________________________________________________________
______

Exe m ple d'utilisation de l'opérate ur typeid

O n note ra bie n q ue , pour type id, le type du pointe ur adp re s te bien point *, m ais q u'e n re vanch e , le type de
l'obje t pointé (*adp) q uant à lui, e s t bien déte rm iné par la nature e xacte de l'obje t pointé .

R e m arques :

1) R appe lons q ue la norm e n'im pos e pas le nom e xact q ue doit fournir ce t opé rate ur ;on n'e s t donc pas
assuré q ue le nom de type s e ra toujours point, point *, pointcol*com m e ici.
416 Program m e r e n langage C+ +
2) Ici, les m é th ode s affich e ont é té pré vue s vides ;e lles ne s e rve nt e n fait q u'à assure r le polym orph ism e .
En son absence, l'opé rate ur type id s e conte nte rait de fournir com m e type d'un obje t pointé ce lui dé fini
par le type (statiq ue ) du pointe ur.
3) Note z bie n q ue s i les fonctions virtue lles pe rm e ttaie nt d'aboutir à un ce rtain typage dynam iq ue , ce
dernie r ne conce rnait q ue les fonctions m e m bre appe lée s : on appe lait bien la fonction m e m bre
corre s pondant au type de l'obje t pointé , m ais on ne disposait, e n re vanch e , d'aucun m oye n pe rm e ttant de
connaî tre le type de ce t obje t pointé . O u, pour e xprim e r les ch oses d'une autre m aniè re , on obte nait le
com porte m e nt corre s pondant au type de l'obje t pointé , m ais on ne pouvait pas e n connaî tre e xplicite m e nt
le type .

1.2 Util
is ation de s opé rate urs d e com parais on de Type _info

Voici, toujours inspiré du program m e re latif aux fonctions virtue lles , un e xe m ple m ontrant l'usage de
l'opé rate ur ==.

_______________________________________________________________________________
______

#include <iostream.h>
#include <typeinfo.h> // pour typeid
class point
{ public :
virtual void affiche ()
{ } // ici vide - utile pour le polymorphisme
} ;
class pointcol : public point
{ public :
void affiche ()
{ } // ici vide
} ;
main()
{ point p1, p2 ;
pointcol pc ;
point * adp1, * adp2 ;
adp1 = &p1 ; adp2 = &p2 ;
cout << "En A : les objets pointes par adp1 et adp2 sont " ;
if (typeid(*adp1) == typeid (*adp2)) cout << "meme type\n" ;
else cout << "type different\n" ;
adp1 = &p1 ; adp2 = &pc ;
cout << "En B : les objets pointes par adp1 et adp2 sont " ;
if (typeid(*adp1) == typeid (*adp2)) cout << "meme type\n" ;
else cout << "type different\n" ;
} _______________________

En A : les objets pointes par adp1 et adp2 sont de meme type


En B : les objets pointes par adp1 et adp2 sont de type different
_______________________________________________________________________________
______

Exe m ple de com parais on de types dynam ique s ave c l'opérate ur typeid
Anne xe C : les apports du C+ + ANSI 417
1.3 Exe m pl
e ave c de s ré fé re nce s

Voici un de rnie r e xe m ple où l'on appliq ue l'opé rate ur== de type id à des ré fé re nce s . O n voit q u'on dispose
ainsi d'un m oye n de s 'assure r dynam iq ue m e nt (au m om e nt de l'e xé cution) de l'ide ntité de type de deux
obje ts re çus e n argum e nt d'une fonction.

_______________________________________________________________________________
______

#include <iostream.h>
#include <typeinfo.h> // pour typeid
class point
{ public :
virtual void affiche ()
{ } // ici vide
} ;
class pointcol : public point
{ public :
void affiche ()
{ } // ici vide
} ;
void fct (point & a, point & b)
{ if (typeid(a) == typeid(b))
cout << "reference a des objets de meme type \n" ;
else cout << "reference a des objets de type different \n" ;
}
main()
{ point p ;
pointcol pc1, pc2 ;
cout << "Appel A : " ; fct (p, pc1) ;
cout << "Appel B : " ; fct (pc1, pc2) ;
}
_______________________

Appel A : reference a des objets de meme type


Appel B : reference a des objets de type different
_______________________________________________________________________________
______

Exe m ple d'utilisation de typeid ave c de s ré fé re nce s

2. LES NO UVEAUX O PÉRA TEURS D E "CAST"

En C+ + , com m e e n C, ile s t possible de ré aliser des conve rsions explicite s , à l'aide d'un opé rate ur de
"cast". Le s conve rsions acce pté e s com porte nt nature llem e nt toute s les conve rsions im plicite s légales
auxq ue lles s 'ajoute nt q ue lque s autre s pouvant ê tre dégradante s ou dé pe ndantes de l'im plém e ntation.

La norm e ANSI pré voit de cons e rve r ce s possibilité s , tout e n proposant de nouve aux opé rate urs de "cast",
plus é vocate urs de la nature de la conve rsion et de sa portabilité é ve ntue lle ;ils sont form é s com m e les
opé rate urs classiques à l'aide du type s ouh aité , leq ue le s t com plété d'un m ot clé pré cisant le type de
conve rsion :

• cons t_cas t : pour ajoute r ou supprim e r à un type l'un de s m odificate urs cons t ou volatile,
418 Program m e r e n langage C+ +
• re inte rpre t_cas t : pour les conve rsions dont le ré s ultat dépend de l'im plém e ntation ;typiq ue m e nt, il
s'agit des conve rsions d'entie r ve rs pointe ur e t de pointe ur ve rs e ntie r.
• s tatic_cas t : pour les conve rsions indé pe ndantes de l'im plém e ntation. En fait, les conve rsions de pointe ur
ve rs pointe ur e ntre nt dans ce tte caté gorie , m algé les diffé re nce s q ui pe uve nt apparaî tre lié e s aux
contraintes d'aligne m e nt propre s à ch aq ue im plém e ntation.
Voici q ue lque s e xe m ples com m e nté s :

_______________________________________________________________________________
______

#include <iostream.h>
main ()
{
int n = 12 ;
const int * ad1 = &n ;
int * ad2 ;

ad2 = (int *) ad1 ; // ancienne forme conseillée


// (ad2 = ad1 serait rejetée)
ad2 = const_cast <int*> (ad1) ; // forme ANSI conseillée
ad1 = ad2 ; // légale
ad1 = (const int *) ad2 ; // forme ancienne conseillée
ad1 = const_cast <const int *> (ad2) ; // forme ANSI conseillée

const int p = 12 ;
const int const * ad3 = &p ;
int * ad4 ;

ad4 = (int *) ad3 ; // ancienne forme conseillée


// (ad4 = ad3 serait rejetée)
ad4 = const_cast <int *> (ad3) ; // forme ANSI conseillée

ad3 = ad4 ; // légale


ad3 = (const int const *) ad4 ; // ancienne forme conseillée
ad3 = const_cast <const int const *> (ad4) ; // forme ANSI conseillée
}
_______________________________________________________________________________
______

Exe m ples d'utilisation de l'opérate ur cons t_cas t < ...>

_______________________________________________________________________________
______

#include <iostream.h>
main ()
{ long n ;
int * adi ;
adi = (int *) n ; // ancienne forme conseillée
// (adi = n serait rejetée)
adi = reinterpret_cast <int *> (n) ; // forme ANSI conseillée

n = (long) adi ; // ancienne forme conseillée


// (n = adi serait rejetée)
Anne xe C : les apports du C+ + ANSI 419
n = reinterpret_cast <long> (adi) ; // forme ANSI conseillée

int p ;
p = n ; // acceptée
p = (int) n ; // ancienne forme conseillée
p = static_cast <int> (n) ; // forme ANSI conseillée
}
_______________________________________________________________________________
______

Exe m ples d'utilisation de s opérate urs re inte rpre t_cas t < ...> e t s tatic_cas t

R e m arque :

Ce s nouve aux opé rate urs n'apporte nt aucune possibilité de conve rsion supplém e ntaire . Iln'e n ira pas de
m ê m e de l'opé rate ur dynam ic_cas t, é tudié ci-aprè s.

3. LES "CAST" D Y NA M IQUES

3.1 Introduction

Nous ve nons de voir com m e nt les possibilités d'identification de s type s à l'e xé cution com plète nt le
polym orph ism e offe rt par les fonctions virtue lles e n pe rm e ttant d'identifie r le type des obje ts pointé s ou
ré fé re ncé s .

Ce pe ndant, une lacune s ubsiste : on sait agir sur l'obje t pointé e n fonction de s on type , on pe ut connaî tre le
type e xact de ce t obje t m ais le type propre m e nt dit des pointe urs utilisés dans ce polym orph ism e re s te ce lui
défini à la com pilation. Par e xe m ple, si l'on sait q ue adp pointe s ur un obje t de type pointcol(dérivé de
point), on pourrait souh aite r conve rtir sa valeur e n un pointe ur de type pointcol*.

Le proje t de norm e C+ + pré voit ce tte possibilité , par le biais d'opérate urs dits "cast dynam iq ue s ". Ainsi,
ave c l'h ypoth è s e pré cédente (on e s t sûr q ue adp pointe ré e llem e nt sur un obje t de type pointcol), on pourra
é crire :

pointcol * adpc = dynamic_cast <pointcol *> (adp) ;

Bie n e nte ndu, e n com pilation, la s e ule vé rification q ui s e ra faite e s t q ue ce tte conve rsion est (pe ut-ê tre )
acce ptable car l'obje t pointé par adp e s t d'un type point ou dé rivé e t pointcole s t lui-m ê m e dérivé de point.
M ais, ce n'e s t q u'au m om e nt de l'e xé cution q u'on saura si la conve rsion est ré alisable ou non. Par e xe m ple,
si adp pointait sur un obje t de type point, la conve rsion éch oue rait.

3.2 D 'une m aniè re gé né ral


e

L'opé rate ur dynam ic_cas t aboutit si l'obje t ré e llem e nt pointé e s t, par rapport au type d'arrivé e d e m andé ,
d'un type identiq ue ou d'un type desce ndant (m ais dans un conte xte de polym orph ism e , c'e s t-à -dire q u'il
doit e xiste r au m oins une fonction virtue lle).

Lors q ue l'opé rate ur n'aboutit pas :

• ilfournit le pointe ur NU LLs'ils'agit d'une conve rsion de pointe ur,


• ildéclench e une e xce ption bad_cast s'ils'agit d'une conve rsion de réfé re nce .
420 Program m e r e n langage C+ +
3.3 Exe m pl
e

Voici un e xe m ple faisant inte rve nir une h ié rarch ie de trois classes dérivé e s les unes des autre s .

_______________________________________________________________________________
______

#include <iostream.h>
#include <typeinfo.h> // pour typeid
class A
{ public :
virtual void affiche () // vide ici - utile pour le polymorphisme
{ }
} ;
class B : public A
{ public :
void affiche ()
{ }
} ;
class C : public B
{ public :
void affiche ()
{ }
} ;
main()
{ A a ; B b ; C c ;
A * ada, * ada1 ;
B * adb, * adb1 ;
C * adc ;
ada = &a ; // ada de type A* pointe sur un A ;
// sa conversion dynamique en B* ne marche pas
adb = dynamic_cast <B *> (ada) ; cout << "dc <B*>(ada) " << adb << "\n" ;
ada = &b ; // ada de type A* pointe sur un B ;
// sa conversion dynamique en B* marche
adb = dynamic_cast <B *> (ada) ; cout << "dc <B*> ada " << adb << "\n" ;
// sa conversion dynamique en A* marche
ada1 = dynamic_cast <A*> (ada) ; cout << "dc <A*> ada " << ada1 << "\n" ;
// mais sa conversion dynamique en C* ne marche pas
adc = dynamic_cast <C *> (ada) ; cout << "dc <C*> ada " << adc << "\n" ;
adb = &b ; // adb de type B* pointe sur un B
// sa conversion dynamique en A* marche
ada1 = dynamic_cast <A *> (adb) ; cout << "dc <A*> adb " << ada1 << "\n" ;
// sa conversion dynamique en B* marche
adb1 = dynamic_cast <B *> (adb) ; cout << "dc <A*> adb1 " << adb1 << "\n" ;
// mais sa conversion dynamique en C* ne marche pas
adc = dynamic_cast <C *> (adb) ; cout << "dc <C*> adb1 " << adc << "\n" ;
} _______________________

dc <B*>(ada) 0x00000000
dc <B*> ada 0x54820ffc
dc <A*> ada 0x54820ffc
dc <C*> ada 0x00000000
dc <A*> adb 0x54820ffc
dc <A*> adb1 0x54820ffc
dc <C*> adb1 0x00000000
Anne xe C : les apports du C+ + ANSI 421
_______________________________________________________________________________
______

Exe m ple d'utilisation de l'opérte ur dynam ic_cas t


ANNEXE D :
LES D IFFÉRENTES SO RTES
D E FO NCTIO NS EN C+ +

Nous vous fournissons ici la liste des diffé re nte s s ortes de fonctions q ue l'on pe ut re ncontre r e n C+ + e n
pré cisant, dans ch aq ue cas, si elle pe ut ê tre définie com m e fonction m e m bre ou am ie , s'ile xiste une ve rsion
par dé faut, si elle e s t h é rité e e t si elle pe ut ê tre virtue lle.

Type de M em bre Version H érité e Peut ê tre


fonction ou am ie par défaut virtuel l
e

constructe ur m e m bre oui non non


destructe ur m e m bre oui non oui
conve rsion m e m bre non oui oui

affe ctation m e m bre oui non oui


() m e m bre non oui oui
[] m e m bre non oui oui

-> m e m bre non oui oui


ne w m e m bre s tatiq ue non oui oui

delete m e m bre s tatiq ue non oui oui

autre opé rate ur l'un ou l'autre non oui oui


autre fonction m e m bre non oui oui
m e m bre
fonction am ie am ie non non non
ANNEXE E :
CO M PTAGE D E RÉFÉRENCES

Nous avons vu q ue , dè s lors q u'un obje t com porte une partie dynam iq ue , ile s t né ce s s aire de procéder à des
copie s "profonde s " plutôt q u'à des copie s "superficie lles " e t ce ci aussi bien dans le constructe ur de re copie
q ue dans l'opé rate ur d'affe ctation. D ans ce cas, on pe ut se dem ande r s'il e s t vraim e nt né ce s s aire de
dupliq ue r la partie dynam iq ue de l'obje t.

En fait, si cette partie dynam ique est toujours m anipul é e gl


obal em ent1, ile s t possible d'évite r une te lle
duplication e n faisant appe là la te ch niq ue du "com pte ur de ré fé re nce s ". Elle consiste à com pte r, e n
pe rm ane nce , le nom bre de ré fé re nce s à un e m place m e nt dynam iq ue , c'e s t-à -dire le nom bre de pointe urs
diffé re nts la désignant à un instant donné . Dans ces conditions, lors q u'un obje t e s t détruit, ilsuffit de n'en
détruire la partie dynam iq ue corre s pondante q ue s i son com pte ur de ré fé re nce s e s t nulpour é vite r les ris q ue s
de libération m ultiple q ue nous avons souve nt é voq ué s .

Pour m e ttre e n œuvre ce tte te ch niq ue , deux points doive nt ê tre pré cis é s .

a) L'em pl
acem ent du com pteur de références

A priori, de ux possibilité s vie nne nt à l'e s prit : dans l'obje t lui-m ê m e ou dans la partie dynam iq ue associé e à
l'obje t. La pre m iè re s olution n'e s t guè re e xploitable car e lle oblige rait d'une part à dupliq ue r ce com pte ur
autant de fois q u'ily a d'obje ts pointant sur une m ê m e zone e t, d'autre part, ils e rait trè s difficile d'effe ctue r
la m ise à jour de s com pte urs de tous les obje ts désignant la m ê m e zone . M anife s te m e nt donc, le com pte ur de
ré fé re nce doit ê tre associé , non pas à un obje t, m ais à sa partie dynam iq ue .

b) Les m é th odes devant agir sur l


e com pteur de références

Le com pte ur de ré fé re nces doit ê tre m is à jour ch aq ue fois q ue le nom bre d'obje ts désignant l'e m place m e nt
corre s pondant ris q ue d'ê tre m odifié . Ce la conce rne donc :

• le constructe ur de re copie : ildoit initialiser un nouve lobje t pointant sur un e m place m e nt déjà ré fé re ncé
e t donc incré m e nte r son com pte ur de ré fé re nce s ,
• l'opé rate ur d'affe ctation ;une instruction te lle q ue a = b doit :
- décré m e nte r le com pte ur de ré fé re nces de l'e m place m e nt ré fé re ncé par a e t procéder à sa libération
lors q ue le com pte ur e s t nul,
- incré m e nte r le com pte ur de ré fé re nces de l'e m place m e nt ré fé re ncé par b.
Bie n e nte ndu, ile s t indispensable q ue le constructe ur de re copie e xiste e t q ue l'opé rate ur d'affe ctation soit
surdéfini. Le non-re s pe ct de l'une de ces deux conditions e t l'utilisation de s m é th ode s par dé faut q ui e n
découle e ntraî ne raie nt des re copies d'obje ts sans m ise à jour de s com pte urs de ré fé re nce s ...

1 - Ce ne s e rait pas l
e cas par e xe m pl
e pour une cl
as s e "ve cte ur dynam iq ue " dans l
aq ue l
le on aurait s urdéfini l
'opé rate ur [].
424 Program m e r e n langage C+ +
Nous vous proposons un "cane vas général" applicable à toute classe de type X possédant une partie
dynam iq ue de type T. Ici, pour ré aliser l'association de la partie dynam iq ue e t du com pte ur associé , nous
utilisons une structure de nom partie _dyn. La partie dynam iq ue de X s e ra gé ré e par un pointe ur sur une
structure de type partie _dyn.

_______________________________________________________________________________
____

// T désigne un type quelconque (éventuellement classe)

struct partie_dyn // structure "de service" pour la partie dynamique de


l'objet
{ long nref ; // compteur de référence associé
T * adr ; // pointeur sur partie dynamique (de type T)
} ;
class X
{ // membres donnée non dynamiques
// .....
partie_dyn * adyn ; // pointeur sur partie dynamique
void decremente () // fonction "de service" - décrémente le
{ if (!--adyn->nref) // compteur de référence et détruit
{ delete adyn->adr ; // la partie dynamique si nécessaire
delete adyn ;
}
}
public :
X ( ) // constructeur "usuel"
{ // construction partie non dynamique
// .....
// construction partie dynamique
adyn = new partie_dyn ;
adyn->adr = new T ;
adyn->nref = 1 ;
}
X (X & x) // constructeur de recopie
{ // recopie partie non dynamique
// .....
// recopie partie dynamique
adyn = x.adyn ;
adyn->nref++ ; // incrémentation compteur références
}
~X () // destructeur
{ decremente () ;
}
X & operator = (X & x) // surdéfinition opérateur affectation
{ if (this != &x) // on ne fait rien pour a=a
// traitement partie non dynamique
// .....
// traitement partie dynamique
{ decremente () ;
x.adyn->nref++ ;
adyn = x.adyn ;
}
return * this ;
Anne xe E : com ptage de ré fé re nce s 425
}
} ;
_______________________________________________________________________________
____

Un cane vas généralpour le "com ptage de ré fé re nce s "


ANNEXE F :
LES A LGO RITH M ES
STANDARD

Ce tte anne xe fournit le rôle e xact des algorith m e s propos é s par la biblioth è q ue s tandard. Ils sont clas s é s
suivant les m ê m e s caté gorie s q ue ce lles du ch apitre XXI q ui e xpliq ue le fonctionne m e nt de la plupart d'entre
e ux. La nature des ité rate urs re çus e n argum e nt e s t pré cis é e e n utilisant les abré viations suivante s :

• Ie Ité rate ur d'e ntré e ,


• Is Ité rate ur de s ortie ,
• Iu Ité rate ur unidire ctionne l,
• Ib Ité rate ur bidire ctionne l,
• Ia Ité rate ur à accè s direct.
Nous indiq uons la com plexité de ch aq ue algorith m e , dans le cas où elle n'e s t pas triviale. Com m e le fait la
norm e , nous l'e xprim ons e n un nom bre pré cis d'opérations (é ve ntue llem e nt sous form e d'un m axim um ),
plutôt q u'ave c la notation de Landau m oins précise. Pour allége r le te xte , nous avons conve nu q ue
lors q u'une s e ule s é q ue nce e s t conce rné e , N désigne son nom bre d'élém e nts ;lors q ue deux s é q ue nce s s ont
conce rné e s , N1 dé s igne le nom bre d'élém e nts de la pre m iè re e t N2 ce lui de la s e conde . Dans quelque s rare s
cas, d'autre s notations s e ront né ce s s aire s : e lles s e ront alors e xplicitées dans le te xte .

Note z q ue , par souci de s im plicité , lors q u'aucune am biguïté n'e xiste ra, nous utiliserons souve nt l'abus de
langage q ui consiste à parler de s é lém e nts d'un inte rvalle [début, fin) plutôt q ue d e s é lém e nts désignés par
ce t inte rvalle. D'autre part, les prédicats ou fonctions de rappe lpré vus dans les algorith m e s corre s ponde nt
toujours à des obje ts fonction ;ce la signifie q u'on pe ut re courir à des clas s e s fonction prédéfinie s , à s e s
propre s clas s e s fonction ou à des fonctions ordinaire s .

1. A LGO RITH M ES D 'INITIA LISATIO N D E SEQUENCES EXISTANTES

FILL void fil


l(Iu début, Iu fin, val
eur)
Place valeur dans l'inte rvalle [début, fin)

FILL_N void fil


l_n (Is position, NbFois, val
eur)
Place valeur NbFois cons é cutive s à partir de position ;les e m place m e nts corre s pondants
doive nt e xiste r.

CO PY Is copy (Ie début, Ie fin, Is position)


Copie l'inte rvalle [début, fin), à partir de position ;les e m place m e nts corre s pondants doive nt
e xiste r ;la valeur de position (e t s e ulem e nt ce lle-ci) ne doit pas apparte nir à l'inte rvalle
Anne xe F : Le s algorith m e s s tandards 427
[début, fin) ;si te le s t le cas, on pe ut toujours re courir à copy_back w ard ;re nvoie un ité rate ur
sur la fin de l'inte rvalle où s'e s t faite la copie .

CO PY_BACK W AR D Ib copy_back w ard (Ib début, Ib fin, Ib position)


Com m e copy, copie l'inte rvalle [début, fin), e n progre s s ant du dernier élém e nt ve rs le
pre m ie r, à partir de position q ui dé s igne donc l'e m place m e nt de la pre m iè re copie , m ais aussi
la fin de l'inte rvalle ;les e m place m e nts corre s pondants doive nt e xiste r ;la valeur de position
(e t s e ulem e nt ce lle-ci) ne doit pas apparte nir à l'inte rvalle [début, fin) ;re nvoie un ité rate ur sur
le début de l'inte rvalle (derniè re valeur copié e ) où s'e s t faite la copie ;ce t algorith m e e s t
surtout utile e n re m place m e nt de copy lors q ue le début de l'inte rvalle d'arrivé e appartie nt à
l'inte rvalle de départ.

GENER A TE void generate (Iu début, Iu fin, fct_gen)


Appelle, pour ch acune des valeurs de l'inte rvalle [début, fin), la fonction fct_ge n e t affe cte la
valeur fournie à l'e m place m e nt corre s pondant.

GENER A TE_N void generate_n (Iu début, NbFois, fct_gen)


M ê m e ch os e q ue ge ne rate , m ais l'inte rvalle e s t défini par sa position début e t son nom bre de
valeurs NbFois (la fonction fct_ge n e s t bien appe lée NfFois).

SW AP_R A NGES Iu sw ap_ranges (Iu début_1, Iu fin_1, Iu début_2)


Ech ange les é lém e nts de l'inte rvalle [début, fin) ave c l'inte rvalle de m ê m e taille com m e nçant
e n début_2. Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Com plexité : N é ch ange s .

2. A LGO RITH M ES D E RECH ERCH E

FIND Ie find (Ie début, Ie fin, val


eur)
Fournit un ité rate ur sur le pre m ie r é lém e nt de l'inte rvalle [début, fin) é galà valeur (au s e ns de
==) s'ile xiste , la valeur fin sinon ;(atte ntion, ilne s 'agit pas néce s s aire m e nt de e nd()).
Com plexité : au m axim um N com paraisons d'égalité .

FIND_IF Ie find_if (Ie début, Ie fin, pré d icat_u)


Fournit un ité rate ur sur le pre m ie r é lém e nt de l'inte rvalle [début, fin) satisfaisant au prédicat
unaire prédicat_u spécifié , s'il e xiste , la valeur fin sinon ;(atte ntion, il ne s 'agit pas
né ce s s aire m e nt de e nd()). Com plexité : au m axim um N appe ls du prédicat.

FIND_END Iu find_end (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2)


Fournit un ité rate ur sur le dernie r é lém e nt de l'inte rvalle [début_1, fin_1) te lq ue les é lém e nts
de la s é q ue nce débutant e n début_1 soit é gaux (au s e ns de ==) aux é lém e nts de l'inte rvalle
[début_2, fin_2). Si un te lé lém e nt n'e xiste pas, fournit la valeur fin_1 (atte ntion, ilne s 'agit
pas néce s s aire m e nt de e nd(). Com plexité : au m axim um (N1- N2 + 1) * N2 com paraisons.

Iu find_end (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2, pré d icat_b)


428 Program m e r e n langage C+ +
Fonctionne com m e la ve rsion pré cédente , ave c ce tte diffé re nce q ue la com paraison d'égalité
e s t re m placé e par l'application du prédicat binaire prédicat_b. Com plexité : au m axim um (N1-
N2 + 1) * N2 appe ls du prédicat.

FIND_FIR ST_O F

Iu find_first_of (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2)


R e ch e rch e , dans l'inte rvalle [début_1, fin_1), le pre m ie r é lém e nt é gal(au s e ns de ==) à l'un
des élém e nts de l'inte rvalle [début_2, fin_2). Fournit un ité rate ur sur ce t é lém e nt s'ile xiste , la
valeur de fin_1, dans le cas contraire . Com plexité : au m axim um N1 *N2 com paraisons.

Iu find_first_of (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2, pré d icat_b)


R e ch e rch e , dans l'inte rvalle [début_1, fin_1), le pre m ie r é lém e nt satisfaisant, ave c l'un de s
é lém e nts de l'inte rvalle [début_2, fin_2) au prédicat binaire prédicat_b. Fournit un ité rate ur
sur ce t é lém e nt s'ile xiste , la valeur de fin_1, dans le cas contraire . Com plexité : au m axim um
N1 *N2 appe ls du prédicat

ADJACENT_FIND

Iu adjacent_find (Iu début, Iu fin)


R e ch e rch e , dans l'inte rvalle [début, fin), la pre m iè re occurre nce de deux élém e nts succe s s ifs
é gaux (==) ;fournit un ité rate ur sur le pre m ie r des deux é lém e nts é gaux, s'ils e xiste nt, la
valeur fin sinon.

Iu adjacent_find (Iu début, Iu fin, pré d icat_b)


R e ch e rch e , dans l'inte rvalle [début, fin), la pre m iè re occurre nce de deux élém e nts succe s s ifs
satisfaisant au prédicat binaire prédicat_b ;fournit un ité rate ur sur le pre m ie r des deux
é lém e nts, s'ils e xiste nt, la valeur fin sinon.

SEAR CH Iu search (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2)


R e ch e rch e , dans l'inte rvalle [début_1, fin_1), la pre m iè re occurre nce d'une séquence
d'élém e nts identiq ue (==) à ce lle de l'inte rvalle [début_2, fin_2). Fournit un ité rate ur sur le
pre m ie r é lém e nt si ce tte occurre nce , si elle e xiste , la fin fin_1 sinon. Com plexité : au
m axim um N1 *N2 com paraisons.

Iu search (Iu début_1, Iu fin_1, Iu début_2, Iu fin_2, pré d icat_b)


Fonctionne com m e la ve rsion pré cédente de s e arch , ave c ce tte diffé re nce q ue la com paraison
de deux élém e nts de ch acune des deux séquence s s e fait par le prédicat binaire prédicat_b, au
lie u de s e faire par é galité . Com plexité : au m axim um N1 *N2 appe ls du prédicat.

SEAR CH _N Iu search _n (Iudébut, Iu fin, NbFois, val


eur)
R e ch e rch e dans l'inte rvalle [début, fin), une s é q ue nce de NbFois é lém e nts é gaux (au s e ns de
==) à valeur. Fournit un ité rate ur sur le pre m ie r é lém e nt si une te lle s é q ue nce e xiste , la
valeur fin sinon. Com plexité : au m axim um N com paraisons.
Anne xe F : Le s algorith m e s s tandards 429
Iu search _n (Iudébut, Iu fin, NbFois, val
eur, prédicat_b)
Fonctionne com m e la ve rsion pré cédente ave c ce tte diffé re nce q ue la com paraison entre un
é lém e nt e t valeur s e fait par le prédicat binaire prédicat_b, au lie u de s e faire par é galité .
Com plexité : au m axim um N applications du prédicat.

M AX_ELEM ENT

Iu m ax_el
em ent (Iu début, Iu fin)
Fournit un ité rate ur sur le pre m ie r é lém e nt de l'inte rvalle [début, fin) q ui ne s oit infé rie ur (< )
à aucun de s autre s é lém e nts de l'inte rvalle. Com plexité : e xacte m e nt N-1 com paraisons.

Iu m ax_el
em ent (Iu début, Iu fin, pré d icat_b)
Fonctionne com m e la ve rsion pré cédente de m ax_e lem e nt, m ais e n utilisant le prédicat binaire
prédicat_b e n lie u e t place de l'opé rate ur < . Com plexité : e xacte m e nt N-1 appe ls du prédicat.

M IN_ELEM ENT

Iu m in_el
em ent (Iu début, Iu fin)
Fournit un ité rate ur sur le pre m ie r é lém e nt de l'inte rvalle [début, fin) te lq u'aucun de s autre s
é lém e nts de l'inte rvalle ne lui soit infé rie ur (< ). Com plexité : e xacte m e nt N-1 com paraisons.

Iu m in_el
em ent (Iu début, Iu fin, pré d icat_b)
Fonctionne com m e la ve rsion pré cédente de m in_e lem e nt, m ais e n utilisant le prédicat binaire
prédicat_b e n lie u e t place de l'opé rate ur < . Com plexité : e xacte m e nt N-1 appe ls du prédicat.

3. A LGO RITH M ES D E TRANSFO RM A TIO N D 'UNE SEQUENCE

R E VER SE void reverse (Ib début, Ib fin)


Inve rs e le conte nu de l'inte rvalle [début, fin). Com plexité e xacte m e nt N/2 é ch ange s .

R E VER SE_CO PY Is reverse_copy (Ib début, Ib fin, Is position)


Copie l'inte rvalle [début, fin), dans l'ordre inve rs e , à partir de position ;les e m place m e nts
corre s pondants doive nt e xiste r ;atte ntion, ici position désigne donc l'e m place m e nt de la
pre m iè re copie e t aussi le début de l'inte rvalle ;re nvoie un ité rate ur sur la fin de l'inte rvalle
où s'e s t faite la copie . Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Com plexité :
e xacte m e nt N affe ctations.

R E PLACE void repl


ace (Iu début, Iu fin, anc_val
eur, nouv_val
eur)
R e m place , dans l'inte rvalle [début, fin), tous les é lém e nts é gaux (==) à anc_valeur par
nouv_valeur. Com plexité : e xacte m e nt N com paraisons.

R E PLACE_IF void repl


ace_if (Iu début, Iu fin, pré d icat_u, nouv_val
eur)
R e m place , dans l'inte rvalle [début, fin), tous les é lém e nts satisfaisant au prédicat unaire
prédicat_u par nouv_valeur. Com plexité : e xacte m e nt N applications du prédicat.
430 Program m e r e n langage C+ +
R E PLACE_CO PY

Is repl
ace_copy (Ie début, Ie fin, Is position, anc_val
eur, nouv_val
eur)
R e copie l'inte rvalle [début, fin) à partir de position, e n re m plaçant tous les é lém e nts é gaux
(==) à anc_valeur par nouv_valeur ;les e m place m e nts corre s pondants doive nt e xiste r.
Fournit un ité rate ur sur la fin de l'inte rvalle où s'e s t faite la copie . Les deux inte rvalles ne
doive nt pas s e ch e vauch e r. Com plexité : e xacte m e nt N com paraisons.

R E PLACE_CO PY_IF

Is repl
ace_copy_if (Ie début, Ie fin, Is position, pré d icat_u, nouv_val
eur)
R e copie l'inte rvalle [début, fin) à partir de position, e n re m plaçant tous les é lém e nts
satisfaisant au prédicat unaire prédicat_u par nouv_valeur ;les e m place m e nts corre s pondants
doive nt e xiste r Fournit un ité rate ur sur la fin de l'inte rvalle où s'e s t faite la copie . Les deux
inte rvalles ne doive nt pas s e ch e vauch e r. Com plexité : e xacte m e nt N applications du prédicat.

R O TATE void rotate (Iu début, Iu m il


ieu, Iu fin)
Effe ctue une pe rm utation circulaire (ve rs la gauch e ) des élém e nts de l'inte rvalle [début, fin)
dont l'am pleur e s t te lle q ue , aprè s perm utation, l'é lém e nt désigné par m ilie u soit ve nu e n
début. Com plexité : au m axim um N é ch ange s .

R O TATE_CO PY Is rotate_copy (Iu début, Iu m il


ieu, Iu fin, Is position)
R e copie , à partir de position, les é lém e nts de l'inte rvalle [début, fin), affe ctés d'une
pe rm utation circulaire définie de la m ê m e façon q ue pour rotate ; les e m place m e nts
corre s pondants doive nt e xiste r. Fournit un ité rate ur sur la fin de l'inte rvalle où s'e s t faite la
copie . Com plexité : au m axim um N affe ctations.

PAR TITIO N Ib partition (Ib début, Ib fin, Prédicat_u)


Effe ctue une partition de l'inte rvalle [début, fin) e n s e fondant sur le prédicat unaire
prédicat_u ;ils'agit d'une ré organisation te lle q ue tous les é lém e nts satisfaisant au prédicat
arrive nt avant tous les autre s . Fournit un ité rate ur it te lq ue les é lém e nts de l'inte rvalle [début,
it) satisfont au prédicat, tandis q ue les é lém e nts de l'inte rvalle [it, fin) n'y satisfont pas.
Com plexité : au m axim um N/2 é ch ange s e t e xacte m e nt N appe ls du prédicat.

STABLE_PAR TITIO N Ib stabl


e_partition (Ib début, Ib fin, Prédicat_u)
Fonctionne com m e partition, ave c ce tte diffé re nce q ue les positions re latives des diffé re nts
é lém e nts à l'inté rie ur de ch acune des deux partie s s oie nt pré s e rvé e s . Com plexité : e xacte m e nt
N appe ls du prédicat e t au m axim um N Log N é ch ange s (e t m ê m e k N si l'on dispose de
suffisam m e nt de m é m oire ).

NEXT_PER M UTATIO N

boolnext_perm utation (Ib début, Ib fin)


Ce t algorith m e ré alise ce q ue l'on nom m e la "pe rm utation suivante " des élém e nts de
l'inte rvalle [début, fin). Ilsuppose que l'e ns e m ble des pe rm utations possibles e s t ordonné à
partir de l'opé rate ur < , d'une m aniè re lexicograph iq ue . O n considè re q ue la pe rm utation
suivant la derniè re possible n'e s t rie n d'autre q ue la pre m iè re . Fournit la valeur true s'il
e xistait bien une perm utation suivante e t la valeur false dans le cas où l'on e s t re ve nu à la
pre m iè re pe rm utation possible. Com plexité : au m axim um N/2 é ch ange s .
Anne xe F : Le s algorith m e s s tandards 431
boolnext_perm utation (Ib début, Ib fin, pré d icat_b)
Fonctionne com m e la ve rsion pré cédente , ave c ce tte s e ule diffé re nce q ue l'e ns e m ble des
pe rm utations possibles e t ordonné à partir du prédicat binaire prédicat_b. Com plexité : au
m axim um N/2 é ch ange s .

PR E V_PER M UTATIO N

boolprev_perm utation (Ib début, Ib fin)

boolprev_perm utation (Ib début, Ib fin, pré d icat_b)


Ces deux algorith m e s fonctionne nt com m e ne xt_pe rm utation, e n inve rsant sim plem e nt l'ordre
des perm utations possibles .

R A NDO M _SH UFFLE

void random _sh uffl


e (Ia début, Ia fin)
R é partit au h asard les é lém e nts de l'inte rvalle [début, fin). Com plexité : e xacte m e nt N-1
é ch ange s .

void random _sh uffl


e (Ia début, Ia fin, générateur)
M ê m e ch os e q ue random _sh uffle, m ais e n utilisant la fonction gé né rate ur pour gé né re r de s
nom bre s au h asard. Ce tte fonction doit fournir une valeur apparte nant à l'inte rvalle [0, n), n
é tant une valeur fournie e n argum e nt. Com plexité : e xacte m e nt N-1 é ch ange s .

TR A NSFO R M

Is transform (Ie début, Ie fin, Is position, opération_u)


Place à partir de position (les é lém e nts corre s pondants doive nt e xiste r) les valeurs obte nue s e n
appliq uant la fonction unaire (à un argum e nt) opé ration_u à ch acune des valeurs de
l'inte rvalle [début, fin). Fournit un ité rate ur sur la fin de l'inte rvalle ainsi rem pli.

Is transform (Ie début_1, Ie fin_1, Ie début_2, Is position, opération_b)


Place à partir de position (les é lém e nts corre s pondants doive nt e xiste r) les valeurs obte nue s e n
appliq uant la fonction binaire (à deux argum e nts) opé ration_b à ch acune des valeurs de m ê m e
rang de l'inte rvalle [début_1, fin_1) e t de l'inte rvalle de m ê m e taille com m e nçant e n début_2.
Fournit un ité rate ur sur la fin de l'inte rvalle ainsi rem pli.

4. A LGO RITH M ES D E SUPPRESSIO N

R E M O VE Iu rem ove (Iu début, Iu fin, val


eur)
Fournit un ité rate ur it te lq ue l'inte rvalle [début, it) contie nne toute s les valeurs initialem e nt
pré s e ntes dans l'inte rvalle [début, fin), débarrassées de ce lles q ui sont é gales (==) à valeur.
Atte ntion, aucun é lém e nt n'e s t détruit ;tout au plus, pe ut-il avoir ch angé de valeur.
L'algorith m e e s t stable, c’e s t-à -dire q ue les valeurs non é lim iné e s cons e rve nt leur ordre re latif.
Com plexité : e xacte m e nt N com paraisons.
432 Program m e r e n langage C+ +
R E M O VE_IF Iu rem ove_if (Iu début, Iu fin, pré d icat_u)
Fonctionne com m e re m ove , ave c ce tte diffé re nce q ue la condition d'é lim ination e s t fournie
sous form e d'un prédicat unaire prédicat_u. Com plexité : e xacte m e nt N appe ls du prédicat.

R E M O VE_CO PY Is rem ove_copy (Ie début, Ie fin, Is position, val


eur)
R e copie l'inte rvalle [début, fin) à partir de position (les é lém e nts corre s pondants doive nt
e xiste r), e n supprim ant les é lém e nts é gaux (==) à valeur. Fournit un ité rate ur sur la fin de
l'inte rvalle où s'e s t faite la copie . Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Com m e
re m ove , l'algorith m e e s t stable. Com plexité : e xacte m e nt N com paraisons.

R E M O VE_CO PY_IF Is rem ove_if (Ie début, Ie fin, Is position, pré d icat_u)
Fonctionne com m e re m ove _copy, ave c ce tte diffé re nce q ue la condition d'é lim ination e s t
fournie s ous form e d'un prédicat unaire prédicat_u. Com plexité : e xacte m e nt N appe ls du
prédicat.

UNIQUE Iu unique (Iu début, Iu fin)


Fournit un ité rate ur it te lq ue l'inte rvalle [début, it) corre s ponde à l'inte rvalle [début, fin),
dans leq ue lles s é q ue nces de plusieurs valeurs cons é cutive s é gales (==) sont re m placé e s par
la pre m iè re . Atte ntion, aucun é lém e nt n'e s t détruit ;tout au plus, pe ut-ilavoir ch angé de place
e t de valeur. Com plexité : e xacte m e nt N com paraisons.

Iu unique (Iu début, Iu fin, pré d icat_b)


Fonctionne com m e la ve rsion pré cédente , ave c ce tte diffé re nce q ue la condition de ré pé tition
e s t fournie s ous form e d'un prédicat binaire prédicat_b. Com plexité : e xacte m e nt N appe ls du
prédicat.

UNIQUE_CO PY

Is unique_copy (Ie début, Ie fin, Is position)


R e copie l'inte rvalle [début, fin) à partir de position (les é lém e nts corre s pondants doive nt
e xiste r), e n ne cons e rvant q ue la pre m iè re valeur de s s é q ue nces de plusieurs valeurs
cons é cutive s é gales (==). Fournit un ité rate ur sur la fin de l'inte rvalle où s'e s t faite la copie .
Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Com plexité : e xacte m e nt N com paraisons.

Is unique_copy (Ie début, Ie fin, Is position, pré d icat_b)


Fonctionne com m e unique _copy, ave c ce tte diffé re nce q ue la condition de ré pé tition de deux
valeurs e s t fournie s ous form e d'un prédicat binaire prédicat_u. O n note ra q ue la décision
d'élim ination d'une valeur s e fait toujours par com paraison ave c la pré cédente e t non ave c la
pre m iè re d'une séquence ;ce tte re m arq ue n'a e n fait d'im portance q u'au cas où le prédicat
fourni ne s e rait pas transitif... Com plexité : e xacte m e nt N appe ls du prédicat.
Anne xe F : Le s algorith m e s s tandards 433
5. A LGO RITH M ES D E TRI

SO R T void sort (Ia début, Ia fin)


Trie les é lém e nts de l'inte rvalle [début, fin), e n s e fondant sur l'opé rate ur < . L'algorith m e
n'e s t pas stable, c’ e s t-à -dire q ue l'ordre re latif des élém e nts é q uivalents (au s e ns de <) n'e s t
pas néce s s aire m e nt re s pe cté . Com plexité : e n m oye nne N Log N com paraisons.

void sort (Ia début, Ia fin, fct_com p)


Trie les é lém e nts de l'inte rvalle [début, fin), e n s e fondant sur le prédicat binaire fct_com p.
Com plexité : e n m oye nne N Log N appe ls du prédicat.

STABLE_SO R T

void stabl
e_sort (Ia début, Ia fin)
Trie les é lém e nts de l'inte rvalle [début, fin), e n se basant sur l'opé rate ur < . Contraire m e nt à
sort, ce t algorith m e e s t stable. Com plexité : au m axim um N (Log N)2 com paraisons ;si
l'im plém e ntation dispose d'assez de m é m oire , on pe ut desce ndre à N Log N com paraisons.

void stabl
e_sort (Ia début, Ia fin, fct_com p)
M ê m e ch os e q ue s table_sort e n se basant sur le prédicat binaire fct_com p q ui doit
corre s pondre à une re lation d'ordre faible s trict. Com plexité : au m axim um N (Log N)2
applications du prédicat ;si l'im plém e ntation dispose d'assez de m é m oire , on pe ut desce ndre à
N Log N appe ls.

PAR TIAL_SO R T

void partial
_sort (Ia début, Ia m il
ieu, Ia fin)
R é alise un tri partie ldes élém e nts de l'inte rvalle [début, fin), e n se basant sur l'opé rate ur < e t
e n plaçant les pre m ie rs é lém e nts conve nablem e nt triés dans l'inte rvalle [début, m ilie u) (c'e s t la
taille de ce t inte rvalle q ui dé finit l'am pleur du tri). Le s é lém e nts de l'inte rvalle [m ilie u, fin)
sont placés dans un ordre q ue lconq ue . Aucune contrainte de stabilité n'e s t im pos é e .
Com plexité : e nviron N Log N' com paraisons, N' étant le nom bre d'élém e nts trié s .

void partial
_sort (Ia début, Ia m il
ieu, Ia fin, fct_com p)
Fonctionne com m e partial_sort, ave c ce tte diffé re nce q u'au lie u de s e fonde r sur l'opé rate ur
< , ce t algorith m e s e fonde s ur le prédicat binaire fct_com p q ui doit corre s pondre à une
re lation d'ordre faible s trict. Com plexité : e nviron N Log N' com paraisons, N' étant le
nom bre d'élém e nts trié s .

PAR TIAL_SO R T_CO PY

Ia partial
_sort_copy (Ie début, Ie fin, Ia pos_début, Ia pos_fin)
Place dans l'inte rvalle [pos_début, pos_fin) le ré s ultat du tri partie lou totaldes élém e nts de
l'inte rvalle [début, fin). Si l'inte rvalle de destination com porte plus d'élém e nts q ue l'inte rvalle
de départ, ses dernie rs é lém e nts ne seront pas utilisés. Fournit un ité rate ur sur la fin de
l'inte rvalle de destination (pos_fin lors q ue ce dernie r e s t de taille infé rie ure ou é gale à
l'inte rvalle d'origine ). Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Com plexité :
e nviron N Log N' com paraisons, N' étant le nom bre d'élém e nts e ffe ctive m e nt trié s .
434 Program m e r e n langage C+ +
Ia partial
_sort_copy (Ie début, Ie fin, Ia pos_début, Ia pos_fin, fct_com p)
Fonctionne com m e partial_sort_copy ave c ce tte diffé re nce q u'au lie u de s e fonde r sur
l'opé rate ur < , ce t algorith m e s e fonde s ur le prédicat binaire fct_com p q ui doit corre s pondre à
une re lation d'ordre faible s trict. Com plexité : e nviron N Log N' com paraisons, N' étant le
nom bre d'élém e nts trié s .

NTH _ELEM ENT

void nth _el


em ent (Ia début, Ia position, Ia fin)
Place dans l'e m place m e nt désigné par position –q ui doit donc apparte nir à l'inte rvalle [début,
fin) –l'é lém e nt de l'inte rvalle [début, fin) q ui s e trouve rait là, à la suite d'un tri. Le s autre s
é lém e nts de l'inte rvalle pe uve nt ch ange r de place . Com plexité : e n m oye nne N com paraisons.

void nth _el


em ent (Ia début, Ia position, Ia fin, fct_com p)
Fonctionne com m e la ve rsion pré cédente , ave c ce tte diffé re nce q u'au lie u de s e fonde r sur
l'opé rate ur < , ce t algorith m e s e fonde s ur le prédicat binaire fct_com p q ui doit corre s pondre à
une re lation d'ordre faible s trict. Com plexité : e n m oye nne N applications du prédicat.

6. A LGO RITH M ES D E RECH ERCH E ET D E FUSIO NS SUR D ES SEQUENCES


O RD O NNEES

N.B. Tous ce s algorith m e s pe uve nt fonctionne r ave c de sim ples ité rate urs unidire ctionne ls. M ais, lors q ue
l'on dispose d'ité rate urs à accè s direct, on pe ut augm e nte r légè re m e nt les pe rform ance s , dans la m e s ure où
ce rtaine s s é ries de p incré m e ntations de la form e it+ + pe uve nt ê tre re m placé e s par une s e ule it+ =p ;plus
pré cis é m e nt, on pas s e d e O (N) à O (Log N) incré m e ntations.

LO W ER _BO UND

Iu l
ow er_bound (Iu début, Iu fin, val
eur)
Fournit un ité rate ur sur la pre m iè re position où valeur pe ut ê tre ins é ré e , com pte te nu de
l'ordre induit par l'opé rate ur < . Com plexité : au m axim um Log N+ 1 com paraisons.

Iu l
ow er_bound (Iu début, Iu fin, val
eur, fct_com p)
Fournit un ité rate ur sur la pre m iè re position où valeur pe ut ê tre ins é ré e , com pte te nu de
l'ordre induit par le prédicat binaire fct_com p. Com plexité : au m axim um Log N+ 1
com paraisons.

UPPER _BO UND

Iu upper_bound (Iu début, Iu fin, val


eur)
Fournit un ité rate ur sur la derniè re position où valeur pe ut ê tre ins é ré e , com pte te nu de l'ordre
induit par l'opé rate ur < . Com plexité : au m axim um Log N+ 1 com paraisons.

Iu upper_bound (Iu début, Iu fin, val


eur, fct_com p)
Fournit un ité rate ur sur la derniè re position où valeur pe ut ê tre ins é ré e , com pte te nu de l'ordre
induit par le prédicat binaire fct_com p. Com plexité : au m axim um Log N+ 1 com paraisons.
Anne xe F : Le s algorith m e s s tandards 435
EQUAL_R A NGE

pair <Iu, Iu> equal


_range (Iu début, Iu fin, val
eur)
Fournit le plus grand inte rvalle [it1, it2) te lq ue valeur puis s e ê tre ins é ré e e n n'im porte q ue l
point de ce t inte rvalle, com pte te nu de l'ordre induit par l'opé rate ur < . Com plexité : au
m axim um 2 Log N+ 1 com paraisons.

pair <Iu, Iu> equal


_range (Iu début, Iu fin, val
eur, fct_com p)
Fonctionne com m e la ve rsion pré cédente , e n se basant sur l'ordre induit par le prédicat binaire
fct_com p au lie u de l'opé rate ur < .

BINARY_SEAR CH

boolbinary_search (Iu début, Iu fin, val


eur)
Fournit la valeur true s'ile xiste , dans l'inte rvalle [début, fin), un é lém e nt é q uivalent à valeur,
e t la valeur false , dans le cas contraire . Com plexité : au plus Log N+ 2 com paraisons.

boolbinary_search (Iu début, Iu fin, val


eur, fct_com p)
Fournit la valeur true s'ile xiste , dans l'inte rvalle [début, fin), un é lém e nt é q uivalent à valeur
(au s e ns de la re lation induite par le prédicat fct_com p) e t la valeur false dans le cas contraire .
Com plexité : au plus Log N+ 2 appe ls du prédicat.

M ER GE Is m erge (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position)


Fusionne les deux inte rvalles [début_1, fin_1) e t [début_2, fin_2), à partir de position (les
é lém e nts corre s pondants doive nt e xiste r), e n s e fondant sur l'ordre induit par l'opé rate ur < .
L'algorith m e e s t stable : l'ordre re latif d'élém e nts é q uivalents dans l'un de s inte rvalles
d'origine e s t re s pe cté dans l'inte rvalle d'arrivé e ;si des élém e nts é q uivalents apparais s e nt dans
les inte rvalles à fusionne r, ce ux du pre m ie r inte rvalle apparais s e nt toujours avant ce ux du
s e cond. L'inte rvalle d'arrivé e ne doit pas s e ch e vauch e r ave c les inte rvalles d'origine (en
re vanch e , rie n n'inte rdit q ue les deux inte rvalles d'origine se ch e vauch e nt). Com plexité : au
plus N1+ N2-1 com paraisons.

Is m erge (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position, fct_com p)


Fonctionne com m e la ve rsion pré cédente , ave c ce tte diffé re nce q ue l'on se bas e s ur l'ordre
induit par le prédicat binaire fct_com p. Com plexité : au plus N1+ N2-1 appe ls du prédicat.

INPLACE_M ER GE

void inpl
ace_m erge (Ib début, Ib m il
ieu, Ib fin)
Fusionne les deux inte rvalles [début, m ilie u) e t [m ilie u, fin) dans l'inte rvalle [début, fin) e n s e
basant sur l'ordre induit par l'opé rate ur < . Com plexité : N-1 com paraisons si l'on dispose de
suffisam m e nt de m é m oire , N Log N com paraisons sinon.

void inpl
ace_m erge (Ib début, Ib m il
ieu, Ib fin, fct_com p)
Fonctionne com m e la ve rsion pré cédente , ave c ce tte diffé re nce q ue l'on se bas e s ur l'ordre
induit par le prédicat binaire fct_com p. Com plexité : N-1 appe ls du prédicat, si l'on dispose de
suffisam m e nt de m é m oire , N Log N appe ls sinon.
436 Program m e r e n langage C+ +
7. A LGO RITH M ES A CARACTERE NUM ERIQUE

ACCUM ULATE

val
eur accum ul
ate (Ie debut, Ie fin, val
_init)
Fournit la valeur obte nue e n ajoutant (opé rate ur + ) à la valeur initiale val_init, la valeur de
ch acun de s é lém e nts de l'inte rvalle [début, fin).

val
eur accum ul
ate (Ie debut, Ie fin, val
_initial
e, fct_cum ul
)
Fonctionne com m e la ve rsion pré cédente , e n la gé né ralisant : l'opé ration appliq ué e n'é tant
plus définie par l'opé rate ur + , m ais par la fonction fct_cum ul, re ce vant deux argum e nts du
type d e s é lém e nts conce rné s e t fournissant un ré s ultat de ce m ê m e type (la valeur accum ulée
courante e s t fournie e n pre m ie r argum e nt, ce lle de l'é lém e nt courant, e n s e cond).

INNER _PR O DUCT

val
eur inner_product (Ie début_1, Ie fin_1, Ie début_2, val
_init)
Fournit le produit scalaire de la s é q ue nce des valeurs de l'inte rvalle [début_1, fin_2) e t de la
s é q ue nce de valeurs de m ê m e longue ur débutant e n début_2, augm e nté de la valeur initiale
val_init.

val
eur inner_product (Ie début_1, Ie fin_1, Ie début_2, val
_init, fct_cum ul
, fct_prod)
Fonctionne com m e la ve rsion pré cédente , e n re m plaçant l'opé ration de cum ul(+ ) par l'appe l
de la fonction fct_cum ul(la valeur cum ulée e s t fournie e n pre m ie r argum e nt) e t l'opé ration de
produit par l'appe lde la fonction fct_prod (la valeur courante du prem ie r inte rvalle é tant
fournie e n pre m ie r argum e nt).

PAR TIAL_SUM

Is partial
_sum (Ie début, Ie fin, Is position)
Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), un inte rvalle de m ê m e
taille q ue l'inte rvalle [début, fin), conte nant les s om m e s partie lles du prem ie r inte rvalle : le
pre m ie r é lém e nt corre s pond à la pre m iè re valeur de [début, fin), le s e cond é lém e nt à la som m e
des deux prem iè re s valeurs e t ainsi de suite . Fournit un ité rate ur sur la fin de l'inte rvalle cré é .

Is partial
_sum (Ie début, Ie fin, Is position, fct_cum ul
)
Fonctionne com m e la ve rsion pré cédente , e n re m plaçant l'opé ration de s om m ation (+ ) par
l'appe lde la fonction fct_cum ul(la valeur cum ulée e s t fournie e n pre m ie r argum e nt).

ADJACENT_DIFFER E NCE

Is ajacent_difference (Ie début, Ie fin, Is position)


Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), un inte rvalle de m ê m e
taille q ue l'inte rvalle [début, fin), conte nant les diffé re nce s e ntre deux é lém e nts cons é cutifs de
ce pre m ie r inte rvalle : l'é lém e nt de rang i, h orm is le pre m ie r, s'obtie nt e n faisant la diffé re nce
(opé rate ur -) e ntre l'é lém e nt de rang i e t ce lui de rang i-1. Le pre m ie r é lém e nt re s te inch angé .
Fournit un ité rate ur sur la fin de l'inte rvalle cré é .
Anne xe F : Le s algorith m e s s tandards 437
Is ajacent_difference (Ie début, Ie fin, Is position, fct_diff)
Fonctionne com m e la ve rsion pré cédente , e n re m plaçant l'opé ration de diffé re nce (-) par
l'appe lde la fonction fct_diff.

8. A LGO RITH M ES A CARACTERE ENSEM BLISTE

INCLUDES boolincl
udes (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2)
Fournit la valeur true si, à toute valeur apparte nant à l'inte rvalle [début_1, fin_1), corre s pond
une valeur é gale (==) dans l'inte rvalle [début_2, fin_2), ave c la m ê m e pluralité : autre m e nt
dit, (si une valeur figure n fois dans le pre m ie r inte rvalle, e lle devra figure r au m oins n fois
dans le s e cond inte rvalle). Com plexité : au m axim um 2 N1*N2-1 com paraisons.

boolincl
udes (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, fct_com p)
Fonctionne com m e la ve rsion pré cédente , m ais e n utilisant le prédicat binaire fct_com p pour
décide r de l'é galité de deux valeurs. Com plexité : au m axim um 2 N1*N2-1 appe ls du prédicat

SET_UNIO N

Is set_union (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position)


Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), une s é q ue nce form é e
des élém e nts apparte nant au m oins à l'un des deux inte rvalles [début_1, fin_1) [début_2,
fin_2), ave c la pluralité m axim ale : si un élém e nt apparaî t n fois dans le pre m ie r inte rvalle e t
n' fois dans le s e cond, ilapparaî tra m ax(n, n') fois dans le ré s ultat. Le s é lém e nts doive nt ê tre
trié s s uivant la m ê m e re lation R e t l'é galité de deux élém e nts (==) devra corre s pondre aux
classes d'équivalence de R . Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Fournit un
ité rate ur sur la fin de l'inte rvalle cré é . Com plexité : au m axim um 2*N1*N2-1 com paraisons.

Is set_union (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position, fct_com p)


Fonctionne com m e la ve rsion pré cédente , m ais e n utilisant le prédicat binaire fct_com p pour
décide r de l'é galité de deux valeurs. Là e ncore , ce dernie r doit corre s pondre aux clas s e s
d'équivalence de la re lation ayant s e rvi à ordonne r les deux inte rvalles . Com plexité : au
m axim um 2*N1*N2-1 appe ls du prédicat.

SET_INTER SECTIO N

Is set_intersection (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position)


Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), une s é q ue nce form é e
des élém e nts apparte nant sim ultané m e nt aux de ux inte rvalles [début_1, fin_1) [début_2, fin_2),
ave c la pluralité m inim ale : si un élém e nt apparaî t n fois dans le pre m ie r inte rvalle e t n' fois
dans le s e cond, ilapparaî tra m in(n, n') fois dans le ré s ultat. Le s é lém e nts doive nt ê tre trié s
suivant la m ê m e re lation R e t l'é galité de deux élém e nts (==) devra corre s pondre aux clas s e s
d'équivalence de R . Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Fournit un ité rate ur sur
la fin de l'inte rvalle cré é . Com plexité : au m axim um 2*N1*N2-1 com paraisons.
438 Program m e r e n langage C+ +
Is set_intersection (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position, fct_com p)
Fonctionne com m e la ve rsion pré cédente , m ais e n utilisant le prédicat binaire fct_com p pour
décide r de l'é galité de deux valeurs. Là e ncore , ce dernie r doit corre s pondre aux clas s e s
d'équivalence de la re lation ayant s e rvi à ordonne r les deux inte rvalles . Com plexité : au
m axim um 2*N1*N2-1 appe ls du prédicat.

SET_DIFFER E NCE

Is set_difference (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position)


Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), une s é q ue nce form é e
des élém e nts apparte nant à l'inte rvalle [début_1, fin_1) sans apparte nir à l'inte rvalle [début_2,
fin_2) ;on tie nt com pte de la pluralité : si un élém e nt apparaî t n fois dans le pre m ie r inte rvalle
e t n' fois dans le s e cond, ilapparaî tra m ax(0, n-n') fois dans le ré s ultat. Le s é lém e nts doive nt
ê tre trié s s uivant la m ê m e re lation R e t l'é galité de deux élém e nts (==) devra corre s pondre
aux classes d'équivalence de R . Les deux inte rvalles ne doive nt pas s e ch e vauch e r. Fournit un
ité rate ur sur la fin de l'inte rvalle cré é . Com plexité : au m axim um 2*N1*N2-1 com paraisons.

Is set_difference (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position, fct_com p)


Fonctionne com m e la ve rsion pré cédente , m ais e n utilisant le prédicat binaire fct_com p pour
décide r de l'é galité de deux valeurs. Là e ncore , ce dernie r doit corre s pondre aux clas s e s
d'équivalence de la re lation ayant s e rvi à ordonne r les deux inte rvalles . Com plexité : au
m axim um 2*N1*N2-1 appe ls du prédicat.

SET_SYM M ETR IC_DIFFER E NCE

Is set_sym etric_difference (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position)


Cré e , à partir de position (les é lém e nts corre s pondants doive nt e xiste r), une s é q ue nce form é e
des élém e nts apparte nant à l'inte rvalle [début_1, fin_1) sans apparte nir à l'inte rvalle [début_2,
fin_2) ou apparte nant au s e cond, sans apparte nir au pre m ir ;on tie nt com pte de la pluralité : si
un é lém e nt apparaî t n fois dans le pre m ie r inte rvalle e t n' fois dans le s e cond, ilapparaî tra |n-
n'| fois dans le ré s ultat. Le s é lém e nts doive nt ê tre trié s s uivant la m ê m e re lation R e t l'é galité
de deux élém e nts (==) devra corre s pondre aux classes d'équivalence de R . Les deux
inte rvalles ne doive nt pas s e ch e vauch e r. Fournit un ité rate ur sur la fin de l'inte rvalle cré é .
Com plexité : au m axim um 2*N1*N2-1 com paraisons.

Is set_sym etric_difference (Ie début_1, Ie fin_1, Ie début_2, Ie fin_2, Is position,


fct_com p)
Fonctionne com m e la ve rsion pré cédente , m ais e n utilisant le prédicat binaire fct_com p pour
décide r de l'é galité de deux valeurs. Là e ncore , ce dernie r doit corre s pondre aux clas s e s
d'équivalence de la re lation ayant s e rvi à ordonne r les deux inte rvalles . Com plexité : au
m axim um 2*N1*N2-1 appe ls du prédicat.

9 . ALGO RITH M ES D IVERS

CO UNT nom bre count (Ie début, Ie fin, val


eur)
Fournit le nom bre de valeurs de l'inte rvalle [début, fin) é gales à valeur (au s e ns de ==).
Anne xe F : Le s algorith m e s s tandards 439
nom bre count (Ie début, Ie fin, pré d icat_u)
Fournit le nom bre de valeurs de l'inte rvalle [début, fin) satisfaisant au prédicat unaire
prédicat_u.

FO R _EACH fct for_each (Ie début, Ie fin, fct)


Appliq ue la fonction fct à ch acun de s é lém e nts de l'inte rvalle [début, fin) ;fournit fct e n
ré s ultat.

EQUAL boolequal(Ie début_1, Ie fin_1, Ie début_2)


Fournit la valeur true si tous les é lém e nts de l'inte rvalle [début_1, fin_2) sont é gaux (au s e ns
de ==) aux é lém e nts corre s pondants de l'inte rvalle de m ê m e taille com m e nçant e n début_2.

boolequal(Ie début_1, Ie fin_1, Ie début_2, pré d icat_b)


Fonctionne com m e la ve rsion pré cédente , e n utilisant le prédicat binaire prédicat_b, à la place
de l'opé rate ur ==.

ITER _SW AP void iter_sw ap (Iu pos1, Iu pos2)


Ech ange les valeurs des élém e nts désignés par les deux ité rate urs pos1 e t pos2.
CO RRECTIO N D ES EXERCICES

Nous vous fournissons ici la "corre ction" de s e xe rcices dont l'é noncé e s t pré cédé de l'indication (C). Bie n
e nte ndu, les program m e s proposés doive nt ê tre considérés com m e une s olution parm i (be aucoup) d'autre s .

CH A PITRE V

Exe rcice 5.2

#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{ double x, y, z ;
public :
void initialise (double, double, double) ;
void homothetie (double) ;
void affiche () ;
} ;
/* définition des fonctions membre de la classe vecteur */
void vecteur::initialise (double a, double b, double c)
{ x = a ; y = b ; z = c ;
}
void vecteur::homothetie (double coeff)
{
x = x * coeff ; y = y * coeff ; z = z * coeff ;
}
void vecteur::affiche ()
{
cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
/* programme de test de la classe vecteur */
main()
{ vecteur v1, v2 ;
v1.initialise (1.0, 2.5, 5.8) ; v1.affiche () ;
v2.initialise (12.5, 3.8, 0.0) ; v2.affiche () ;
v1.homothetie (3.5) ; v1.affiche () ;
v2 = v1 ; v2.affiche () ;
}

Exe rcice 5.3

#include <iostream.h>
/* déclaration de la classe vecteur */
Corre ction de s e xe rcice s 441
class vecteur
{ double x, y, z ;
public :
vecteur (double, double, double) ; // constructeur
void homothetie (double) ;
void affiche () ;
} ;
/* définition des fonctions membre de la classe vecteur */
vecteur::vecteur (double a, double b, double c) // attention, pas de void ..
{
x = a ; y = b ; z = c ;
}
void vecteur::homothetie (double coeff)
{ x = x * coeff ; y = y * coeff ; z = z * coeff ;
}
void vecteur::affiche ()
{ cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
/* programme de test de la classe vecteur */
main()
{ vecteur v1(1.0, 2.5, 5.8) ; // vecteur v1 serait ici invalide
vecteur v2(12.5, 3.8, 0.0) ;
v1.affiche () ;
v2.affiche () ;
v1.homothetie (3.5) ; v1.affiche () ;
v2 = v1 ; v2.affiche () ;
}

CH A PITRE VI

Exe rcice 6.1

a)A ve c de s fonctions m e m bre indé pe ndante s


#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{ double x, y, z ;
public :
vecteur () ; // constructeur 1
vecteur (double, double, double) ; // constructeur 2
void affiche () ;
} ;
/* définition des fonctions membre de la classe vecteur */
vecteur::vecteur ()
{
x=0 ; y=0 ; z=0 ;
}
vecteur::vecteur (double a, double b, double c)
{
x = a ; y = b ; z = c ;
}
void vecteur::affiche ()
{
442 Program m e r e n langage C+ +
cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
/* programme de test de la classe vecteur */
main()
{ vecteur v1 ; // attention vecteur v1 () aurait une autre signification
// v1 serait une fonction sans argument, fournissant un
// résultat de type vecteur
vecteur v2(12.5, 3.8, 0.0) ;
// ces déclarations seraient ici invalides :
// vecteur v3 (5) ; vecteur v4 (2.5, 4) ;
v1.affiche () ;
v2.affiche () ;
}

b)A ve c de s fonctions m e m bre "e n l


igne "
#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{
double x, y, z ;
public :
vecteur () // constructeur 1
{ x=0 ; y=0 ; z=0 ; }
vecteur (double a, double b, double c) // constructeur 2
{ x=a ; y=b ; z=c ; }
void affiche ()
{ cout << "Vecteur de coordonnées : "
<< x << " " << y << " " << z << "\n" ;
}
} ;

/* programme de test de la classe vecteur */


main()
{
vecteur v1, v2(3,4,5) ;
v1.affiche () ;
v2.affiche () ;
}

Exe rcice 6.2

#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{
double x, y, z ;
public :
vecteur () ; // constructeur 1
vecteur (double, double, double) ; // constructeur 2
void affiche () ;
Corre ction de s e xe rcice s 443
int prod_scal (vecteur) ;
} ;

/* définition des fonctions membre de la classe vecteur */


vecteur::vecteur ()
{
x=0 ; y=0 ; z=0 ;
}
vecteur::vecteur (double a, double b, double c)
{
x = a ; y = b ; z = c ;
}
void vecteur::affiche ()
{
cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
int vecteur::prod_scal (vecteur v)
{
return (x * v.x + y * v.y + z * v.z) ;
}
main() /* programme de test de la classe vecteur */
{
vecteur v1 (1,2,3) ;
vecteur v2 (5,4,3) ;
v1.affiche () ; v2.affiche () ;
int ps ;
ps = v1.prod_scal (v2) ; cout << "V1.V2 = " << ps << "\n" ;
ps = v2.prod_scal (v1) ; cout << "V2.V1 = " << ps << "\n" ;
cout << "V1.V1 = " << v1.prod_scal (v1) << "\n" ;
cout << "V2.V2 = " << v2.prod_scal (v2) << "\n" ;
}

Exe rcice 6.3

#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{ double x, y, z ;
public :
vecteur () ; // constructeur 1
vecteur (double, double, double) ; // constructeur 2
void affiche () ;
int prod_scal (vecteur) ;
vecteur somme (vecteur) ;
} ;
/* définition des fonctions membre de la classe vecteur */
vecteur::vecteur ()
{ x=0 ; y=0 ; z=0 ;
}
vecteur::vecteur (double a, double b, double c)
{ x = a ; y = b ; z = c ;
}
void vecteur::affiche ()
{ cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
444 Program m e r e n langage C+ +
int vecteur::prod_scal (vecteur v)
{ return (x * v.x + y * v.y + z * v.z) ;
}
vecteur vecteur::somme (vecteur v)
{ vecteur res ;
res.x = x + v.x ; res.y = y + v.y ; res.z = z + v.z ;
return res ;
}
/* programme de test de la classe vecteur */
main()
{ vecteur v1 (1,2,3) ;
vecteur v2 (5,4,3) ;
vecteur v3 ;
v1.affiche () ; v2.affiche () ; v3.affiche () ;
v3 = v1.somme (v2) ; v3.affiche () ;
v3 = v2.somme (v1) ; v3.affiche () ;
}

Exe rcice 6.4

a)Trans m is s ion par adre s s e de s val


e urs de type ve cte ur
/* déclaration de la classe vecteur */
class vecteur
{ double x, y, z ;
public :
vecteur () ; // constructeur 1
vecteur (double, double, double) ; // constructeur 2
void affiche () ;
int prod_scal (vecteur *) ;
vecteur somme (vecteur *) ;
} ;
/* définition des fonctions membre de la classe vecteur */
vecteur::vecteur ()
{
x=0 ; y=0 ; z=0 ;
}
vecteur::vecteur (double a, double b, double c)
{
x = a ; y = b ; z = c ;
}
void vecteur::affiche ()
{
cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
int vecteur::prod_scal (vecteur * adv)
{
return (x * adv->x + y * adv->y + z * adv->z) ;
// on pourrait écrire, de façon plus symétrique :
// return (this->x * adv->x + this->y * adv->y + this->z * adv-> z ; }
}
vecteur vecteur::somme (vecteur * adv)
{
vecteur res ;
res.x = x + adv->x ; res.y = y + adv->y ; res.z = z + adv->z ;
Corre ction de s e xe rcice s 445
// ou, pour conserver la symétrie :
// res.x = this->x + adv-> x ; .......
return res ;
// attention, on ne peut pas transmettre l'adresse de res, car
// il s'agit d'une variable automatique
}
/* programme de test de la classe vecteur */
main()
{
vecteur v1 (1,2,3) ;
vecteur v2 (5,4,3) ;
vecteur v3 ;
v1.affiche () ; v2.affiche () ; v3.affiche () ;
v3 = v1.somme (&v2) ; v3.affiche () ;
v3 = v2.somme (&v1) ; v3.affiche () ;
}

b)Trans m is s ion par ré fé re nce de s val


e urs de type ve cte ur
#include <iostream.h>
/* déclaration de la classe vecteur */
class vecteur
{
double x, y, z ;
public :
vecteur () ; // constructeur 1
vecteur (double, double, double) ; // constructeur 2
void affiche () ;
int prod_scal (vecteur &) ;
vecteur somme (vecteur &) ;
} ;

/* définition des fonctions membre de la classe vecteur */


vecteur::vecteur ()
{
x=0 ; y=0 ; z=0 ;
}
vecteur::vecteur (double a, double b, double c)
{
x = a ; y = b ; z = c ;
}
void vecteur::affiche ()
{
cout << "Vecteur de coordonnées : " << x << " " << y << " " << z << "\n" ;
}
int vecteur::prod_scal (vecteur & v)
{
return (x * v.x + y * v.y + z * v.z) ;
}
vecteur vecteur::somme (vecteur & v)
{
vecteur res ;
res.x = x + v.x ; res.y = y + v.y ; res.z = z + v.z ;
return res ;
446 Program m e r e n langage C+ +
// attention, on ne peut pas transmettre l'adresse de res, car
// il s'agit d'une variable automatique
}

/* programme de test de la classe vecteur */


main()
{
vecteur v1 (1,2,3) ;
vecteur v2 (5,4,3) ;
vecteur v3 ;
v1.affiche () ; v2.affiche () ; v3.affiche () ;
v3 = v1.somme (v2) ; v3.affiche () ;
v3 = v2.somme (v1) ; v3.affiche () ;
}

CH A PITRE VII

Exe rcice 7.5


#include <iostream.h>
/* déclaration (et définition) de la classe pile_entier */
/* ici, toutes les fonctions membre sont "inline" */
const Max = 20 ;
class pile_entier
{ int dim ; // nombre maximal d'entiers de la pile
int * adr ; // adresse emplacement des dim entiers
int nelem ; // nombre d'entiers actuellement empilés
public :
pile_entier (int n = Max) // constructeur(s)
{ adr = new int [dim=n] ;
nelem = 0 ;
}
~pile_entier () // destructeur
{ delete adr ;
}
void empile (int p)
{ if (nelem < dim) adr[nelem++] = p ; }
int depile ()
{ if (nelem > 0) return adr[--nelem] ;
else return 0 ; // faute de mieux !
}
int pleine ()
{ return (nelem == dim) ; }
int vide ()
{ return (nelem == 0 ) ; }
} ;

Exe rcice 7.6

/* programme d'essai de la classe pile_entier */


main()
{
int i ;
Corre ction de s e xe rcice s 447
/* exemples d'utilisation de piles automatiques */
pile_entier a(3), // une pile de 3 entiers
b ; // une pile de 20 entiers (par défaut)
cout << "a pleine ? " << a.pleine () << "\n" ;
cout << "a vide ? " << a.vide () << "\n" ;
a.empile (3) ; a.empile (9) ; a.empile (11) ;
cout << "Contenu de a : " ;
for (i=0 ; i<3 ; i++) cout << a.depile () << " " ;
cout << "\n" ;
for (i=0 ; i<30 ; i++) b.empile (10*i) ;
cout << "Contenu de b : " ;
for (i=0 ; i<30 ; i++) if ( ! b.vide() ) cout << b.depile () << " " ;
cout << "\n" ;

/* exemple d'utilisation d'une pile dynamique */


pile_entier * adp = new pile_entier (5) ;
// pointeur sur une pile de 5 entiers
cout << "pile dynamique vide ? " << adp->vide () << "\n" ;
for (i=0 ; i<10 ; i++) adp->empile (10*i) ;
cout << "Contenu de la pile dynamique : " ;
for (i=0 ; i<10 ; i++) if ( ! adp->vide() ) cout << adp->depile () << " " ;
}

Exe rcice 7.8

#include <iostream.h>
/* déclaration (et définition) de la classe pile_entiers */
const Max = 20 ;
class pile_entier
{
int dim ; // nombre maximal d'entiers de la pile
int * adr ; // adresse emplacement des dim entiers
int nelem ; // nombre d'entiers actuellement empilés

public :
pile_entier (int n = Max) // constructeur(s)
{ adr = new int [dim=n] ;
nelem = 0 ;
}
~pile_entier () // destructeur
{ delete adr ;
}
void empile (int p)
{ if (nelem < dim) adr[nelem++] = p ; }
int depile ()
{ if (nelem > 0) return adr[--nelem] ;
else return 0 ; // faute de mieux !
}
int pleine ()
{ return (nelem == dim) ; }
int vide ()
{ return (nelem == 0 ) ; }
pile_entier (pile_entier &) ; // constructeur de recopie
448 Program m e r e n langage C+ +
} ;
pile_entier::pile_entier (pile_entier & p)
{ adr = new int [dim = p.dim] ;
nelem = p.nelem ;
int i ;
for (i=0 ; i<nelem ; i++) adr[i] = p.adr[i] ;
}

/* programme d'essai de la classe pile_entier */


main()
{
int i ;
pile_entier a(3) ; // une pile a de 3 entiers
a.empile (5) ; a.empile (12) ;
pile_entier b = a ; // une pile b égale à a
cout << "Contenu de b : " ;
for (i=0 ; i<3 ; i++) if ( ! b.vide() ) cout << b.depile () << " " ;
cout << "\n" ;
}

CH A PITRE IX

Exe rcice 9 .3

a)A ve c une fonction m e m bre


#include <iostream.h>
/* classe point avec surdéfinition de == comme fonction membre */
class point
{ int x, y ;
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
int operator == (point & p) // on pourrait ne pas transmettre par référence
{ return ( (p.x == x) && (p.y == y) ) ; }
} ;

/* programme de test de la classe point */


main()
{ point a(2,3), b(1), c(2,3) ;
cout << " a == b " << (a == b) << "\n" ; // attention : parenthèses
cout << " b == a " << (b == a) << "\n" ; // indispensables, compte tenu
cout << " a == c " << (a == c) << "\n" ; // des priorités relatives de
cout << " c == a " << (c == a) << "\n" ; // de == et de <<
}

b)A ve c une fonction am ie


#include <iostream.h>
/* classe point avec surdéfinition de == comme fonction amie */
class point
{ int x, y ;
Corre ction de s e xe rcice s 449
public :
point (int abs=0, int ord=0) { x=abs ; y=ord ; }
friend int operator == (point &, point &) ;
} ;
int operator == (point & p, point & q)
{ return ( (p.x == q.x) && (p.y == q.y) ) ;
}

/* programme de test de la classe point */


main()
{ point a(2,3), b(1), c(2,3) ;
cout << " a == b " << (a == b) << "\n" ; // attention : parenthèses
cout << " b == a " << (b == a) << "\n" ; // indispensables, compte tenu
cout << " a == c " << (a == c) << "\n" ; // des priorités relatives de
cout << " c == a " << (c == a) << "\n" ; // de == et de <<
}

Exe rcice 9 .4

a)A ve c de s fonctions m e m bre


#include <iostream.h>
/* la classe pile_entiers */
/* avec surdéfinition des opérateurs < et > comme fonctions membre */
class pile_entier
{ int dim ; // nombre maximal d'entiers de la pile
int * adr ; // adresse emplacement des dim entiers
int nelem ; // nombre d'entiers actuellement empilés
public :
pile_entier (int n) // constructeur
{ adr = new int [dim=n] ;
nelem = 0 ;
}
~pile_entier () // destructeur
{ delete adr ;
}
void operator < (int n)
{ if (nelem < dim) adr[nelem++] = n ;
}
void operator > (int & n ) // attention & indispensable ici
{ if (nelem > 0) n = adr[--nelem] ;
}
} ;
/* programme d'essai de la classe pile_entier */
main()
{
int i, n ;
pile_entier a(3) ;
a < 3 ; a < 9 ; a < 11 ;
cout << "Contenu de a : " ;
for (i=0 ; i<3 ; i++)
{ a > n ; cout << n << " " ; }
cout << "\n" ;
}
450 Program m e r e n langage C+ +

b)A ve c de s fonctions am ie s
#include <iostream.h>
/* la classe pile_entiers */
/* avec surdéfinition des opérateurs < et > comme fonctions amies */
class pile_entier
{ int dim ; // nombre maximal d'entiers de la pile
int * adr ; // adresse emplacement des dim entiers
int nelem ; // nombre d'entiers actuellement empilés
public :
pile_entier (int n) // constructeur
{ adr = new int [dim=n] ;
nelem = 0 ;
}
~pile_entier () // destructeur
{ delete adr ;
}
friend void operator < (pile_entier &, int) ; // & non indispensable
friend void operator > (pile_entier &, int &) ; // int & indispensable ici
} ;
void operator < (pile_entier & p, int n)
{ if (p.nelem < p.dim) p.adr[p.nelem++] = n ;
}
void operator > (pile_entier & p, int & n)
{ if (p.nelem > 0) n = p.adr[--p.nelem] ;
}
/* programme d'essai de la classe pile_entier */
main()
{ int i, n ;
pile_entier a(3) ;
a < 3 ; a < 9 ; a < 11 ;
cout << "Contenu de a : " ;
for (i=0 ; i<3 ; i++)
{ a > n ; cout << n << " " ; }
cout << "\n" ;
}

Exe rcice 9 .5

#include <iostream.h>
class chaine
{ int lg ; // longueur actuelle de la chaîne
char * adr ; // adresse zone contenant la chaîne
public :
chaine () ; // constructeur I
chaine (char *) ; // constructeur II
chaine (chaine &) ; // constructeur III (par recopie)
~chaine () // destructeur ("inline")
{ delete adr ; }
void affiche () ;
chaine & operator = (chaine &) ;
int operator == (chaine &) ;
chaine operator + (chaine &) ;
Corre ction de s e xe rcice s 451
char & operator [] (int) ;
} ;
chaine::chaine () // constructeur I
{ lg = 0 ; adr=0 ;
}
chaine::chaine (char * adc) // constructeur II (à partir d'une chaîne C)
{ char * ad = adc ;
lg = 0 ;
while (*ad++) lg++ ; // calcul longueur chaîne C
adr = new char [lg] ;
for (int i=0 ; i<lg ; i++) // recopie chaîne C
adr[i] = adc[i] ;
}
chaine::chaine (chaine & ch) // constructeur III (par recopie)
{ adr = new char [lg = ch.lg] ;
for (int i=0; i<lg ; i++)
adr[i] = ch.adr[i] ;
}
void chaine::affiche ()
{ for (int i=0; i<lg; i++)
cout << adr[i] ; // en version < 2.0, utilisez printf
}
chaine & chaine::operator = (chaine & ch)
{ if (this != & ch) // on ne fait rien pour a=a
{ delete adr ;
adr = new char [lg = ch.lg] ;
for (int i=0; i<lg ; i++)
adr[i] = ch.adr[i] ;
}
return * this ; // pour pouvoir utiliser
} // la valeur de a=b
int chaine::operator == (chaine & ch)
{ for (int i=0 ; i<lg ; i++)
if (adr[i] != ch.adr[i]) return 0 ;
return 1 ;
}
chaine chaine::operator + (chaine & ch) // attention : la valeur de retour
{ chaine res ; // est à transmettre par valeur
res.adr = new char [res.lg = lg + ch.lg] ;
int i ;
for (i=0 ; i<lg ; i++) res.adr[i] = adr[i] ;
for (i=0 ; i<ch.lg ; i++) res.adr[i+lg] = ch.adr[i] ;
return res ;
}
char & chaine::operator [] (int i)
{ return adr[i] ; // ici, on n'a pas prévu de
} // vérification de la valeur de i
main()
{ chaine a ; cout << "chaine a : " ; a.affiche () ; cout << "\n" ;
chaine b("bonjour") ; cout << "chaine b : " ; b.affiche () ; cout << "\n" ;
chaine c=b ; cout << "chaine c : " ; c.affiche () ; cout << "\n" ;
chaine d("hello") ;
a = b = d ;
cout << "chaine b : " ; b.affiche () ; cout << "\n" ;
cout << "chaine a : " ; a.affiche () ; cout << "\n" ;
452 Program m e r e n langage C+ +
cout << "a == b : " << (a == b) << "\n" ;
chaine x("salut "), y("chère "), z("madame");
a = x + y + z ;
cout << "chaine a : " ; a.affiche () ; cout << "\n" ;
a = a ;
cout << "chaine a : " ; a.affiche () ; cout << "\n" ;
chaine e("xxxxxxxxxx") ;
for (char cr='a', i=0 ; cr<'f' ; cr++, i++ ) e[i] = cr ;
cout << "chaine e : " ; e.affiche () ; cout << "\n" ;
}
IND EX
454 Program m e r e n langage C+ +
Inde x 455

Vous aimerez peut-être aussi