630
Claude Delannoy C++ pour les programmeurs C C++ pour les programmeurs C

C++ pour les programmeurs C - bibliotheque.pssfp.net

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: C++ pour les programmeurs C - bibliotheque.pssfp.net

Acqueacuterir une parfaite maicirctrise du C++ et de la programmation objet

C++ pour les programmeurs C est la reacuteeacutedition avec un nouveau titre mieux adapteacute au public viseacute du grand classique deClaude Delannoy Programmer en C++ qui srsquoest imposeacute au fil de ses six eacuteditions successives comme la reacutefeacuterence en languefranccedilaise sur ce langage Destineacute aux programmeurs C souhaitant migrer vers le C++ lrsquoouvrage insiste tout particuliegraverement sur la bonne compreacutehen-sion des concepts objet et sur lacquisition de meacutethodes de programmation rigoureuses Entiegraverement fondeacute sur la norme ANSIISO lrsquoouvrage couvre tous les aspects du langage et de sa bibliothegraveque standard (STLou Standard Template Library) et traite en profondeur des points les plus deacutelicats auxquels est confronteacute un programmeurC++ lors de la creacuteation de ses propres classes et de la conception drsquoapplications professionnellesChaque notion nouvelle et chaque fonction du langage sont illustreacutees de programmes complets dont le code source est fournisur le site wwweditions-eyrollescom Tout au long de lrsquoouvrage des notes soulignent les diffeacuterences majeures entre le C++et Java de maniegravere agrave eacutetablir des passerelles entre les deux langages Un autre ouvrage du mecircme auteur conccedilu pour les programmeurs issus drsquoautres environnements que le C est publieacute simultaneacutement aux Eacuteditions Eyrolles sous letitre Apprendre le C++

Au sommaireC++ et programmation orienteacutee objet bull Points communs et diffeacuterences entre C et C++ bull Les entreacutees-sorties conversationnelles duC ++ bull Les speacutecificiteacutes du C ++ bull Classes et objets bull Les proprieacuteteacutes des fonctions membres bull Construction destruction et initialisa-tion des objets bull Les fonctions amies bull La surdeacutefinition dopeacuterateurs bull Les conversions de type deacutefinies par lutilisateur bull Lespatrons de fonctions bull Les patrons de classes bull Lheacuteritage simple bull Lheacuteritage multiple bull Les fonctions virtuelles et le polymorphis-me bull Les flots bull La gestion des exceptions bull Geacuteneacuteraliteacutes sur la bibliothegraveque standard (STL) bull Les conteneurs seacutequentiels bull Les conte-neurs associatifs bull Les algorithmes standards bull La classe string bull Les outils numeacuteriques bull Les espaces de noms Annexes Mise encorrespondance drsquoarguments bull Utilisation de code eacutecrit en C bull Compleacutements sur les exceptions bull Les diffeacuterents types de fonctionsen C++ bull Comptage de reacutefeacuterences bull Les pointeurs sur des membres bull Les algorithmes standards bull Corrigeacute des exercices

Sur le site wwweditions-eyrollescom

bull Dialoguez avec lrsquoauteurbull Teacuteleacutechargez le code source des exemples du livre

Code

eacutedite

ur

G122

31 bull

ISBN

-13

978

-2-2

12-1

2231

-2

32 euro

C++p

our

les

prog

ram

meu

rsC

C D

elann

oy

Claude DelannoyIngeacutenieur informaticien au CNRS Claude Delannoy possegravede une grande pratique de la formationcontinue et de lrsquoenseignement supeacuterieur Reacuteputeacutes pour la qualiteacute de leur deacutemarche peacutedagogique ses ouvrages sur les langages et la programmation totalisent plus de 250 000 exemplaires vendus

97

82

21

21

22

31

2

Claude Delannoy

C++pour les

programmeursCC++

pour lesprogrammeursC

delC++ 2006 120907 1100 Page 1

C++pour les

programmeursC

delannoy C++ titre 30907 2041 Page 2

CHEZ LE MEcircME EacuteDITEUR

Du mecircme auteur

C Delannoy ndash Exercices en langage C++ Ndeg12201 3e eacutedition 2007 336 pages

C Delannoy ndash Apprendre le C++ Ndeg12135 2007 760 pages

C Delannoy ndash Programmer en Java (Java 5 et 6) Ndeg12232 5e eacutedition 780 pages + CD-Rom

C Delannoy ndash Exercices en Java (Java 5) Ndeg11989 2e eacutedition 2006 330 pages

C Delannoy ndash Langage C Ndeg11123 1998 944 pages (reacuteeacutedition au format semi-poche)

C Delannoy ndash Programmer en langage C Avec exercices corrigeacutes Ndeg11072 1996 280 pages

C Delannoy ndash Exercices en langage C Ndeg11105 1997 260 pages

Autres ouvrages dans la mecircme collection

P Roques ndash UML 2 par la pratique Cours et exercices Ndeg12014 5e eacutedition 2006 360 pages

X Blanc I MounIeR ndash UML 2 pour les deacuteveloppeurs Cours et exercices corrigeacutes Ndeg12029 2006 218 pages

H BeRsInI I Wellesz ndash Lrsquoorienteacute objet Cours et exercices en UML 2 avec PHP Java Python C et C++ Ndeg12084 3e eacutedition 2007 520 pages

J engels ndash XHTML et CSS cours et exercices Ndeg11637 2005 350 pages

J engels ndash PHP 5 cours et exercicesNdeg11407 2005 518 pages

Autres ouvrages

I HoRton ndash Visual C++ 6 Avec un CD-Rom contenant le produit Microsoft Visual C++ 6 Introductory Edition Ndeg9043 1999 1 250 pages

G leBlanc ndash C et NET 20 Ndeg11778 2006 700 pages

E DasPet et C PIeRRe de geyeR ndash PHP 5 avanceacute Ndeg12167 4e eacutedition 2007 780 pages

a goncalves ndash Cahier du programmeur Java EE5 Ndeg12038 2007 330 pages

c PoRteneuve ndash Bien deacutevelopper pour le Web 20 Ndeg12028 2006 560 pages

Claude Delannoy

C++pour les

programmeursC

delannoy C++ titre 30907 2041 Page 1

compositeur
Fichier en piegravece jointe
9782212122312jpg

EacuteDITIONS EYROLLES61 bd Saint-Germain75240 Paris Cedex 05

wwweditions-eyrollescom

Le code de la proprieacuteteacute intellectuelle du 1er juillet 1992 interdit en effet expresseacutement la photocopie agrave usage collectif sans autorisation des ayants droit Or cette pratique srsquoest geacuteneacuteraliseacutee notamment dans les eacutetablissements drsquoenseignement provoquant une baisse brutale des achats de livres au point que la possibiliteacute mecircme pour les auteurs de creacuteer des œuvres nouvelles et de les faire eacutediter correctement est aujourdrsquohui menaceacuteeEn application de la loi du 11 mars 1957 il est interdit de reproduire inteacutegralement ou partiellement le

preacutesent ouvrage sur quelque support que ce soit sans autorisation de lrsquoeacutediteur ou du Centre Franccedilais drsquoExploitation du Droit de Copie 20 rue des Grands-Augustins 75006 Pariscopy Groupe Eyrolles 1993-2004 pour le texte de la preacutesente eacuteditioncopy Groupe Eyrolles 2007 pour la nouvelle preacutesentation (nouveau titre) ISBN 978-2-212-12231-2

6e eacutedition 2004 2e tirage 2007 avec nouvelle preacutesentation

Deacutepocirct leacutegal Septembre 2007Ndeg drsquoeacutediteur 7703

Table des matiegraveres

Avant-propos XXIII

Chapitre 1 Geacuteneacuteraliteacutes concernant C++ 1

1 - La Programmation Orienteacutee Objet 1

11 Probleacutematique de la programmation 1

12 La programmation structureacutee 2

13 Les apports de la Programmation Orienteacutee Objet 2

131 Objet 2

132 Encapsulation 3

133 Classe 3

134 Heacuteritage 3

135 Polymorphisme 4

14 POO et langages 4

2 - C++ C ANSI et POO 5

3 - Les speacutecificiteacutes de C++ 5

4 - C++ et la programmation orienteacutee objet 6

Chapitre 2 Les incompatibiliteacutes entre C++ et C 9

1 - Les deacutefinitions de fonctions en C++ 10

2 - Les prototypes en C++ 10

3 - Arguments et valeur de retour drsquoune fonction 13

31 Points communs agrave C et C++ 13

C++ pour programmeurs CVI

32 Diffeacuterences entre C et C++ 13

321 Fonctions sans arguments 14

322 Fonctions sans valeur de retour 14

4 - Le qualificatif const 14

41 Porteacutee 14

42 Utilisation dans une expression 15

5 - Compatibiliteacute entre le type void et les autres pointeurs 16

Chapitre 3 Les entreacutees-sorties conversationnelles du C++ 17

1 - Geacuteneacuteraliteacutes 17

2 - Affichage agrave lrsquoeacutecran 18

21 Quelques exemples 18

22 Le fichier en-tecircte iostream 20

23 Les possibiliteacutes drsquoeacutecriture sur cout 20

3 - Lecture au clavier 21

31 Introduction 21

32 Les diffeacuterentes possibiliteacutes de lecture sur cin 22

33 Exemple classique drsquoutilisation des seacuteparateurs 23

34 Lecture drsquoune suite de caractegraveres 23

35 Les risques induits par la lecture au clavier 24

351 Manque de synchronisme entre clavier et eacutecran 24

352 Blocage de la lecture 25

353 Boucle infinie sur un caractegravere invalide 25

Chapitre 4 Les speacutecificiteacutes du C++ 27

1 - Le commentaire de fin de ligne 28

2 - Deacuteclarations et initialisations 28

21 Regravegles geacuteneacuterales 28

22 Cas des instructions structureacutees 29

3 - La notion de reacutefeacuterence 30

31 Transmission des arguments en C 30

32 Exemple de transmission drsquoargument par reacutefeacuterence 31

33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argument 33

331 Induction de risques indirects 33

332 Absence de conversion 34

333 Cas drsquoun argument effectif constant 34

334 Cas drsquoun argument muet constant 35

34 Transmission par reacutefeacuterence drsquoune valeur de retour 35

341 Introduction 35

342 On obtient une lvalue 36

343 Conversion 36

344 Valeur de retour et constance 37

Table des matiegraveresVII

35 La reacutefeacuterence dune maniegravere geacuteneacuterale 37

351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument 38

352 Initialisation de reacutefeacuterence 38

4 - Les arguments par deacutefaut 39

41 Exemples 39

42 Les proprieacuteteacutes des arguments par deacutefaut 41

5 - Surdeacutefinition de fonctions 42

51 Mise en œuvre de la surdeacutefinition de fonctions 42

52 Exemples de choix dune fonction surdeacutefinie 43

53 Regravegles de recherche dune fonction surdeacutefinie 46

531 Cas des fonctions agrave un argument 46

532 Cas des fonctions agrave plusieurs arguments 47

533 Le meacutecanisme de la surdeacutefinition de fonctions 47

6 - Les opeacuterateurs new et delete 49

61 Exemples dutilisation de new 49

62 Syntaxe et rocircle de new 50

63 Exemples dutilisation de lopeacuterateur delete 50

64 Syntaxe et rocircle de lopeacuterateur delete 51

65 Lrsquoopeacuterateur new (nothrow) 51

66 Gestion des deacutebordements de meacutemoire avec set_new_handler 52

7 - La speacutecification inline 53

71 Rappels concernant les macros et les fonctions 53

72 Utilisation de fonctions en ligne 54

8 - Les espaces de noms 56

9 - Le type bool 57

10 - Les nouveaux opeacuterateurs de cast 57

Chapitre 5 Classes et objets 61

1 - Les structures en C++ 62

11 Rappel les structures en C 62

12 Deacuteclaration dune structure comportant des fonctions membres 63

13 Deacutefinition des fonctions membres 64

14 Utilisation dune structure comportant des fonctions membres 65

15 Exemple reacutecapitulatif 66

2 - Notion de classe 67

3 - Affectation drsquoobjets 70

4 - Notions de constructeur et de destructeur 72

41 Introduction 72

42 Exemple de classe comportant un constructeur 73

43 Construction et destruction des objets 75

44 Rocircles du constructeur et du destructeur 76

45 Quelques regravegles 79

C++ pour programmeurs CVIII

5 - Les membres donneacutees statiques 80

51 Le qualificatif static pour un membre donneacutee 80

52 Initialisation des membres donneacutees statiques 81

53 Exemple 82

6 - Exploitation drsquoune classe 83

61 La classe comme composant logiciel 83

62 Protection contre les inclusions multiples 85

63 Cas des membres donneacutees statiques 86

64 En cas de modification drsquoune classe 86

641 La deacuteclaration des membres publics nrsquoa pas changeacute 86

642 La deacuteclaration des membres publics a changeacute 87

7 - Les classes en geacuteneacuteral 87

71 Les autres sortes de classes en C++ 87

72 Ce quon peut trouver dans la deacuteclaration dune classe 87

73 Deacuteclaration dune classe 88

Chapitre 6 Les proprieacuteteacutes des fonctions membres 91

1 - Surdeacutefinition des fonctions membres 91

11 Exemple 92

12 Incidence du statut public ou priveacute drsquoune fonction membre 93

2 - Arguments par deacutefaut 94

3 - Les fonctions membres en ligne 95

4 - Cas des objets transmis en argument drsquoune fonction membre 97

5 - Mode de transmission des objets en argument 99

51 Transmission de ladresse dun objet 99

52 Transmission par reacutefeacuterence 101

53 Les problegravemes poseacutes par la transmission par valeur 102

6 - Lorsqursquoune fonction renvoie un objet 102

7 - Autoreacutefeacuterence le mot cleacute this 103

8 - Les fonctions membres statiques 104

9 - Les fonctions membres constantes 106

91 Rappels sur lrsquoutilisation de const en C 106

92 Deacutefinition drsquoune fonction membre constante 107

93 Proprieacuteteacutes drsquoune fonction membre constante 107

10 - Les membres mutables 109

Chapitre 7 Construction destruction et initialisation des objets 111

1 - Les objets automatiques et statiques 112

11 Dureacutee de vie 112

12 Appel des constructeurs et des destructeurs 113

13 Exemple 113

Table des matiegraveresIX

2 - Les objets dynamiques 115

21 Les structures dynamiques 115

22 Les objets dynamiques 116

221 Points communs avec les structures dynamiques 116

222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete 117

223 Exemple 117

3 - Le constructeur de recopie 118

31 Preacutesentation 118

311 Il nexiste pas de constructeur approprieacute 119

312 Il existe un constructeur approprieacute 119

313 Lorsqursquoon souhaite interdire la contruction par recopie 120

32 Exemple 1 objet transmis par valeur 121

321 Emploi du constructeur de recopie par deacutefaut 121

322 Deacutefinition dun constructeur de recopie 123

33 Exemple 2 objet en valeur de retour dune fonction 125

4 - Initialisation dun objet lors de sa deacuteclaration 127

5 - Objets membres 129

51 Introduction 129

52 Mise en œuvre des constructeurs et des destructeurs 129

53 Le constructeur de recopie 132

6 - Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur 132

7 - Les tableaux drsquoobjets 133

71 Notations 133

72 Constructeurs et initialiseurs 134

73 Cas des tableaux dynamiques dobjets 135

8 - Les objets temporaires 136

Chapitre 8 Les fonctions amies 141

1 - Exemple de fonction indeacutependante amie drsquoune classe 142

2 - Les diffeacuterentes situations drsquoamitieacute 144

21 Fonction membre dune classe amie dune autre classe 145

22 Fonction amie de plusieurs classes 146

23 Toutes les fonctions dune classe amies dune autre classe 147

3 - Exemple 147

31 Fonction amie indeacutependante 148

32 Fonction amie membre dune classe 149

4 - Exploitation de classes disposant de fonctions amies 150

Chapitre 9 La surdeacutefinition drsquoopeacuterateurs 151

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs 152

11 Surdeacutefinition dopeacuterateur avec une fonction amie 153

12 Surdeacutefinition dopeacuterateur avec une fonction membre 154

13 Opeacuterateurs et transmission par reacutefeacuterence 156

C++ pour programmeurs CX

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral 157

21 Se limiter aux opeacuterateurs existants 157

22 Se placer dans un contexte de classe 158

23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateur 159

24 Cas des opeacuterateurs ++ et -- 160

25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinie 161

26 Les conversions 162

27 Choix entre fonction membre et fonction amie 163

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur = 163

31 Rappels concernant le constructeur par recopie 163

32 Cas de lrsquoaffectation 164

33 Algorithme proposeacute 165

34 Valeur de retour 167

35 En deacutefinitive 167

36 Exemple de programme complet 167

37 Lorsqursquoon souhaite interdire lrsquoaffectation 169

4 - La forme canonique dune classe 170

5 - Exemple de surdeacutefinition de lopeacuterateur [ ] 171

6 - Surdeacutefinition de lopeacuterateur () 173

7 - Surdeacutefinition des opeacuterateurs new et delete 174

71 Surdeacutefinition de new et delete pour une classe donneacutee 175

72 Exemple 175

73 Drsquoune maniegravere geacuteneacuterale 177

Chapitre 10 Les conversions de type deacutefinies par lrsquoutilisateur 181

1 - Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur 182

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base 184

21 Deacutefinition de lopeacuterateur de cast 184

22 Exemple dutilisation 184

23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonction 185

24 Appel implicite de lopeacuterateur de cast dans leacutevaluation dune expression 187

25 Conversions en chaicircne 188

26 En cas dambiguiumlteacute 190

3 - Le constructeur pour la conversion type de base -gt type classe 191

31 Exemple 191

32 Le constructeur dans une chaicircne de conversions 193

33 Choix entre constructeur ou opeacuterateur daffectation 193

34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur 195

35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit 197

4 - Les conversions drsquoun type classe en un autre type classe 198

41 Exemple simple dopeacuterateur de cast 198

42 Exemple de conversion par un constructeur 199

43 Pour donner une signification agrave un opeacuterateur deacutefini dans une autre classe 200

5 - Quelques conseils 203

Table des matiegraveresXI

Chapitre 11 Les patrons de fonctions 205

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions 206

11 Creacuteation dun patron de fonctions 206

12 Premiegraveres utilisations du patron de fonctions 207

13 Autres utilisations du patron de fonctions 208

131 Application au type char 208

132 Application agrave un type classe 209

14 Contraintes drsquoutilisation drsquoun patron 210

2 - Les paramegravetres de type drsquoun patron de fonctions 211

21 Utilisation des paramegravetres de type dans la deacutefinition dun patron 211

22 Identification des paramegravetres de type dune fonction patron 212

23 Nouvelle syntaxe dinitialisation des variables des types standard 213

24 Limitations des patrons de fonctions 214

3 - Les paramegravetres expressions drsquoun patron de fonctions 215

4 - Surdeacutefinition de patrons 216

41 Exemples ne comportant que des paramegravetres de type 216

42 Exemples comportant des paramegravetres expressions 219

5 - Speacutecialisation de fonctions de patron 220

51 Geacuteneacuteraliteacutes 220

52 Les speacutecialisations partielles 221

6 - Algorithme drsquoinstanciation drsquoune fonction patron 222

Chapitre 12 Les patrons de classes 225

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes 226

11 Creacuteation dun patron de classes 226

12 Utilisation dun patron de classes 228

13 Contraintes drsquoutilisation drsquoun patron de classes 228

14 Exemple reacutecapitulatif 229

2 - Les paramegravetres de type drsquoun patron de classes 231

21 Les paramegravetres de type dans la creacuteation dun patron de classes 231

22 Instanciation dune classe patron 231

3 - Les paramegravetres expressions drsquoun patron de classes 233

31 Exemple 233

32 Les proprieacuteteacutes des paramegravetres expressions 235

4 - Speacutecialisation drsquoun patron de classes 235

41 Exemple de speacutecialisation dune fonction membre 236

42 Les diffeacuterentes possibiliteacutes de speacutecialisation 237

421 On peut speacutecialiser une fonction membre pour tous les paramegravetres 237

422 On peut speacutecialiser une fonction membre ou une classe 237

423 On peut preacutevoir des speacutecialisations partielles de patrons de classes 237

5 - Paramegravetres par deacutefaut 238

6 - Patrons de fonctions membres 238

C++ pour programmeurs CXII

7 - Identiteacute de classes patrons 239

8 - Classes patrons et deacuteclarations drsquoamitieacute 239

81 Deacuteclaration de classes ou fonctions ordinaires amies 239

82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons 240

83 Deacuteclaration drsquoun autre patron de fonctions ou de classes 241

9 - Exemple de classe tableau agrave deux indices 241

Chapitre 13 Lrsquoheacuteritage simple 245

1 - La notion drsquoheacuteritage 246

2 - Utilisation des membres de la classe de base dans une classe deacuteriveacutee 248

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee 250

31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacutee 250

32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacutee 252

33 Redeacutefinition et surdeacutefinition 252

4 - Appel des constructeurs et des destructeurs 254

41 Rappels 254

42 La hieacuterarchisation des appels 255

43 Transmission dinformations entre constructeurs 255

44 Exemple 256

45 Compleacutements 258

5 - Controcircle des accegraves 258

51 Les membres proteacutegeacutes 259

52 Exemple 259

53 Inteacuterecirct du statut proteacutegeacute 260

54 Deacuterivation publique et deacuterivation priveacutee 261

541 Rappels concernant la deacuterivation publique 261

542 Deacuterivation priveacutee 262

55 Les possibiliteacutes de deacuterivation proteacutegeacutee 263

56 Reacutecapitulation 264

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee 264

61 Conversion dun type deacuteriveacute en un type de base 265

62 Conversion de pointeurs 266

63 Limitations lieacutees au typage statique des objets 266

64 Les risques de violation des protections de la classe de base 269

7 - Le constructeur de recopie et lrsquoheacuteritage 270

71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopie 271

72 La classe deacuteriveacutee deacutefinit un constructeur de recopie 271

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage 273

81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur = 273

82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur = 274

9 - Heacuteritage et forme canonique dune classe 277

Table des matiegraveresXIII

10 - Lrsquoheacuteritage et ses limites 278

101 La situation dheacuteritage 278

1011 Le type du reacutesultat de lappel 279

1012 Le type des arguments de f 279

102 Exemples 280

1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point 280

1022 Heacuteritage dans pointcol de la fonction coincide de point 280

11 - Exemple de classe deacuteriveacutee 281

12 - Patrons de classes et heacuteritage 284

121 Classe ordinaire deacuterivant dune classe patron 285

122 Deacuterivation de patrons avec les mecircmes paramegravetres 286

123 Deacuterivation de patrons avec introduction drsquoun nouveau paramegravetre 286

13 - Lrsquoheacuteritage en pratique 287

131 Deacuterivations successives 287

132 Diffeacuterentes utilisations de lrsquoheacuteritage 289

133 Exploitation drsquoune classe deacuteriveacutee 289

Chapitre 14 Lheacuteritage multiple 291

1 - Mise en œuvre de lheacuteritage multiple 292

2 - Pour reacutegler les eacuteventuels conflits les classes virtuelles 296

3 - Appels des constructeurs et des destructeurs cas des classes virtuelles 298

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle 300

Chapitre 15 Les fonctions virtuelles et le polymorphisme 305

1 - Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire 306

2 - Le meacutecanisme des fonctions virtuelles 306

3 - Autre situation ougrave la ligature dynamique est indispensable 308

4 - Les proprieacuteteacutes des fonctions virtuelles 311

41 Leurs limitations sont celles de lrsquoheacuteritage 311

42 La redeacutefinition dune fonction virtuelle nest pas obligatoire 312

43 Fonctions virtuelles et surdeacutefinition 313

44 Le type de retour drsquoune fonction virtuelle redeacutefinie 313

45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe 314

46 Quelques restrictions et conseils 314

461 Seule une fonction membre peut ecirctre virtuelle 314

462 Un constructeur ne peut pas ecirctre virtuel 315

463 Un destructeur peut ecirctre virtuel 315

464 Cas particulier de lrsquoopeacuterateur drsquoaffectation 316

5 - Les fonctions virtuelles pures pour la creacuteation de classes abstraites 317

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene 319

7 - Le meacutecanisme drsquoidentification dynamique des objets 324

C++ pour programmeurs CXIV

8 - Identification de type agrave lexeacutecution 326

81 Utilisation du champ name de type_info 326

82 Utilisation des opeacuterateurs de comparaison de type_info 328

83 Exemple avec des reacutefeacuterences 328

9 - Les cast dynamiques 329

Chapitre 16 Les flots 333

1 - Preacutesentation geacuteneacuterale de la classe ostream 335

11 Lopeacuterateur ltlt 335

12 Les flots preacutedeacutefinis 336

13 La fonction put 337

14 La fonction write 337

141 Cas des caractegraveres 337

142 Autres cas 337

15 Quelques possibiliteacutes de formatage avec ltlt 338

151 Action sur la base de numeacuteration 338

152 Action sur le gabarit de linformation eacutecrite 339

153 Action sur la preacutecision de lrsquoinformation eacutecrite 341

154 Choix entre notation flottante ou exponentielle 341

2 - Preacutesentation geacuteneacuterale de la classe istream 342

21 Lrsquoopeacuterateur gtgt 343

211 Cas des caractegraveres 343

212 Cas des chaicircnes de caractegraveres 344

213 Les types accepteacutes par gtgt 344

22 La fonction get 345

23 Les fonctions getline et gcount 345

24 La fonction read 347

241 Cas des caractegraveres 347

242 Autres cas 347

25 Quelques autres fonctions 347

3 - Statut drsquoerreur drsquoun flot 348

31 Les bits derreur 348

32 Actions concernant les bits derreur 348

321 Accegraves aux bits derreur 349

322 Modification du statut derreur 349

33 Surdeacutefinition des opeacuterateurs () et 349

34 Exemples 350

4 - Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur 352

41 Meacutethode 352

42 Exemple 353

5 - Gestion du formatage 355

51 Le statut de formatage dun flot 356

52 Description du mot deacutetat du statut de formatage 357

Table des matiegraveresXV

53 Action sur le statut de formatage 358

531 Les manipulateurs non parameacutetriques 358

532 Les manipulateurs parameacutetriques 359

533 Les fonctions membres 360

6 - Connexion drsquoun flot agrave un fichier 362

61 Connexion dun flot de sortie agrave un fichier 362

62 Connexion dun flot dentreacutee agrave un fichier 364

63 Les possibiliteacutes daccegraves direct 365

64 Les diffeacuterents modes douverture dun fichier 367

7 - Les anciennes possibiliteacutes de formatage en meacutemoire 368

71 La classe ostrstream 369

72 La classe istrstream 370

Chapitre 17 La gestion des exceptions 373

1 - Premier exemple drsquoexception 374

11 Comment lancer une exception linstruction throw 374

12 Utilisation dun gestionnaire dexception 375

13 Reacutecapitulatif 376

2 - Second exemple 378

3 - Le meacutecanisme de gestion des exceptions 380

31 Poursuite de lexeacutecution du programme 380

32 Prise en compte des sorties de blocs 382

4 - Choix du gestionnaire 382

41 Le gestionnaire reccediloit toujours une copie 383

42 Regravegles de choix drsquoun gestionnaire drsquoexception 383

43 Le cheminement des exceptions 384

44 Redeacuteclenchement drsquoune exception 386

5 - Speacutecification dinterface la fonction unexpected 387

6 - Les exceptions standard 390

61 Geacuteneacuteraliteacutes 390

62 Les exceptions deacuteclencheacutees par la bibliothegraveque standard 390

63 Les exceptions utilisables dans un programme 391

64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exception 391

641 Exemple 1 392

642 Exemple 2 393

Chapitre 18 Geacuteneacuteraliteacutes sur la bibliothegraveque standard 395

1 - Notions de conteneur diteacuterateur et dalgorithme 395

11 Notion de conteneur 396

12 Notion diteacuterateur 396

13 Parcours dun conteneur avec un iteacuterateur 397

131 Parcours direct 397

132 Parcours inverse 398

C++ pour programmeurs CXVI

14 Intervalle diteacuterateur 398

15 Notion dalgorithme 399

16 Iteacuterateurs et pointeurs 400

2 - Les diffeacuterentes sortes de conteneurs 400

21 Conteneurs et structures de donneacutees classiques 400

22 Les diffeacuterentes cateacutegories de conteneurs 401

3 - Les conteneurs dont les eacuteleacutements sont des objets 401

31 Construction copie et affectation 402

32 Autres opeacuterations 403

4 - Efficaciteacute des opeacuterations sur des conteneurs 403

5 - Fonctions preacutedicats et classes fonctions 404

51 Fonction unaire 404

52 Preacutedicats 405

53 Classes et objets fonctions 405

531 Utilisation dobjet fonction comme fonction de rappel 405

532 Classes fonction preacutedeacutefinies 406

6 - Conteneurs algorithmes et relation dordre 407

61 Introduction 407

62 Proprieacuteteacutes agrave respecter 408

7 - Les geacuteneacuterateurs dopeacuterateurs 409

Chapitre 19 Les conteneurs seacutequentiels 411

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque 412

11 Construction 412

111 Construction dun conteneur vide 412

112 Construction avec un nombre donneacute deacuteleacutements 412

113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur 412

114 Construction agrave partir dune seacutequence 413

115 Construction agrave partir dun autre conteneur de mecircme type 413

12 Modifications globales 413

121 Opeacuterateur daffectation 414

122 La fonction membre assign 414

123 La fonction clear 415

124 La fonction swap 415

13 Comparaison de conteneurs 415

131 Lopeacuterateur == 415

132 Lopeacuterateur lt 416

133 Exemples 416

14 Insertion ou suppression deacuteleacutements 416

141 Insertion 417

142 Suppression 417

143 Cas des insertionssuppressions en fin pop_back et push_back 418

Table des matiegraveresXVII

2 - Le conteneur vector 418

21 Accegraves aux eacuteleacutements existants 419

211 Accegraves par iteacuterateur 419

212 Accegraves par indice 419

213 Cas de laccegraves au dernier eacuteleacutement 420

22 Insertions et suppressions 420

23 Gestion de lemplacement meacutemoire 420

231 Introduction 420

232 Invalidation diteacuterateurs ou de reacutefeacuterences 421

233 Outils de gestion de lemplacement meacutemoire dun vecteur 421

24 Exemple 422

25 Cas particulier des vecteurs de booleacuteens 423

3 - Le conteneur deque 424

31 Preacutesentation geacuteneacuterale 424

32 Exemple 425

4 - Le conteneur list 426

41 Accegraves aux eacuteleacutements existants 426

42 Insertions et suppressions 427

421 Suppression des eacuteleacutements de valeur donneacutee 427

422 Suppression des eacuteleacutements reacutepondant agrave une condition 427

43 Opeacuterations globales 428

431 Tri dune liste 428

432 Suppression des eacuteleacutements en double 428

433 Fusion de deux listes 429

434 Transfert dune partie de liste dans une autre 430

44 Gestion de lemplacement meacutemoire 430

45 Exemple 431

5 - Les adaptateurs de conteneur queue stack et priority_queue 432

51 Ladaptateur stack 432

52 Ladaptateur queue 433

53 Ladaptateur priority_queue 434

Chapitre 20 Les conteneurs associatifs 437

1 - Le conteneur map 438

11 Exemple introductif 438

12 Le patron de classes pair 440

13 Construction dun conteneur de type map 440

131 Constructions utilisant la relation dordre par deacutefaut 441

132 Choix de lordre intrinsegraveque du conteneur 441

133 Pour connaicirctre la relation dordre utiliseacutee par un conteneur 442

134 Conseacutequences du choix de lordre dun conteneur 443

14 Accegraves aux eacuteleacutements 443

141 Accegraves par lopeacuterateur [ ] 443

142 Accegraves par iteacuterateur 443

143 Recherche par la fonction membre find 444

C++ pour programmeurs CXVIII

15 Insertions et suppressions 444

151 Insertions 445

152 Suppressions 446

16 Gestion meacutemoire 446

17 Autres possibiliteacutes 447

18 Exemple 447

2 - Le conteneur multimap 448

21 Preacutesentation geacuteneacuterale 448

22 Exemple 449

3 - Le conteneur set 451

31 Preacutesentation geacuteneacuterale 451

32 Exemple 451

33 Le conteneur set et lensemble matheacutematique 452

4 - Le conteneur multiset 452

5 - Conteneurs associatifs et algorithmes 453

Chapitre 21 Les algorithmes standard 455

1 - Notions geacuteneacuterales 455

11 Algorithmes et iteacuterateurs 455

12 Les cateacutegories diteacuterateurs 456

121 Iteacuterateur en entreacutee 456

122 Iteacuterateur en sortie 456

123 Hieacuterarchie des cateacutegories diteacuterateurs 457

13 Algorithmes et seacutequences 457

14 Iteacuterateur dinsertion 458

15 Iteacuterateur de flot 460

151 Iteacuterateur de flot de sortie 460

152 Iteacuterateur de flot dentreacutee 461

2 - Algorithmes dinitialisation de seacutequences existantes 462

21 Copie dune seacutequence dans une autre 462

22 Geacuteneacuteration de valeurs par une fonction 463

3 - Algorithmes de recherche 466

31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire 466

32 Algorithmes de recherche de maximum ou de minimum 467

4 - Algorithmes de transformation dune seacutequence 468

41 Remplacement de valeurs 469

42 Permutations de valeurs 469

421 Rotation 469

422 Geacuteneacuteration de permutations 470

423 Permutations aleacuteatoires 471

43 Partitions 472

5 - Algorithmes dits de suppression 472

6 - Algorithmes de tris 474

Table des matiegraveresXIX

7 - Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees 476

71 Algorithmes de recherche binaire 476

72 Algorithmes de fusion 476

8 - Algorithmes agrave caractegravere numeacuterique 478

9 - Algorithmes agrave caractegravere ensembliste 479

10 - Algorithmes de manipulation de tas 480

Chapitre 22 La classe string 485

1 - Geacuteneacuteraliteacutes 486

2 - Construction 486

3 - Opeacuterations globales 487

4 - Concateacutenation 488

5 - Recherche dans une chaicircne 488

51 Recherche dune chaicircne ou dun caractegravere 489

52 Recherche dun caractegravere preacutesent ou absent dune suite 489

6 - Insertions suppressions et remplacements 490

61 Insertions 490

62 Suppressions 491

63 Remplacements 492

7 - Les possibiliteacutes de formatage en meacutemoire 493

71 La classe ostringstream 494

72 La classe istringstream 495

721 Preacutesentation 495

722 Utilisation pour fiabiliser les lectures au clavier 495

Chapitre 23 Les outils numeacuteriques 499

1 - La classe complex 499

2 - La classe valarray et les classes associeacutees 501

21 Constructeurs des classes valarray 501

22 Lrsquoopeacuterateur [] 502

23 Affectation et changement de taille 502

24 Calcul vectoriel 502

25 Seacutelection de valeurs par masque 504

26 Sections de vecteurs 505

27 Vecteurs drsquoindices 506

3 - La classe bitset 507

Chapitre 24 Les espaces de noms 511

1 - Creacuteation drsquoespaces de noms 511

11 Exemple de creacuteation drsquoun nouvel espace de noms 512

12 Exemple avec deux espaces de noms 513

C++ pour programmeurs CXX

13 Espace de noms et fichier en-tecircte 514

14 Instructions figurant dans un espace de noms 514

15 Creacuteation increacutementale drsquoespaces de noms 515

2 - Les instructions using 516

21 La deacuteclaration using pour les symboles 516

211 Preacutesentation geacuteneacuterale 516

212 Masquage et ambiguiumlteacutes 518

22 La directive using pour les espaces de noms 519

3 - Espaces de noms et surdeacutefinition 521

4 - Imbrication des espaces de noms 523

5 - Transitiviteacute de la directive using 523

6 - Les alias 524

7 - Les espaces anonymes 524

8 - Espaces de noms et deacuteclaration drsquoamitieacute 525

Annexes 527

Annexe A Mise en correspondance drsquoarguments 529

1 - Deacutetermination des fonctions candidates 529

2 - Algorithme de recherche drsquoune fonction agrave un seul argument 530

21 Recherche dune correspondance exacte 530

22 Promotions numeacuteriques 531

23 Conversions standard 531

24 Conversions deacutefinies par lutilisateur 532

25 Fonctions agrave arguments variables 532

26 Exception cas des champs de bits 532

3 - Fonctions agrave plusieurs arguments 533

4 - Fonctions membres 533

Annexe B Utilisation de code eacutecrit en C 535

1 - Prototypes 535

2 - Fonctions sans arguments 535

3 - Fonctions sans valeur de retour 535

4 - Le qualificatif const 536

5 - Les pointeurs de type void 536

6 - Mots cleacutes 536

7 - Les constantes de type caractegravere 537

8 - Les deacutefinitions multiples 537

9 - Linstruction goto 538

10 - Les eacutenumeacuterations 538

Table des matiegraveresXXI

11 - Initialisation de tableaux de caractegraveres 538

12 - Les noms de fonctions 538

Annexe C Compleacutements sur les exceptions 539

1 - Les problegravemes poseacutes par les objets automatiques 539

2 - La technique de gestion de ressources par initialisation 540

3 - Le concept de pointeur intelligent la classe auto_ptr 542

Annexe D Les diffeacuterentes sortes de fonctions en C++ 545

Annexe E Comptage de reacutefeacuterences 547

Annexe F Les pointeurs sur des membres 551

1 - Rappels sur les pointeurs sur des fonctions en C 551

2 - Les pointeurs sur des fonctions membres 552

3 - Les pointeurs sur des membres donneacutees 553

4 - Lrsquoheacuteritage et les pointeurs sur des membres 554

Annexe G Les algorithmes standard 557

1 - Algorithmes dinitialisation de seacutequences existantes 558

2 - Algorithmes de recherche 559

3 - Algorithmes de transformation dune seacutequence 561

4 - Algorithmes de suppression 564

5 - Algorithmes de tri 566

6 - Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees 568

7 - Algorithmes agrave caractegravere numeacuterique 570

8 - Algorithmes agrave caractegravere ensembliste 571

9 - Algorithmes de manipulation de tas 574

10 - Algorithmes divers 575

Correction des exercices 577

Index 593

Avant-propos

1 Historique de C++La programmation orienteacutee objet (en abreacutegeacute POO) est doreacutenavant universellement recon-

nue pour les avantages qursquoelle procure Notamment elle ameacuteliore largement la productiviteacute

des deacuteveloppeurs la robustesse la portabiliteacute et lrsquoextensibiliteacute de leurs programmes Enfin et

surtout elle permet de deacutevelopper des composants logiciels entiegraverement reacuteutilisables

Un certain nombre de langages dits langages orienteacutes objet (LOO) ont eacuteteacute deacutefinis de tou-

tes piegraveces pour appliquer les concepts de POO Crsquoest ainsi que sont apparus dans un premier

temps des langages comme Smalltalk Simula ou Eiffel puis plus reacutecemment Java Le lan-

gage C++ quant agrave lui a eacuteteacute conccedilu suivant une deacutemarche quelque peu diffeacuterente par B

Stroustrup (ATampT) son objectif a eacuteteacute en effet dadjoindre au langage C un certain nombre

de speacutecificiteacutes lui permettant dappliquer les concepts de POO Ainsi C++ preacutesente-t-il sur

un vrai LOO loriginaliteacute decirctre fondeacute sur un langage reacutepandu Ceci laisse au programmeur

toute liberteacute dadopter un style plus ou moins orienteacute objet en se situant entre les deux extrecirc-

mes que constituent la poursuite dune programmation classique dune part une pure POO

dautre part Si une telle liberteacute preacutesente le risque de ceacuteder dans un premier temps agrave la faci-

liteacute en meacutelangeant les genres (la POO ne renie pas la programmation classique - elle lenri-

chit) elle permet eacutegalement une transition en douceur vers la POO pure avec tout le

beacuteneacutefice quon peut en escompter agrave terme

De sa conception jusquagrave sa normalisation le langage C++ a quelque peu eacutevolueacute Initiale-

ment un certain nombre de publications de ATampT ont servi de reacutefeacuterence du langage Les der-

niegraveres en date sont la version 20 en 1989 les versions 21 et 3 en 1991 Crsquoest cette derniegravere

qui a servi de base au travail du comiteacute ANSI lequel sans la remettre en cause la enrichie de

Avant-proposAVANT-PROPOS

XXIV

quelques extensions et surtout de composants standard originaux se preacutesentant sous forme de

fonctions et de classes geacuteneacuteriques qursquoon deacutesigne souvent par le sigle STL1 La norme deacutefini-

tive de C++ a eacuteteacute publieacutee par lANSI et par lISO en 1998 et a fait lobjet dune reacutevision

publieacutee en 2003 sous la reacutefeacuterence ISO 148822003

2 Objectifs et structure de lrsquoouvrageCet ouvrage a eacuteteacute speacutecifiquement conccedilu pour tous ceux qui posseacutedant deacutejagrave une pratique du

langage C2 souhaitent maicirctriser la programmation orienteacutee objet en C++ Il srsquoadresse agrave la

fois aux eacutetudiants aux deacuteveloppeurs et aux enseignants en informatique

Conccedilu sous forme drsquoun cours complet il expose progressivement agrave la fois

bull les diffeacuterentes notions fondamentales de la POO et la faccedilon dont elles srsquoexpriment en C++

(classes et objets meacutethodes constructeur destructeur heacuteritage polymorphisme)

bull les speacutecificiteacutes non orienteacutees objet du langage C++ crsquoest-agrave-dire celles qui permettent agrave

C++ drsquoecirctre un C ameacutelioreacute (reacutefeacuterence argument par deacutefaut surdeacutefinition de fonctions fonc-

tions en ligne espaces de noms)

bull les speacutecificiteacutes orienteacutees objet du C++ fonctions amies surdeacutefinition drsquoopeacuterateurs patrons

de classes et de fonctions heacuteritage multiple flots bibliothegraveque standard

Chacune de ces notions est illustreacutee systeacutematiquement par un programme complet assorti

dun exemple dexeacutecution montrant comment la mettre en œuvre dans un contexte reacuteel Celui-

ci peut eacutegalement servir agrave une prise de connaissance intuitive ou agrave une reacutevision rapide de la

notion en question agrave une expeacuterimentation directe dans votre propre environnement de travail

ou encore de point de deacutepart agrave une expeacuterimentation personnelle

Les chapitres les plus importants ont eacuteteacute doteacutes dexercices3 comportant

bull des suggestions de manipulations destineacutees agrave mieux vous familiariser avec votre

environnement par effet dentraicircnement elles vous feront probablement imaginer dautres

expeacuterimentations de votre cru

bull des programmes agrave reacutediger dans ce cas un exemple de correction est fourni en fin de volu-

me

Lrsquoaspect didactique a eacuteteacute privileacutegieacute sans pour autant nuire agrave lrsquoexhaustiviteacute de lrsquoouvrage

Nous couvrons lrsquoensemble de la programmation en C++ des notions fondamentales de la

POO jusqursquoaux aspects tregraves speacutecifiques au langage (mais neacuteanmoins fondamentaux) afin

1 Standard Template Library

2 Le cas eacutecheacuteant on pourra trouver un cours complet de langage C dans Programmer en langage C ou une reacutefeacuterence

exhaustive de sa norme dans Langage C du mecircme auteur chez le mecircme eacutediteur

3 De nombreux autres exercices peuvent ecirctre trouveacutes dans Exercices en langage C++ du mecircme auteur chez le mecircme

eacutediteur

3 - Lrsquoouvrage la norme de C++ C et JavaXXV

de rendre le lecteur parfaitement opeacuterationnel dans la conception le deacuteveloppement et la

mise au point de ses propres classes Crsquoest ainsi que nous avons soigneusement eacutetudieacute les

conseacutequences de la liberteacute qursquooffre C++ de choisir le mode de gestion de la meacutemoire alloueacutee

aux objets (automatique ou dynamique)1 De mecircme nous avons largement insisteacute sur le rocircle

du constructeur de recopie ainsi que sur la redeacutefinition de lopeacuterateur daffectation eacuteleacutements

qui conduisent agrave la notion de classe canonique Toujours dans le mecircme esprit nous avons

pris soin de bien deacutevelopper les notions indispensables que sont la ligature dynamique et les

classes abstraites lesquelles deacutebouchent sur la notion la plus puissante du langage quest le

polymorphisme De mecircme la STL a eacuteteacute eacutetudieacutee en deacutetail apregraves avoir pris soin drsquoexposer

preacutealablement drsquoune part les notions de classes et de fonctions geacuteneacuteriques drsquoautre part celles

de conteneur diteacuterateur et dalgorithmes qui conditionnent la bonne utilisation de la plupart

de ses composants

3 Lrsquoouvrage la norme de C++ C et JavaCet ouvrage est entiegraverement fondeacute sur la norme ANSIISO du langage C++ Degraves le deacutebut le

lecteur est sensibiliseacute aux quelques incompatibiliteacutes existant entre C++ et C de sorte qursquoil

pourra reacuteutiliser convenablement en C++ du code eacutecrit en C Drsquoautre part compte tenu de la

populariteacute du langage Java nous avons introduit de nombreuses remarques titreacutees En Java

Elles mettent lrsquoaccent sur les diffeacuterences majeures existant entre Java et C++ Elles seront

utiles au lecteur qui apregraves la maicirctrise du C++ souhaitera aborder lrsquoeacutetude de Java

Cet ouvrage correspond en fait agrave une refonte des eacuteditions preacuteceacutedentes de Programmer en

C++ Nous continuons drsquoy mentionner les apports de la norme par rapport agrave la version 3 du

langage publieacutee en 1991 ainsi que les quelques diffeacuterences avec les versions anteacuterieures

Ces remarques initialement preacutevues pour faciliter lrsquoutilisation drsquoanciens environnements de

programmation deviennent de moins en moins pertinentes mais dans la mesure ougrave elles ne

pertubent pas lrsquoapprentissage du langage nous avons preacutefeacutereacute les conserver pour leur carac-

tegravere historique en particulier elles mettent en avant les points deacutelicats du langage pour les-

quels la genegravese a eacuteteacute quelque peu difficile

1 Certains langages objet dont Java gegraverent tous les objets de maniegravere dynamique

1

Geacuteneacuteraliteacutes concernant C++

Le langage C++ a eacuteteacute conccedilu agrave partir de 1982 par Bjarne Stroustrup (ATampT Bell Laboratories)

avec un objectif preacutecis ajouter au langage C des classes analogues agrave celles du langage

Simula Il srsquoagissait donc de greffer sur un langage classique des possibiliteacutes de Program-

mation Orienteacutee Objet Avant de vous preacutesenter le reacutesultat auquel a abouti B Stroustrup

commenccedilons par examiner succinctement ce qursquoest la Programmation Orienteacutee Objet

1 La Programmation Orienteacutee Objet

11 Probleacutematique de la programmationJusqursquoagrave maintenant lrsquoactiviteacute de programmation a toujours susciteacute des reacuteactions diverses

allant jusqursquoagrave la contradiction totale Pour certains en effet il ne srsquoagit que drsquoun jeu de cons-

truction enfantin dans lequel il suffit drsquoenchaicircner des instructions eacuteleacutementaires (en nombre

restreint) pour parvenir agrave reacutesoudre nrsquoimporte quel problegraveme ou presque Pour drsquoautres au

contraire il srsquoagit de produire (au sens industriel du terme) des logiciels avec des exigences

de qualiteacute qursquoon tente de mesurer suivant certains critegraveres notamment

bull lrsquoexactitude aptitude drsquoun logiciel agrave fournir les reacutesultats voulus dans des conditions nor-

males drsquoutilisation (par exemple donneacutees correspondant aux speacutecifications)

bull la robustesse aptitude agrave bien reacuteagir lorsque lrsquoon srsquoeacutecarte des conditions normales

drsquoutilisation

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

2

bull lrsquoextensibiliteacute faciliteacute avec laquelle un programme pourra ecirctre adapteacute pour satisfaire agrave une

eacutevolution des speacutecifications

bull la reacuteutilisabiliteacute possibiliteacute drsquoutiliser certaines parties (modules) du logiciel pour reacutesoudre

un autre problegraveme

bull la portabiliteacute faciliteacute avec laquelle on peut exploiter un mecircme logiciel dans diffeacuterentes

impleacutementations

bull lrsquoefficience temps drsquoexeacutecution taille meacutemoire

La contradiction nrsquoest souvent qursquoapparente et essentiellement lieacutee agrave lrsquoimportance des projets

concerneacutes Par exemple il est facile drsquoeacutecrire un programme exact et robuste lorsqursquoil com-

porte une centaine drsquoinstructions il en va tout autrement lorsqursquoil srsquoagit drsquoun projet de dix

hommes-anneacutees De mecircme les aspects extensibiliteacute et reacuteutilisabiliteacute nrsquoauront guegravere

drsquoimportance dans le premier cas alors qursquoils seront probablement cruciaux dans le second

ne serait-ce que pour des raisons eacuteconomiques

12 La programmation structureacuteeLa programmation structureacutee a manifestement fait progresser la qualiteacute de la production des

logiciels Mais avec le recul il faut bien reconnaicirctre que ses propres fondements lui impo-

saient des limitations naturelles En effet la programmation structureacutee reposait sur ce que

lrsquoon nomme souvent lrsquoeacutequation de Wirth agrave savoir

Algorithmes + Structures de donneacutees = Programmes

Bien sucircr elle a permis de structurer les programmes et partant drsquoen ameacuteliorer lrsquoexactitude et

la robustesse On avait espeacutereacute qursquoelle permettrait eacutegalement drsquoen ameacuteliorer lrsquoextensibiliteacute et

la reacuteutilisabiliteacute Or en pratique on srsquoest aperccedilu que lrsquoadaptation ou la reacuteutilisation drsquoun logi-

ciel conduisait souvent agrave casser le module inteacuteressant et ceci parce qursquoil eacutetait neacutecessaire de

remettre en cause une structure de donneacutees Preacuteciseacutement ce type de difficulteacutes eacutemane direc-

tement de lrsquoeacutequation de Wirth qui deacutecouple totalement les donneacutees des proceacutedures agissant

sur ces donneacutees

13 Les apports de la Programmation Orienteacutee Objet

131 ObjetCrsquoest lagrave qursquointervient la Programmation Orienteacutee Objet (en abreacutegeacute POO) fondeacutee justement

sur le concept drsquoobjet agrave savoir une association des donneacutees et des proceacutedures (qursquoon appelle

alors meacutethodes) agissant sur ces donneacutees Par analogie avec lrsquoeacutequation de Wirth on pourrait

dire que lrsquoeacutequation de la POO est

Meacutethodes + Donneacutees = Objet

1 - La Programmation Orienteacutee Objet3

132 Encapsulation

Mais cette association est plus qursquoune simple juxtaposition En effet dans ce que lrsquoon pour-

rait qualifier de POO pure1 on reacutealise ce que lrsquoon nomme une encapsulation des don-

neacutees Cela signifie qursquoil nrsquoest pas possible drsquoagir directement sur les donneacutees drsquoun objet il

est neacutecessaire de passer par lrsquointermeacutediaire de ses meacutethodes qui jouent ainsi le rocircle drsquointer-

face obligatoire On traduit parfois cela en disant que lrsquoappel drsquoune meacutethode est en fait

lrsquoenvoi drsquoun message agrave lrsquoobjet

Le grand meacuterite de lrsquoencapsulation est que vu de lrsquoexteacuterieur un objet se caracteacuterise unique-

ment par les speacutecifications2 de ses meacutethodes la maniegravere dont sont reacuteellement implanteacutees les

donneacutees eacutetant sans importance On deacutecrit souvent une telle situation en disant qursquoelle reacutealise

une abstraction des donneacutees (ce qui exprime bien que les deacutetails concrets drsquoimpleacutementation

sont cacheacutes) A ce propos on peut remarquer qursquoen programmation structureacutee une proceacutedure

pouvait eacutegalement ecirctre caracteacuteriseacutee (de lrsquoexteacuterieur) par ses speacutecifications mais que faute

drsquoencapsulation lrsquoabstraction des donneacutees nrsquoeacutetait pas reacutealiseacutee

Lrsquoencapsulation des donneacutees preacutesente un inteacuterecirct manifeste en matiegravere de qualiteacute de logiciel

Elle facilite consideacuterablement la maintenance une modification eacuteventuelle de la structure

des donneacutees drsquoun objet nrsquoa drsquoincidence que sur lrsquoobjet lui-mecircme les utilisateurs de lrsquoobjet

ne seront pas concerneacutes par la teneur de cette modification (ce qui nrsquoeacutetait bien sucircr pas le cas

avec la programmation structureacutee) De la mecircme maniegravere lrsquoencapsulation des donneacutees facilite

grandement la reacuteutilisation drsquoun objet

133 Classe

En POO apparaicirct geacuteneacuteralement le concept de classe3 qui correspond simplement agrave la geacuteneacute-

ralisation de la notion de type que lrsquoon rencontre dans les langages classiques En effet une

classe nrsquoest rien drsquoautre que la description drsquoun ensemble drsquoobjets ayant une structure de

donneacutees commune4 et disposant des mecircmes meacutethodes Les objets apparaissent alors comme

des variables drsquoun tel type classe (en POO on dit aussi qursquoun objet est une instance de sa

classe)

134 Heacuteritage

Un autre concept important en POO est celui drsquoheacuteritage Il permet de deacutefinir une nouvelle

classe agrave partir drsquoune classe existante (qursquoon reacuteutilise en bloc ) agrave laquelle on ajoute de nou-

1 Nous verrons en effet que les concepts de la POO peuvent ecirctre appliqueacutes drsquoune maniegravere plus ou moins rigou-

reuse En particulier en C++ lrsquoencapsulation ne sera pas obligatoire ce qui ne veut pas dire qursquoelle ne soit pas sou-

haitable

2 Noms arguments et rocircles

3 Dans certains langages (Turbo Pascal par exemple) le mot classe est remplaceacute par objet et le mot objet par varia-

ble

4 Bien entendu seule la structure est commune les donneacutees eacutetant propres agrave chaque objet En revanche les meacutetho-

des sont effectivement communes agrave lrsquoensemble des objets drsquoune mecircme classe

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

4

velles donneacutees et de nouvelles meacutethodes La conception de la nouvelle classe dite qui

heacuterite des proprieacuteteacutes et des aptitudes de lrsquoancienne peut ainsi srsquoappuyer sur des reacutealisations

anteacuterieures parfaitement au point et les speacutecialiser agrave volonteacute Comme on peut srsquoen douter

lrsquoheacuteritage facilite largement la reacuteutilisation de produits existants drsquoautant plus qursquoil peut ecirctre

reacuteiteacutereacute autant de fois que neacutecessaire (la classe C peut heacuteriter de B qui elle-mecircme heacuterite

de A)1

135 Polymorphisme

Geacuteneacuteralement en POO une classe deacuteriveacutee peut redeacutefinir (crsquoest-agrave-dire modifier) certaines

des meacutethodes heacuteriteacutees de sa classe de base Cette possibiliteacute est la cleacute de ce que lrsquoon nomme

le polymorphisme crsquoest-agrave-dire la possibiliteacute de traiter de la mecircme maniegravere des objets de

types diffeacuterents pour peu qursquoils soient tous de classes deacuteriveacutees de la mecircme classe de base

Plus preacuteciseacutement on utilise chaque objet comme srsquoil eacutetait de cette classe de base mais son

comportement effectif deacutepend de sa classe effective (deacuteriveacutee de cette classe de base) en par-

ticulier de la maniegravere dont ses propres meacutethodes ont eacuteteacute redeacutefinies Le polymorphisme ameacute-

liore lrsquoextensibiliteacute des programmes en permettant drsquoajouter de nouveaux objets dans un

sceacutenario preacuteeacutetabli et eacuteventuellement eacutecrit avant drsquoavoir connaissance du type effectif de ces

objets

14 POO et langagesNous venons drsquoeacutenoncer les grands principes de la POO sans nous attacher agrave un langage par-

ticulier

Or manifestement certains langages peuvent ecirctre conccedilus (de toutes piegraveces) pour appliquer agrave

la lettre ces principes et reacutealiser ce que nous nommons de la POO pure Crsquoest par exem-

ple le cas de Simula Smalltalk ou plus reacutecemment Eiffel ou Java Le mecircme pheacutenomegravene a eu

lieu en son temps pour la programmation structureacutee avec Pascal

A lrsquoopposeacute on peut toujours tenter drsquoappliquer avec plus ou moins de bonheur ce que nous

aurions tendance agrave nommer une philosophie POO agrave un langage classique (Pascal C)

On retrouve lagrave une ideacutee comparable agrave celle qui consistait agrave appliquer les principes de la pro-

grammation structureacutee agrave des langages comme Fortran ou Basic

Le langage C++ se situe agrave mi-chemin entre ces deux points de vue Il a en effet eacuteteacute obtenu en

ajoutant agrave un langage classique (C) les outils permettant de mettre en œuvre tous les princi-

pes de la POO Programmer en C++ va donc plus loin qursquoadopter une philosophie POO en

C mais moins loin que de faire de la POO pure avec Eiffel

La solution adopteacutee par B Stroustrup a le meacuterite de preacuteserver lrsquoexistant (compatibiliteacute avec

C++ de programmes deacutejagrave eacutecrits en C) elle permet eacutegalement une transition en douceur de

la programmation structureacutee vers la POO En revanche elle nrsquoimpose nullement lrsquoapplica-

1 En C++ les techniques de meacutethodes virtuelles eacutelargissent encore plus la porteacutee de lrsquoheacuteritage mais il nrsquoest pas

possible pour lrsquoinstant drsquoen faire percevoir lrsquointeacuterecirct

2 - C++ C ANSI et POO5

tion stricte des principes de POO Comme vous le verrez en C++ rien ne vous empecircchera

(sauf votre bon sens ) de faire cohabiter des objets (dignes de ce nom parce que reacutealisant

une parfaite encapsulation de leurs donneacutees) avec des fonctions classiques reacutealisant des effets

de bord sur des variables globales

2 C++ C ANSI et POOPreacuteceacutedemment nous avons dit drsquoune faccedilon quelque peu simpliste que C++ se preacutesentait

comme un sur-ensemble du langage C offrant des possibiliteacutes de POO Il nous faut main-

tenant nuancer cette affirmation car il existe quelques incompatibiliteacutes entre le C et le C++

tels qursquoils sont deacutefinis par leurs normes respectives Celles-ci comme nous le verrons sont

neacuteanmoins mineures elles sont pour la plupart dues agrave la diffeacuterence drsquoesprit des deux langa-

ges ainsi qursquoagrave la toleacuterance dont a fait preuve la norme ANSI du C en cherchant agrave preacuteserver

lrsquoexistant (certaines toleacuterances ont disparu en C++)

Drsquoautre part les extensions du C++ par rapport au C ANSI ne sont pas toutes veacuteritablement

lieacutees agrave la POO Certaines pourraient en effet ecirctre ajouteacutees avec profit au langage C sans

qursquoil devienne pour autant orienteacute objet1

En fait nous pourrions caracteacuteriser C++ par cette formule

C++ = C + E + S + P

bull C deacutesigne le C norme ANSI

bull E repreacutesente les eacutecarts de C++ par rapport agrave la norme ANSI de C

bull S repreacutesente les speacutecificiteacutes de C++ qui ne sont pas veacuteritablement axeacutees sur la POO

bull P repreacutesente les possibiliteacutes de POO

Les principaux eacutecarts par rapport agrave la norme sont deacutecrits au chapitre 2 ils sont accompa-

gneacutes de rappels concernant la norme C ANSI Ils concernent essentiellement

bull les deacutefinitions de fonctions en-tecirctes prototypes arguments et valeur de retour

bull la porteacutee du qualificatif const

bull les compatibiliteacutes entre pointeurs

3 Les speacutecificiteacutes de C++Comme nous lrsquoavons dit C++ preacutesente par rapport au C ANSI des extensions qui ne sont

pas veacuteritablement orienteacutees POO Elles seront deacutecrites au chapitre 4 En voici un bref

reacutesumeacute

1 Drsquoailleurs certaines extensions de C++ par rapport agrave la premiegravere deacutefinition du C ont eacuteteacute introduites dans le C

ANSI (prototypes fonctions agrave arguments variables)

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

6

bull nouvelle forme de commentaire (en fin de ligne)

bull plus grande liberteacute dans lrsquoemplacement des deacuteclarations

bull notion de reacutefeacuterence facilitant la mise en œuvre de la transmission drsquoarguments par adresse

bull surdeacutefinition des fonctions attribution drsquoun mecircme nom agrave diffeacuterentes fonctions la recon-

naissance de la fonction reacuteellement appeleacutee se faisant drsquoapregraves le type et le nombre des argu-

ments figurant dans lrsquoappel (on parle parfois de signature)

bull nouveaux opeacuterateurs de gestion dynamique de la meacutemoire new et delete

bull possibiliteacute de deacutefinir des fonctions en ligne (inline) ce qui accroicirct la vitesse drsquoexeacutecution

sans perdre pour autant le formalisme des fonctions

4 C++ et la programmation orienteacutee objetLes possibiliteacutes de POO repreacutesentent bien sucircr lrsquoessentiel de lrsquoapport de C++

C++ dispose de la notion de classe (geacuteneacuteralisation de la notion de type deacutefini par lrsquoutilisa-

teur) Une classe comportera

bull la description drsquoune structure de donneacutees

bull des meacutethodes

Sur le plan du vocabulaire C++ utilise des termes qui lui sont propres On parle en effet de

bull membres donneacutees pour deacutesigner les diffeacuterents membres de la structure de donneacutees asso-

cieacutee agrave une classe

bull fonctions membres pour deacutesigner les meacutethodes

A partir drsquoune classe on pourra instancier des objets (nous dirons geacuteneacuteralement creacuteer des

objets)

bull soit par des deacuteclarations usuelles (de type classe)

bull soit par allocation dynamique en faisant appel au nouvel opeacuterateur new

C++ permet lrsquoencapsulation des donneacutees mais il ne lrsquoimpose pas On peut le regretter mais il

ne faut pas perdre de vue que par sa conception mecircme (extension de C) le C++ ne peut pas

ecirctre un langage de POO pure Bien entendu il reste toujours possible au concepteur de faire

preuve de rigueur en srsquoastreignant agrave certaines regravegles telles que lrsquoencapsulation absolue

Comme la plupart des langages objets C++ permet de deacutefinir ce que lrsquoon nomme des cons-

tructeurs de classe Un constructeur est une fonction membre particuliegravere qui est exeacutecuteacutee au

moment de la creacuteation drsquoun objet de la classe Le constructeur peut notamment prendre en

charge lrsquoinitialisation drsquoun objet au sens le plus large du terme crsquoest-agrave-dire sa mise dans un

eacutetat initial permettant son bon fonctionnement ulteacuterieur il peut srsquoagir de banales initialisa-

tions de membres donneacutees mais eacutegalement drsquoune preacuteparation plus eacutelaboreacutee correspondant au

deacuteroulement drsquoinstructions voire drsquoune allocation dynamique drsquoemplacements neacutecessaires agrave

4 - C++ et la programmation orienteacutee objet7

lrsquoutilisation de lrsquoobjet Lrsquoexistence drsquoun constructeur garantit que lrsquoobjet sera toujours initia-

liseacute ce qui constitue manifestement une seacutecuriteacute

De maniegravere similaire une classe peut disposer drsquoun destructeur fonction membre exeacutecuteacutee

au moment de la destruction drsquoun objet Celle-ci preacutesentera surtout un inteacuterecirct dans le cas

drsquoobjets effectuant des allocations dynamiques drsquoemplacements ces derniers pourront ecirctre

libeacutereacutes par le destructeur

Une des originaliteacutes de C++ par rapport agrave drsquoautres langages de POO reacuteside dans la possibi-

liteacute de deacutefinir des fonctions amies drsquoune classe Il srsquoagit de fonctions usuelles (qui ne sont

donc pas des fonctions membres drsquoune classe) qui sont autoriseacutees (par une classe) agrave acceacuteder

aux donneacutees (encapsuleacutees) de la classe Certes le principe drsquoencapsulation est violeacute mais

uniquement par des fonctions ducircment autoriseacutees agrave le faire

La classe est un type deacutefini par lrsquoutilisateur La notion de surdeacutefinition drsquoopeacuterateurs va per-

mettre de doter cette classe drsquoopeacuterations analogues agrave celles que lrsquoon rencontre pour les types

preacutedeacutefinis Par exemple on pourra deacutefinir une classe complexe (destineacutee agrave repreacutesenter des

nombres complexes) et la munir des opeacuterations drsquoaddition de soustraction de multiplication

et de division Qui plus est ces opeacuterations pourront utiliser les symboles existants + -

C dispose de possibiliteacutes de conversions explicites ou implicites C++ permet de les eacutelargir

aux types deacutefinis par lrsquoutilisateur que sont les classes Par exemple on pourra donner un sens

agrave la conversion int -gt complexe ou agrave la conversion complexe -gt float (complexe eacutetant une

classe)

Naturellement C++ dispose de lrsquoheacuteritage et mecircme de possibiliteacutes dites drsquoheacuteritage multiple

permettant agrave une classe drsquoheacuteriter simultaneacutement de plusieurs autres Le polymorphisme est

mis en place sur la demande explicite du programmeur par le biais de ce que lrsquoon nomme

(curieusement) des fonctions virtuelles (en Java le polymorphisme est natif et le program-

meur nrsquoa donc pas agrave srsquoen preacuteoccuper)

En matiegravere drsquoentreacutees-sorties C++ comporte de nouvelles possibiliteacutes fondeacutees sur la notion de

flot Leurs avantages sur les entreacutees-sorties de C sont en particulier

bull la simpliciteacute drsquoutilisation

bull une taille meacutemoire reacuteduite (on nrsquointroduit que ce qui est utile)

bull la possibiliteacute de leur donner un sens pour les types deacutefinis par lrsquoutilisateur que sont les clas-

ses (gracircce au meacutecanisme de surdeacutefinition drsquoopeacuterateur)

Bien qursquoelles soient lieacutees agrave lrsquoaspect POO nous ferons une premiegravere preacutesentation de ces

nouvelles possibiliteacutes drsquoentreacutees-sorties degraves le chapitre 3 Cela nous permettra de reacutealiser rapi-

dement des programmes dans lrsquoesprit du C++

Dans ses derniegraveres versions (et a fortiori dans sa norme ANSI) le C++ a eacuteteacute doteacute de la notion

de patron Un patron permet de deacutefinir des modegraveles utilisables pour geacuteneacuterer diffeacuterentes clas-

ses ou diffeacuterentes fonctions qualifieacutees parfois de geacuteneacuteriques mecircme si cette geacuteneacutericiteacute nrsquoest

pas totalement inteacutegreacutee dans le langage lui-mecircme comme crsquoest par exemple le cas avec

ADA

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

8

Enfin la norme ANSI a notablement accru le contenu de la bibliothegraveque standard de C++

qui vient compleacuteter celle du C toujours disponible En particulier on y trouve de nombreux

patrons de classes et de fonctions permettant de mettre en œuvre les structures de donneacutees les

plus importantes (vecteurs dynamiques listes chaicircneacutees chaicircnes) et les algorithmes les plus

usuels eacutevitant ainsi drsquoavoir agrave reacuteinventer la roue agrave la moindre occasion

2

Les incompatibiliteacutesentre C++ et C

A priori le langage C++ peut ecirctre consideacutereacute comme une extension du langage C Tout pro-

gramme eacutecrit en C devrait donc pouvoir ecirctre traduit correctement par un compilateur C++ et

son exeacutecution devrait alors fournir les mecircmes reacutesultats que ceux obtenus en utilisant un com-

pilateur C

Si ce point de vue correspond effectivement au souhait du concepteur du langage C++ en

pratique un certain nombre drsquoincompatibiliteacutes avec le C ANSI ont subsisteacute inheacuterentes agrave

lrsquoesprit dans lequel les deux langages ont eacuteteacute conccedilus

Nous allons deacutecrire ici les incompatibiliteacutes les plus importantes en particulier celles qui se

reacuteveacuteleraient quasiment agrave coup sucircr dans la mise au point de vos premiers programmes C++

Par ailleurs quelques autres incompatibiliteacutes mineures seront abordeacutees au cours des pro-

chains chapitres Elles seront toutes reacutecapituleacutees en Annexe B

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

10

1 Les deacutefinitions de fonctions en C++Suivant la norme ANSI il existe en C deux faccedilons de deacutefinir1 une fonction Supposez que

nous ayons agrave deacutefinir une fonction nommeacutee fexple fournissant une valeur de retour2 de type

double et recevant deux arguments lrsquoun de type int lrsquoautre de type double Nous pouvons

pour cela proceacuteder de lrsquoune des deux faccedilons suivantes

double fexple (u v) double fexple (int u double v)int u double v corps de la fonction corps de la fonction

La premiegravere forme eacutetait la seule preacutevue par la deacutefinition initiale de Kernighan et Ritchie La

seconde a eacuteteacute introduite par la norme ANSI qui nrsquoa toutefois pas exclu lrsquoancienne3

Le langage C++ nrsquoaccepte quant agrave lui que la seconde forme

double fexple (int u double v) corps de la fonction

Remarque

Comme en C ANSI lorsqursquoune fonction fournit une valeur de type int le mot int peut

ecirctre omis dans lrsquoen-tecircte Cependant nous ne vous conseillons guegravere drsquoemployer cette

possibiliteacute qui nuit agrave la lisibiliteacute des programmes

2 Les prototypes en C++Nous venons de voir que le C++ eacutetait plus restrictif que le C ANSI en matiegravere de deacutefinition

de fonctions Il en va de mecircme pour les deacuteclarations de fonctions En C ANSI lorsque vous

utilisiez une fonction qui nrsquoavait pas eacuteteacute deacutefinie auparavant dans le mecircme fichier source

vous pouviez

bull ne pas la deacuteclarer (on consideacuterait alors que sa valeur de retour eacutetait de type int)

bull la deacuteclarer en ne preacutecisant que le type de la valeur de retour par exemple

double fexple

1 Ne confondez pas la deacutefinition drsquoune fonction et sa deacuteclaration La premiegravere correspond agrave la description agrave

lrsquoaide drsquoinstructions C de ce que fait une fonction La seconde correspond agrave une simple information (nom de la

fonction et eacuteventuellement type des arguments et de la valeur de retour) fournie au compilateur

2 On parle eacutegalement de reacutesultat fourni par la fonction de valeur retourneacutee

3 Dans le seul but de rendre compatible avec la norme des anciens programmes ou des anciens compilateurs

2 - Les prototypes en C++11

bull la deacuteclarer agrave lrsquoaide de ce que lrsquoon nomme un prototype par exemple

double fexple (int double)

En C++ un appel de fonction ne sera accepteacute que si le compilateur connaicirct le type des argu-

ments et celui de sa valeur de retour Cela signifie que la fonction en question doit avoir fait

lrsquoobjet drsquoune deacuteclaration sous la forme drsquoun prototype (ou agrave la rigueur avoir eacuteteacute preacuteala-

blement deacutefinie dans le mecircme fichier source1)

Nrsquooubliez pas que chaque fois que le compilateur rencontre un appel de fonction il compare

les types des arguments effectifs avec ceux des arguments muets correspondants2 En cas de

diffeacuterence il met en place les conversions neacutecessaires pour que la fonction reccediloive des argu-

ments du bon type Les conversions possibles ne se limitent pas aux conversions non deacutegra-

dantes (telles que char -gt double int -gt long) En effet elles comportent toutes les

conversions autoriseacutees lors drsquoune affectation On peut donc y rencontrer des conversions

deacutegradantes telles que int -gt char double -gt float double -gt int

Voici un exemple illustrant ce point

double fexple (int double) deacuteclaration 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

Exemple de conversions de types lors de lrsquoappel drsquoune fonction

Lorsque la deacutefinition de la fonction et sa deacuteclaration (sous forme drsquoun prototype) figurent

dans le mecircme fichier source le compilateur est en mesure de veacuterifier la coheacuterence entre lrsquoen-

tecircte de la fonction et le prototype Srsquoil nrsquoy a pas correspondance de types (exacte cette fois)

on obtient une erreur de compilation Voici un exemple correct

1 Toutefois mecircme dans ce cas le prototype reste conseilleacute notamment pour eacuteviter tout problegraveme en cas drsquoeacuteclate-

ment du fichier source

2 Nous supposons que le compilateur connaicirct le type des arguments de la fonction ce qui est toujours le cas en C++

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

12

double fexple (int double) deacuteclaration de fexple main()

deacutefinition de fexple double fexple (int u double v) corps de la fonction

En revanche celui-ci conduit agrave une erreur de compilation

double fexple (int float) deacuteclaration de fexple main() deacutefinition de fexple double fexple (int u double v) erreur de compilation corps de la fonction

Bien entendu si la deacutefinition de la fonction et sa deacuteclaration (donc son utilisation1) ne figu-

rent pas dans le mecircme fichier source aucun controcircle ne peut plus ecirctre effectueacute par le compi-

lateur En geacuteneacuteral agrave partir du moment ougrave lrsquoon doit utiliser une fonction en dehors du fichier

ougrave elle est deacutefinie (ou agrave partir de plusieurs fichiers source diffeacuterents) on place son prototype

dans un fichier en-tecircte ce dernier est incorporeacute en cas de besoin par la directive include

ce qui eacutevite tout risque de faute drsquoeacutecriture du prototype

Remarques

1 Comme en C la porteacutee du prototype est limiteacutee agrave

ndash la partie du fichier source situeacutee agrave la suite de sa deacuteclaration si elle figure agrave un niveau

global crsquoest-agrave-dire en dehors de toute deacutefinition de fonction2 crsquoeacutetait le cas du proto-

type de fexple dans nos preacuteceacutedents exemples

ndash la fonction dans laquelle il figure dans le cas contraire

2 Le prototype peut prendre une forme plus eacutetoffeacutee3 dans laquelle figurent eacutegalement des

noms drsquoarguments Ainsi le prototype de notre fonction fexple du deacutebut du

paragraphe 2 pourrait eacutegalement srsquoeacutecrire

double fexple (int a double x)

1 A moins qursquoon ne lrsquoait deacuteclareacutee sans lrsquoutiliser ce qui arrive freacutequemment lorsque lrsquoon fait appel agrave des fichiers en-

tecircte

2 Y compris la fonction main

3 On parle alors parfois de prototype complet par opposition agrave prototype reacuteduit

3 - Arguments et valeur de retour drsquoune fonction13

ou encore

double fexple (int u double v)

Dans ce cas les noms drsquoarguments (a et x dans le premier exemple u et v dans le

second) ne jouent aucun rocircle Ils sont purement et simplement ignoreacutes par le compila-

teur de sorte que ces prototypes restent parfaitement eacutequivalents aux preacuteceacutedents On

peut trouver un inteacuterecirct agrave cette possibiliteacute lorsque lrsquoon souhaite accompagner ce proto-

type de commentaires deacutecrivant le rocircle des diffeacuterents arguments (cela peut srsquoaveacuterer pra-

tique dans le cas ougrave lrsquoon place ce prototype dans un fichier en-tecircte)

3 Arguments et valeur de retour drsquoune fonction

31 Points communs agrave C et C++En C++ comme en C ANSI les arguments drsquoune fonction ainsi que la valeur de retour

peuvent

bull ne pas exister

bull ecirctre une valeur scalaire drsquoun des types de base (caractegraveres entiers flottants pointeurs)

bull ecirctre une valeur de type structure

La derniegravere possibiliteacute a eacuteteacute introduite dans le langage C par la norme ANSI Nous verrons

qursquoen C++ elle se geacuteneacuteralise aux objets de type classe Pour lrsquoinstant notez simplement qursquoil

subsiste en C++ comme en C ANSI une dispariteacute entre les tableaux et les structures puisque

bull il est possible de transmettre la valeur drsquoune structure aussi bien en argument qursquoen valeur

de retour

bull il nrsquoest pas possible de faire de mecircme avec les tableaux

Notez qursquoil srsquoagit lagrave drsquoune dispariteacute difficile agrave reacutesorber compte tenu de la volonteacute des con-

cepteurs du langage C de rendre eacutequivalents le nom drsquoun tableau et son adresse

Bien entendu il est toujours possible de transmettre lrsquoadresse drsquoun tableau et cette remarque

vaut eacutegalement pour une structure

32 Diffeacuterences entre C et C++En fait ces diffeacuterences ne portent que sur la syntaxe des en-tecirctes et des prototypes des fonc-

tions et uniquement dans deux cas preacutecis

bull fonctions sans arguments

bull fonctions sans valeur de retour

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

14

321 Fonctions sans argumentsAlors qursquoen C ANSI on peut employer le mot void pour deacutefinir (en-tecircte) ou deacuteclarer (proto-

type) une fonction sans argument en C++ on fournit une liste vide Ainsi lagrave ougrave en C on

deacuteclarait

float fct (void)

on deacuteclarera en C++

float fct ( )

322 Fonctions sans valeur de retourEn C ANSI on peut utiliser le mot void pour deacutefinir (en-tecircte) ou deacuteclarer (prototype) une

fonction sans valeur de retour En C++ on doit absolument le faire comme dans cet

exemple

void fct (int double)

La deacuteclaration

fct (int double)

conduirait C++ agrave consideacuterer que fct fournit une valeur de retour de type int (voir la remarque

du paragraphe 1)

4 Le qualificatif constLa norme C ANSI a introduit le qualificatif const Il permet de speacutecifier qursquoun symbole cor-

respond agrave quelque chose dont la valeur ne doit pas changer ce qui peut permettre au com-

pilateur de signaler les tentatives de modification (lorsque cela lui est possible )

Si cela reste vrai en C++ un certain nombre de diffeacuterences importantes apparaissent qui con-

cernent la porteacutee du symbole concerneacute et son utilisation dans une expression

41 PorteacuteeLorsque const srsquoapplique agrave des variables locales automatiques aucune diffeacuterence nrsquoexiste

entre C et C++ la porteacutee eacutetant limiteacutee au bloc ou agrave la fonction concerneacutee par la deacuteclaration

En revanche lorsque const srsquoapplique agrave une variable globale C++ limite la porteacutee du sym-

bole au fichier source contenant la deacuteclaration (comme srsquoil avait reccedilu lrsquoattribut static) C

nrsquoimposait aucune limitation

Pourquoi cette diffeacuterence La principale raison reacuteside dans lrsquoideacutee qursquoavec la regravegle adopteacutee

par C++ il devient plus facile de remplacer certaines instructions define par des deacuteclarations

de constantes Ainsi lagrave ougrave en C vous proceacutediez de cette faccedilon

define N 8 define N 3

fichier 1 fichier 2

4 - Le qualificatif const15

vous pouvez en C++ proceacuteder ainsi

const int N = 8 const int N = 3

fichier 1 fichier 2

En C vous auriez obtenu une erreur au moment de lrsquoeacutedition de liens Vous auriez pu lrsquoeacuteviter

bull soit en deacuteclarant N static dans au moins un des deux fichiers (ou mieux dans les deux)

static const int N = 8 static const int N = 3

Cela aurait alors eacuteteacute parfaitement eacutequivalent agrave ce que fait C++ avec les premiegraveres

deacuteclarations

bull soit si N avait eu la mecircme valeur dans les deux fichiers en placcedilant dans le second fichier

extern const int N

Mais dans ce cas il ne se serait plus agi drsquoun remplacement de define

42 Utilisation dans une expressionRappelons que lrsquoon nomme expression constante une expression dont la valeur est calculeacutee

lors de la compilation Ainsi avec

const int p = 3

lrsquoexpression

2 p 5

nrsquoest pas une expression constante en C alors qursquoelle en est une en C++

Ce point est particuliegraverement sensible dans les deacuteclarations de tableaux (statiques ou automa-

tiques) dont les dimensions doivent obligatoirement ecirctre des expressions constantes (mecircme

pour les tableaux automatiques le compilateur doit connaicirctre la taille agrave reacuteserver sur la pile )

Ainsi les instructions

const int nel = 15 double t1 [nel + 1] t2[2 nel] [nel]

seront accepteacutees en C++ alors qursquoelles eacutetaient refuseacutees en C

Remarques

1 En toute rigueur la possibiliteacute que nous venons de deacutecrire ne constitue pas une incompa-

tibiliteacute entre C et C++ puisqursquoil srsquoagit drsquoune faciliteacute suppleacutementaire

2 Drsquoune maniegravere geacuteneacuterale C++ a eacuteteacute conccedilu pour limiter au maximum lrsquoemploi des direc-

tives du preacuteprocesseur (on devrait pouvoir se contenter de include et des directives

drsquoinclusion conditionnelle) Les modifications apporteacutees au qualificatif const vont

effectivement dans ce sens1

1 Encore faut-il que le programmeur C++ accepte de changer les habitudes qursquoil avait ducirc prendre en C (faute de

pouvoir faire autrement)

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

16

5 Compatibiliteacute entre le type void et les autres pointeurs

En C ANSI le type geacuteneacuterique void est compatible avec les autres types pointeurs et ce

dans les deux sens Ainsi avec ces deacuteclarations

void gen int adi

ces deux affectations sont leacutegales en C ANSI

gen = adi adi = gen

Elles font intervenir des conversions implicites agrave savoir

int -gt void pour la premiegravere

void -gt int pour la seconde

En C++ seule la conversion drsquoun pointeur quelconque en void peut ecirctre implicite Ainsi

avec les deacuteclarations preacuteceacutedentes seule lrsquoaffectation

gen = adi

est accepteacutee Bien entendu il reste toujours possible de faire appel explicitement agrave la conver-

sion void -gt int en utilisant lrsquoopeacuterateur de cast

adi = (int ) gen

Remarque

On peut dire que la conversion drsquoun pointeur de type quelconque en void revient agrave ne

srsquointeacuteresser qursquoagrave lrsquoadresse correspondant au pointeur en ignorant son type En revanche

la conversion inverse de void en un pointeur de type donneacute revient agrave associer (peut-ecirctre

arbitrairement ) un type agrave une adresse Manifestement cette seconde possibiliteacute est plus

dangereuse que la premiegravere elle peut mecircme obliger le compilateur agrave introduire des modi-

fications de lrsquoadresse de deacutepart dans le seul but de respecter certaines contraintes drsquoali-

gnement (lieacutees au type drsquoarriveacutee) Crsquoest la raison pour laquelle cette conversion ne fait

plus partie des conversions implicites en C++

3

Les entreacutees-sortiesconversationnelles du C++

C++ dispose de toutes les routines offertes par la bibliothegraveque standard du C ANSI Mais il

comporte eacutegalement de nouvelles possibiliteacutes dentreacutees-sorties Celles-ci reposent sur les

notions de flots et de surdeacutefinition dopeacuterateur que nous naborderons quulteacuterieurement

Il ne serait pas judicieux cependant dattendre que vous ayez eacutetudieacute ces diffeacuterents points pour

commencer agrave eacutecrire des programmes complets reacutedigeacutes dans lesprit de C++ Cest pourquoi

nous allons vous preacutesenter ces nouvelles possibiliteacutes dentreacutees-sorties dans ce chapitre de

maniegravere assez informelle en nous limitant agrave ce que nous nommons laspect conversationnel

agrave savoir

bull la lecture sur lentreacutee standard geacuteneacuteralement le clavier

bull lrsquoeacutecriture sur la sortie standard geacuteneacuteralement lrsquoeacutecran

1 GeacuteneacuteraliteacutesLes routines (fonctions et macros) de la bibliothegraveque standard du C ANSI1 sont utilisables

en C++ en particulier celles relatives aux entreacutees-sorties pour ce faire il vous suffit

1 Lun des grands meacuterites de cette norme est de deacutefinir outre le langage C lui-mecircme les caracteacuteristiques dun certain

nombre de routines formant ce que lon nomme la bibliothegraveque standard

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

18

dinclure les fichiers en-tecircte habituels1 pour obtenir les prototypes et autres deacuteclarations

neacutecessaires agrave leur bonne utilisation

Mais C++ dispose en outre de possibiliteacutes dentreacutees-sorties ayant les caracteacuteristiques

suivantes

bull simpliciteacute dutilisation en particulier on pourra souvent saffranchir de la notion de for-

mat si chegravere aux fonctions de la famille printf ou scanf

bull diminution de la taille du module objet correspondant alors que par exemple un seul appel

de printf introduit obligatoirement dans le module objet un ensemble dinstructions en cou-

vrant toutes les eacuteventualiteacutes lemploi des nouvelles possibiliteacutes offertes par C++ nrsquointrodui-

ra que les seules instructions neacutecessaires

bull possibiliteacutes extensibles aux types que vous deacutefinirez vous-mecircme sous forme de classes

Nous allons examiner ces possibiliteacutes en nous limitant agrave lrsquoaspect conversationnel crsquoest-agrave-dire

agrave la lecture sur lrsquoentreacutee standard et agrave lrsquoaffichage sur la sortie standard

2 Affichage agrave lrsquoeacutecran

21 Quelques exemplesAvant deacutetudier les diffeacuterentes possibiliteacutes offertes par C++ examinons quelques exemples

Exemple 1Lagrave ougrave en C on eacutecrivait

printf (bonjour)

en C++ on utilisera

cout ltlt bonjour

Linterpreacutetation deacutetailleacutee de cette instruction neacutecessiterait des connaissances qui ne seront

introduites quulteacuterieurement Pour linstant il vous suffit de retenir les points suivants

bull cout deacutesigne un flot de sortie preacutedeacutefini associeacute agrave lentreacutee standard du C (stdout)

bull ltlt est un opeacuterateur dont lopeacuterande de gauche (ici cout) est un flot et lopeacuterande de droi-

te une expression de type quelconque Linstruction preacuteceacutedente peut ecirctre interpreacuteteacutee com-

me ceci le flot cout reccediloit la valeur bonjour

1 Toutefois la norme de C++ a preacutevu que les noms de ces fichiers soient preacutefixeacutes par c et que le suffixe h disparaisse

Par exemple on trouvera ltcstdiogt au lieu de ltstdiohgt

2 - Affichage agrave lrsquoeacutecran19

Exemple 2

Consideacuterons ces instructions

int n = 25

cout ltlt valeur

cout ltlt n

Elles affichent le reacutesultat suivant

valeur 25

Vous constatez que nous avons utiliseacute le mecircme opeacuterateur ltlt pour envoyer sur le flot cout

dabord une information de type chaicircne ensuite une information de type entier Le rocircle de

lopeacuterateur ltlt est manifestement diffeacuterent dans les deux cas dans le premier on a transmis

les caractegraveres de la chaicircne dans le second on a proceacutedeacute agrave un formatage1 pour convertir une

valeur binaire entiegravere en une suite de caractegraveres Cette possibiliteacute dattribuer plusieurs signifi-

cations agrave un mecircme opeacuterateur correspond agrave ce que lon nomme en C++ la surdeacutefinition dopeacute-

rateur (que nous aborderons en deacutetail au chapitre 9)

Exemple 3

Dans les exemples preacuteceacutedents nous avions utiliseacute une instruction diffeacuterente pour chaque

information transmise au flot cout En fait les deux instructions

cout ltlt valeur

cout ltlt n

peuvent se condenser en une seule

cout ltlt valeur ltlt n

Lagrave encore linterpreacutetation exacte de cette possibiliteacute sera fournie ulteacuterieurement mais dores

et deacutejagrave nous pouvons dire quelle reacuteside dans deux points

bull lopeacuterateur ltlt est associatif de gauche agrave droite comme lrsquoopeacuterateur drsquoorigine

bull le reacutesultat fourni par lopeacuterateur ltlt quand il reccediloit un flot en premier opeacuterande est ce mecircme

flot apregraves quil a reccedilu linformation concerneacutee

Ainsi linstruction preacuteceacutedente est eacutequivalente agrave

(cout ltlt valeur ) ltlt n

Celle-ci peut sinterpreacuteter comme ceci

bull dans un premier temps le flot cout reccediloit la chaicircne valeur

bull dans un deuxiegraveme temps le flot cout ltlt valeur cest-agrave-dire le flot cout augmenteacute de

bonjour reccediloit la valeur de n

Si cette interpreacutetation ne vous paraicirct pas eacutevidente il vous suffit dadmettre pour linstant

quune instruction telle que

cout ltlt ----- ltlt ----- ltlt ----- ltlt -----

1 Ici ce formatage est implicite dans le cas de printf on laurait expliciteacute (d)

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

20

permet denvoyer sur le flot cout les informations symboliseacutees par des traits dans lordre ougrave

elles apparaissent

22 Le fichier en-tecircte iostreamEn C lrsquoutilisation de fonctions telles que printf ou scanf neacutecessitait lrsquoincorporation du fichier

en-tecircte ltstdiohgt qui contenait les deacuteclaration approprieacutees De faccedilon comparable les deacutecla-

rations neacutecessaires agrave lrsquoutilisation des entreacutees-sorties speacutecifiques agrave C++ figurent dans un

fichier en-tecircte de nom ltiostreamgt Cependant lrsquoutilisation des symboles deacuteclareacutes dans ce

fichier iostream fait appel agrave la notion drsquoespace de noms introduite elle-aussi par la norme

Cette notion sera preacutesenteacutee sommairement au chapitre 4 et eacutetudieacutee plus en deacutetail au chapitre

24 Pour lrsquoinstant sachez qursquoelle oblige agrave introduire dans votre programme une instruction de

deacuteclaration using dont la porteacutee se deacutefinit comme celle de toute deacuteclaration et qui se preacute-

sente ainsi

using namespace std on utilisera les symboles deacutefinis dans lrsquoespace de noms standard srsquoappelant std

Remarque

Avant la norme on utilisait un fichier nommeacute ltiostreamhgt et lrsquoinstruction using nrsquoexis-

tait pas Certains environnements fonctionnent encore ainsi Parfois il faut recourir agrave

ltiostreamgt sans utiliser using1 (qui pourrait provoquer une erreur de compilation)

23 Les possibiliteacutes drsquoeacutecriture sur coutNous venons de voir des exemples deacutecriture de chaicircnes et dentiers Dune maniegravere geacuteneacuterale

vous pouvez utiliser lopeacuterateur ltlt pour envoyer sur cout la valeur dune expression de lun

des types suivants

bull type de base quelconque (caractegravere entier signeacute ou non flottant)

bull chaicircne de caractegraveres (char ) on obtient laffichage des caractegraveres constituant la chaicircne

bull pointeur autre que char on obtient ladresse correspondante (en hexadeacutecimal) si on

veut obtenir ladresse dune chaicircne de caractegraveres et non les caractegraveres quelle contient on

peut toujours convertir cette chaicircne (de type char ) en void

Voici un exemple complet de programme illustrant ces possibiliteacutes accompagneacute drsquoun exem-

ple drsquoexeacutecution dans un environnement PC2

1 Ces impleacutementations acceptent geacuteneacuteralement using pour les fichiers en-tecircte relatifs aux composants standard

2 Lrsquoimpleacutementation nrsquointervient ici que dans lrsquoaffichage de pointeurs

3 - Lecture au clavier21

include ltiostreamgtusing namespace std main() int n = 25 long p = 250000 unsigned q = 63000 char c = a float x = 123456789 double y = 123456789e16 char ch = bonjour int ad = amp n

cout ltlt valeur de n ltlt n ltlt n cout ltlt valeur de p ltlt p ltlt n cout ltlt caractere c ltlt c ltlt n cout ltlt valeur de q ltlt q ltlt n cout ltlt valeur de x ltlt x ltlt n cout ltlt valeur de y ltlt y ltlt n cout ltlt chaine ch ltlt ch ltlt n cout ltlt adresse de n ltlt ad ltlt n cout ltlt adresse de ch ltlt (void ) ch ltlt n

valeur de n 25valeur de p 250000caractere c avaleur de q 63000valeur de x 123457valeur de y 123457e+017chaine ch bonjouradresse de n 006AFDF4adresse de ch 0046D0D4

Les possibiliteacutes drsquoeacutecriture sur cout

3 Lecture au clavier

31 IntroductionDe mecircme quil existe un flot de sortie preacutedeacutefini cout associeacute agrave la sortie standard du C (stdout)

il existe un flot dentreacutee preacutedeacutefini nommeacute cin associeacute agrave lentreacutee standard du C (stdin) De

mecircme que lopeacuterateur ltlt permet denvoyer des informations sur un flot de sortie (donc en

particulier sur cout) lopeacuterateur gtgt permet de recevoir1 de linformation en provenance dun

flot dentreacutee (donc en particulier de cin)

1 On dit aussi extraire

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

22

Par exemple linstruction (n eacutetant de type int)

cin gtgt n

demandera de lire des caractegraveres sur le flot cin et de les convertir en une valeur de type int

Dune maniegravere geacuteneacuterale

cin gtgt n gtgt p

sera eacutequivalent agrave

(cin gtgt n) gtgt p

Pour donner une interpreacutetation imageacutee (et peu formelle) analogue agrave celle fournie pour cout

nous pouvons dire que la valeur de n est dabord extraite du flot cin ensuite la valeur de p

est extraite du flot cin gtgt n (comme pour ltlt le reacutesultat de lopeacuterateur gtgt est un flot) cest-

agrave-dire de ce quest devenu le flot cin apregraves quon en a extrait la valeur de n

32 Les diffeacuterentes possibiliteacutes de lecture sur cinDune maniegravere geacuteneacuterale vous pouvez utiliser lopeacuterateur gtgt pour acceacuteder agrave des informations

de type de base quelconque (signeacute ou non pour les types entiers) ou agrave des chaicircnes de caractegrave-

res1 (char ) Comme avec scanf ou getchar les caractegraveres frappeacutes au clavier sont apregraves vali-

dation par une fin de ligne enregistreacutes dans un tampon La lecture se fait dans ce tampon qui

est reacutealimenteacute en cas de besoin drsquoinformations suppleacutementaires Les informations du tampon

non exploiteacutees lors drsquoune lecture restent disponibles pour la lecture suivante

Par ailleurs une bonne part des conventions danalyse des caractegraveres lus sont les mecircmes que

celles employeacutees par scanf Ainsi

bull les diffeacuterentes informations sont seacutepareacutees par un ou plusieurs caractegraveres parmi ceux-ci2 es-

pace tabulation horizontale (t) ou verticale (v) fin de ligne (n) ou encore changement de

page (f)3

bull un caractegravere invalide pour lusage quon doit en faire (un point pour un entier une lettre

pour un nombre) arrecircte lexploration du flot comme si lon avait rencontreacute un seacuteparateur

mais ce caractegravere invalide sera agrave nouveau pris en compte lors dune prochaine lecture

En revanche contrairement agrave ce qui se produisait pour scanf la lecture dun caractegravere sur cin

commence par sauter les seacuteparateurs aussi nest-il pas possible de lire directement ces

caractegraveres seacuteparateurs Nous verrons comment y parvenir dans le chapitre consacreacute aux flots

1 Il nest pas preacutevu de lire la valeur dun pointeur en pratique cela naurait guegravere dinteacuterecirct et de plus preacutesenterait de

grand risques

2 On les appelle parfois des espaces-blancs (de langlais white spaces)

3 Dans les environnements PC la fin de ligne est repreacutesenteacutee par deux caractegraveres conseacutecutifs elle nrsquoen reste pas

moins vue par le programme comme un seul et unique caractegravere (n) cette remarque vaut en fait pour tous les fichiers

de type texte comme on le verra dans le chapitre consacreacute aux flots

3 - Lecture au clavier23

33 Exemple classique drsquoutilisation des seacuteparateursLe programme suivant illustre une situation classique dans laquelle la gestion des caractegraveres

seacuteparateurs ne pose pas de problegraveme particulier

include ltiostreamgtusing namespace std main() int n float x char t[81] do cout ltlt donnez un entier une chaine et un flottant cin gtgt n gtgt t gtgt x cout ltlt merci pour ltlt n ltlt ltlt t ltlt et ltlt x ltlt n while (n)

donnez un entier une chaine et un flottant 15 bonjour 825merci pour 15 bonjour et 825donnez un entier une chaine et un flottant 15

bonjour

825merci pour 15 bonjour et 825donnez un entier une chaine et un flottant 0 bye 0merci pour 0 bye et 0

Usage classique des seacuteparateurs

34 Lecture drsquoune suite de caractegraveresLrsquoexemple suivant montre que la faccedilon dont C++ gegravere les seacuteparateurs peut srsquoaveacuterer deacuterou-

tante lorsque lrsquoon est ameneacute agrave lire une suite de caractegraveres

include ltiostreamgtusing namespace std main() char tc[129] pour conserver les caractegraveres lus sur cin int i = 0 position courante dans le tableau tc

cout ltlt donnez une suite de caracteres terminee par un point n do cin gtgt tc[i] attention pas de test de deacutebordement dans tc while (tc[i++] = ) cout ltlt nnVoici les caracteres effectivement lus n i=0

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

24

do cout ltlt tc[i] while (tc[i++] = )

donnez une suite de caracteres terminee par un point Voyez comme

C++pose quelques problegravemeslors de la lecture dune

suite de caractegraveres

Voici les caracteres effectivement lus VoyezcommeC++posequelquesproblegravemeslorsdelalecturedunesuitedecaractegraveres

Quand on cherche agrave lire une suite de caractegraveres

35 Les risques induits par la lecture au clavierNous vous proposons deux exemples montrant que en C++ comme en C on peut dans cer-

tains cas aboutir agrave

bull un manque de synchronisme apparent entre le clavier et lrsquoeacutecran

bull un blocage de la lecture par un caractegravere invalide

bull une boucle infinie due agrave la preacutesence drsquoun caractegravere invalide

351 Manque de synchronisme entre clavier et eacutecran

Cet exemple illustre lrsquoexistence drsquoun tampon On y voit comment une lecture peut utiliser

une information non exploiteacutee par la preacuteceacutedente Ici lrsquoutilisateur nrsquoa pas agrave reacutepondre agrave la ques-

tion poseacutee agrave la troisiegraveme ligne

include ltiostreamgtusing namespace std main() int n p cout ltlt donnez une valeur pour n cin gtgt n cout ltlt merci pour ltlt n ltlt n cout ltlt donnez une valeur pour p cin gtgt p cout ltlt merci pour ltlt p ltlt n

3 - Lecture au clavier25

donnez une valeur pour n 12 25merci pour 12donnez une valeur pour p merci pour 25

Quand le clavier et lrsquoeacutecran semblent mal synchroniseacutes

352 Blocage de la lecture

Voyez cet exemple qui montre comment une maladresse de lrsquoutilisateur (ici frappe drsquoune let-

tre au lieu drsquoun chiffre) peut entraicircner un comportement deacuteconcertant du programme

include ltiostreamgtusing namespace std main() int n = 12 char c = rsquoarsquo cout ltlt donnez un entier et un caractere n cin gtgt n gtgt c cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n cout ltlt donnez un caractere cin gtgt c cout ltlt merci pour ltlt c

donnez un entier et un caractere x 25merci pour 4467164 et adonnez un caractere merci pour a

Clavier bloqueacute par un caractegravere invalide

Lors de la premiegravere lecture de n lrsquoopeacuterateur gtgt a rencontreacute le caractegravere x manifestement

invalide Comme il nrsquoeacutetait alors pas capable de fabriquer une valeur entiegravere il a laisseacute la

valeur de n inchangeacutee et il a bloqueacute la lecture Ainsi la tentative de lecture ulteacuterieure drsquoun

caractegravere dans c nrsquoa pas deacutebloqueacute la situation la lecture eacutetant bloqueacutee la valeur de c est res-

teacutee inchangeacutee (le flot est resteacute bloqueacute et drsquoautres tentatives de lecture seraient traiteacutees de la

sorte)

353 Boucle infinie sur un caractegravere invalide

Ce petit exemple montre comment une maladresse lors de lrsquoexeacutecution (ici frappe drsquoune lettre

pour un chiffre) peut entraicircner le bouclage drsquoun programme

include ltiostreamgtusing namespace std

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

26

main() int n do cout ltlt donnez un nombre entier cin gtgt n cout ltlt voici son carre ltlt nn ltlt n while (n)

donnez un nombre entier 3voici son carre 9donnez un nombre entier agravevoici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9

Boucle infinie sur un caractegravere invalide

Ici il faudra interrompre lrsquoexeacutecution du programme suivant une deacutemarche approprieacutee deacutepen-

dant de lrsquoenvironnement

Remarque

Il est possible drsquoameacuteliorer le comportement des programmes preacuteceacutedents Pour ce faire il

est neacutecessaire de faire appel agrave des eacuteleacutements qui seront preacutesenteacutes plus tard dans cet

ouvrage Nous verrons comment tester lrsquoeacutetat drsquoun flot et le deacutebloquer au paragraphe 3 du

chapitre 16 et mecircme geacuterer convenablement les lectures en utilisant un formatage en

meacutemoire au paragraphe 72 du chapitre 22

4

Les speacutecificiteacutes du C++

Le langage C++ dispose dun certain nombre de speacutecificiteacutes qui ne sont pas veacuteritablement

axeacutees sur la POO Il sagit essentiellement des suivantes

bull nouvelle forme de commentaire (en fin de ligne)

bull emplacement libre des deacuteclarations

bull notion de reacutefeacuterence

bull arguments par deacutefaut dans les deacuteclarations des fonctions

bull surdeacutefinition de fonctions

bull opeacuterateurs new et delete

bull fonctions en ligne (inline)

bull nouveaux opeacuterateurs de cast

bull existence drsquoun type booleacuteen bool

bull notion drsquoespace de noms

Dune maniegravere geacuteneacuterale ces possibiliteacutes seront pour la plupart souvent utiliseacutees conjointe-

ment avec celles de POO Cest ce qui justifie que nous les exposions degraves maintenant

Les speacutecificiteacutes du C++CHAPITRE 4

28

1 Le commentaire de fin de ligneEn C ANSI un commentaire peut ecirctre introduit en nimporte quel endroit ougrave un espace est

autoriseacute1 en le faisant preacuteceacuteder de et suivre de Il peut alors eacuteventuellement seacutetendre sur

plusieurs lignes

En C++ vous pouvez en outre utiliser des commentaires de fin de ligne en introduisant les

deux caractegraveres Dans ce cas tout ce qui est situeacute entre et la fin de la ligne est un com-

mentaire Notez que cette nouvelle possibiliteacute napporte quun surcroicirct de confort et de

seacutecuriteacute en effet une ligne telle que

cout ltlt bonjourn formule de politesse

peut toujours ecirctre eacutecrite ainsi

cout ltlt bonjourn formule de politesse

Vous pouvez mecircler (volontairement ou non ) les deux formules Dans ce cas notez que

dans

partie1 partie2 partie3

le commentaire ouvert par ne se termine quau prochain donc partie1 et partie2 sont

des commentaires tandis que partie3 est consideacutereacute comme appartenant aux instructions De

mecircme dans

partie1 partie2 partie3 partie4

le commentaire introduit par srsquoeacutetend jusqursquoagrave la fin de la ligne Il concerne donc partie2

partie3 et partie 4

Remarques

1 Le commentaire de fin de ligne constitue le seul cas ougrave la fin de ligne joue un rocircle signifi-

catif autre que celui dun simple seacuteparateur

2 Si lon utilise systeacutematiquement le commentaire de fin de ligne on peut alors faire

appel agrave et pour inhiber un ensemble dinstructions (contenant eacuteventuellement des

commentaires) en phase de mise au point

2 Deacuteclarations et initialisations

21 Regravegles geacuteneacuteralesC++ savegravere plus souple que le C ANSI en matiegravere de deacuteclarations Plus preacuteciseacutement en C++

il nest plus obligatoire de regrouper au deacutebut les deacuteclarations effectueacutees au sein dune fonc-

tion ou au sein dun bloc Celles-ci peuvent ecirctre effectueacutees ougrave bon vous semble pour peu

1 Donc en pratique nimporte ougrave pourvu quon ne coupe pas en deux un identificateur ou une chaicircne constante

2 - Deacuteclarations et initialisations29

quelles apparaissent avant que lon en ait besoin leur porteacutee reste limiteacutee agrave la partie du bloc

ou de la fonction suivant leur deacuteclaration

Par ailleurs les expressions utiliseacutees pour initialiser une variable scalaire peuvent ecirctre quel-

conques alors quen C elles ne peuvent faire intervenir que des variables dont la valeur est

connue degraves lentreacutee dans la fonction concerneacutee

Voici un exemple incorrect en C ANSI et accepteacute en C++

main() int n n = int q = 2n - 1

La deacuteclaration tardive de q permet de linitialiser1 avec une expression dont la valeur neacutetait

pas connue lors de lentreacutee dans la fonction (ici main)

22 Cas des instructions structureacuteesLinstruction suivante est accepteacutee en C++

for (int i=0 )

Lagrave encore la variable i a eacuteteacute deacuteclareacutee seulement au moment ougrave lon en avait besoin Sa porteacutee

est dapregraves la norme limiteacutee au bloc reacutegi par linstruction for On notera quil nexiste aucune

faccedilon deacutecrire des instructions eacutequivalentes en C

Cette possibiliteacute sapplique agrave toutes les instructions structureacutees crsquoest-agrave-dire aux instructions

for switch while et dowhile

Remarque

Le rocircle de ces deacuteclarations agrave linteacuterieur dinstructions structureacutees na eacuteteacute fixeacute que tardive-

ment par la norme ANSI Dans les versions anteacuterieures ce genre de deacuteclaration eacutetait cer-

tes autoriseacute mais tout se passait comme si elle figurait agrave lexteacuterieur du bloc ainsi

lexemple preacuteceacutedent eacutetait interpreacuteteacute comme si lon avait eacutecrit

int i

for (i=0 )

1 Noubliez pas quen C (comme en C++) il est possible dinitialiser une variable automatique scalaire agrave laide dune

expression quelconque

Les speacutecificiteacutes du C++CHAPITRE 4

30

3 La notion de reacutefeacuterenceEn C les arguments et la valeur de retour dune fonction sont transmis par valeur Pour simu-

ler en quelque sorte ce qui se nomme transmission par adresse dans dautres langages il est

alors neacutecessaire de jongler avec les pointeurs (la transmission se fait toujours par valeur

mais dans ce cas il sagit de la valeur dun pointeur) En C++ le principal inteacuterecirct de la notion

de reacutefeacuterence est quelle permet de laisser le compilateur mettre en œuvre les bonnes instruc-

tions pour assurer un transfert par adresse Pour mieux vous en faire saisir linteacuterecirct nous

vous proposons de vous rappeler comment il fallait proceacuteder en C

31 Transmission des arguments en C

Exemple 1Consideacuterons lrsquoexemple suivant qui illustre le fait qursquoen C les arguments sont toujours trans-

mis par valeur

include ltiostreamgtusing namespace std main()

void echange (int int) int n=10 p=20 cout ltlt avant appel ltlt n ltlt ltlt p ltlt n echange (n p) cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int a int b)

int c cout ltlt debut echange ltlt a ltlt ltlt b ltlt n c = a a = b b = c cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20debut echange 10 20fin echange 20 10apres appel 10 20

Les arguments sont transmis par valeur

Lors de lappel drsquoechange il y a transmission des valeurs de n et de p on peut consideacuterer que

la fonction les a recopieacutees dans des emplacements locaux correspondant agrave ses arguments for-

mels a et b et quelle a effectivement travailleacute sur ces copies

3 - La notion de reacutefeacuterence31

Exemple 2

Bien entendu il est toujours possible de programmer une fonction echange pour quelle opegravere

sur des variables de la fonction qui lappelle il suffit tout simplement de lui fournir en argu-

ment ladresse de ces variables comme dans lexemple suivant

include ltiostreamgt

using namespace std

main()

void echange (int int )

int n=10 p=20

cout ltlt avant appel ltlt n ltlt ltlt p ltlt n

echange (ampn ampp)

cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int a int b)

int c

cout ltlt debut echange ltlt a ltlt ltlt b ltlt n

c = a a = b b = c

cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20

debut echange 10 20

fin echange 20 10

apres appel 20 10

Mise en œuvre par le programmeur dune transmission par adresse

Notez bien les diffeacuterences entre les deux exemples agrave la fois dans leacutecriture de la fonction

echange mais aussi dans son appel Ce dernier point signifie que lutilisateur de la fonction

(qui nest pas toujours celui qui la eacutecrite) doit savoir sil faut lui transmettre une variable ou

son adresse1

32 Exemple de transmission drsquoargument par reacutefeacuterenceC++ permet de demander au compilateur de prendre lui-mecircme en charge la transmission des

arguments par adresse on parle alors de transmission dargument par reacutefeacuterence Le pro-

gramme ci-dessous montre comment appliquer un tel meacutecanisme agrave notre fonction echange

1 Certes ici si lon veut que la fonction echange puisse faire correctement son travail le choix simpose Mais il

nen va pas toujours ainsi

Les speacutecificiteacutes du C++CHAPITRE 4

32

include ltiostreamgt

using namespace std

main()

void echange (int amp int amp)

int n=10 p=20

cout ltlt avant appel ltlt n ltlt ltlt p ltlt n

echange (n p) attention ici pas de ampn ampp

cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int amp a int amp b)

int c

cout ltlt debut echange ltlt a ltlt ltlt b ltlt n

c = a a = b b = c

cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20

deacutebut echange 10 20

fin echange 20 10

apregraves appel 20 10

Utilisation de la transmission darguments par reacutefeacuterence en C++

Dans linstruction

void echange (int amp a int amp b)

la notation int amp a signifie que a est une information de type int transmise par reacutefeacuterence

Notez bien que dans la fonction echange on utilise simplement le symbole a pour deacutesigner

cette variable dont la fonction aura reccedilu effectivement ladresse (et non la valeur) il nest

plus utile (et ce serait une erreur ) de faire appel agrave lopeacuterateur dindirection

Autrement dit il suffit davoir fait ce choix de transmission par reacutefeacuterence au niveau de

len-tecircte de la fonction pour que le processus soit entiegraverement pris en charge par le com-

pilateur1

Le mecircme pheacutenomegravene sapplique au niveau de lutilisation de la fonction Il suffit en effet

davoir speacutecifieacute dans le prototype les arguments (ici les deux) que lon souhaite voir trans-

mis par reacutefeacuterence Au niveau de lappel

echange (n p)

nous navons plus agrave nous preacuteoccuper du mode de transmission utiliseacute

1 Cette possibiliteacute est analogue agrave lutilisation du mot cleacute var dans len-tecircte dune proceacutedure en Pascal

3 - La notion de reacutefeacuterence33

Remarques

1 Nous avons parleacute de transmission par reacutefeacuterence drsquoun argument Mais on peut eacutegalement

dire qursquoon transmet agrave une fonction la reacutefeacuterence agrave un argument effectif cela traduit mieux

le fait que lrsquoinformation fournie agrave la fonction est bien lrsquoadresse drsquoun emplacement Mais

en comparaison avec la transmission par pointeurs ce mode de transmission offre une

certaine protection en effet la reacutefeacuterence agrave une variable ne peut pas ecirctre utiliseacutee directe-

ment (volontairement ou par erreur) pour acceacuteder agrave des emplacements voisins comme on

le ferait avec une adresse reccedilue par le biais drsquoun pointeur1

2 Lorsquon doit transmettre en argument la reacutefeacuterence agrave un pointeur on est ameneacute agrave utili-

ser ce genre deacutecriture

int amp adr adr est une reacutefeacuterence agrave un pointeur sur un int

En Java

La notion de reacutefeacuterence existe en Java mais elle est entiegraverement transparente au program-

meur Plus preacuteciseacutement les variables drsquoun type de base sont transmises par valeur tandis

que les objets sont transmis par reacutefeacuterence Il reste cependant possible de creacuteer explicite-

ment une copie drsquoun objet en utilisant une meacutethode approprieacutee dite de clonage

33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argumentLa transmission par reacutefeacuterence drsquoun argument entraicircne un certain nombre de conseacutequences qui

nrsquoexistaient pas dans le cas de la transmission par valeur ou lorsqursquoon transmettait lrsquoadresse

drsquoun emplacement par le biais drsquoun pointeur

331 Induction de risques indirectsComme on lrsquoa vu sur lrsquoexemple preacuteceacutedent la transmission darguments par reacutefeacuterence simpli-

fie leacutecriture de la fonction correspondante Le choix du mode de transmission par reacutefeacuterence

est fait au moment de leacutecriture de la fonction concerneacutee Lutilisateur de la fonction na plus agrave

sen soucier ensuite si ce nest au niveau de la deacuteclaration du prototype de la fonction

(dailleurs ce prototype proviendra en geacuteneacuteral dun fichier en-tecircte)

En contrepartie lemploi de la transmission par reacutefeacuterence accroicirct les risques drsquoeffets de

bord non deacutesireacutes En effet lorsquil appelle une fonction lutilisateur ne sait plus sil trans-

met au bout du compte la valeur ou ladresse dun argument (la mecircme notation pouvant deacutesi-

gner lune ou lautre des deux possibiliteacutes) Il risque donc de modifier une variable dont il

pensait navoir transmis quune copie de la valeur

1 Il reste cependant possible drsquoaffecter agrave un pointeur lrsquoadresse de la variable dont on a reccedilu la reacutefeacuterence

Les speacutecificiteacutes du C++CHAPITRE 4

34

332 Absence de conversionDegraves lors qursquoune fonction a preacutevu une transmission par reacutefeacuterence les possibiliteacutes de conver-

sion preacutevues en cas de transmission par valeur disparaissent Voyez cet exemple

void f (int amp n) f reccediloit la reacutefeacuterence agrave un entierfloat x f(x) appel illeacutegal

A partir du moment ougrave la fonction reccediloit directement lrsquoadresse drsquoun emplacement qursquoelle

considegravere comme contenant un entier qursquoelle peut eacuteventuellement modifier il va de soi qursquoil

nrsquoest plus possible drsquoeffectuer une quelconque conversion de la valeur qui srsquoy trouve

La transmission par reacutefeacuterence impose donc agrave un argument effectif drsquoecirctre une lvalue du

type preacutevu pour lrsquoargument muet Nous verrons cependant au paragraphe 334 que les

arguments muets constants feront exception agrave cette regravegle et que dans ce cas des conversions

seront possibles

Remarque

Avec le prototype preacuteceacutedent de f lappel fct (ampn) serait rejeteacute En effet une reacutefeacuterence

nrsquoest pas un pointeur mecircme si au bout du compte lrsquoinformation transmise agrave la fonction

est une adresse En particulier lrsquousage qui est fait dans la traduction des instructions de la

fonction nrsquoest pas le mecircme dans le cas drsquoun pointeur on utilise directement sa valeur

quitte agrave mentionner une indirection avec lrsquoopeacuterateur avec une reacutefeacuterence lrsquoindirection

est ajouteacutee automatiquement par le compilateur

333 Cas drsquoun argument effectif constantSupposons quune fonction fct ait pour prototype

void fct (int amp)

Le compilateur refusera alors un appel de la forme suivante (n eacutetant de type int)

fct (3) incorrect f ne peut pas modifier une constante

Il en ira de mecircme pour

const int c = 15 fct (c) incorrect f ne peut pas modifier une constante

Ces refus sont logigues En effet si les appels preacuteceacutedents eacutetaient accepteacutes ils conduiraient agrave

fournir agrave fct ladresse dune constante (3 ou c) dont elle pourrait tregraves bien modifier la valeur1

1 On verra cependant au paragraphe 334 qursquoune telle transmission sera autoriseacutee si la fonction a effectivement preacutevu

dans son en-tecircte de travailler sur une constante

3 - La notion de reacutefeacuterence35

334 Cas drsquoun argument muet constant

En revanche consideacuterons une fonction de prototype

void fct1 (const int amp)

La deacuteclaration const int amp correspond agrave une reacutefeacuterence agrave une constante1 Les appels suivants

seront corrects

const int c = 15 fct1 (3) correct ici fct1 (c) correct ici

Lacceptation de ces instructions se justifie cette fois par le fait que fct a preacutevu de recevoir

une reacutefeacuterence agrave quelque chose de constant le risque de modification eacutevoqueacute preacuteceacutedemment

nexiste donc plus (du moins en theacuteorie car les possibiliteacutes de veacuterification du compilateur ne

sont pas complegravetes)

Qui plus est un appel tel fct1 (exp) (exp deacutesignant une expression quelconque) sera accepteacute

quel que soit le type de exp En effet dans ce cas il y a creacuteation dune variable temporaire (de

type int) qui recevra le reacutesultat de la conversion de exp en int Par exemple

void fct1 (const int amp) float x fct1 (x) correct f reccediloit la reacutefeacuterence agrave une variable temporaire contenant le reacutesultat de la conversion de x en int

En deacutefinitive lrsquoutilisation de const pour un argument muet transmis par reacutefeacuterence est lourde

de conseacutequences Certes comme on srsquoy attend cela amegravene le compilateur agrave verifier la cons-

tance de lrsquoargument concerneacute au sein de la fonction Mais de surcroicirct on autorise la creacuteation

drsquoune copie de lrsquoargument effectif (preacuteceacutedeacutee drsquoune conversion) degraves lors que ce dernier est

constant et drsquoun type diffeacuterent de celui attendu2

Cette remarque prendra encore plus drsquoacuiteacute dans le cas ougrave lrsquoargument en question sera un

objet

34 Transmission par reacutefeacuterence drsquoune valeur de retour

341 Introduction

Le meacutecanisme que nous venons dexposer pour la transmission des arguments sapplique agrave la

valeur de retour dune fonction Il est cependant moins naturel Consideacuterons ce petit

exemple

1 Contrairement agrave un pointeur une reacutefeacuterence est toujours constante de sorte que la deacuteclaration int const amp nrsquoa aucun

sens il nrsquoen allait pas de mecircme pour int const qui deacutesignait un pointeur constant sur un entier

2 Dans le cas drsquoune constante du mecircme type la norme laisse lrsquoimpleacutementation libre drsquoen faire ou non une copie

Geacuteneacuteralement la copie nrsquoest faite que pour les constantes drsquoun type scalaire

Les speacutecificiteacutes du C++CHAPITRE 4

36

int amp f () return n on suppose ici n de type int

Un appel de f provoquera la transmission en retour non plus drsquoune valeur mais de la reacutefeacute-

rence de n Cependant si lrsquoon utilise f drsquoune faccedilon usuelle

int p p = f() affecte agrave p la valeur situeacutee agrave la reacutefeacuterence fournie par f

une telle transmission ne semble guegravere preacutesenter drsquointeacuterecirct par rapport agrave une transmission par

valeur

Qui plus est il est neacutecessaire que n ne soit pas locale agrave la fonction sous peine de reacutecupeacuterer

une reacutefeacuterence (adresse) agrave quelque chose qui nrsquoexiste plus1

Effectivement on conccediloit qursquoon a plus rarement besoin de recevoir une reacutefeacuterence drsquoune

fonction que de lui en fournir

342 On obtient une lvalueDegraves lors qursquoune fonction renvoie une reacutefeacuterence il devient possible drsquoutiliser son appel

comme une lvalue Voyez cet exemple

int amp f () int n float x

f() = 2 n + 5 agrave la reacutefeacuterence fournie par f on range la valeur de lrsquoexpression 2n+5 de type intf() = x agrave la reacutefeacuterence fournie par f on range la valeur de x apregraves conversion en int

Le principal inteacuterecirct de la transmission par reacutefeacuterence drsquoune valeur de retour napparaicirctra que

lorsque nous eacutetudierons la surdeacutefinition dopeacuterateurs En effet dans certains cas il sera indis-

pensable quun opeacuterateur (en fait une fonction) fournisse une lvalue en reacutesultat Ce sera preacute-

ciseacutement le cas de lrsquoopeacuterateur []

343 ConversionContrairement agrave ce qui se produisait pour les arguments aucune contrainte drsquoexactitude de

type ne pegravese sur une valeur de retour car il reste toujours possible de la soumettre agrave une con-

version avant de lrsquoutiliser

1 Cette erreur srsquoapparente agrave celle due agrave la transmission en valeur de retour drsquoun pointeur sur une variable locale Elle

est encore plus difficile agrave deacutetecter dans la mesure ougrave le seul moment ougrave lrsquoon peut utiliser la reacutefeacuterence concerneacutee est

lrsquoappel lui-mecircme (alors qursquoun pointeur peut ecirctre utiliseacute agrave volonteacute) dans un environnement ne modifiant pas la

valeur drsquoune variable lors de sa destruction aucune erreur ne se manifeste ce nrsquoest que lors du portage dans un

environnement ayant un comportement diffeacuterent que les choses deviennent catastrophiques

3 - La notion de reacutefeacuterence37

inf amp f () float x x = f() OK on convertira en int la valeur situeacutee agrave la reacutefeacuterence reccedilue en retour de f

Nous verrons au paragraphe 344 qursquoil nrsquoen va plus de mecircme lorsque la valeur de retour est

une reacutefeacuterence agrave une constante

344 Valeur de retour et constance Si une fonction preacutevoit dans son en-tecircte un retour par reacutefeacuterence elle ne pourra pas mention-

ner de constante dans lrsquoinstruction return En effet si tel eacutetait le cas on prendrait le risque

que la fonction appelante modifie la valeur en question

int n=3 variable globalefloat x=35 idemint amp f1 () return 5 interdit return n OK return x interdit

Une exception a lieu lorsque lrsquoen-tete mentionne une reacutefeacuterence agrave une constante Dans ce cas

si return mentionne une constante on renverra la reacutefeacuterence drsquoune copie de cette constante

preacuteceacutedeacutee drsquoune eacuteventuelle conversion

const int amp f2 () return 5 OK on renvoie la reacutefeacuterence agrave une copie temporaire return n OK return x OK on renvoie la reacutefeacuterence agrave un int temporaire obtenu par conversion de la valeur de x

Mais on notera qursquoune telle reacutefeacuterence agrave une constante ne pourra plus ecirctre utiliseacutee comme une

lvalue

const int amp f () int n float x f() = 2 n + 5 erreur f() nrsquoest pas une lvaluef() = x idem

35 La reacutefeacuterence dune maniegravere geacuteneacuteraleNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Lessentiel concernant la notion de reacutefeacuterence a eacuteteacute preacutesenteacute dans les paragraphes preacuteceacutedents

Cependant en toute rigueur la notion de reacutefeacuterence peut intervenir en dehors de la notion

dargument ou de valeur de retour Crsquoest ce que nous allons examiner ici

Les speacutecificiteacutes du C++CHAPITRE 4

38

351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument

Dune maniegravere geacuteneacuterale il est possible de deacuteclarer un identificateur comme reacutefeacuterence dune

autre variable Consideacuterez par exemple ces instructions

int n

int amp p = n

La seconde signifie que p est une reacutefeacuterence agrave la variable n Ainsi dans la suite n et p deacutesigne-

ront le mecircme emplacement meacutemoire Par exemple avec

n = 3

cout ltlt p

nous obtiendrons la valeur 3

Remarque

Il nrsquoest pas possible de deacutefinir des pointeurs sur des reacutefeacuterences ni des tableaux de reacutefeacuteren-

ces

352 Initialisation de reacutefeacuterence

La deacuteclaration

int amp p = n

est en fait une deacuteclaration de reacutefeacuterence (ici p) accompagneacutee dune initialisation (agrave la reacutefeacuterence

de n) Dune faccedilon geacuteneacuterale il nest pas possible de deacuteclarer une reacutefeacuterence sans linitialiser

comme dans

int amp p incorrect car pas dinitialisation

Notez bien quune fois deacuteclareacutee (et initialiseacutee) une reacutefeacuterence ne peut plus ecirctre modifieacutee

Dailleurs aucun meacutecanisme nest preacutevu agrave cet effet si ayant deacuteclareacute int amp p=n vous eacutecri-

vez p=q il sagit obligatoirement de laffectation de la valeur de q agrave lemplacement de reacutefeacute-

rence p et non de la modification de la reacutefeacuterence q

On ne peut pas initialiser une reacutefeacuterence avec une constante La deacuteclaration suivante est

incorrecte

int amp n = 3 incorrecte

Cela est logique puisque si cette instruction eacutetait accepteacutee elle reviendrait agrave initialiser n avec

une reacutefeacuterence agrave la valeur (constante) 3 Dans ces conditions linstruction suivante conduirait

agrave modifier la valeur de la constante 3

n = 5

En revanche il est possible de deacutefinir des reacutefeacuterences constantes1 qui peuvent alors ecirctre initia-

liseacutees par des constantes Ainsi la deacuteclaration suivante est-elle correcte

const int amp n = 3

1 Depuis la version 3 de C++

4 - Les arguments par deacutefaut39

Elle geacutenegravere une variable temporaire (ayant une dureacutee de vie imposeacutee par lemplacement de la

deacuteclaration) contenant la valeur 3 et place sa reacutefeacuterence dans n On peut dire que tout se passe

comme si vous aviez eacutecrit

int temp = 3 int amp n = temp

avec cette diffeacuterence que dans le premier cas vous navez pas explicitement accegraves agrave la varia-

ble temporaire

Enfin les deacuteclarations suivantes sont encore correctes

float x const int amp n = x

Elles conduisent agrave la creacuteation drsquoune variable temporaire contenant le reacutesultat de la conversion

de x en int et placent sa reacutefeacuterence dans n Ici encore tout se passe comme si vous aviez eacutecrit

ceci (sans toutefois pouvoir acceacuteder agrave la variable temporaire temp)

float x int temp = x const int amp n = temp

Remarque

En toute rigueur lrsquoappel drsquoune fonction conduit agrave une initialisation des arguments

muets Dans le cas drsquoune reacutefeacuterence ce sont donc les regravegles que nous venons de deacutecrire qui

sont utiliseacutees Il en va de mecircme pour une valeur de retour On retrouve ainsi le comporte-

ment deacutecrit aux paragraphes 33 et 34

4 Les arguments par deacutefaut

41 ExemplesEn C ANSI il est indispensable que lappel dune fonction contienne autant darguments que

la fonction en attend effectivement C++ permet de saffranchir en partie de cette regravegle gracircce

agrave un meacutecanisme dattribution de valeurs par deacutefaut agrave des arguments

Exemple 1Consideacuterez lexemple suivant

include ltiostreamgtusing namespace std main() int n=10 p=20 void fct (int int=12) proto avec une valeur par deacutefaut fct (n p) appel normal fct (n) appel avec un seul argument fct() serait ici rejeteacute

Les speacutecificiteacutes du C++CHAPITRE 4

40

void fct (int a int b) en-tecircte habituelle

cout ltlt premier argument ltlt a ltlt n

cout ltlt second argument ltlt b ltlt n

premier argument 10

second argument 20

premier argument 10

second argument 12

Exemple de deacutefinition de valeur par deacutefaut pour un argument

La deacuteclaration de fct ici dans la fonction main est reacutealiseacutee par le prototype

void fct (int int = 12)

La deacuteclaration du second argument apparaicirct sous la forme

int = 12

Celle-ci preacutecise au compilateur que en cas dabsence de ce second argument dans un eacuteven-

tuel appel de fct il lui faudra faire comme si lappel avait eacuteteacute effectueacute avec cette valeur

Les deux appels de fct illustrent le pheacutenomegravene Notez quun appel tel que

fct ( )

serait rejeteacute agrave la compilation puisquici il neacutetait pas preacutevu de valeur par deacutefaut pour le pre-

mier argument de fct

Exemple 2

Voici un second exemple dans lequel nous avons preacutevu des valeurs par deacutefaut pour tous les

arguments de fct

include ltiostreamgt

using namespace std

main()

int n=10 p=20

void fct (int=0 int=12) proto avec deux valeurs par deacutefaut

fct (n p) appel normal

fct (n) appel avec un seul argument

fct () appel sans argument

void fct (int a int b) en-tecircte habituelle

cout ltlt premier argument ltlt a ltlt n

cout ltlt second argument ltlt b ltlt n

4 - Les arguments par deacutefaut41

premier argument 10

second argument 20

premier argument 10

second argument 12

premier argument 0

second argument 12

Exemple de deacutefinition de valeurs par deacutefaut pour plusieurs arguments

42 Les proprieacuteteacutes des arguments par deacutefautLorsquune deacuteclaration preacutevoit des valeurs par deacutefaut les arguments concerneacutes doivent obli-

gatoirement ecirctre les derniers de la liste

Par exemple une deacuteclaration telle que

float fexple (int = 5 long int = 3)

est interdite En fait une telle interdiction relegraveve du pur bon sens En effet si cette deacutecla-

ration eacutetait accepteacutee lappel suivant

fexple (10 20)

pourrait ecirctre interpreacuteteacute aussi bien comme

fexple (5 10 20)

que comme

fexple (10 20 3)

Notez bien que le meacutecanisme proposeacute par C++ revient agrave fixer les valeurs par deacutefaut dans la

deacuteclaration de la fonction et non dans sa deacutefinition Autrement dit ce nest pas le concep-

teur de la fonction qui deacutecide des valeurs par deacutefaut mais lutilisateur Une conseacutequence

immeacutediate de cette particulariteacute est que les arguments soumis agrave ce meacutecanisme et les valeurs

correspondantes peuvent varier dune utilisation agrave une autre en pratique toutefois ce point

ne sera guegravere exploiteacute ne serait-ce que parce que les deacuteclarations de fonctions sont en geacuteneacute-

ral figeacutees une fois pour toutes dans un fichier en-tecircte

Nous verrons que les arguments par deacutefaut se reacuteveacuteleront particuliegraverement preacutecieux lorsquil

sagira de fabriquer ce que lon nomme le constructeur dune classe

Remarques

1 Si lon souhaite attribuer une valeur par deacutefaut agrave un argument de type pointeur on prendra

garde de seacuteparer par au moins un espace les caractegraveres et = dans le cas contraire ils

seraient interpreacuteteacutes comme lopeacuterateur daffectation = ce qui conduirait agrave une erreur

Les speacutecificiteacutes du C++CHAPITRE 4

42

2 Les valeurs par deacutefaut ne sont pas neacutecessairement des expressions constantes Elles ne

peuvent toutefois pas faire intervenir de variables locales1

En Java

Les arguments par deacutefaut nrsquoexistent pas en Java

5 Surdeacutefinition de fonctionsDune maniegravere geacuteneacuterale on parle de surdeacutefinition2 lorsquun mecircme symbole possegravede plu-

sieurs significations diffeacuterentes le choix de lune des significations se faisant en fonction du

contexte Cest ainsi que C comme la plupart des langages eacutevolueacutes utilise la surdeacutefinition

dun certain nombre dopeacuterateurs Par exemple dans une expression telle que

a + b

la signification du + deacutepend du type des opeacuterandes a et b suivant le cas il pourra sagir dune

addition dentiers ou dune addition de flottants De mecircme le symbole peut deacutesigner sui-

vant le contexte une multiplication dentiers de flottants ou une indirection3

Un des grands atouts de C++ est de permettre la surdeacutefinition de la plupart des opeacuterateurs

(lorsquils sont associeacutes agrave la notion de classe) Lorsque nous eacutetudierons cet aspect nous ver-

rons quil repose en fait sur la surdeacutefinition de fonctions Cest cette derniegravere possibiliteacute que

nous proposons deacutetudier ici pour elle-mecircme

Pour pouvoir employer plusieurs fonctions de mecircme nom il faut bien sucircr un critegravere (autre

que le nom) permettant de choisir la bonne fonction En C++ ce choix est baseacute (comme pour

les opeacuterateurs citeacutes preacuteceacutedemment en exemple) sur le type des arguments Nous commence-

rons par vous preacutesenter un exemple complet montrant comment mettre en œuvre la surdeacutefini-

tion de fonctions Nous examinerons ensuite diffeacuterentes situations dappel dune fonction

surdeacutefinie avant deacutetudier les regravegles deacutetailleacutees qui preacutesident au choix de la bonne fonction

51 Mise en œuvre de la surdeacutefinition de fonctionsNous allons deacutefinir et utiliser deux fonctions nommeacutees sosie La premiegravere posseacutedera un argu-

ment de type int la seconde un argument de type double ce qui les diffeacuterencie bien lune de

lautre Pour que lrsquoexeacutecution du programme montre clairement la fonction effectivement

appeleacutee nous introduisons dans chacune une instruction daffichage approprieacutee Dans le pro-

1 Ni la valeur this pour les fonctions membres (this sera eacutetudieacute au chapitre 5)

2 De overloading parfois traduit par surcharge

3 On parle parfois de deacutereacutefeacuterence cela correspond agrave des situations telles que

int a

a = 5

5 - Surdeacutefinition de fonctions43

gramme dessai nous nous contentons dappeler successivement la fonction surdeacutefinie sosie

une premiegravere fois avec un argument de type int une seconde fois avec un argument de type

double

include ltiostreamgtusing namespace std

void sosie (int) les prototypesvoid sosie (double)

main() le programme de test int n=5

double x=25 sosie (n) sosie (x) void sosie (int a) la premiegravere fonction cout ltlt sosie numero I a = ltlt a ltlt n void sosie (double a) la deuxiegraveme fonction cout ltlt sosie numero II a = ltlt a ltlt n

sosie numero I a = 5sosie numero II a = 25

Exemple de surdeacutefinition de la fonction sosie

Vous constatez que le compilateur a bien mis en place lappel de la bonne fonction sosie au

vu de la liste darguments (ici reacuteduite agrave un seul)

52 Exemples de choix dune fonction surdeacutefinieNotre preacuteceacutedent exemple eacutetait simple dans la mesure ougrave nous appelions toujours la fonction

sosie avec un argument ayant exactement lun des types preacutevus dans les prototypes (int ou

double) On peut se demander ce qui se produirait si nous lappelions par exemple avec un

argument de type char long ou pointeur ou si lon avait affaire agrave des fonctions comportant

plusieurs arguments

Avant de preacutesenter les regravegles de deacutetermination dune fonction surdeacutefinie examinons tout

dabord quelques situations assez intuitives

Les speacutecificiteacutes du C++CHAPITRE 4

44

Exemple 1void sosie (int) sosie Ivoid sosie (double) sosie IIchar c float y sosie(c) appelle sosie I apregraves conversion de c en intsosie(y) appelle sosie II apregraves conversion de y en doublesosie(d) appelle sosie I apregraves conversion de d en int

Exemple 2void affiche (char ) affiche Ivoid affiche (void ) affiche IIchar ad1 double ad2 affiche (ad1) appelle affiche Iaffiche (ad2) appelle affiche II apregraves conversion de ad2 en void

Exemple 3void essai (int double) essai Ivoid essai (double int) essai IIint n p double z char c essai(nz) appelle essai Iessai(cz) appelle essai I apregraves conversion de c en intessai(np) erreur de compilation

Compte tenu de son ambiguiumlteacute le dernier appel conduit agrave une erreur de compilation En effet

deux possibiliteacutes existent ici convertir p en double sans modifier n et appeler essai I ou au

contraire convertir n en double sans modifier p et appeler essai II

Exemple 4void test (int n=0 double x=0) test Ivoid test (double y=0 int p=0) test IIint n double z test(nz) appelle test Itest(zn) appelle test IItest(n) appelle test Itest(z) appelle test IItest() erreur de compilation compte tenu de lrsquoambiguiumlteacute

Exemple 5

Avec ces deacuteclarations

void truc (int) truc Ivoid truc (const int) truc II

vous obtiendrez une erreur de compilation En effet C++ na pas preacutevu de distinguer int de

const int Cela se justifie par le fait que les deux fonctions truc recevant une copie de linfor-

5 - Surdeacutefinition de fonctions45

mation agrave traiter il nrsquoy a aucun risque de modifier la valeur originale Notez bien qursquoici

lrsquoerreur tient agrave la seule preacutesence des deacuteclarations de chose indeacutependamment drsquoun appel quel-

conque

Exemple 6

En revanche consideacuterez maintenant ces deacuteclarations

void chose (int ) chose Ivoid chose (const int ) chose IIint n = 3 const p = 5

Cette fois la distinction entre int et const int est justifieacutee En effet on peut tregraves bien preacute-

voir que chose I modifie la valeur de la lvalue1 dont elle reccediloit ladresse tandis que chose II

nen fait rien Cette distinction est possible en C+ de sorte que

chose (ampn) appelle chose Ichose (ampp) appelle chose II

Exemple 7

Les reflexions de lrsquoexemple preacuteceacutedent agrave propos des pointeurs srsquoappliquent aux reacutefeacuterences

void chose (int amp) chose Ivoid chose (const int amp) chose IIint n = 3 const int p = 5 chose (n) appelle chose Ichose (p) appelle chose II

Remarque

En dehors de la situation examineacutee ici on notera que le mode de transmission (reacutefeacuterence

ou valeur) nrsquointervient pas dans le choix drsquoune fonction surdeacutefinie Par exemple les

deacuteclarations suivantes conduiraient agrave une erreur de compilation due agrave leur ambiguiumlteacute

(indeacutependamment de tout appel de chose)

void chose (int amp) void chose (int)

Exemple 8

Lrsquoexemple preacuteceacutedent a montreacute comment on pouvait distinguer entre deux fonctions agissant

lrsquoune sur une reacutefeacuterence lrsquoautre sur une reacutefeacuterence constante Mais lrsquoutilisation de reacutefeacuterences

possegravede des conseacutequences plus subtiles comme le montrent ces exemples (revoyez eacuteventuel-

lement le paragraphe 334)

1 Rappelons quon nomme lvalue la reacutefeacuterence agrave quelque chose dont on peut modifier la valeur Ce terme provient de

la contraction de left value qui deacutesigne quelque chose qui peut apparaicirctre agrave gauche dun opeacuterateur daffectation

Les speacutecificiteacutes du C++CHAPITRE 4

46

void chose (int amp) chose Ivoid chose (const int amp) chose IIint n float x chose (n) appelle chose Ichose (2) appelle chose II apregraves copie eacuteventuelle de 2 dans un entier1 temporaire dont la reacutefeacuterence sera transmise agrave chosechose (x) appelle chose II apregraves conversion de la valeur de x en un entier temporaire dont la reacutefeacuterence sera transmise agrave chose

53 Regravegles de recherche dune fonction surdeacutefiniePour linstant nous vous preacutesenterons plutocirct la philosophie geacuteneacuterale ce qui sera suffisant

pour leacutetude des chapitres suivants Au cours de cet ouvrage nous serons ameneacute agrave vous

apporter des informations compleacutementaires De plus lensemble de toutes ces regravegles sont

reprises en Annexe A

531 Cas des fonctions agrave un argument

Le compilateur recherche la meilleure correspondance possible Bien entendu pour pou-

voir deacutefinir ce quest cette meilleure correspondance il faut quil dispose dun critegravere deacuteva-

luation Pour ce faire il est preacutevu diffeacuterents niveaux de correspondance

1) Correspondance exacte on distingue bien les uns des autres les diffeacuterents types de base

en tenant compte de leur eacuteventuel attribut de signe2 de plus comme on la vu dans les

exemples preacuteceacutedents lattribut const peut intervenir dans le cas de pointeurs ou de reacutefeacuteren-

ces

2) Correspondance avec promotions numeacuteriques cest-agrave-dire essentiellement

char et short ndashgt int

float ndashgt double

Rappelons qursquoun argument transmis par reacutefeacuterence ne peut ecirctre soumis agrave aucune conver-

sion sauf lorsqursquoil srsquoagit de la reacutefeacuterence agrave une constante

3) Conversions dites standard il sagit des conversions leacutegales en C++ cest-agrave-dire de celles

qui peuvent ecirctre imposeacutees par une affectation (sans opeacuterateur de cast) cette fois il peut

sagir de conversions deacutegradantes puisque notamment toute conversion dun type numeacute-

rique en un autre type numeacuterique est accepteacutee

Dautres niveaux sont preacutevus en particulier on pourra faire intervenir ce que lon nomme

des conversions deacutefinies par lutilisateur (CDU) qui ne seront eacutetudieacutees qursquoau

chapitre 10

1 Comme lrsquoautorise la norme lrsquoimpleacutementation est libre de faire ou non une copie dans ce cas

2 Attention en C++ char est diffeacuterent de signed char et de unsigned char

5 - Surdeacutefinition de fonctions47

Lagrave encore un argument transmis par reacutefeacuterence ne pourra ecirctre soumis agrave aucune conversion

sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante

La recherche sarrecircte au premier niveau ayant permis de trouver une correspondance qui doit

alors ecirctre unique Si plusieurs fonctions conviennent au mecircme niveau de correspondance il y

a erreur de compilation due agrave lambiguiumlteacute rencontreacutee Bien entendu si aucune fonction ne

convient agrave aucun niveau il y a aussi erreur de compilation

532 Cas des fonctions agrave plusieurs arguments

Lideacutee geacuteneacuterale est quil doit se deacutegager une fonction meilleure que toutes les autres Pour

ce faire le compilateur seacutelectionne pour chaque argument la ou les fonctions qui reacutealisent

la meilleure correspondance (au sens de la hieacuterarchie deacutefinie ci-dessus) Parmi lensemble des

fonctions ainsi seacutelectionneacutees il choisit celle (si elle existe et si elle est unique) qui reacutealise

pour chaque argument une correspondance au moins eacutegale agrave celle de toutes les autres fonc-

tions1

Si plusieurs fonctions conviennent lagrave encore on aura une erreur de compilation due agrave lambi-

guiumlteacute rencontreacutee De mecircme si aucune fonction ne convient il y aura erreur de compilation

Notez que les fonctions comportant un ou plusieurs arguments par deacutefaut sont traiteacutees

comme si plusieurs fonctions diffeacuterentes avaient eacuteteacute deacutefinies avec un nombre croissant

darguments

533 Le meacutecanisme de la surdeacutefinition de fonctions

Jusquici nous avons examineacute la maniegravere dont le compilateur faisait le choix de la bonne

fonction en raisonnant sur un seul fichier source agrave la fois Mais il serait tout agrave fait

envisageable

bull de compiler dans un premier temps un fichier source contenant la deacutefinition de nos deux

fonctions nommeacutees sosie

bull dutiliser ulteacuterieurement ces fonctions dans un autre fichier source en nous contentant den

fournir les prototypes

Or pour que cela soit possible leacutediteur de liens doit ecirctre en mesure deffectuer le lien entre le

choix opeacutereacute par le compilateur et la bonne fonction figurant dans un autre module objet

Cette reconnaissance est baseacutee sur la modification par le compilateur des noms externes

des fonctions celui-ci fabrique un nouveau nom fondeacute dune part sur le nom interne de la

fonction dautre part sur le nombre et la nature de ses arguments

Il est tregraves important de noter que ce meacutecanisme sapplique agrave toutes les fonctions quelles

soient surdeacutefinies ou non (il est impossible de savoir si une fonction compileacutee dans un fichier

source sera surdeacutefinie dans un autre) On voit donc quun problegraveme se pose degraves que lon sou-

haite utiliser dans un programme C++ une fonction eacutecrite et compileacutee en C (ou dans un autre

1 Ce qui revient agrave dire quil considegravere lintersection des ensembles constitueacutes des fonctions reacutealisant la meilleure

correspondance pour chacun des arguments

Les speacutecificiteacutes du C++CHAPITRE 4

48

langage utilisant les mecircmes conventions dappels de fonction notamment lassembleur ou le

Fortran) En effet une telle fonction ne voit pas son nom modifieacute suivant le meacutecanisme eacutevo-

queacute Une solution existe toutefois deacuteclarer une telle fonction en faisant preacuteceacuteder son proto-

type de la mention extern C Par exemple si nous avons eacutecrit et compileacute en C une fonction

den-tecircte

double fct (int n char c)

et que nous souhaitons lrsquoutiliser dans un programme C++ il nous suffira de fournir son pro-

totype de la faccedilon suivante

extern C double fct (int char)

Remarques

1 Il existe une forme collective de la deacuteclaration extern qui se preacutesente ainsi

extern C void exple (int) double chose (int char float)

2 Le problegraveme eacutevoqueacute pour les fonctions C (assembleur ou Fortran) se pose a priori

pour toutes les fonctions de la bibliothegraveque standard C que lon reacuteutilise en C++ En

fait dans la plupart des environnements cet aspect est automatiquement pris en charge

au niveau des fichiers en-tecircte correspondants (ils contiennent des deacuteclarations extern

conditionnelles)

3 Il est possible drsquoemployer au sein drsquoun mecircme programme C++ une fonction C (assem-

bleur ou Fortran) et une ou plusieurs autres fonctions C++ de mecircme nom (mais drsquoargu-

ments diffeacuterents) Par exemple nous pouvons utiliser dans un programme C++ la

fonction fct preacuteceacutedente et deux fonctions C++ drsquoen-tecircte

void fct (double x) void fct (float y)

en proceacutedant ainsi

extern C void fct (int) void fct (double) void fct (float)

Suivant la nature de lrsquoargument drsquoappel de fct il y aura bien appel de lrsquoune des trois

fonctions fct Notez qursquoil nrsquoest pas possible de mentionner plusieurs fonctions C de

nom fct

En Java

La surdeacutefinition des fonctions existe en Java Les regravegles de recherche de la bonne fonc-

tion sont extrecircmement simples car il existe peu de possibiliteacutes de conversions implicites

6 - Les opeacuterateurs new et delete49

6 Les opeacuterateurs new et deleteEn langage C la gestion dynamique de meacutemoire fait appel agrave des fonctions de la bibliothegraveque

standard telles que malloc et free Bien entendu comme toutes les fonctions standard celles-

ci restent utilisables en C++

Mais dans le contexte de la Programmation Orienteacutee Objet C++ a introduit deux nouveaux

opeacuterateurs new et delete particuliegraverement adapteacutes agrave la gestion dynamique dobjets Ces opeacute-

rateurs peuvent eacutegalement ecirctre utiliseacutes pour des variables classiques1 Dans ces conditions

par souci dhomogeacuteneacuteiteacute et de simpliciteacute il est plus raisonnable en C++ dutiliser systeacutemati-

quement ces opeacuterateurs que lon ait affaire agrave des variables classiques ou agrave des objets Cest

pourquoi nous vous les preacutesentons degraves maintenant

61 Exemples dutilisation de new

Exemple 1Avec la deacuteclaration

int ad

linstruction

ad = new int

permet dallouer lespace meacutemoire neacutecessaire pour un eacuteleacutement de type int et daffecter agrave ad

ladresse correspondante En C vous auriez obtenu le mecircme reacutesultat en eacutecrivant (lopeacuterateur

de cast ici int eacutetant facultatif)

ad = (int ) malloc (sizeof (int))

Comme les deacuteclarations ont un emplacement libre en C++ vous pouvez mecircme deacuteclarer la

variable ad au moment ougrave vous en avez besoin en eacutecrivant par exemple

int ad = new int

Exemple 2Avec la deacuteclaration

char adc

linstruction

adc = new char[100]

alloue lemplacement neacutecessaire pour un tableau de 100 caractegraveres et place ladresse (de

deacutebut) dans adc En C vous auriez obtenu le mecircme reacutesultat en eacutecrivant

adc = (char ) malloc (100)

1 Un objet eacutetant en fait une variable dun type particulier

Les speacutecificiteacutes du C++CHAPITRE 4

50

62 Syntaxe et rocircle de newLrsquoopeacuterateur unaire (agrave un seul opeacuterande) new sutilise ainsi

new type

ougrave type repreacutesente un type absolument quelconque Il fournit comme reacutesultat un pointeur (de

type type) sur lemplacement correspondant lorsque lallocation a reacuteussi

Lrsquoopeacuterateur new accepte eacutegalement une syntaxe de la forme

new type [n]

ougrave n deacutesigne une expression entiegravere quelconque (non neacutegative) Cette instruction alloue alors

lemplacement neacutecessaire pour n eacuteleacutements du type indiqueacute si lrsquoopeacuteration a reacuteussi elle fournit

en reacutesultat un pointeur (toujours de type type ) sur le premier eacuteleacutement de ce tableau

La norme de C++ preacutevoit quen cas deacutechec new deacuteclenche ce que lon nomme une exception

de type bad_alloc Ce meacutecanisme de gestion des exceptions est eacutetudieacute en deacutetail au chapitre

17 Vous verrez que si rien nest preacutevu par le programmeur pour traiter une exception le pro-

gramme sinterrompt

Il est cependant possible de demander agrave new de se comporter diffeacuteremment en cas drsquoeacutechec

comme nous le verrons aux paragraphes 65 et 66

Remarque

En toute rigueur new peut ecirctre utiliseacute pour allouer un emplacement pour un tableau agrave plu-

sieurs dimensions par exemple

new type [n] [10]

Dans ce cas new fournit un pointeur sur des tableaux de 10 entiers (dont le type se note

type () [10]) Drsquoune maniegravere geacuteneacuterale la premiegravere dimension peut ecirctre une expression

entiegravere quelconque les autres doivent obligatoirement ecirctre des expressions constantes

Cette possibiliteacute est rarement utiliseacutee en pratique

En Java

Il existe eacutegalement un opeacuterateur new Mais il ne srsquoapplique pas aux types de base il est

reacuteserveacute aux objets

63 Exemples dutilisation de lopeacuterateur deleteLorsque lon souhaite libeacuterer un emplacement alloueacute preacutealablement par new on doit absolu-

ment utiliser lopeacuterateur delete Ainsi pour libeacuterer les emplacements creacuteeacutes dans les exemples

du paragraphe 61 on eacutecrit

delete ad

6 - Les opeacuterateurs new et delete51

pour lemplacement alloueacute par

ad = new int

et

delete adc

pour lemplacement alloueacute par

adc = new char [100]

64 Syntaxe et rocircle de lopeacuterateur deleteLa syntaxe usuelle de lopeacuterateur delete est la suivante (adresse eacutetant une expression devant

avoir comme valeur un pointeur sur un emplacement alloueacute par new)

delete adresse

Notez bien que le comportement du programme nest absolument pas deacutefini lorsque

bull vous libeacuterez par delete un emplacement deacutejagrave libeacutereacute nous verrons que des preacutecautions

devront ecirctre prises lorsque lon deacutefinit des constructeurs et des destructeurs de certains

objets

bull vous fournissez agrave delete une mauvaise adresse ou un pointeur obtenu autrement que par

new (malloc par exemple)

Remarque

Il existe une autre syntaxe de delete de la forme delete [] adresse qui nintervient que

dans le cas de tableaux dobjets et dont nous parlerons au paragraphe 7 du chapitre 7

65 Lrsquoopeacuterateur new (nothrow)Comme lrsquoa montreacute le paragraphe 62 new deacuteclenche une exception bad_alloc en cas

drsquoeacutechec Dans les versions drsquoavant la norme new fournissait (comme malloc) un pointeur nul

en cas drsquoeacutechec Avec la norme on peut retrouver ce comportement en utilisant au lieu de

new lrsquoopeacuterateur new(stdnothrow) (std est superflu degraves lors qursquoon a bien deacuteclareacute cet

espace de nom par using)

A titre drsquoexemple voici un programme qui alloue des emplacements pour des tableaux

dentiers dont la taille est fournie en donneacutee et ce jusquagrave ce quil ny ait plus suffisam-

ment de place (notez quici nous utilisons toujours la mecircme variable adr pour recevoir

les diffeacuterentes adresses des tableaux ce qui dans un programme reacuteel ne serait probable-

ment pas acceptable)

include ltcstdlibgt ancien ltstdlibhgt pour exitinclude ltiostreamgtusing namespace std

Les speacutecificiteacutes du C++CHAPITRE 4

52

main() long taille int adr int nbloc cout ltlt Taille souhaitee cin gtgt taille for (nbloc=1 nbloc++) adr = new (nothrow) int [taille] if (adr==0) cout ltlt manque de memoire n exit (-1) cout ltlt Allocation bloc numero ltlt nbloc ltlt n

Taille souhaitee 4000000Allocation bloc numero 1Allocation bloc numero 2Allocation bloc numero 3 manque de memoire

Exemple drsquoutilisation de new(nothrow)

66 Gestion des deacutebordements de meacutemoire avec set_new_handler

Comme on lrsquoa vu au paragraphe 62 new deacuteclenche une exception bad_alloc en cas drsquoeacutechec

Mais il est eacutegalement possible de deacutefinir une fonction de votre choix et de demander quelle

soit appeleacutee en cas de manque de meacutemoire Il vous suffit pour cela dappeler la fonction

set_new_handler en lui fournissant en argument ladresse de la fonction que vous avez preacute-

vue pour traiter le cas de manque de meacutemoire Voici comment nous pourrions adapter

lrsquoexemple preacuteceacutedent

include ltcstdlibgt ancien ltstdlibhgt pour exitinclude ltnewgt pour set_new_handler (parfois ltnewhgt)include ltiostreamgtusing namespace std

main() void deborde () proto fonction appeleacutee en cas manque meacutemoire set_new_handler (deborde) long taille int adr int nbloc cout ltlt Taille de bloc souhaitee (en entiers) cin gtgt taille

7 - La speacutecification inline53

for (nbloc=1 nbloc++) adr = new int [taille] cout ltlt Allocation bloc numero ltlt nbloc ltlt n

void deborde () fonction appeleacutee en cas de manque meacutemoire cout ltlt Memoire insuffisanten cout ltlt Abandon de lexecutionn exit (-1)

Taille de bloc souhaitee (en entiers) 4000000Allocation bloc numero 1Allocation bloc numero 2Allocation bloc numero 3Memoire insuffisante pour allouer 16000000 octetsAbandon de lexecutionPress any key to continue

Exemple drsquoutilisation de set_new_handler

7 La speacutecification inline

71 Rappels concernant les macros et les fonctionsEn langage C vous savez quil existe deux notions assez voisines agrave savoir les macros et les

fonctions Une macro et une fonction sutilisent apparemment de la mecircme faccedilon en faisant

suivre leur nom dune liste drsquoarguments entre parenthegraveses Cependant

bull les instructions correspondant agrave une macro sont incorporeacutees agrave votre programme1 chaque

fois que vous lappelez

bull les instructions correspondant agrave une fonction sont geacuteneacutereacutees une seule fois2 agrave chaque ap-

pel il y aura seulement mise en place des instructions neacutecessaires pour eacutetablir la liaison en-

tre le programme3 et la fonction sauvegarde de leacutetat courant (valeurs de certains

registres par exemple) recopie des valeurs des arguments branchement avec conservation

de ladresse de retour recopie de la valeur de retour restauration de leacutetat courant et retour

dans le programme Toutes ces instructions neacutecessaires agrave la mise en œuvre de lappel de la

1 En toute rigueur lincorporation est reacutealiseacutee au niveau du preacuteprocesseur lequel introduit les instructions en langage

C correspondant agrave lexpansion de la macro ces instructions peuvent dailleurs varier dun appel agrave un autre

2 Par le compilateur cette fois sous forme dinstructions en langage machine

3 En toute rigueur il faudrait plutocirct parler de fonction appelante

Les speacutecificiteacutes du C++CHAPITRE 4

54

fonction nexistent pas dans le cas de la macro On peut donc dire que la fonction permet de

gagner de lespace meacutemoire en contrepartie dune perte de temps dexeacutecution Bien entendu

la perte de temps sera dautant plus faible que la fonction sera de taille importante

bull contrairement aux fonctions les macros peuvent entraicircner des effets de bord indeacutesirables

ou du moins impreacutevus Voici deux exemples

- Si une macro introduit de nouvelles variables celles-ci peuvent interfeacuterer avec dautres

variables de mecircme nom Ce risque nexiste pas avec une fonction sauf si lon utilise vo-

lontairement cette fois des variables globales

- Une macro deacutefinie par

carre(x) x x

et appeleacutee par

carre(a++)

geacuteneacuterera les instructions

a++ a++

qui increacutementent deux fois la variable a

En C lorsque lon a besoin dune fonction courte et que le temps drsquoexeacutecution est primordial

on fait geacuteneacuteralement appel agrave une macro malgreacute les inconveacutenients que cela implique En C++

il existe une solution plus satisfaisante utiliser une fonction en ligne (inline)

72 Utilisation de fonctions en ligneUne fonction en ligne se deacutefinit et sutilise comme une fonction ordinaire agrave la seule diffeacute-

rence quon fait preacuteceacuteder son en-tecircte de la speacutecification inline En voici un exemple

include ltcmathgt ancien ltmathhgt pour sqrtinclude ltiostreamgtusing namespace std deacutefinition drsquoune fonction en ligne inline double norme (double vec[3]) int i double s = 0

for (i=0 ilt3 i++) s+= vec[i] vec[i] return sqrt(s) exemple drsquoutilisation main() double v1[3] v2[3] int i for (i=0 ilt3 i++) v1[i] = i v2[i] = 2i-1

7 - La speacutecification inline55

cout ltlt norme de v1 ltlt norme(v1) ltlt n cout ltlt norme de v2 ltlt norme(v2) ltlt n

norme de v1 223607norme de v2 331662

Exemple de deacutefinition et dutilisation dune fonction en ligne

La fonction norme a pour but de calculer la norme dun vecteur agrave trois composantes quon lui

fournit en argument

La preacutesence du mot inline demande au compilateur de traiter la fonction norme diffeacuteremment

dune fonction ordinaire A chaque appel de norme le compilateur devra incorporer au sein

du programme les instructions correspondantes (en langage machine1) Le meacutecanisme habi-

tuel de gestion de lappel et du retour nexistera plus (il ny a plus besoin de sauvegardes

recopies) ce qui permet une eacuteconomie de temps En revanche les instructions correspon-

dantes seront geacuteneacutereacutees agrave chaque appel ce qui consommera une quantiteacute de meacutemoire croissant

avec le nombre dappels

Il est tregraves important de noter que par sa nature mecircme une fonction en ligne doit ecirctre deacutefinie

dans le mecircme fichier source que celui ougrave on lutilise Elle ne peut plus ecirctre compileacutee

seacutepareacutement Cela explique quil nrsquoest pas neacutecessaire de deacuteclarer une telle fonction (sauf si

elle est utiliseacutee au sein dun fichier source avant drsquoecirctre deacutefinie) Ainsi on ne trouve pas dans

notre exemple de deacuteclaration telle que

double norme (double)

Cette absence de possibiliteacute de compilation seacutepareacutee constitue une contrepartie notable aux

avantages offerts par la fonction en ligne En effet pour quune mecircme fonction en ligne

puisse ecirctre partageacutee par diffeacuterents programmes il faudra absolument la placer dans un fichier

en-tecircte2 (comme on le fait avec une macro)

Comparaison entre macro fonction et fonction en ligne

1 Notez quil sagit bien ici dun travail effectueacute par le compilateur lui-mecircme alors que dans le cas dune macro un

travail comparable eacutetait effectueacute par le preacuteprocesseur

2 A moins den eacutecrire plusieurs fois la deacutefinition ce qui ne serait pas raisonnable compte tenu des risques derreurs

que cela comporte

Avantages Inconveacutenients

Macro - Eacuteconomie de temps dexeacutecution

- Perte despace meacutemoire- Risque deffets de bord non deacutesireacutes- Pas de compilation seacutepareacutee possible

Fonction - Eacuteconomie despace meacutemoire- Compilation seacutepareacutee possible

- Perte de temps dexeacutecution

Fonction en ligne - Eacuteconomie de temps dexeacutecution

- Perte despace meacutemoire- Pas de compilation seacutepareacutee possible

Les speacutecificiteacutes du C++CHAPITRE 4

56

Remarque

La deacuteclaration inline constitue une demande effectueacutee aupregraves du compilateur Ce dernier

peut eacuteventuellement (par exemple si la fonction est volumineuse) ne pas lintroduire en

ligne et en faire une fonction ordinaire De mecircme si vous utilisez quelque part (au sein du

fichier source concerneacute) ladresse dune fonction deacuteclareacutee inline le compilateur en fera

une fonction ordinaire (dans le cas contraire il serait incapable de lui attribuer une

adresse et encore moins de mettre en place un eacuteventuel appel dune fonction situeacutee agrave cette

adresse)

8 Les espaces de nomsLorsque lon doit utiliser plusieurs bibliothegraveques dans un programme on peut ecirctre confronteacute

au problegraveme dit de pollution de lespace des noms lieacute agrave ce quun mecircme identificateur peut

tregraves bien avoir eacuteteacute utiliseacute par plusieurs bibliothegraveques Le mecircme problegraveme peut se poser agrave un

degreacute moindre toutefois lors du deacuteveloppement de gros programmes Cest la raison pour

laquelle la norme ANSI du C++ a introduit le concept drsquoespace de noms Il sagit simple-

ment de donner un nom agrave un espace de deacuteclarations en proceacutedant ainsi

namespace une_bibli deacuteclarations usuelles

Pour se reacutefeacuterer agrave des identificateurs deacutefinis dans cet espace de noms on utilisera une instruc-

tion using

using namespace une_bibli ici les identificateurs de une_bibli sont connus

On peut lever lambiguiumlteacute risquant dapparaicirctre lorsquon utilise plusieurs espaces de noms

comportant des identificateurs identiques il suffit pour cela de faire appel agrave lopeacuterateur de

reacutesolution de porteacutee par exemple

une_biblipoint on se reacutefegravere agrave lidentificateur point de lespace de noms une_bibli

On peut aussi utiliser linstruction using pour faire un choix permanent

using une_biblipoint doreacutenavant lidentificateur point employeacute seul correspondra agrave celui deacutefini dans lespace de noms une_bibli

Tous les identificateurs des fichiers en-tecircte standard sont deacutefinis dans lrsquoespace de noms std

aussi est-il neacutecessaire de recourir systeacutematiquement agrave lrsquoinstruction

using namespace std utilisation des fichiers en-tecircte standard

Geacuteneacuteralement cette instruction figurera agrave un niveau global comme nous lrsquoavons fait dans les

exemples preacuteceacutedents En revanche elle ne peut apparaicirctre que si lrsquoespace de noms qursquoelle

mentionne existe deacutejagrave en pratique cela signifie que cette instruction sera placeacutee apregraves

lrsquoinclusion des fichiers en-tecircte

9 - Le type bool57

Ces quelques consideacuterations seront suffisantes pour lrsquoinstant Les espaces de noms seront

eacutetudieacutes en deacutetail au chapitre 24

Remarque

Certains environnements ne respectent pas encore la norme sur le plan des espaces de

noms Lrsquoinstruction using peut alors ecirctre indisponible En geacuteneacuteral dans de tels environne-

ments les fichiers en-tecircte sont encore suffixeacutes par h Certains environnements permettent

drsquoutiliser indiffeacuteremment ltiostreamgt avec using ou ltiostreamhgt sans using1

9 Le type boolCe type est tout naturellement formeacute de deux valeurs noteacutees true et false En theacuteorie les

reacutesultats des comparaisons ou des combinaisons logiques doivent ecirctre de ce type Toutefois

il existe des conversions implicites

bull de bool en numeacuterique true devenant 1 et false devenant 0

bull de numeacuterique (y compris flottant) en bool toute valeur non nulle devenant true et zeacutero de-

venant false

Dans ces conditions tout se passe finalement comme si bool eacutetait un type eacutenumeacutereacute ainsi

deacutefini

typedef enum false=0 true bool

En deacutefinitive ce type bool sert surtout agrave apporter plus de clarteacute aux programmes sans remet-

tre en cause quoi que ce soit

10 Les nouveaux opeacuterateurs de castEn C++ comme en C il est possible de reacutealiser des conversions explicites agrave laide dun opeacutera-

teur de cast Les conversions accepteacutees comportent naturellement toutes les conversions

implicites leacutegales auxquelles sajoutent quelques autres pouvant ecirctre deacutegradantes ou deacutepen-

dantes de limpleacutementation

La norme ANSI de C++ a conserveacute ces possibiliteacutes tout en proposant de nouveaux opeacutera-

teurs de cast plus eacutevocateurs de la nature de la conversion et de sa portabiliteacute eacuteventuelle Ils

sont formeacutes comme les opeacuterateurs classiques agrave laide du type souhaiteacute compleacuteteacute dun mot cleacute

preacutecisant le type de conversion

bull const_cast pour ajouter ou supprimer agrave un type lun des modificateurs const ou volatile (les

types de deacutepart et drsquoarriver ne devant diffeacuterer que par ces modificateurs)

1 Une telle instruction using provoquera une erreur si aucun fichier en-tecircte se reacutefeacuterant agrave lrsquoespace de noms std nrsquoa eacuteteacute

inclus Ce sera notamment le cas si on se limite agrave ltiostreamhgt

Les speacutecificiteacutes du C++CHAPITRE 4

58

bull reinterpret_cast pour les conversions dont le reacutesultat deacutepend de limpleacutementation typique-

ment il sagit des conversions dentier vers pointeur et de pointeur vers entier

bull static_cast pour les conversions indeacutependantes de limpleacutementation En fait les conversions

de pointeur vers pointeur entrent dans cette cateacutegorie malgreacute les diffeacuterences qui peuvent ap-

paraicirctre agrave cause des contraintes dalignement propres agrave chaque impleacutementation

Voici quelques exemples commenteacutes

include ltiostreamgtusing namespace std

main () int n = 12 const int ad1 = ampn int ad2 ad2 = (int ) ad1 ancienne forme conseilleacutee (ad2 = ad1 serait rejeteacutee) ad2 = const_cast ltint gt (ad1) forme ANSI conseilleacutee ad1 = ad2 leacutegale ad1 = (const int ) ad2 forme ancienne conseilleacutee ad1 = const_cast ltconst int gt (ad2) forme ANSI conseilleacutee

const int p = 12 const int const ad3 = ampp int ad4

ad4 = (int ) ad3 ancienne forme conseilleacutee (ad4 = ad3 serait rejeteacutee) ad4 = const_cast ltint gt (ad3) forme ANSI conseilleacutee

Exemples dutilisation de lopeacuterateur const_cast ltgt

include ltiostreamgtusing namespace std

main () long n int adi adi = (int ) n ancienne forme conseilleacutee (adi = n serait rejeteacutee) adi = reinterpret_cast ltint gt (n) forme ANSI conseilleacutee

n = (long) adi ancienne forme conseilleacutee (n = adi serait rejeteacutee)

10 - Les nouveaux opeacuterateurs de cast59

n = reinterpret_cast ltlonggt (adi) forme ANSI conseilleacutee

int p p = n accepteacutee p = (int) n ancienne forme conseilleacutee p = static_cast ltintgt (n) forme ANSI conseilleacutee

Exemples dutilisation des opeacuterateurs reinterpret_cast ltgt et static_cast

Remarque

Ces nouveaux opeacuterateurs napportent aucune possibiliteacute de conversion suppleacutementaire Il

nen ira pas de mecircme de lopeacuterateur dynamic_cast eacutetudieacute au chapitre 15

5

Classes et objets

Avec ce chapitre nous abordons veacuteritablement les possibiliteacutes de POO de C++ Comme

nous lavons dit dans le premier chapitre celles-ci reposent entiegraverement sur le concept de

classe Une classe est la geacuteneacuteralisation de la notion de type deacutefini par lutilisateur1 dans

lequel se trouvent associeacutees agrave la fois des donneacutees (membres donneacutees) et des meacutethodes (fonc-

tions membres) En POO pure les donneacutees sont encapsuleacutees et leur accegraves ne peut se faire

que par le biais des meacutethodes C++ vous autorise agrave nrsquoencapsuler quune partie des donneacutees

dune classe (cette deacutemarche reste cependant fortement deacuteconseilleacutee) Il existe mecircme un type

particulier correspondant agrave la geacuteneacuteralisation du type structure du C dans lequel sont effecti-

vement associeacutees des donneacutees et des meacutethodes mais sans aucune encapsulation

En pratique ce nouveau type structure du C++ sera rarement employeacute sous cette forme geacuteneacute-

raliseacutee En revanche sur le plan conceptuel il correspond agrave un cas particulier de la classe il

sagit en effet dune classe dans laquelle aucune donneacutee nest encapsuleacutee Cest pour cette rai-

son que nous commencerons par preacutesenter le type structure de C++ (mot cleacute struct) ce qui

nous permettra dans un premier temps de nous limiter agrave la faccedilon de mettre en œuvre lasso-

ciation des donneacutees et des meacutethodes Nous ne verrons qursquoensuite comment sexprime lencap-

sulation au sein dune classe (mot cleacute class)

Comme une classe (ou une structure) nest quun simple type deacutefini par lutilisateur les objets

possegravedent les mecircmes caracteacuteristiques que les variables ordinaires en particulier en ce qui

concerne leurs diffeacuterentes classes dallocation (statique automatique dynamique) Cepen-

dant pour rester simple et nous consacrer au concept de classe nous ne consideacutererons dans

1 En C les types deacutefinis par lutilisateur sont les structures les unions et les eacutenumeacuterations

Classes et objetsCHAPITRE 5

62

ce chapitre que des objets automatiques (deacuteclareacutes au sein dune fonction quelconque) ce qui

correspond au cas le plus naturel Ce nest qursquoau chapitre 7 que nous aborderons les autres

classes dallocation des objets

Par ailleurs nous introduirons ici les notions tregraves importantes de constructeur et de destruc-

teur (il ny a guegravere dobjets inteacuteressants qui ny fassent pas appel) Lagrave encore compte tenu de

la richesse de cette notion et de son interfeacuterence avec dautres (comme les classes dalloca-

tion) il vous faudra attendre la fin du chapitre 7 pour en connaicirctre toutes les possibiliteacutes

Nous eacutetudierons ensuite ce qursquoon nomme les membres donneacutees statiques ainsi que la

maniegravere de les intialiser Enfin ce premier des trois chapitres consacreacutes aux classes nous per-

mettra de voir comment exploiter une classe en C++ en recourant aux possibiliteacutes de compi-

lation seacutepareacutee

1 Les structures en C++

11 Rappel les structures en CEn C une deacuteclaration telle que

struct point int x int y

deacutefinit un type structure nommeacute point (on dit aussi un modegravele de structure nommeacute point ou

parfois par abus de langage la structure point1) Quant agrave x et y on dit que ce sont des champs

ou des membres2 de la structure point

On deacuteclare ensuite des variables du type point par des instructions telles que

struct point a b

Celle-ci reacuteserve lemplacement pour deux structures nommeacutees a et b de type point Laccegraves

aux membres (champs) de a ou de b se fait agrave laide de lopeacuterateur point () par exemple ay

deacutesigne le membre y de la structure a

En C++ nous allons pouvoir dans une structure associer aux donneacutees constitueacutees par ses

membres des meacutethodes quon nommera fonctions membres Rappelons que puisque les

donneacutees ne sont pas encapsuleacutees dans la structure une telle association est relativement arti-

ficielle et son principal inteacuterecirct est de preacuteparer agrave la notion de classe

1 Dans ce cas il y a ambiguiumlteacute car le mecircme mot structure deacutesignera agrave la fois un type et des objets dun type structure

Comme le contexte permet geacuteneacuteralement de trancher nous utiliserons souvent ce terme

2 Cest plutocirct ce dernier terme que lon emploiera en C++

1 - Les structures en C++63

12 Deacuteclaration dune structure comportant des fonctions membres

Supposons que nous souhaitions associer agrave la structure point preacuteceacutedente trois fonctions

bull initialise pour attribuer des valeurs aux coordonneacutees dun point

bull deplace pour modifier les coordonneacutees dun point

bull affiche pour afficher un point ici nous nous contenterons par souci de simpliciteacute daffi-

cher les coordonneacutees du point

Voici comment nous pourrions deacuteclarer notre structure point

------------ Deacuteclaration du type point ------------- struct point deacuteclaration classique des donneacutees int x int y deacuteclaration des fonctions membre (meacutethodes) void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration dune structure comportant des meacutethodes

Outre la deacuteclaration classique des donneacutees1 apparaissent les deacuteclarations (en-tecirctes) de nos

trois fonctions Notez bien que la deacutefinition de ces fonctions ne figure pas agrave ce niveau de sim-

ple deacuteclaration elle sera reacutealiseacutee par ailleurs comme nous le verrons un peu plus loin

Ici nous avons preacutevu que la fonction membre initialise recevra en arguments deux valeurs de

type int A ce niveau rien nrsquoindique dit lusage qui sera fait de ces deux valeurs Ici bien

entendu nous avons eacutecrit len-tecircte de initialise en ayant agrave lesprit lideacutee quelle affecterait aux

membres x et y les valeurs reccedilues en arguments Les mecircmes remarques srsquoappliquent aux deux

autres fonctions membres

Vous vous attendiez peut-ecirctre agrave trouver pour chaque fonction membre un argument suppleacute-

mentaire preacutecisant la structure (variable) sur laquelle elle doit opeacuterer2 Nous verrons com-

ment cette information sera automatiquement fournie agrave la fonction membre lors de son appel

1 On parle parfois de variables par analogie avec les fonctions membres

2 Pour quune telle information ne soit pas neacutecessaire il faudrait dupliquer les fonctions membres en autant

dexemplaires quil y a de structures de type point ce qui serait particuliegraverement inefficace

Classes et objetsCHAPITRE 5

64

13 Deacutefinition des fonctions membresElle se fait par une deacutefinition (presque) classique de fonction Voici ce que pourrait ecirctre la

deacutefinition de initialise

void pointinitialise (int abs int ord)

x = abs

y = ord

Dans len-tecircte le nom de la fonction est

pointinitialise

Le symbole correspond agrave ce que lon nomme lopeacuterateur de reacutesolution de porteacutee lequel

sert agrave modifier la porteacutee drsquoun identificateur Ici il signifie que lidentificateur initialise con-

cerneacute est celui deacutefini dans point En labsence de ce preacutefixe (point) nous deacutefinirions

effectivement une fonction nommeacutee initialise mais celle-ci ne serait plus associeacutee agrave point il

sagirait dune fonction ordinaire nommeacutee initialise et non plus de la fonction membre ini-

tialise de la structure point

Si nous examinons maintenant le corps de la fonction initialise nous trouvons une

affectation

x = abs

Le symbole abs deacutesigne classiquement la valeur reccedilue en premier argument Mais x quant agrave

lui nest ni un argument ni une variable locale En fait x deacutesigne le membre x correspondant

au type point (cette association eacutetant reacutealiseacutee par le point de len-tecircte) Quelle sera preacuteciseacute-

ment la structure1 concerneacutee Lagrave encore nous verrons comment cette information sera trans-

mise automatiquement agrave la fonction initialise lors de son appel

Nous ninsistons pas sur la deacutefinition des deux autres fonctions membres vous trouverez ci-

dessous lensemble des deacutefinitions des trois fonctions

----- Deacutefinition des fonctions membres du type point ----

include ltiostreamgt

using namespace std

void pointinitialise (int abs int ord)

x = abs y = ord

void pointdeplace (int dx int dy)

x += dx y += dy

1 Ici le terme structure est bien synonyme de variable de type structure

1 - Les structures en C++65

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

Deacutefinition des fonctions membres

Les instructions ci-dessus ne peuvent pas ecirctre compileacutees seules Elles neacutecessitent lrsquoincorpora-

tion des instructions de deacuteclaration correspondantes preacutesenteacutees au paragraphe 12 Celles-ci

peuvent figurer dans le mecircme fichier ou mieux faire lrsquoobjet drsquoun fichier en-tecircte seacutepareacute

14 Utilisation dune structure comportant des fonctions membresDisposant du type point tel quil vient drsquoecirctre deacuteclareacute au paragraphe 12 et deacutefini au paragra-

phe 13 nous pouvons deacuteclarer autant de structures de ce type que nous le souhaitons Par

exemple

point a b 1

deacuteclare deux structures nommeacutees a et b chacune posseacutedant des membres x et y et disposant

des trois meacutethodes initialise deplace et affiche A ce propos nous pouvons dores et deacutejagrave

remarquer que si chaque structure dispose en propre de chacun de ses membres il nen va pas

de mecircme des fonctions membres celles-ci ne sont geacuteneacutereacutees2 quune seule fois (le contraire

conduirait manifestement agrave un gaspillage de meacutemoire )

Laccegraves aux membres x et y de nos structures a et b pourrait se deacuterouler comme en C ainsi

pourrions-nous eacutecrire

ax = 5

Ce faisant nous acceacutederions directement aux donneacutees sans passer par lintermeacutediaire des

meacutethodes Certes nous ne respecterions pas le principe dencapsulation mais dans ce cas

preacutecis (de structure et pas encore de classe) ce serait accepteacute en C++3

On procegravede de la mecircme faccedilon pour lappel dune fonction membre Ainsi

ainitialise (52)

signifie appeler la fonction membre initialise pour la structure a en lui transmettant en

arguments les valeurs 5 et 2 Si lon fait abstraction du preacutefixe a cet appel est analogue agrave un

appel classique de fonction Bien entendu cest justement ce preacutefixe qui va preacuteciser agrave la fonc-

tion membre quelle est la structure sur laquelle elle doit opeacuterer Ainsi linstruction

x = abs

1 Ou struct point a b le mot struct est facultatif en C++

2 Exception faite des fonctions en ligne

3 Ici justement les fonctions membres preacutevues pour notre structure point permettent de respecter le principe

dencapsulation

Classes et objetsCHAPITRE 5

66

de pointinitialise placera dans le champ x de la structure a la valeur reccedilue pour abs (cest-agrave-

dire 5)

Remarques

1 Un appel tel que ainitialise (52) pourrait ecirctre remplaceacute par

ax = 5 ay = 2

Nous verrons preacuteciseacutement quil nen ira plus de mecircme dans le cas dune (vraie) classe

pour peu quon y ait convenablement encapsuleacute les donneacutees

2 En jargon POO on dit eacutegalement que ainitialise (5 2) constitue lenvoi dun mes-

sage (initialise accompagneacute des informations 5 et 2) agrave lobjet a

15 Exemple reacutecapitulatifVoici un programme reprenant la deacuteclaration du type point la deacutefinition de ses fonctions

membres et un exemple drsquoutilisation dans la fonction main

include ltiostreamgtusing namespace std ------------ Deacuteclaration du type point ------------- struct point deacuteclaration classique des donneacutees int x int y deacuteclaration des fonctions membres (meacutethodes) void initialise (int int) void deplace (int int) void affiche ()

----- Deacutefinition des fonctions membres du type point ---- void pointinitialise (int abs int ord) x = abs y = ord void pointdeplace (int dx int dy) x += dx y += dy void pointaffiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n main() point a b ainitialise (5 2) aaffiche () adeplace (-2 4) aaffiche () binitialise (1-1) baffiche ()

2 - Notion de classe67

Je suis en 5 2

Je suis en 3 6

Je suis en 1 -1

Exemple de deacutefinition et dutilisation du type point

Remarques

1 La syntaxe mecircme de lappel dune fonction membre fait que celle-ci reccediloit obligatoire-

ment un argument implicite du type de la structure correspondante Une fonction membre

ne peut pas ecirctre appeleacutee comme une fonction ordinaire Par exemple cette instruction

initialise (31)

sera rejeteacutee agrave la compilation (agrave moins quil nexiste par ailleurs une fonction ordinaire

nommeacutee initialise)

2 Dans la deacuteclaration dune structure il est permis (mais geacuteneacuteralement peu conseilleacute)

dintroduire les donneacutees et les fonctions dans un ordre quelconque (nous avons systeacute-

matiquement placeacute les donneacutees avant les fonctions)

3 Dans notre exemple de programme complet nous avons introduit

ndash la deacuteclaration du type point

ndash la deacutefinition des fonctions membres

ndash la fonction (main) utilisant le type point

Mais bien entendu il serait possible de compiler seacutepareacutement le type point crsquoest drsquoailleurs

ainsi que lrsquoon pourra reacuteutiliser un composant logiciel Nous y reviendrons au

paragraphe 6

4 Il reste possible de deacuteclarer des structures geacuteneacuteraliseacutees anonymes mais cela est tregraves peu

utiliseacute

2 Notion de classeComme nous lavons deacutejagrave dit en C++ la structure est un cas particulier de la classe Plus preacute-

ciseacutement une classe sera une structure dans laquelle seulement certains membres etou fonc-

tions membres seront publics cest-agrave-dire accessibles de lexteacuterieur les autres membres

eacutetant dits priveacutes

La deacuteclaration dune classe est voisine de celle dune structure En effet il suffit

bull de remplacer le mot cleacute struct par le mot cleacute class

Classes et objetsCHAPITRE 5

68

bull de preacuteciser quels sont les membres publics (fonctions ou donneacutees) et les membres priveacutes en

utilisant les mots cleacutes public et private

Par exemple faisons de notre preacuteceacutedente structure point une classe dans laquelle tous les

membres donneacutees sont priveacutes et toutes les fonctions membres sont publiques Sa deacuteclaration

serait simplement la suivante

------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes private facultatif (voir remarque 4) int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration dune classe

Ici les membres nommeacutes x et y sont priveacutes tandis que les fonctions membres nommeacutees ini-

tialise deplace et affiche sont publiques

En ce qui concerne la deacutefinition des fonctions membres dune classe elle se fait exactement

de la mecircme maniegravere que celle des fonctions membres dune structure (quil sagisse de fonc-

tions publiques ou priveacutees) En particulier ces fonctions membres ont accegraves agrave lensemble des

membres (publics ou priveacutes) de la classe

Lutilisation dune classe se fait eacutegalement comme celle dune structure A titre indicatif voici

ce que devient le programme du paragraphe 15 lorsque lon remplace la structure point par la

classe point telle que nous venons de la deacutefinir

include ltiostreamgtusing namespace std ------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes private int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

2 - Notion de classe69

----- Deacutefinition des fonctions membres de la classe point ----

void pointinitialise (int abs int ord)

x = abs y = ord

void pointdeplace (int dx int dy)

x = x + dx y = y + dy

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

-------- Utilisation de la classe point --------

main()

point a b

ainitialise (5 2) aaffiche ()

adeplace (-2 4) aaffiche ()

binitialise (1-1) baffiche ()

Exemple de deacutefinition et dutilisation dune classe (point)

Remarques

1 Dans le jargon de la POO on dit que a et b sont des instances de la classe point ou

encore que ce sont des objets de type point crsquoest geacuteneacuteralement ce dernier terme que

nous utiliserons

2 Dans notre exemple tous les membres donneacutees de point sont priveacutes ce qui correspond

agrave une encapsulation complegravete des donneacutees Ainsi une tentative dutilisation directe (ici

au sein de la fonction main) du membre a

ax = 5

conduirait agrave un diagnostic de compilation (bien entendu cette instruction serait accep-

teacutee si nous avions fait de x un membre public)

En geacuteneacuteral on cherchera agrave respecter le principe dencapsulation des donneacutees quitte agrave

preacutevoir des fonctions membres approprieacutees pour y acceacuteder

3 Dans notre exemple toutes les fonctions membres eacutetaient publiques Il est tout agrave fait

possible den rendre certaines priveacutees Dans ce cas de telles fonctions ne seront plus

accessibles de lrsquoexteacuterieur de la classe Elles ne pourront ecirctre appeleacutees que par dautres

fonctions membres

Classes et objetsCHAPITRE 5

70

4 Les mots cleacutes public et private peuvent apparaicirctre agrave plusieurs reprises dans la deacutefinition

dune classe comme dans cet exemple

class X private public private

Si aucun de ces deux mots napparaicirct au deacutebut de la deacutefinition tout se passe comme si

private y avait eacuteteacute placeacute Cest pourquoi la preacutesence de ce mot neacutetait pas indispensable

dans la deacutefinition de notre classe point

Si aucun de ces deux mots napparaicirct dans la deacutefinition dune classe tous ses membres

seront priveacutes donc inaccessibles Cela sera rarement utile

5 Si lon rend publics tous les membres dune classe on obtient leacutequivalent dune struc-

ture Ainsi ces deux deacuteclarations deacutefinissent le mecircme type point

struct point class point int x public int y int x void initialise () int y void initialise ()

6 Par la suite en lrsquoabsence de preacutecisions suppleacutementaires nous utiliserons le mot classe

pour deacutesigner indiffeacuteremment une vraie classe (class) ou une structure (struct) voire

une union (union) dont nous parlerons un peu plus loin1 De mecircme nous utiliserons le

mot objet pour deacutesigner des instances de ces diffeacuterents types

7 En toute rigueur il existe un troisiegraveme mot protected (proteacutegeacute) qui sutilise de la mecircme

maniegravere que les deux autres il sert agrave deacutefinir un statut intermeacutediaire entre public et

priveacute lequel nintervient que dans le cas de classes deacuteriveacutees Nous en reparlerons au

chapitre 13

8 On peut deacutefinir des classes anonymes comme on pouvait deacutefinir des structures anony-

mes

3 Affectation drsquoobjetsEn C il est possible daffecter agrave une structure la valeur dune autre structure de mecircme type

Ainsi avec les deacuteclarations suivantes

1 La situation de loin la plus reacutepandue restant celle du type class

3 - Affectation drsquoobjets71

struct point int x int y struct point a b

vous pouvez tout agrave fait eacutecrire

a = b

Cette instruction recopie lensemble des valeurs des champs de b dans ceux de a Elle joue le

mecircme rocircle que

ax = bx ay = by

Comme on peut srsquoy attendre cette possibiliteacute srsquoeacutetend aux structures geacuteneacuteraliseacutees (avec fonc-

tions membres) preacutesenteacutees preacuteceacutedemment avec la mecircme signification que pour les structures

usuelles Mais elle srsquoeacutetend aussi aux (vrais) objets de mecircme type Elle correspond tout natu-

rellement agrave une recopie des valeurs des membres donneacutees1 que ceux-ci soient publics ou

non Ainsi avec ces deacuteclarations (notez quici nous avons preacutevu artificiellement x priveacute et y

public)

class point int x public int y point a b

linstruction

b = a

provoquera la recopie des valeurs des membres x et y de a dans les membres correspondants

de b

Contrairement agrave ce qui a eacuteteacute dit pour les structures il nest plus possible ici de remplacer cette

instruction par

bx = ax by = ay

En effet si la deuxiegraveme affectation est leacutegale puisque ici y est public la premiegravere ne lest pas

car x est priveacute2 On notera bien que

1 Les fonctions membres nont aucune raison drsquoecirctre concerneacutees

2 Sauf si laffectation bx = ax eacutetait eacutecrite au sein dune fonction membre de la classe point

Lrsquoaffectation a = b est toujours leacutegale quel que soit le statut (public ou priveacute) des membres donneacutees On peut consideacuterer qursquoelle ne viole pas le principe drsquoencapsu-lation dans la mesure ougrave les donneacutees priveacutees de b (les copies de celles de a apregraves affectation) restent toujours inaccessibles de maniegravere directe

Classes et objetsCHAPITRE 5

72

Remarque

Le rocircle de lopeacuterateur = tel que nous venons de le deacutefinir (recopie des membres donneacutees)

peut paraicirctre naturel ici En fait il ne lest que pour des cas simples Nous verrons des cir-

constances ougrave cette banale recopie saveacuterera insuffisante Ce sera notamment le cas degraves

quun objet comportera des pointeurs sur des emplacements dynamiques la recopie en

question ne concernera pas cette partie dynamique de lobjet elle sera superficielle

Nous reviendrons ulteacuterieurement sur ce point fondamental qui ne trouvera de solution

satisfaisante que dans la surdeacutefinition (pour la classe concerneacutee) de lopeacuterateur = (ou

eacuteventuellement dans lrsquointerdiction de son utilisation)

En Java

En C++ on peut dire que la seacutemantique drsquoaffectation drsquoobjets correspond agrave une recopie

de valeur En Java il srsquoagit simplement drsquoune recopie de reacutefeacuterence apregraves affectation on

se retrouve alors en preacutesence de deux reacutefeacuterences sur un mecircme objet

4 Notions de constructeur et de destructeur

41 IntroductionA priori les objets1 suivent les regravegles habituelles concernant leur initialisation par deacutefaut

seuls les objets statiques voient leurs donneacutees initialiseacutees agrave zeacutero En geacuteneacuteral il est donc

neacutecessaire de faire appel agrave une fonction membre pour attribuer des valeurs aux donneacutees dun

objet Cest ce que nous avons fait pour notre type point avec la fonction initialise

Une telle deacutemarche oblige toutefois agrave compter sur lutilisateur de lobjet pour effectuer lappel

voulu au bon moment En outre si le risque ne porte ici que sur des valeurs non deacutefinies il

nen va plus de mecircme dans le cas ougrave avant mecircme drsquoecirctre utiliseacute un objet doit effectuer un cer-

tain nombre drsquoopeacuterations neacutecessaires agrave son bon fonctionnement par exemple allocation

dynamique de meacutemoire2 veacuterification drsquoexistence de fichier ou ouverture connexion agrave un site

Web Labsence de proceacutedure drsquoinitialisation peut alors devenir catastrophique

C++ offre un meacutecanisme tregraves performant pour traiter ces problegravemes le constructeur Il

sagit dune fonction membre (deacutefinie comme les autres fonctions membres) qui sera appeleacutee

automatiquement agrave chaque creacuteation dun objet Ceci aura lieu quelle que soit la classe dallo-

cation de lobjet statique automatique ou dynamique Notez que les objets automatiques

1 Au sens large du terme

2 Ne confondez pas un objet dynamique avec un objet (par exemple automatique) qui salloue dynamiquement de la

meacutemoire Une situation de ce type sera eacutetudieacutee au prochain chapitre

4 - Notions de constructeur et de destructeur73

auxquels nous nous limitons ici sont creacuteeacutes par une deacuteclaration Ceux de classe dynamique

seront creacuteeacutes par new (nous y reviendrons au chapitre 7)

Un objet pourra aussi posseacuteder un destructeur crsquoest-agrave-dire une fonction membre appeleacutee

automatiquement au moment de la destruction de lobjet Dans le cas des objets automati-

ques la destruction de lobjet a lieu lorsque lon quitte le bloc ou la fonction ougrave il a eacuteteacute

deacuteclareacute

Par convention le constructeur se reconnaicirct agrave ce quil porte le mecircme nom que la classe

Quant au destructeur il porte le mecircme nom que la classe preacuteceacutedeacute drsquoun tilde (~)

42 Exemple de classe comportant un constructeurConsideacuterons la classe point preacuteceacutedente et transformons simplement notre fonction membre

initialise en un constructeur en la renommant point (dans sa deacuteclaration et dans sa deacutefinition)

La deacuteclaration de notre nouvelle classe point se preacutesente alors ainsi

class point deacuteclaration des membres priveacutes int x int y public deacuteclaration des membres publics point (int int) constructeur void deplace (int int) void affiche ()

Deacuteclaration drsquoune classe (point) munie dun constructeur

Comment utiliser cette classe A priori vous pourriez penser que la deacuteclaration suivante

convient toujours

point a

En fait agrave partir du moment ougrave un constructeur est deacutefini il doit pouvoir ecirctre appeleacute (automa-

tiquement) lors de la creacuteation de lobjet a Ici notre constructeur a besoin de deux arguments

Ceux-ci doivent obligatoirement ecirctre fournis dans notre deacuteclaration par exemple

point a(13)

Cette contrainte est en fait un excellent garde-fou

A titre dexemple voici comment pourrait ecirctre adapteacute le programme du paragraphe 2 pour

quil utilise maintenant notre nouvelle classe point

Agrave partir du moment ougrave une classe possegravede un constructeur il nrsquoest plus possible de creacuteer un objet sans fournir les arguments requis par son constructeur (sauf si ce dernier ne possegravede aucun argument )

Classes et objetsCHAPITRE 5

74

include ltiostreamgtusing namespace std ------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes int x int y deacuteclaration des membres publics public point (int int) constructeur void deplace (int int) void affiche () ----- Deacutefinition des fonctions membre de la classe point ---- pointpoint (int abs int ord) x = abs y = ord void pointdeplace (int dx int dy) x = x + dx y = y + dy void pointaffiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n -------- Utilisation de la classe point -------- main() point a(52) aaffiche () adeplace (-2 4) aaffiche () point b(1-1) baffiche ()

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

Exemple dutilisation dune classe (point) munie dun constructeur

Remarques

1 Supposons que lrsquoon deacutefinisse une classe point disposant drsquoun constructeur sans argument

Dans ce cas la deacuteclaration drsquoobjets de type point continuera de srsquoeacutecrire de la mecircme

maniegravere que si la classe ne disposait pas de constructeur

point a deacuteclaration utilisable avec un constructeur sans argument

4 - Notions de constructeur et de destructeur75

Certes la tentation est grande drsquoeacutecrire par analogie avec lrsquoutilisation drsquoun constructeur

comportant des arguments

point a() incorrect

En fait cela repreacutesenterait la deacuteclaration drsquoune fonction nommeacutee a ne recevant aucun

argument et renvoyant un reacutesultat de type point En soi ce ne serait pas une erreur

mais il est eacutevident que toute tentative drsquoutiliser le symbole a comme un objet conduirait

agrave une erreur

2 Nous verrons dans le prochain chapitre que comme toute fonction (membre ou ordi-

naire) un constructeur peut ecirctre surdeacutefini ou posseacuteder des arguments par deacutefaut

3 Lorsqursquoune classe ne deacutefinit aucun constructeur tout se passe en fait comme si elle dis-

posait drsquoun constructeur par deacutefaut ne faisant rien On peut alors dire que lorsqursquoune

classe nrsquoa pas deacutefini de constructeur la creacuteation des objets correspondants se fait en

utilissant ce constructeur par deacutefaut Nous retrouverons drsquoailleurs le mecircme pheacutenomegravene

dans le cas du constructeur de recopie avec cette diffeacuterence toutefois que le construc-

teur par deacutefaut aura alors une action preacutecise

43 Construction et destruction des objetsNous vous proposons ci-dessous un petit programme mettant en eacutevidence les moments ougrave

sont appeleacutes respectivement le constructeur et le destructeur dune classe Nous y deacutefinissons

une classe nommeacutee test ne comportant que ces deux fonctions membres celles-ci affichent

un message nous fournissant ainsi une trace de leur appel En outre le membre donneacutee num

initialiseacute par le constructeur nous permet drsquoidentifier lobjet concerneacute (dans la mesure ougrave

nous nous sommes arrangeacute pour quaucun des objets creacuteeacutes ne contienne la mecircme valeur)

Nous creacuteons des objets automatiques1 de type test agrave deux endroits diffeacuterents dans la fonc-

tion main dune part dans une fonction fct appeleacutee par main dautre part

include ltiostreamgtusing namespace std class test public int num test (int) deacuteclaration constructeur ~test () deacuteclaration destructeur testtest (int n) deacutefinition constructeur num = n cout ltlt ++ Appel constructeur - num = ltlt num ltlt n

1 Rappelons quici nous nous limitons agrave ce cas

Classes et objetsCHAPITRE 5

76

test~test () deacutefinition destructeur cout ltlt -- Appel destructeur - num = ltlt num ltlt n main() void fct (int) test a(1) for (int i=1 ilt=2 i++) fct(i) void fct (int p) test x(2p) notez lexpression (non constante) 2p

++ Appel constructeur - num = 1++ Appel constructeur - num = 2-- Appel destructeur - num = 2++ Appel constructeur - num = 4-- Appel destructeur - num = 4-- Appel destructeur - num = 1

Construction et destruction des objets

44 Rocircles du constructeur et du destructeurDans les exemples preacuteceacutedents le rocircle du constructeur se limitait agrave une initialisation de lobjet

agrave laide des valeurs quil avait reccedilues en arguments Mais le travail reacutealiseacute par le constructeur

peut ecirctre beaucoup plus eacutelaboreacute Voici un programme exploitant une classe nommeacutee hasard

dans laquelle le constructeur fabrique dix valeurs entiegraveres aleacuteatoires quil range dans le mem-

bre donneacutee val (ces valeurs sont comprises entre zeacutero et la valeur qui lui est fournie en

argument)

include ltiostreamgtinclude ltcstdlibgt pour la fonction rand using namespace std class hasard int val[10] public hasard (int) void affiche () hasardhasard (int max) constructeur il tire 10 valeurs au hasard rappel rand fournit un entier entre 0 et RAND_MAX int i for (i=0 ilt10 i++) val[i] = double (rand()) RAND_MAX max void hasardaffiche () pour afficher les 10 valeurs int i for (i=0 ilt10 i++) cout ltlt val[i] ltlt cout ltlt n

4 - Notions de constructeur et de destructeur77

main() hasard suite1 (5) suite1affiche () hasard suite2 (12) suite2affiche ()

0 2 0 4 2 2 1 4 4 32 10 8 6 3 0 1 4 1 1

Un constructeur de valeurs aleacuteatoires

En pratique on preacutefeacuterera drsquoailleurs disposer dune classe dans laquelle le nombre de valeurs

(ici fixeacute agrave dix) pourra ecirctre fourni en argument du constructeur Dans ce cas il est preacutefeacuterable

que lespace (variable) soit alloueacute dynamiquement au lieu decirctre surdimensionneacute Il est alors

tout naturel de faire effectuer cette allocation dynamique par le constructeur lui-mecircme Les

donneacutees de la classe hasard se limiteront ainsi agrave

class hasard int nbval nombre de valeurs int val pointeur sur un tableau de valeurs

Bien sucircr il faudra preacutevoir que le constructeur reccediloive en argument outre la valeur maximale

le nombre de valeurs souhaiteacutees

Par ailleurs agrave partir du moment ougrave un emplacement a eacuteteacute alloueacute dynamiquement il faut se

soucier de sa libeacuteration lorsquil sera devenu inutile Lagrave encore il paraicirct tout naturel de con-

fier ce travail au destructeur de la classe

Voici comment nous pourrions adapter en ce sens lrsquoexemple preacuteceacutedent

include ltiostreamgtinclude ltcstdlibgt pour la fonction rand using namespace std class hasard int nbval nombre de valeurs int val pointeur sur les valeurs public hasard (int int) constructeur ~hasard () destructeur void affiche () hasardhasard (int nb int max) int i val = new int [nbval = nb] for (i=0 iltnb i++) val[i] = double (rand()) RAND_MAX max

Classes et objetsCHAPITRE 5

78

hasard~hasard ()

delete val

void hasardaffiche () pour afficher les nbavl valeurs

int i

for (i=0 iltnbval i++) cout ltlt val[i] ltlt

cout ltlt n

main()

hasard suite1 (10 5) 10 valeurs entre 0 et 5

suite1affiche ()

hasard suite2 (6 12) 6 valeurs entre 0 et 12

suite2affiche ()

0 2 0 4 2 2 1 4 4 3

2 10 8 6 3 0

Exemple de classe dont le constructeur effectue une allocation dynamique de meacutemoire

Dans le constructeur linstruction

val = new [nbval = nb]

joue le mecircme rocircle que

nbval = nb

val = new [nbval]

Remarques

1 Ne confondez pas une allocation dynamique effectueacutee au sein dune fonction membre

dun objet (souvent le constructeur) avec une allocation dynamique dun objet dont nous

parlerons plus tard

2 Lorsquun constructeur se contente dattribuer des valeurs initiales aux donneacutees dun

objet le destructeur est rarement indispensable En revanche il le devient degraves que

comme dans notre exemple lobjet est ameneacute (par le biais de son constructeur ou

dautres fonctions membres) agrave allouer dynamiquement de la meacutemoire

3 Comme nous lavons deacutejagrave mentionneacute degraves quune classe contient comme dans notre

dernier exemple des pointeurs sur des emplacements alloueacutes dynamiquement laffecta-

tion entre objets de mecircme type ne concerne pas ces parties dynamiques geacuteneacuteralement

cela pose problegraveme et la solution passe par la surdeacutefinition de lopeacuterateur = Autrement

dit la classe hasard deacutefinie dans le dernier exemple ne permettrait pas de traiter correc-

tement laffectation dobjets de ce type

4 - Notions de constructeur et de destructeur79

45 Quelques regraveglesUn constructeur peut comporter un nombre quelconque drsquoarguments eacuteventuellement aucun

Par deacutefinition un constructeur ne renvoie pas de valeur aucun type ne peut figurer devant

son nom (dans ce cas preacutecis la preacutesence de void est une erreur)

Par deacutefinition un destructeur ne peut pas disposer drsquoarguments et ne renvoie pas de valeur

Lagrave encore aucun type ne peut figurer devant son nom (et la preacutesence de void est une erreur)

En theacuteorie constructeurs et destructeurs peuvent ecirctre publics ou priveacutes En pratique agrave moins

drsquoavoir de bonnes raisons de faire le contraire il vaut mieux les rendre publics

On notera que si un destructeur est priveacute il ne pourra plus ecirctre appeleacute directement ce qui

nrsquoest geacuteneacuteralement pas grave dans la mesure ougrave cela est rarement utile

En revanche la privatisation drsquoun constructeur a de lourdes conseacutequences puisqursquoil ne sera

plus utilisable sauf par des fonctions membres de la classe elle-mecircme

Informations compleacutementaires

Voici quelques circonstances ougrave un constructeur priveacute peut se justifier

ndash la classe concerneacutee ne sera pas utiliseacutee telle quelle car elle est destineacutee agrave donner nais-

sance par heacuteritage agrave des classes deacuteriveacutees qui quant agrave elles pourront disposer drsquoun

constructeur public (nous reviendrons plus tard sur cette situation dite de classe abs-

traite)

ndash la classe dispose drsquoautres constructeurs (nous verrons bientocirct qursquoun constructeur peut

ecirctre surdeacutefini) dont au moins un est public

ndash on cherche agrave mettre en œuvre un motif de conception1 particulier le singleton il

srsquoagit de faire en sorte qursquoune mecircme classe ne puisse donner naissance qursquoagrave un seul ob-

jet et que toute tentative de creacuteation drsquoun nouvel objet se contente de renvoyer la reacutefeacute-

rence de cet unique objet Dans ce cas on peut preacutevoir un constructeur priveacute (de corps

vide) dont la preacutesence fait qursquoil est impossible de creacuteer explicitement des objets du type

(du moins si ce constructeur nrsquoest pas surdeacutefini) La creacuteation drsquoobjets se fait alors par

appel drsquoune fonction membre qui reacutealise elle-mecircme les allocations neacutecessaires crsquoest-

agrave-dire le travail drsquoun constructeur habituel et qui en outre srsquoassure de lrsquouniciteacute de

lrsquoobjet

En Java

Le constructeur possegravede les mecircmes proprieacuteteacutes qursquoen C++ et une classe peut ne pas com-

porter de constructeur Mais en Java les membres donneacutees sont toujours initialiseacutes par

deacutefaut (valeur nulle) et ils peuvent eacutegalement ecirctre initialiseacutes lors de leur deacuteclaration (la

1 Pattern en anglais

Classes et objetsCHAPITRE 5

80

mecircme valeur eacutetant alors attribueacutee agrave tous les objets du type) Ces deux possiliteacutes (initiali-

sation par deacutefaut et initialisation explicite) nrsquoexistent pas en C++ comme nous le verrons

plus tard de sorte qursquoil est pratiquement toujours neacutecessaire de preacutevoir un constructeur

mecircme dans des situations drsquoinitialisation simple

5 Les membres donneacutees statiques

51 Le qualificatif static pour un membre donneacuteeA priori lorsque dans un mecircme programme on creacutee diffeacuterents objets dune mecircme classe cha-

que objet possegravede ses propres membres donneacutees Par exemple si nous avons deacutefini une

classe exple1 par

class exple1

int n

float x

une deacuteclaration telle que

exple1 a b

conduit agrave une situation que lon peut scheacutematiser ainsi

Une faccedilon (parmi dautres) de permettre agrave plusieurs objets de partager des donneacutees consiste agrave

deacuteclarer avec le qualificatif static les membres donneacutees quon souhaite voir exister en un seul

exemplaire pour tous les objets de la classe Par exemple si nous deacutefinissons une classe

exple2 par

class exple2

static int n

float x

la deacuteclaration

exple2 a b

an

ax

bn

bx

Objet a Objet b

5 - Les membres donneacutees statiques81

conduit agrave une situation que lon peut scheacutematiser ainsi

On peut dire que les membres donneacutees statiques sont des sortes de variables globales dont la

porteacutee est limiteacutee agrave la classe

52 Initialisation des membres donneacutees statiquesPar leur nature mecircme les membres donneacutees statiques nexistent quen un seul exemplaire

indeacutependamment des objets de la classe (mecircme si aucun objet de la classe na encore eacuteteacute

creacuteeacute) Dans ces conditions leur initialisation ne peut plus ecirctre faite par le constructeur de la

classe

On pourrait penser quil est possible dinitialiser un membre statique lors de sa deacuteclaration

comme dans

class exple2 static int n = 2 erreur

En fait cela nest pas permis car compte tenu des possibiliteacutes de compilation seacutepareacutee le

membre statique risquerait de se voir reacuteserver diffeacuterents emplacements1 dans diffeacuterents

modules objet

Un membre statique doit donc ecirctre initialiseacute explicitement (agrave lexteacuterieur de la deacuteclaration de

la classe) par une instruction telle que

int exple2n = 5

Cette deacutemarche est utilisable aussi bien pour les membres statiques priveacutes que publics

Par ailleurs contrairement agrave ce qui se produit pour une variable ordinaire un membre stati-

que nest pas initialiseacute par deacutefaut agrave zeacutero

Remarque

Depuis la norme les membres statiques constants peuvent eacutegalement ecirctre initialiseacutes au

moment de leur deacuteclaration Mais il reste quand mecircme neacutecessaire de les deacuteclarer agrave lrsquoexteacute-

an

ax

Objet a Objet b

bx

bn

1 On retrouve le mecircme pheacutenomegravene pour les variables globales en langage C elles peuvent ecirctre deacuteclareacutees plusieurs

fois mais elles ne doivent ecirctre deacutefinies quune seule fois

Classes et objetsCHAPITRE 5

82

rieur de la classe (sans valeur cette fois) pour provoquer la reacuteservation de lrsquoemplacement

meacutemoire correspondant Par exemple

class exple3 static const int n=5 initialisation OK dpeuis la norme ANSI const int exple3n deacuteclaration indispensable (sans valeur)

53 ExempleVoici un exemple de programme exploitant cette possibiliteacute dans une classe nommeacutee

cpte_obj afin de connaicirctre agrave tout moment le nombre dobjets existants Pour ce faire nous

avons deacuteclareacute avec lattribut statique le membre ctr Sa valeur est increacutementeacutee de 1 agrave chaque

appel du constructeur et deacutecreacutementeacutee de 1 agrave chaque appel du destructeur

include ltiostreamgtusing namespace std

class cpte_obj static int ctr compteur du nombre dobjets creacuteeacutes

public cpte_obj () ~cpte_obj () int cpte_objctr = 0 initialisation du membre statique ctrcpte_objcpte_obj () constructeur cout ltlt ++ construction il y a maintenant ltlt ++ctr ltlt objetsn cpte_obj~cpte_obj () destructeur cout ltlt -- destruction il reste maintenant ltlt --ctr ltlt objetsn 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

6 - Exploitation drsquoune classe83

++ construction il y a maintenant 2 objets-- destruction il reste maintenant 1 objets-- destruction il reste maintenant 0 objets

Exemple dutilisation de membre statique

Remarque

En C le terme statique avait deacutejagrave deux significations de classe statique ou de porteacutee

limiteacutee au fichier source1 En C++ lorsquil sapplique aux membres dune classe il en

possegravede donc une troisiegraveme indeacutependant dune quelconque instance de la classe Nous

verrons au prochain chapitre quil pourra sappliquer aux fonctions membres avec la

mecircme signification

En Java

Les membres donneacutees statiques existent eacutegalement en Java et on utilise le mot cleacute static

pour leur deacuteclaration (crsquoest drsquoailleurs la seule signification de ce mot cleacute) Comme en

C++ ils peuvent ecirctre initialiseacutes lors de leur deacuteclaration mais ils peuvent aussi lrsquoecirctre par

le biais drsquoun bloc drsquoinitialisation qui contient alors des instructions exeacutecutables ce que ne

permet pas C++

6 Exploitation drsquoune classe

61 La classe comme composant logicielJusqursquoici nous avions regroupeacute au sein drsquoun mecircme programme trois sortes drsquoinstructions

destineacutees agrave

bull la deacuteclaration de la classe

bull la deacutefinition de la classe

bull lrsquoutilisation de la classe

En pratique on aura souvent inteacuterecirct agrave deacutecoupler la classe de son utilisation Crsquoest tout natu-

rellement ce qui se produira avec une classe drsquointeacuterecirct geacuteneacuteral utiliseacutee comme un composant

seacutepareacute des diffeacuterentes applications

1 Du moins quand on lemployait pour deacutesigner ce qui eacutetait qualifieacute par le mot cleacute static

Classes et objetsCHAPITRE 5

84

On sera alors geacuteneacuteralement ameneacute agrave isoler les seules instructions de deacuteclaration de la classe

dans un fichier en-tecircte (extension h) qursquoil suffira drsquoinclure (par include) pour compiler

lrsquoapplication

Par exemple le concepteur de la classe point du paragraphe 42 pourra creacuteer le fichier en-tecircte

suivant

class point deacuteclaration des membres priveacutes

int x int y

public deacuteclaration des membres publics point (int int) constructeur

void deplace (int int) void affiche ()

Fichier en-tecircte pour la classe point

Si ce fichier se nomme pointh le concepteur fabriquera alors un module objet en compilant

la deacutefinition de la classe point

include ltiostreamgt

include pointh pour introduire les deacuteclarations de la classe pointusing namespace std

----- Deacutefinition des fonctions membre de la classe point ----

pointpoint (int abs int ord) x = abs y = ord

void pointdeplace (int dx int dy) x = x + dx y = y + dy

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

Fichier agrave compiler pour obtenir le module objet de la classe point

Pour faire appel agrave la classe point au sein drsquoun programme lrsquoutilisateur proceacutedera alors ainsi

bull il inclura la deacuteclaration de la classe point dans le fichier source contenant son programme

par une directive telle que

include pointh

6 - Exploitation drsquoune classe85

bull il incorporera le module objet correspondant au moment de lrsquoeacutedition de liens de son propre

programme En principe agrave ce niveau la plupart des eacutediteurs de liens nrsquointroduisent que les

fonctions reacuteellement utiliseacutees de sorte qursquoil ne faut pas craindre de preacutevoir trop de meacutethodes

pour une classe

Parfois on trouvera plusieurs classes diffeacuterentes au sein drsquoun mecircme module objet et drsquoun

mecircme fichier en-tecircte de faccedilon comparable agrave ce qui se produit avec les fonctions de la biblio-

thegraveque standard1 Lagrave encore en geacuteneacuteral seules les fonctions reacuteellement utiliseacutees seront incor-

poreacutees agrave lrsquoeacutedition de liens de sorte qursquoil est toujours possible drsquoeffectuer des regroupements

de classes posseacutedant quelques affiniteacutes

Signalons que bon nombre drsquoenvironnements disposent drsquooutils2 permettant de prendre auto-

matiquement en compte les deacutependances existant entre les diffeacuterents fichiers sources et les

diffeacuterents fichiers objets concerneacutes dans ce cas lors drsquoune modification quelle qursquoelle soit

seules les compilations neacutecessaires sont effectueacutees

Remarque

Comme une fonction ordinaire une fonction membre peut ecirctre deacuteclareacutee sans qursquoon nrsquoen

fournisse de deacutefinition Si le programme fait appel agrave cette fonction membre ce nrsquoest qursquoagrave

lrsquoeacutedition de liens qursquoon srsquoapercevra de son absence En revanche si le programme nrsquouti-

lise pas cette fonction membre lrsquoeacutedition de liens se deacuteroulera normalement car il nrsquointro-

duit que les fonctions effectivement appeleacutees

62 Protection contre les inclusions multiplesPlus tard nous verrons quil existe diffeacuterentes circonstances pouvant amener lutilisateur

dune classe agrave inclure plusieurs fois un mecircme fichier en-tecircte lors de la compilation dun mecircme

fichier source (sans mecircme quil nen ait conscience ) Ce sera notamment le cas dans les

situations dobjets membres et de classes deacuteriveacutees

Dans ces conditions on risque daboutir agrave des erreurs de compilation lieacutees tout simplement agrave

la redeacutefinition de la classe concerneacutee

En geacuteneacuteral on reacuteglera ce problegraveme en proteacutegeant systeacutematiquement tout fichier en-tecircte des

inclusions multiples par une technique de compilation conditionnelle comme dans

ifndef POINT_H

define POINT_H

deacuteclaration de la classe point

endif

1 Avec cette diffeacuterence que dans le cas des fonctions standard on nrsquoa pas agrave speacutecifier les modules objets concerneacutes

au moment de lrsquoeacutedition de liens

2 On parle souvent de projet de fichier projet de fichier make

Classes et objetsCHAPITRE 5

86

Le symbole deacutefini pour chaque fichier en-tecircte sera choisi de faccedilon agrave eacuteviter tout risque de dou-

blons Ici nous avons choisi le nom de la classe (en majuscules) suffixeacute par _H

63 Cas des membres donneacutees statiquesNous avons vu (paragraphe 52) quun membre donneacutee statique doit toujours ecirctre initialiseacute

explicitement Degraves quon est ameneacute agrave consideacuterer une classe comme un composant seacutepareacute le

problegraveme se pose alors de savoir dans quel fichier source placer une telle initialisation

fichier en-tecircte fichier deacutefinition de la classe fichier utilisateur (dans notre exemple du para-

graphe 53 ce problegraveme ne se posait pas car nous navions quun seul fichier source)

On pourrait penser que le fichier en-tecircte est un excellent candidat pour cette initialisation degraves

lors quil est proteacutegeacute contre les inclusions multiples En fait il nen est rien en effet si lutili-

sateur compile seacutepareacutement plusieurs fichiers source utilisant la mecircme classe plusieurs

emplacements seront geacuteneacutereacutes pour le mecircme membre statique et en principe leacutedition de liens

deacutetectera cette erreur

Comme par ailleurs il nest guegravere raisonnable de laisser lutilisateur initialiser lui-mecircme un

membre statique on voit qursquoen deacutefinitive

64 En cas de modification drsquoune classeA priori lorsqursquoune classe est consideacutereacutee comme un composant logiciel crsquoest qursquoelle est au

point et ne devrait plus ecirctre modifieacutee Si une modification srsquoavegravere neacutecessaire malgreacute tout il

faut envisager deux situations assez diffeacuterentes

641 La deacuteclaration des membres publics nrsquoa pas changeacuteCrsquoest ce qui se produit lorsqursquoon se limite agrave des modifications internes nrsquoayant acune reacuteper-

cussion sur la maniegravere drsquoutiliser la classe (son interface avec lrsquoexteacuterieur reste la mecircme) Il

peut srsquoagir de transformation de structures de donneacutees encapsuleacutees (priveacutees) de modification

drsquoalgorithmes de traitement

Dans ce cas les programmes utilisant la classe nrsquoont pas agrave ecirctre modifieacutes Neacuteanmoins il

doivent ecirctre recompileacutes avec le nouveau fichier en-tecircte correspondant1 On proceacutedera

ensuite agrave une eacutedition de liens en incorporant le nouveau module objet

On voit donc que C++ permet une maintenance facile drsquoune classe agrave laquelle on souhaite

apporter des modifications internes (corrections drsquoerreurs ameacutelioration des performances)

nrsquoatteignant pas la speacutecification de son interface

Il est conseilleacute de preacutevoir lrsquoinitialisation des membres donneacutees statiques dans le fichier contenant la deacutefinition de la classe

1 Une telle limitation nrsquoexiste pas dans tous les langages de POO En C++ elle se justifie par le besoin qursquoa le

compilateur de connaicirctre la taille des objets (statiques ou automatiques) pour leur allouer un emplacement

7 - Les classes en geacuteneacuteral87

642 La deacuteclaration des membres publics a changeacute

Ici il est clair que les programmes utilisant la classe risquent de neacutecessiter des modifications

Cette situation devra bien sucircr ecirctre eacuteviteacutee dans la mesure du possible Elle doit ecirctre consideacutereacutee

comme une faute de conception de la classe Nous verrons drsquoailleurs que ces problegravemes pour-

ront souvent ecirctre reacutesolus par lrsquoutilisation du meacutecanisme drsquoheacuteritage qui permet drsquoadapter une

classe (censeacutee ecirctre au point) sans la remettre en cause

7 Les classes en geacuteneacuteralNous apportons ici quelques compleacutements drsquoinformation sur des situations peu usuelles

71 Les autres sortes de classes en C++Nous avons deacutejagrave eu loccasion de dire que C++ qualifiait de classe les types deacutefinis par

struct et class La caracteacuteristique dune classe au sens large que lui donne C++1 est dasso-

cier au sein dun mecircme type des membres donneacutees et des fonctions membres

Pour C++ les unions sont aussi des classes Ce type peut donc disposer de fonctions mem-

bres Notez bien que comme pour le type struct les donneacutees correspondantes ne peuvent pas

se voir attribuer un statut particulier elles sont de fait publiques

Remarque

C++ emploie souvent le mot classe pour deacutesigner indiffeacuteremment un type class struct ou

union De mecircme on parle souvent drsquoobjet pour deacutesigner des variables de lrsquoun de ces trois

types Cet abus de langage semble assez licite dans la mesure ougrave ces trois types jouis-

sent pratiquement des mecircmes proprieacuteteacutes notamment au niveau de lrsquoheacuteritage toutefois

seul le type class permet lrsquoencapsulation des donneacutees Lorsqursquoil sera neacutecessaire drsquoecirctre

plus preacutecis nous parlerons de vraie classe pour deacutesigner le type class

72 Ce quon peut trouver dans la deacuteclaration dune classeEn dehors des deacuteclarations de fonctions membres la plupart des instructions figurant dans

une deacuteclaration de classe seront des deacuteclarations de membres donneacutees dun type quelconque

Neacuteanmoins on peut eacutegalement y rencontrer des deacuteclarations de type y compris dautres types

classes dans ce cas leur porteacutee est limiteacutee agrave la classe (mais on peut recourir agrave lrsquoopeacuterateur de

reacutesolution de porteacutee ) comme dans cet exemple

1 Et non la POO dune maniegravere geacuteneacuterale qui associe lencapsulation des donneacutees agrave la notion de classe

Classes et objetsCHAPITRE 5

88

class A

public

class B classe B deacuteclareacutee dans la classe A

main()

A a

AB b deacuteclaration drsquoun objet b du type de la classe B de A

En pratique cette situation se rencontre peu souvent

Par ailleurs il nest pas possible dinitialiser un membre donneacutee dune classe lors de sa

deacuteclaration Cette interdiction est justifieacutee pour au moins deux raisons

bull une telle initialisation risquerait de faire double emploi avec le constructeur

bull une telle initialisation constituerait une deacutefinition du membre correspondant (et non plus une

simple deacuteclaration) or cette deacutefinition risquerait dapparaicirctre plusieurs fois en cas de com-

pilation seacutepareacutee ce qui est illeacutegal1

En revanche la deacuteclaration de membres donneacutees constants2 est autoriseacutee comme dans

class exple

int n membre donneacutee usuel

const int p membre donneacutee constant - initialisation impossible

agrave ce niveau

Dans ce cas on notera bien que chaque objet du type exple posseacutedera un membre p Crsquoest ce

qui explique qursquoil ne soit pas possible dinitialiser le membre constant au moment de sa

deacuteclaration3 Pour y parvenir la seule solution consistera agrave utiliser une syntaxe particuliegravere

du constructeur (qui devient donc obligatire) telle quelle sera preacutesenteacutee au paragraphe 5 du

chapitre 7 (relatif aux objets membres)

73 Deacuteclaration dune classeLa plupart du temps les classes seront deacuteclareacutees agrave un niveau global Neacuteanmoins il est permis

de deacuteclarer des classes locales agrave une fonction Dans ce cas leur porteacutee est naturellement limi-

teacutee agrave cette fonction (cest bien ce qui en limite linteacuterecirct)

1 On retrouve le mecircme pheacutenomegravene pour les membres donneacutees statiques et pour les variables globales en langage C

ils peuvent ecirctre deacuteclareacutes plusieurs fois mais ils ne doivent ecirctre deacutefinis quune seule fois

2 Ne confondez pas la notion de membre donneacutee constant (chaque objet en possegravede un sa valeur ne peut pas ecirctre

modifieacutee) et la notion de membre donneacutee statique (tous les objets dune mecircme classe partagent le mecircme sa valeur

peut changer)

3 Sauf comme on lrsquoa vu au paragraphe 52 srsquoil srsquoagit drsquoun membre statique constant dans ce cas ce membre est

unique pour tous les objets de la classe

7 - Les classes en geacuteneacuteral89

ExercicesNB les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 Expeacuterimentez (eacuteventuellement sur un exemple de ce chapitre) la compilation seacutepareacutee

dune classe (creacuteation dun module objet et dun fichier en-tecircte) et son utilisation au

sein dun programme

2 (C) Ecrivez une classe vecteur (de type class et non struct) comportant

bull comme membres donneacutees priveacutes trois composantes de type double

bull comme fonctions membres publiques

ndash initialise pour attribuer des valeurs aux composantes

ndash homothetie pour multiplier les composantes par une valeur fournie en argu-

ment

ndash affiche pour afficher les composantes du vecteur

3 (C) Ecrivez une classe vecteur analogue agrave la preacuteceacutedente dans laquelle la fonction initia-

lise est remplaceacutee par un constructeur

4 Expeacuterimentez la creacuteation drsquoun fichier en-tecircte et drsquoun module objet rassemblant deux

classes diffeacuterentes

5 Veacuterifiez que lorsqursquoune classe comporte un membre donneacutee statique ce dernier peut

ecirctre utiliseacute mecircme lorsquaucun objet de ce type na eacuteteacute deacuteclareacute

6 Mettez en eacutevidence les problegravemes poseacutes par laffectation entre objets comportant une

partie dynamique Pour ce faire utilisez la classe hasard du second exemple du para-

graphe 44 en ajoutant simplement des instructions affichant ladresse contenue dans

val dans le constructeur dune part dans le destructeur dautre part Vous constaterez

quavec ces deacuteclarations

hasard h1(10 3)

hasard h2(20 5)

une instruction telle que

h2 = h1

nentraicircne pas toutes les recopies escompteacutees et que de surcroicirct elle conduit agrave libeacuterer

deux fois le mecircme emplacement (en fin de fonction)

6

Les proprieacuteteacutes desfonctions membres

Le chapitre preacuteceacutedent vous a preacutesenteacute les concepts fondamentaux de classe dobjet de cons-

tructeur et de destructeur Ici nous allons eacutetudier un peu plus en deacutetail lapplication aux fonc-

tions membres des possibiliteacutes offertes par C++ pour les fonctions ordinaires surdeacutefinition

arguments par deacutefaut fonction en ligne transmission par reacutefeacuterence

Nous verrons eacutegalement comment une fonction membre peut recevoir en argument outre

lobjet layant appeleacute (transmis implicitement) un ou plusieurs objets de type classe Ici nous

nous limiterons au cas dobjets de mecircme type que la classe dont la fonction est membre les

autres situations correspondant agrave une violation du principe dencapsulation ne seront exami-

neacutees que plus tard dans le cadre des fonctions amies

Nous verrons ensuite comment acceacuteder au sein dune fonction membre agrave ladresse de lobjet

layant appeleacute en utilisant le mot cleacute this

Enfin nous examinerons les cas particuliers des fonctions membres statiques et des fonctions

membres constantes ainsi que lemploi de pointeurs sur des fonctions membres

1 Surdeacutefinition des fonctions membresNous avons deacutejagrave vu comment C++ nous autorise agrave surdeacutefinir les fonctions ordinaires Cette

possibiliteacute sapplique eacutegalement aux fonctions membres dune classe y compris au construc-

teur (mais pas au destructeur puisquil ne possegravede pas drsquoarguments)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

92

11 ExempleVoyez cet exemple dans lequel nous surdeacutefinissons

bull le constructeur point le choix du bon constructeur se faisant ici suivant le nombre

drsquoarguments

ndash 0 argument les deux coordonneacutees attribueacutees au point construit sont toutes deux nulles

ndash 1 argument il sert de valeur commune aux deux coordonneacutees

ndash 2 arguments cest le cas usuel que nous avions deacutejagrave rencontreacute

bull la fonction affiche de maniegravere quon puisse lappeler

ndash sans argument comme auparavant

ndash avec un argument de type chaicircne dans ce cas elle affiche le texte correspondant avant

les coordonneacutees du point

include ltiostreamgtusing namespace std 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 chaicircne) pointpoint () constructeur 1 x = 0 y = 0 pointpoint (int abs) constructeur 2 x = y = abs pointpoint (int abs int ord) constructeur 3 x = abs y = ord void pointaffiche () fonction affiche 1 cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n void pointaffiche (char message) fonction affiche 2 cout ltlt message affiche () main() point a appel constructeur 1 aaffiche () appel fonction affiche 1 point b (5) appel constructeur 2 baffiche (Point b - ) appel fonction affiche 2 point c (3 12) appel constructeur 3 caffiche (Hello ---- ) appel fonction affiche 2

1 - Surdeacutefinition des fonctions membres93

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple de surdeacutefinition de fonctions membres (point et affiche)

Remarques

1 En utilisant les possibiliteacutes drsquoarguments par deacutefaut il est souvent possible de diminuer le

nombre de fonctions surdeacutefinies Cest le cas ici pour la fonction affiche comme nous le

verrons dailleurs dans le paragraphe suivant

2 Ici dans la fonction affiche(char ) nous faisons appel agrave lautre fonction membre affi-

che() En effet une fonction membre peut toujours en appeler une autre (quelle soit

publique ou non) Une fonction membre peut mecircme sappeler elle-mecircme dans la

mesure ougrave lon a preacutevu le moyen de rendre fini le processus de reacutecursiviteacute qui en

deacutecoule

12 Incidence du statut public ou priveacute drsquoune fonction membreMais par rapport agrave la surdeacutefinition des fonctions indeacutependantes il faut maintenant tenir

compte de ce qursquoune fonction membre peut ecirctre priveacutee ou publique Or en C++

Condiseacuterez cet exemple

class A public void f(int n)

private void f(char c)

main()

int n char c A a

af(c)

Lrsquoappel af(c) amegravene le compilateur agrave consideacuterer les deux fonctions f(int) et f(char) et ceci

indeacutependamment de leur statut (public pour la premiegravere priveacute pour la seconde) Lrsquoalgorithme

de recherche de la meilleure fonction conclut alors que f(char) est la meilleure fonction et

qursquoelle est unique Mais comme celle-ci est priveacutee elle ne peut pas ecirctre appeleacutee depuis une

fonction exteacuterieure agrave la classe et lrsquoappel est rejeteacute (et ceci malgreacute lrsquoexistence de f(int) qui

aurait pu convenir) Rappelons que

bull si f(char) est deacutefinie publique elle serait bien appeleacutee par af(c)

bull si f(char) nrsquoest pas deacutefinie du tout af(c) appellerait f(int)

Le statut priveacute ou public drsquoune fonction nrsquointervient pas dans les fonctions consideacute-reacutees En revanche si la meilleure fonction trouveacutee est priveacutee elle ne pourra pas ecirctre appeleacutee (sauf si lrsquoappel figure dans une autre fonction membre de la classe)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

94

En Java

Contrairement agrave ce qui se passe en C++ le statut priveacute ou public drsquoune fonction membre

est bien pris en compte dans le choix des fonctions acceptables Dans ce dernier exem-

ple af(c) appellerait bien f(int) apregraves conversion de c en int comme si la fonction priveacutee

f(int) nrsquoeacutexistait pas

2 Arguments par deacutefautComme les fonctions ordinaires les fonctions membres peuvent disposer drsquoarguments par

deacutefaut Voici comment nous pourrions modifier lexemple preacuteceacutedent pour que notre classe

point ne possegravede plus quune seule fonction affiche disposant drsquoun seul argument de type

chaicircne Celui-ci indique le message agrave afficher avant les valeurs des coordonneacutees et sa valeur

par deacutefaut est la chaicircne vide

include ltiostreamgtusing namespace std 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 deacutefaut) pointpoint () constructeur 1 x = 0 y = 0 pointpoint (int abs) constructeur 2

x = y = abs pointpoint (int abs int ord) constructeur 3 x = abs y = ord void pointaffiche (char message) fonction affiche cout ltlt message ltlt Je suis en ltlt x ltlt ltlt y ltlt n

main() point a appel constructeur 1 aaffiche () point b (5) appel constructeur 2 baffiche (Point b - ) point c (3 12) appel constructeur 3 caffiche (Hello ---- )

3 - Les fonctions membres en ligne95

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple dutilisation drsquoarguments par deacutefaut dans une fonction membre

Remarque

Ici nous avons remplaceacute deux fonctions surdeacutefinies par une seule fonction ayant un argu-

ment par deacutefaut Bien entendu cette simplification nest pas toujours possible Par exem-

ple ici nous ne pouvons pas lappliquer agrave notre constructeur point En revanche si nous

avions preacutevu que dans le constructeur point agrave un seul argument ce dernier repreacutesente

simplement labscisse du point auquel on aurait alors attribueacute une ordonneacutee nulle nous

aurions pu deacutefinir un seul constructeur

pointpoint (int abs = 0 int ord = 0) x = abs y = ord

3 Les fonctions membres en ligneNous avons vu que C++ permet de deacutefinir des fonctions en ligne Ceci accroicirct lefficience

dun programme dans le cas de fonctions courtes Lagrave encore cette possibiliteacute sapplique aux

fonctions membres moyennant cependant une petite nuance concernant sa mise en œuvre

En effet pour rendre en ligne une fonction membre on peut

bull soit fournir directement la deacutefinition de la fonction dans la deacuteclaration mecircme de la classe

dans ce cas le qualificatif inline na pas agrave ecirctre utiliseacute

bull soit proceacuteder comme pour une fonction ordinaire en fournissant une deacutefinition en dehors de

la deacuteclaration de la classe dans ce cas le qualificatif inline doit apparaicirctre agrave la fois devant

la deacuteclaration et devant len-tecircte

Voici comment nous pourrions rendre en ligne les trois constructeurs de notre preacuteceacutedent

exemple en adoptant la premiegravere maniegravere

include ltiostreamgtusing namespace std 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 = )

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

96

void pointaffiche (char message) fonction affiche cout ltlt message ltlt Je suis en ltlt x ltlt ltlt y ltlt n

main() point a appel constructeur 1 aaffiche () point b (5) appel constructeur 2 baffiche (Point b - ) point c (3 12) appel constructeur 3 caffiche (Hello ---- )

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple de fonctions membres en ligne

Remarques

1 Voici comment se serait preacutesenteacutee la deacuteclaration de notre classe si nous avions deacuteclareacute

nos fonctions membres en ligne agrave la maniegravere des fonctions ordinaires (ici nous navons

mentionneacute quun constructeur)

class point public inline point ()

inline pointpoint() x = 0 y = 0

2 Si nous navions eu besoin que dun seul constructeur avec arguments par deacutefaut

(comme dans la remarque du preacuteceacutedent paragraphe) nous aurions pu tout aussi bien le

rendre en ligne avec la premiegravere deacutemarche (deacutefinition de fonction inteacutegreacutee dans la

deacuteclaration de la classe) nous aurions alors speacutecifieacute les valeurs par deacutefaut directement

dans len-tecircte

class point point (int abs = 0 int ord = 0) x = abs y = ord

Nous utiliserons dailleurs un tel constructeur dans lexemple du paragraphe suivant

4 - Cas des objets transmis en argument drsquoune fonction membre97

3 Par sa nature mecircme la deacutefinition dune fonction en ligne doit obligatoirement ecirctre con-

nue du compilateur lorsquil traduit le programme qui lutilise Cette condition est obli-

gatoirement reacutealiseacutee lorsque lon utilise la premiegravere deacutemarche En revanche ce nest

plus vrai avec la seconde en geacuteneacuteral dans ce cas on placera les deacutefinitions des fonc-

tions en ligne agrave la suite de la deacuteclaration de la classe dans le mecircme fichier en-tecircte

Dans tous les cas on voit toutefois que lutilisateur dune classe (qui disposera obliga-

toirement du fichier en-tecircte relatif agrave une classe) pourra toujours connaicirctre la deacutefinition

des fonctions en ligne le fournisseur dune classe ne pourra jamais avoir la certitude

quun utilisateur de cette classe ne tentera pas de les modifier Ce risque nexiste pas

pour les autres fonctions membres (degraves lors que lutilisateur ne dispose que du module

objet relatif agrave la classe)

4 Cas des objets transmis en argument drsquoune fonction membre

Dans les exemples preacuteceacutedents les fonctions membres recevaient

bull un argument implicite du type de leur classe agrave savoir ladresse de lobjet layant appeleacute

bull un certain nombre drsquoarguments qui eacutetaient dun type ordinaire (cest-agrave-dire autre que classe)

Mais une fonction membre peut outre largument implicite recevoir un ou plusieurs argu-

ments du type de sa classe Par exemple supposez que nous souhaitions au sein dune classe

point introduire une fonction membre nommeacutee coincide chargeacutee de deacutetecter la coiumlncidence

eacuteventuelle de deux points Son appel au sein dun programme se preacutesentera obligatoirement

comme pour toute fonction membre sous la forme

acoincide ()

a eacutetant un objet de type point

Il faudra donc impeacuterativement transmettre le second point en argument en supposant quil se

nomme b cela nous conduira agrave un appel de la forme

acoincide (b)

ou ici compte tenu de la symeacutetrie du problegraveme

bcoincide (a)

Voyons maintenant plus preacuteciseacutement comment eacutecrire la fonction coincide Voici ce que peut

ecirctre son en-tecircte en supposant quelle fournit une valeur de retour entiegravere (1 en cas de coiumlnci-

dence 0 dans le cas contraire)

int pointcoincide (point pt)

Dans coincide nous devons donc comparer les coordonneacutees de lobjet fourni implicitement

lors de son appel (ses membres sont deacutesigneacutes comme dhabitude par x et y) avec celles de

lobjet fourni en argument dont les membres sont deacutesigneacutes par ptx et pty Le corps de coin-

cide se preacutesentera donc ainsi

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

98

if ((ptx == x) ampamp (pty == y)) return 1 else return 0

Voici un exemple complet de programme dans lequel nous avons limiteacute les fonctions mem-

bres de la classe point agrave un constructeur et agrave coincide

include ltiostreamgtusing namespace std 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 pointcoincide (point pt) if ( (ptx == x) ampamp (pty == y) ) return 1 else return 0 remarquez la dissymeacutetrie des notations ptx et xmain() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(b) ltlt ou ltlt bcoincide(a) ltlt n cout ltlt b et c ltlt bcoincide(c) ltlt ou ltlt ccoincide(b) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple dobjet transmis en argument agrave une fonction membre

On pourrait penser qursquoon viole le principe drsquoencapsulation dans la mesure ougrave lorsqursquoon

appelle la fonction coincide pour lrsquoobjet a (dans acoincide(b)) elle est autoriseacutee agrave acceacuteder

aux donneacutees de b En fait en C++ nrsquoimporte quelle fonction membre drsquoune classe peut acceacute-

der agrave nrsquoimporte quel membre (public ou priveacute) de nrsquoimporte quel objet de cette classe On

traduit souvent cela en disant que

Remarques

1 Nous aurions pu eacutecrire coincide de la maniegravere suivante

return ((ptx == x) ampamp (pty == y))

En C++ lrsquouniteacute drsquoencapsulation est la classe (et non pas lrsquoobjet )

5 - Mode de transmission des objets en argument99

2 En theacuteorie on peut dire que la coiumlncidence de deux points est symeacutetrique en ce sens

que lordre dans lequel on considegravere les deux points est indiffeacuterent Or cette symeacutetrie ne

se retrouve pas dans la deacutefinition de la fonction coincide pas plus que dans son appel

Cela provient de la transmission en argument implicite de lobjet appelant la fonction

Nous verrons que lrsquoutilisation drsquoune fonction amie permet de retrouver cette symeacute-

trie

3 Notez bien que lrsquouniteacute drsquoencapsulation est la classe concerneacutee pas toutes les classes

existantes Ainsi si A et B sont deux classes diffeacuterentes une fonction membre de A ne

peut heureusement pas acceacuteder aux membres priveacutes drsquoun objet de classe B (pas plus

que ne le pourrait une fonction ordinaire main par exemple) bien entendu elle peut

toujours acceacuteder aux membres publics Nous verrons plus tard qursquoil est possible agrave une

fonction (ordinaire ou membre) de saffranchir de cette interdiction (et donc cette fois

de violer veacuteritablement le principe dencapsulation) par des deacuteclarations damitieacute appro-

prieacutees

En Java

Lrsquouniteacute drsquoencapsulation est eacutegalement la classe

5 Mode de transmission des objets en argument

Dans lrsquoexemple preacuteceacutedent lobjet pt eacutetait transmis classiquement agrave coincide agrave savoir par

valeur Preacuteciseacutement cela signifie donc que lors de lappel

acoincide (b)

les valeurs des donneacutees de b sont recopieacutees dans un emplacement (de type point) local agrave coin-

cide (nommeacute pt)

Comme pour nimporte quel argument ordinaire il est possible de preacutevoir den transmettre

ladresse plutocirct que la valeur ou de mettre en place une transmission par reacutefeacuterence Exami-

nons ces deux possibiliteacutes

51 Transmission de ladresse dun objetIl est possible de transmettre explicitement en argument ladresse dun objet Rappelons que

dans un tel cas on ne change pas le mode de transmission de largument (contrairement agrave ce

qui se produit avec la transmission par reacutefeacuterence) on se contente de transmettre une valeur

qui se trouve ecirctre une adresse et quil faut donc interpreacuteter en conseacutequence dans la fonction

(notamment en employant lopeacuterateur dindirection ) A titre dexemple voici comment nous

pourrions modifier la fonction coincide du paragraphe preacuteceacutedent

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

100

int pointcoincide (point adpt) if (( adpt -gt x == x) ampamp (adpt -gt y == y)) return 1 else return 0

Compte tenu de la dissymeacutetrie naturelle de notre fonction membre cette eacutecriture nest guegravere

choquante Par contre lappel de coincide (au sein de main) le devient davantage

acoincide (ampb)

ou

bcoincide (ampa)

Voici le programme complet ainsi modifieacute

include ltiostreamgtusing namespace std 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 pointcoincide (point adpt) if ( (adpt-gtx == x) ampamp (adpt-gty == y) ) return 1 else return 0

main() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(ampb) ltlt ou ltlt bcoincide(ampa) ltlt n cout ltlt b et c ltlt bcoincide(ampc) ltlt ou ltlt ccoincide(ampb) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple de transmission de ladresse dun objet agrave une fonction membre

Remarque

Noubliez pas quagrave partir du moment ougrave vous fournissez ladresse dun objet agrave une fonction

membre celle-ci peut en modifier les valeurs (elle a accegraves agrave tous les membres sil sagit

dun objet de type de sa classe aux seuls membres publics dans le cas contraire) Si vous

craignez de tels effets de bord au sein de la fonction membre concerneacutee vous pouvez tou-

jours employer le qualificatif const Ainsi ici len-tecircte de coincide aurait pu ecirctre

int pointcoincide (const point adpt)

5 - Mode de transmission des objets en argument101

en modifiant parallegravelement son prototype

int coincide (const point )

Notez toutefois quune telle preacutecaution ne peut pas ecirctre prise avec largument implicite

quest lobjet ayant appeleacute la fonction Ainsi dans coincide muni de len-tecircte ci-dessus

vous ne pourriez plus modifier adpt -gt x mais vous pourriez toujours modifier x Lagrave

encore lrsquoutilisation drsquoune fonction amie permettra drsquoassurer lrsquoeacutegaliteacute de traitement des

deux arguments en particulier au niveau de leur constance

52 Transmission par reacutefeacuterenceComme nous lavons vu lemploi des reacutefeacuterences permet de mettre en place une transmission

par adresse sans avoir agrave en prendre en charge soi-mecircme la gestion Elle simplifie dautant

leacutecriture de la fonction concerneacutee et ses diffeacuterents appels Voici une adaptation de coincide

dans laquelle son argument est transmis par reacutefeacuterence

include ltiostreamgtusing namespace std 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 amp) une fonction membre coincide int pointcoincide (point amp pt) if ( (ptx == x) ampamp (pty == y) ) return 1 else return 0 main() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(b) ltlt ou ltlt bcoincide(a) ltlt n cout ltlt b et c ltlt bcoincide(c) ltlt ou ltlt ccoincide(b) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple de transmission par reacutefeacuterence dun objet agrave une fonction membre

Remarque

La remarque preacuteceacutedente (en fin de paragraphe 51) sur les risques deffets de bord sappli-

que eacutegalement ici Le qualificatif const pourrait y intervenir de maniegravere analogue

int pointcoincide (const point amp pt)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

102

53 Les problegravemes poseacutes par la transmission par valeurNous avons deacutejagrave vu que laffectation dobjets pouvait poser des problegravemes dans le cas ougrave ces

objets posseacutedaient des pointeurs sur des emplacements alloueacutes dynamiquement Ces poin-

teurs eacutetaient effectivement recopieacutes mais il nen allait pas de mecircme des emplacements poin-

teacutes Le transfert drsquoarguments par valeur preacutesente les mecircmes risques dans la mesure ougrave il

sagit eacutegalement dune simple recopie

De mecircme que le problegraveme poseacute par laffectation peut ecirctre reacutesolu par la surdeacutefinition de cet

opeacuterateur celui poseacute par le transfert par valeur peut ecirctre reacutegleacute par lemploi dun constructeur

particulier nous vous montrerons comment degraves le prochain chapitre

Dune maniegravere geacuteneacuterale dailleurs nous verrons que les problegravemes poseacutes par les objets conte-

nant des pointeurs se ramegravenent effectivement agrave laffectation et agrave lrsquoinitialisation1 dont la

recopie en cas de transmission par valeur constitue un cas particulier

6 Lorsqursquoune fonction renvoie un objetCe que nous avons dit agrave propos des arguments dune fonction membre sapplique eacutegalement agrave

sa valeur de retour Cette derniegravere peut ecirctre un objet et on peut choisir entre

bull transmission par valeur

bull transmission par adresse

bull transmission par reacutefeacuterence

Cet objet pourra ecirctre

bull du mecircme type que la classe auquel cas la fonction aura accegraves agrave ses membres priveacutes

bull dun type diffeacuterent de la classe auquel cas la fonction naura accegraves quagrave ses membres publics

La transmission par valeur suscite la mecircme remarque que preacuteceacutedemment par deacutefaut elle se

fait par simple recopie de lobjet Pour les objets comportant des pointeurs sur des emplace-

ments dynamiques il faudra preacutevoir un constructeur particulier (dinitialisation)

En revanche la transmission dune adresse ou la transmission par reacutefeacuterence risquent de poser

un problegraveme qui nexistait pas pour les arguments Si une fonction transmet ladresse ou la

reacutefeacuterence dun objet il vaut mieux eacuteviter quil sagisse dun objet local agrave la fonction cest-agrave-

dire de classe automatique En effet dans ce cas lemplacement de cet objet sera libeacutereacute2 degraves

la sortie de la fonction la fonction appelante reacutecupeacuterera ladresse de quelque chose nexistant

plus vraiment3 Nous reviendrons plus en deacutetail sur ce point dans le chapitre consacreacute agrave la

surdeacutefinition dopeacuterateurs

1 Bien que cela napparaisse pas toujours clairement en C il est tregraves important de noter qursquoen C++ affectation et

initialisation sont deux choses diffeacuterentes

2 Comme nous le verrons en deacutetail au chapitre suivant il y aura appel du destructeur sil existe

7 - Autoreacutefeacuterence le mot cleacute this103

A titre dexemple voici une fonction membre nommeacutee symetrique qui pourrait ecirctre introduite

dans une classe point pour fournir en retour un point symeacutetrique de celui layant appeleacute

point pointsymetrique ( ) point res resx = -x resy = -y return res

Vous constatez quil a eacuteteacute neacutecessaire de creacuteer un objet automatique res au sein de la fonction

Comme nous lavons expliqueacute ci-dessus il ne serait pas conseilleacute den preacutevoir une transmis-

sion par reacutefeacuterence en utilisant cet en-tecircte

point amp pointsymetrique ( )

7 Autoreacutefeacuterence le mot cleacute thisNous avons eu souvent loccasion de dire quune fonction membre dune classe reccediloit une

information lui permettant dacceacuteder agrave lobjet layant appeleacute Le terme information bien

quil soit relativement flou nous a suffi pour expliquer tous les exemples rencontreacutes jusquici

Mais nous navions pas besoin de manipuler explicitement ladresse de lobjet en question Or

il existe des circonstances ougrave cela devient indispensable Songez par exemple agrave la gestion

dune liste chaicircneacutee dobjets de mecircme nature pour eacutecrire une fonction membre inseacuterant un

nouvel objet (supposeacute transmis en argument implicite) il faudra bien placer son adresse dans

lobjet preacuteceacutedent de la liste

Pour reacutesoudre de tels problegravemes C++ a preacutevu le mot cleacute this Celui-ci utilisable unique-

ment au sein dune fonction membre deacutesigne un pointeur sur lobjet layant appeleacute

Ici il serait preacutematureacute de deacutevelopper lexemple de liste chaicircneacutee dont nous venons de parler

nous vous proposons un exemple deacutecole dans la classe point la fonction affiche fournit

ladresse de lobjet layant appeleacute

include ltiostreamgtusing namespace std 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 pointaffiche () cout ltlt Adresse ltlt this ltlt - Coordonnees ltlt x ltlt ltlt y ltlt n

3 Dans certaines impleacutementations un emplacement libeacutereacute nest pas remis agrave zeacutero Ainsi on peut avoir lillusion que

cela marche si lon se contente dexploiter lobjet immeacutediatement apregraves lappel de la fonction

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

104

main() Un petit programme dessai point a(5) b(315) aaffiche () baffiche ()

Adresse 006AFDF0 - Coordonnees 5 0Adresse 006AFDE8 - Coordonnees 3 15

Exemple dutilisation de this

Remarques

A titre purement indicatif la fonction coincide du paragraphe 51 pourrait seacutecrire

int pointcoincide (point adpt) if ((this -gt x == adpt -gt x) ampamp (this -gt y == adpt -gt y)) return 1 else return 0

La symeacutetrie du problegraveme y apparaicirct plus clairement Ce serait moins le cas si lon eacutecri-

vait ainsi la fonction coincide du paragraphe 4

int pointcoincide (point pt) if ((this -gt x == ptx)) ampamp (this -gt y == pty)) return 1 else return 0

En Java

Le mot cleacute this existe eacutegalement en Java avec une signification voisine il deacutesigne lrsquoobjet

ayant appeleacute une fonction membre au lieu de son adresse en C++ (de toute faccedilon la

notion de pointeur nrsquoexiste pas en Java)

8 Les fonctions membres statiquesNous avons deacutejagrave vu (paragraphe 5 du chapitre 5) comment C++ permet de deacutefinir des mem-

bres donneacutees statiques Ceux-ci existent en un seul exemplaire (pour une classe donneacutee)

indeacutependamment des objets de leur classe

Dune maniegravere analogue on peut imaginer que certaines fonctions membres dune classe

aient un rocircle totalement indeacutependant dun quelconque objet ce serait notamment le cas dune

fonction qui se contenterait dagir sur des membres donneacutees statiques

On peut certes toujours appeler une telle fonction en la faisant porter artificiellement sur un

objet de la classe et ce bien que ladresse de cet objet ne soit absolument pas utile agrave la fonc-

tion En fait il est possible de rendre les choses plus lisibles et plus efficaces en deacuteclarant sta-

8 - Les fonctions membres statiques105

tique (mot cleacute static) la fonction membre concerneacutee Dans ce cas en effet son appel ne

neacutecessite plus que le nom de la classe correspondante (accompagneacute naturellement de lopeacute-

rateur de reacutesolution de porteacutee) Comme pour les membres statiques une telle fonction mem-

bre statique peut mecircme ecirctre appeleacutee lorsquil nexiste aucun objet de sa classe

Voici un exemple de programme illustrant lemploi dune fonction membre statique il sagit

de lexemple preacutesenteacute au paragraphe 53 du chapitre 5 dans lequel nous avons introduit une

fonction membre statique nommeacutee compte affichant simplement le nombre dobjets de sa

classe

include ltiostreamgtusing namespace std class cpte_obj static int ctr compteur (statique) du nombre dobjets creacuteeacutes public cpte_obj () ~cpte_obj() static void compte () pour afficher le nombre dobjets creacuteeacutes int cpte_objctr = 0 initialisation du membre statique ctrcpte_objcpte_obj () constructeur cout ltlt ++ construction il y a maintenant ltlt ++ctr ltlt objetsn cpte_obj~cpte_obj () destructeur cout ltlt -- destruction il reste maintenant ltlt --ctr ltlt objetsn void cpte_objcompte () cout ltlt appel compte il y a ltlt ctr ltlt objetsn main() void fct () cpte_objcompte () appel de la fonction membre statique compte alors quaucun objet de sa classe nexiste cpte_obj a cpte_objcompte () fct () cpte_objcompte () cpte_obj b cpte_objcompte () 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

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

106

++ 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

appel compte il y a 2 objets

-- destruction il reste maintenant 1 objets

-- destruction il reste maintenant 0 objets

Deacutefinition et utilisation dune fonction membre statique

En Java

Les fonctions membres statiques existent eacutegalement en Java et elles se deacuteclarent agrave lrsquoaide

du mecircme mot cleacute static

9 Les fonctions membres constantes

91 Rappels sur lrsquoutilisation de const en CEn langage C le qualificatif const peut servir agrave deacutesigner une variable dont on souhaite que la

valeur neacutevolue pas Le compilateur est ainsi en mesure de rejeter deacuteventuelles tentatives de

modification de cette variable Par exemple avec cette deacuteclaration

const int n=20

linstruction suivante sera incorrecte

n = 12 incorrecte n nrsquoest pas une lvalue

De la mecircme maniegravere on ne peut modifier la valeur drsquoun argument muet deacuteclareacute constant

dans lrsquoen-tecircte drsquoune fonction

void f(const int n) ou mecircme void f(const int amp n) - voir remarque

n++ incorrect n nrsquoest pas une lvalue

Remarque

Ne confondez pas un argument muet deacuteclareacute const et un argument effectif deacuteclareacute const

Dans le premier cas la deacuteclaration const constitue une sorte de contrat le program-

meur de la fonction srsquoengage agrave ne pas en modifier la valeur et ce mecircme si au bout du

compte la fonction travaille sur une copie de la valeur de lrsquoargument effectif (ce qui est le

cas avec la transmission par valeur avec une reacutefeacuterence agrave une constante )

9 - Les fonctions membres constantes107

92 Deacutefinition drsquoune fonction membre constanteC++ eacutetend ce concept de constance des variables aux classes ce qui signifie quon peut deacutefi-

nir des objets constants Encore faut-il comprendre ce que lon entend par lagrave En effet dans

le cas dune variable ordinaire le compilateur peut assez facilement identifier les opeacuterations

interdites (celles qui peuvent en modifier la valeur) En revanche dans le cas dun objet les

choses sont moins faciles car les opeacuterations sont geacuteneacuteralement reacutealiseacutees par les fonctions

membres Cela signifie que lutilisateur doit preacuteciser parmi ces fonctions membres lesquel-

les sont autoriseacutees agrave opeacuterer sur des objets constants Il le fera en utilisant le mot const dans

leur deacuteclaration comme dans cet exemple de deacutefinition dune classe point

class point int x y public point () void affiche () const void deplace ()

Remarque

La remarque du paragraphe 91 agrave propos des arguments muets constants srsquoapplique

encore ici Il ne faut pas confondre un argument muet deacuteclareacute const et un argument effec-

tif deacuteclareacute const

93 Proprieacuteteacutes drsquoune fonction membre constanteLe fait de speacutecifier que la fonction affiche est constante a deux conseacutequences

1 Elle est utilisable pour un objet deacuteclareacute constant

Ici nous avons speacutecifieacute que la fonction affiche eacutetait utilisable pour un point constant En

revanche la fonction deplace qui na pas fait lobjet dune deacuteclaration const ne le sera pas

Ainsi avec ces deacuteclarations

point a const point c

les instructions suivantes seront correctes

aaffiche () caffiche () adeplace ()

En revanche celle-ci sera rejeteacutee par le compilateur

cdeplace () incorrecte c est constant alors que deplace ne lrsquoest pas

La mecircme remarque srsquoappliquerait agrave un objet reccedilu en argument

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

108

void f (const point p) ou mecircme void f(const point amp p) - voir remarque paffiche () OK pdeplace () incorrecte

2 Les instructions figurant dans sa deacutefinition ne doivent pas modifier la valeur des membres

de lrsquoobjet point

class point int x y public void affiche () const x++ erreur car affiche a eacuteteacute deacuteclareacutee const

Les membres statiques font naturellement exception agrave cette regravegle car ils ne sont pas associeacutes

agrave un objet particulier

class compte static int n public void test() const n++ OK bien que test soit deacuteclareacutee constante car n est un membre statique

Remarques

1 Le meacutecanisme que nous venons dexposer sapplique aux fonctions membres volatiles et

aux objets volatiles (mot cleacute volatile) Il suffit de transposer tout ce qui vient drsquoecirctre dit en

remplaccedilant le mot cleacute const par le mot cleacute volatile

2 Il est possible de surdeacutefinir une fonction membre en se fondant sur la preacutesence ou

labsence du qualificatif const Ainsi dans la classe point preacuteceacutedente nous pouvons

deacutefinir ces deux fonctions

void affiche () const affiche I void affiche () affiche II

Avec ces deacuteclarations

point a const point c

linstruction aaffiche () appellera la fonction II tandis que caffiche () appellera la fonc-

tion I

On notera bien que si seule la fonction void affiche() est deacutefinie elle ne pourra en aucun

cas ecirctre appliqueacutee agrave un objet constant une instruction telle que caffiche() serait alors

rejeteacutee en compilation En revanche si seule la fonction const void affiche() est deacutefinie

10 - Les membres mutables109

elle pourra ecirctre appliqueacutee indiffeacuteremment agrave des objets constants ou non Une telle atti-

tude est logique

ndash on ne court aucun risque en traitant un objet non constant comme sil eacutetait constant

ndash en revanche il serait dangereux de faire agrave un objet constant ce quon a preacutevu de faire agrave

un objet non constant

3 Pour pouvoir deacuteclarer un objet constant il faut ecirctre sucircr que le concepteur de la classe

correspondante a eacuteteacute exhaustif dans le recencement des fonctions membres constantes

(crsquoest-agrave-dire deacuteclareacutees avec le qualificatif const) Dans le cas contraire on risque de ne

plus pouvoir appliquer certaines fonctionnaliteacutes agrave un tel objet constant Par exemple on

ne pourra pas appliquer la meacutethode affiche agrave un objet constant de type point si celle-ci

nrsquoa pas effectivement eacuteteacute deacuteclareacutee constante dans la classe

En Java

La notion de fonction membre constante nrsquoexiste pas en Java

10 Les membres mutablesUne fonction membre constante ne peut pas modifier les valeurs de membres non statiques

La norme a jugeacute que cette restriction pouvait parfois srsquoaveacuterer trop contraignante Elle a intro-

duit le qualificatif mutable pour deacutesigner des champs dont on accepte la modification mecircme

par des fonctions membres constantes Voici un petit exemple

class truc int x y mutable int n n est modifiable par une fonction membre constante void f() x = 5 n++ rien de nouveau ici void f1() const n++ OK car n est deacuteclareacute mutable x = 5 erreur f1 est const et x nrsquoest pas mutable

Comme on peut srsquoy attendre les membres publics deacuteclareacutes avec le qualificatif mutable sont

modifiables par affectation

class truc2 public int n mutable int p const truc c cn = 5 erreur lrsquoobjet c est constant et n nrsquoest pas mutablecp = 5 OK lrsquoobjet c est constant mais p est mutable

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

110

En Java

En Java il nrsquoexiste pas de membres constants a fortiori il ne peut y avoir de membres

mutables

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 (C) Ecrivez une classe vecteur comportant

bull trois composantes de type double (priveacutees)

bull une fonction affiche

bull deux constructeurs

ndash lun sans arguments initialisant chaque composante agrave 0

ndash lautre avec 3 arguments repreacutesentant les composantes

a) avec des fonctions membres indeacutependantes

b) avec des fonctions membres en ligne

2 (C) Ajoutez agrave la premiegravere classe vecteur preacuteceacutedente une fonction membre nommeacutee

prod_scal fournissant en reacutesultat le produit scalaire de deux vecteurs

3 (C) Ajoutez agrave la classe vecteur preacuteceacutedente (exercice 2) une fonction membre nommeacutee

somme permettant de calculer la somme de deux vecteurs

4 (C) Modifiez la classe vecteur preacuteceacutedente (exercice 3) de maniegravere que toutes les transmis-

sions de valeurs de type vecteur aient lieu

a) par adresse

b) par reacutefeacuterence

7

Construction destructionet initialisation des objets

En langage C une variable peut ecirctre creacuteeacutee de deux faccedilons

bull par une deacuteclaration elle est alors de classe automatique ou statique sa dureacutee de vie est

parfaitement deacutefinie par la nature et lemplacement de sa deacuteclaration

bull en faisant appel agrave des fonctions de gestion dynamique de la meacutemoire (malloc calloc

free) elle est alors dite dynamique sa dureacutee de vie est controcircleacutee par le programme

En langage C++ on retrouvera ces trois classes agrave la fois pour les variables ordinaires et pour

les objets avec cette diffeacuterence que la gestion dynamique fera appel aux opeacuterateurs new et

delete

Dans ce chapitre nous eacutetudierons ces diffeacuterentes possibiliteacutes de creacuteation (donc aussi de des-

truction) des objets Nous commencerons par examiner la creacuteation et la destruction des objets

automatiques et statiques deacutefinis par une deacuteclaration Puis nous montrerons comment creacuteer et

utiliser des objets dynamiques dune maniegravere comparable agrave celle employeacutee pour creacuteer des

variables dynamiques ordinaires en faisant appel agrave une syntaxe eacutelargie de lopeacuterateur new

Nous aborderons ensuite la notion de constructeur de recopie qui intervient dans les situa-

tions dites drsquoinitialisation dun objet cest-agrave-dire lorsquil est neacutecessaire de reacutealiser une

copie dun objet existant Nous verrons quil existe trois situations de ce type transmission

de la valeur dun objet en argument dune fonction transmission de la valeur dun objet en

reacutesultat dune fonction initialisation dun objet lors de sa deacuteclaration par un objet de mecircme

Construction destruction et initialisation des objetsCHAPITRE 7

112

type cette derniegravere possibiliteacute neacutetant quun cas particulier dinitialisation dun objet au

moment de sa deacuteclaration

Puis nous examinerons le cas des objets membres cest-agrave-dire le cas ougrave un type classe pos-

segravede des membres donneacutees eux-mecircme dun type classe Nous aborderons rapidement le cas

du tableau dobjets notion dautant moins importante quun tel tableau nest pas lui-mecircme un

objet

Enfin nous fournirons quelques indications concernant les objets dits temporaires cest-agrave-

dire pouvant ecirctre creacuteeacutes au fil du deacuteroulement du programme1 sans que le programmeur lait

explicitement demandeacute

1 Les objets automatiques et statiquesNous examinons seacutepareacutement

bull leur dureacutee de vie cest-agrave-dire le moment ougrave ils sont creacuteeacutes et celui ougrave ils sont deacutetruits

bull les eacuteventuels appels des constructeurs et des destructeurs

11 Dureacutee de vieLes regravegles sappliquant aux variables ordinaires se transposent tout naturellement aux objets

Les objets automatiques sont ceux creacuteeacutes par une deacuteclaration

bull dans une fonction ceacutetait le cas dans les exemples des chapitres preacuteceacutedents Lrsquoobjet est

creacuteeacute lors de la rencontre de sa deacuteclaration laquelle peut tregraves bien en C++ ecirctre situeacutee apregraves

dautres instructions exeacutecutables2 Il est deacutetruit agrave la fin de lexeacutecution de la fonction

bull dans un bloc lrsquoobjet est aussi creacuteeacute lors de la rencontre de sa deacuteclaration (lagrave encore celle-

ci peut ecirctre preacuteceacutedeacutee au sein de ce bloc dautres instructions exeacutecutables) il est deacutetruit lors

de la sortie du bloc

Les objets statiques sont ceux creacuteeacutes par une deacuteclaration situeacutee

bull en dehors de toute fonction

bull dans une fonction mais assortie du qualificatif static

Les objets statiques sont creacuteeacutes avant le deacutebut de lexeacutecution de la fonction main et deacutetruits

apregraves la fin de son exeacutecution

1 En C il existe deacutejagrave des variables temporaires mais leur existence a moins drsquoimportance que celle des objets

temporaires en C++

2 La distinction entre instruction exeacutecutable et instruction de deacuteclaration nest pas toujours possible dans un langage

comme C++ qui accepte par exemple une instruction telle que

double adr = new double [nelem = 2 n+1]

1 - Les objets automatiques et statiques113

12 Appel des constructeurs et des destructeursRappelons que si un objet possegravede un constructeur sa deacuteclaration (lorsque comme nous le

supposons pour linstant elle ne contient pas drsquoinitialiseur) doit obligatoirement comporter

les arguments correspondants Par exemple si une classe point comporte le constructeur de

prototype

point (int int)

les deacuteclarations suivantes seront incorrectes

point a incorrect le constructeur attend deux argumentspoint b (3) incorrect (mecircme raison)

Celle-ci en revanche conviendra

point a(1 7) correct car le constructeur possegravede deux arguments

Sil existe plusieurs constructeurs il suffit que la deacuteclaration comporte les arguments requis

par lun dentre eux Ainsi si une classe point comporte les constructeurs suivants

point ( ) constructeur 1point (int int) constructeur 2

la deacuteclaration suivante sera rejeteacutee

point a(5) incorrect aucun constructeur agrave un argument

Mais celles-ci conviendront

point a correct appel du constructeur 1point b(1 7) correct appel du constructeur 2

En ce qui concerne la chronologie on peut dire que

bull le constructeur est appeleacute apregraves la creacuteation de lrsquoobjet

bull le destructeur est appeleacute avant la destruction de lobjet

Remarque

Une deacuteclaration telle que

point a attention point a () serait une deacuteclaration drsquoune fonction a

est acceptable dans deux situations fort diffeacuterentes

ndash il nexiste pas de constructeur de point

ndash il existe un constructeur de point sans argument

13 ExempleVoici un exemple de programme mettant en eacutevidence la creacuteation et la destruction dobjets sta-

tiques et automatiques Nous avons deacutefini une classe nommeacutee point dans laquelle le cons-

tructeur et le destructeur affichent un message permettant de repeacuterer

Construction destruction et initialisation des objetsCHAPITRE 7

114

bull le moment de leur appel

bull lrsquoobjet concerneacute (nous avons fait en sorte que chaque objet de type point possegravede des valeurs

diffeacuterentes)

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs int ord) constructeur (inline)

x = abs y = ord

cout ltlt ++ Construction dun point ltlt x ltlt ltlt y ltlt n

~point () destructeur (inline)

cout ltlt -- Destruction du point ltlt x ltlt ltlt y ltlt n

point a(11) un objet statique de classe point

main()

cout ltlt Debut main n

point b(1010) un objet automatique de classe point

int i

for (i=1 ilt=3 i++)

cout ltlt Boucle tour numero ltlt i ltlt n

point b(i2i) objets creacuteeacutes dans un bloc

cout ltlt Fin main n

++ Construction dun point 1 1

Debut main

++ Construction dun point 10 10

Boucle tour numero 1

++ Construction dun point 1 2

-- Destruction du point 1 2

Boucle tour numero 2

++ Construction dun point 2 4

-- Destruction du point 2 4

Boucle tour numero 3

++ Construction dun point 3 6

-- Destruction du point 3 6

Fin main

2 - Les objets dynamiques115

-- Destruction du point 10 10-- Destruction du point 1 1

Construction et destruction dobjets statiques et automatiques

Remarque

Lexistence de constructeurs et de destructeurs conduit agrave des traitements qui napparais-

sent pas explicitement dans les instructions du programme Par exemple ici une deacuteclara-

tion banale telle que

point b(10 10)

entraicircne laffichage dun message

Qui plus est un certain nombre drsquoopeacuterations se deacuteroulent avant le deacutebut ou apregraves lexeacute-

cution de la fonction main1 On pourrait agrave la limite concevoir une fonction main ne

comportant que des deacuteclarations (ce qui serait le cas de notre exemple si nous suppri-

mions linstruction daffichage du tour de boucle) et reacutealisant malgreacute tout un certain

traitement

2 Les objets dynamiquesNous avons deacutejagrave vu comment creacuteer utiliser et deacutetruire des variables dynamiques scalaires (ou

des tableaux de telles variables) en C++ Bien entendu ces possibiliteacutes srsquoeacutetendent aux struc-

tures et aux objets Nous commencerons par les structures ce qui nous permettra un certain

nombre de rappels sur lutilisation des structures dynamiques en C

21 Les structures dynamiquesSupposez que nous ayons deacutefini la structure suivante

struct chose int x double y int t [5]

et que adr soit un pointeur sur des eacuteleacutements de ce type cest-agrave-dire deacuteclareacute en C par

struct chose adr

1 En toute rigueur il en va deacutejagrave de mecircme dans le cas dun programme C (ouverture ou fermeture de fichiers par

exemple) mais il ne sagit pas alors de tacircches programmeacutees explicitement par lauteur du programme dans le cas de

C++ il sagit de tacircches programmeacutees par le concepteur de la classe concerneacutee

Construction destruction et initialisation des objetsCHAPITRE 7

116

ou plus simplement en C++ par

chose adr

Linstruction

adr = new chose

reacutealise une allocation dynamique despace meacutemoire pour un eacuteleacutement de type chose et affecte

son adresse au pointeur adr

Laccegraves aux diffeacuterents champs de cette structure se fait agrave laide de lopeacuterateur -gt Ainsi adr -

gt y deacutesignera le second champ Rappelons que cette notation est en fait eacutequivalente agrave (adr)

y

Lespace meacutemoire ainsi alloueacute pourra ecirctre libeacutereacute par

delete adr

22 Les objets dynamiquesVoyons tout dabord ce quil y a de commun entre la creacuteation dynamique dobjets et celle de

structures avant deacutetudier les nouvelles possibiliteacutes de lopeacuterateur new

221 Points communs avec les structures dynamiquesLe meacutecanisme que nous venons deacutevoquer sapplique aux objets (au sens large) lorsquils ne

possegravedent pas de constructeur Ainsi si nous deacutefinissons le type point suivant

class point

int x y

public

void initialise (int int)

void deplace (int int)

void affiche ( )

et si nous deacuteclarons

point adr

nous pourrons creacuteer dynamiquement un emplacement de type point (qui contiendra donc ici

la place pour deux entiers) et affecter son adresse agrave adr par

adr = new point

Laccegraves aux fonctions membres de lrsquoobjet pointeacute par adr se fera par des appels de la forme

adr -gt initialise (1 3)

adr -gt affiche ( )

ou eacuteventuellement sans utiliser lopeacuterateur -gt par

( adr)initialise (1 3)

( adr)affiche ( )

Si lrsquoobjet contenait des membres donneacutees publics on y acceacutederait de faccedilon comparable

Quant agrave la suppression de lrsquoobjet en question elle se fera ici encore par

delete adr

2 - Les objets dynamiques117

222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete

Nous avons deacutejagrave vu que la philosophie de C++ consiste agrave faire du constructeur (degraves lors quil

existe) un passage obligeacute lors de la creacuteation dun objet Il en va de mecircme pour le destructeur

lors de la destruction dun objet

Cette philosophie sapplique eacutegalement aux objets dynamiques Plus preacuteciseacutement

bull Apregraves lallocation dynamique de lemplacement meacutemoire requis lopeacuterateur new appelle-

ra un constructeur de lrsquoobjet ce constructeur sera deacutetermineacute par la nature des arguments

qui figurent agrave la suite de son appel comme dans

new point (2 5)

On peut dire que le constructeur appeleacute est le mecircme que celui qui aurait eacuteteacute appeleacute par une

deacuteclaration telle que

a = point (2 5)

Bien entendu sil nexiste pas de constructeur ou sil existe un constructeur sans argument

la syntaxe

new point ou new point ()

sera accepteacutee En revanche si tous les constructeurs possegravedent au moins un argument cette

syntaxe sera rejeteacutee

On retrouve lagrave en deacutefinitive les mecircmes regravegles que celles sappliquant agrave la deacuteclaration dun

objet

bull Avant la libeacuteration de lemplacement meacutemoire correspondant lopeacuterateur delete appellera

le destructeur

223 Exemple

Voici un exemple de programme qui creacutee dynamiquement un objet de type point dans la

fonction main et qui le deacutetruit dans une fonction fct (appeleacutee par main) Les messages affi-

cheacutes permettent de mettre en eacutevidence les moments auxquels sont appeleacutes le constructeur et

le destructeur

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) constructeur x=abs y=ord cout ltlt ++ Appel Constructeur n ~point () destructeur (en fait inutile ici) cout ltlt -- Appel Destructeur n

Construction destruction et initialisation des objetsCHAPITRE 7

118

main() void fct (point ) prototype fonction fct point adr cout ltlt Debut main n adr = new point (37) creacuteation dynamique dun objet fct (adr) cout ltlt Fin main n void fct (point adp) cout ltlt Debut fct n delete adp destruction de cet objet cout ltlt Fin fct n

Debut main ++ Appel Constructeur Debut fct -- Appel Destructeur Fin fct Fin main

Exemple de creacuteation dynamique dobjets

En Java

Il nrsquoexiste qursquoune seule maniegravere de geacuterer la meacutemoire alloueacutee agrave un objet agrave savoir de

maniegravere dynamique Les emplacements sont alloueacutes explicitement en faisant appel agrave une

meacutethode nommeacutee eacutegalement new En revanche leur libeacuteration se fait automatiquement

gracircce agrave un ramasse-miettes destineacute agrave reacutecupeacuterer les emplacements qui ne sont plus reacutefeacuteren-

ceacutes

3 Le constructeur de recopie

31 PreacutesentationNous avons vu comment C++ garantissait lappel dun constructeur pour un objet creacuteeacute par une

deacuteclaration ou par new Ce point est fondamental puisquil donne la certitude quun objet ne

pourra ecirctre creacuteeacute sans avoir eacuteteacute placeacute dans un eacutetat initial convenable (du moins jugeacute comme

tel par le concepteur de lrsquoobjet)

Mais il existe des circonstances dans lesquelles il est neacutecessaire de construire un objet mecircme

si le programmeur na pas preacutevu de constructeur pour cela La situation la plus freacutequente est

celle ougrave la valeur dun objet doit ecirctre transmise en argument agrave une fonction Dans ce cas il est

3 - Le constructeur de recopie119

neacutecessaire de creacuteer dans un emplacement local agrave la fonction un objet qui soit une copie de

largument effectif Le mecircme problegraveme se pose dans le cas dun objet renvoyeacute par valeur

comme reacutesultat dune fonction il faut alors creacuteer dans un emplacement local agrave la fonction

appelante un objet qui soit une copie du reacutesultat Nous verrons quil existe une troisiegraveme

situation de ce type agrave savoir le cas ougrave un objet est initialiseacute lors de sa deacuteclaration avec un

autre objet de mecircme type

Dune maniegravere geacuteneacuterale on regroupe ces trois situations sous le nom dinitialisation par

recopie1 Une initialisation par recopie dun objet est donc la creacuteation dun objet par recopie

dun objet existant de mecircme type

Pour reacutealiser une telle initialisation C++ a preacutevu dutiliser un constructeur particulier dit

constructeur de recopie2 (nous verrons plus loin la forme exacte quil doit posseacuteder) Si un

tel constructeur nexiste pas un traitement par deacutefaut est preacutevu on peut dire de faccedilon eacutequi-

valente quon utilise un constructeur de recopie par deacutefaut

En deacutefinitive on peut dire que dans toute situation dinitialisation par recopie il y toujours

appel dun constructeur de recopie mais il faut distinguer deux cas principaux et un cas parti-

culier

311 Il nexiste pas de constructeur approprieacute

Il y alors appel dun constructeur de recopie par deacutefaut geacuteneacutereacute automatiquement par le

compilateur Ce constructeur se contente deffectuer une copie de chacun des membres On

retrouve lagrave une situation analogue agrave celle qui est mise en place (par deacutefaut) lors dune affecta-

tion entre objets de mecircme type Elle posera donc les mecircmes problegravemes pour les objets conte-

nant des pointeurs sur des emplacements dynamiques On aura simplement affaire agrave une

copie superficielle cest-agrave-dire que seules les valeurs des pointeurs seront recopieacutees les

emplacements pointeacutes ne le seront pas ils risquent alors par exemple drsquoecirctre deacutetruits deux

fois

312 Il existe un constructeur approprieacute

Vous pouvez fournir explicitement dans votre classe un constructeur de recopie Il doit

alors sagir dun constructeur disposant drsquoun seul argument3 du type de la classe et transmis

obligatoirement par reacutefeacuterence Cela signifie que son en-tecircte doit ecirctre obligatoirement de lune

de ces deux formes (si la classe concerneacutee se nomme point)

point (point amp) point (const point amp)

Dans ce cas ce constructeur est appeleacute de maniegravere habituelle apregraves la creacuteation de lobjet

Bien entendu aucune recopie nest faite de faccedilon automatique pas mecircme une recopie super-

1 Nous aurions pu nous limiter au terme initialisation sil nexistait pas des situations ougrave lon peut initialiser un objet

avec une valeur ou un objet dun type diffeacuterent

2 En anglais copy constructor

3 En toute rigueur la norme ANSI du C++ accepte eacutegalement un constructeur disposant drsquoarguments

suppleacutementaires pourvu qursquoils possegravedent des valeurs par deacutefaut

Construction destruction et initialisation des objetsCHAPITRE 7

120

ficielle contrairement agrave la situation preacuteceacutedente cest agrave ce constructeur de prendre en charge

linteacutegraliteacute du travail (copie superficielle et copie profonde)

313 Lorsqursquoon souhaite interdire la contruction par recopie

On a vu que la copie par deacutefaut des objets contenant des pointeurs nrsquoeacutetait pas satisfaisante

Dans certains cas plutocirct que de munir une classe du constructeur de recopie voulu le con-

cepteur pourra chercher agrave interdire la copie des objets de cette classe Il dispose alors pour

cela de diffeacuterentes possibiteacutes

Par exemple comme nous venons de le voir un constructeur priveacute nrsquoest pas appelable par un

utilisateur de la classe On peut aussi utiliser la possibliteacute offerte par C++ de deacuteclarer une

fonction sans en fournir de deacutefinition dans ce cas toute tentative de copie (mecircme par une

fonction membre cette fois) sera rejeteacutee par lrsquoeacutediteur de liens Drsquoune maniegravere geacuteneacuterale il

peut ecirctre judicieux de combiner les deux possibiliteacutes crsquoest-agrave-dire drsquoeffectuer une deacuteclaration

priveacutee sans deacutefinition Dans ce cas les tentatives de recopie par lrsquoutilisateur resteront deacutetec-

teacutees en compilation (avec un message explicite) et seules les recopies par une fonction mem-

bre se limiteront agrave une erreur drsquoeacutedition de liens (et ce point ne concerne que le concepteur de

la classe pas son utilisateur )

Remarques

1 Notez bien que C++ impose au constructeur par recopie que son unique argument soit

transmis par reacutefeacuterence (ce qui est logique puisque sinon lappel du constructeur de reco-

pie impliquerait une initialisation par recopie de largument donc un appel du construc-

teur de recopie qui lui-mecircme etc)

Quoi quil en soit la forme suivante serait rejeteacutee en compilation

point (point) incorrect

2 Les deux formes preacuteceacutedentes (point (point amp) et point (const point amp)) pourraient exis-

ter au sein dune mecircme classe Dans ce cas la premiegravere serait utiliseacutee en cas dinitialisa-

tion dun objet par un objet quelconque tandis que la seconde serait utiliseacutee en cas

dinitialisation par un objet constant En geacuteneacuteral comme un tel constructeur de recopie

na logiquement aucune raison de vouloir modifier lrsquoobjet reccedilu en argument il est con-

seilleacute de ne deacutefinir que la seconde forme qui restera ainsi applicable aux deux situa-

tions eacutevoqueacutees (une fonction preacutevue pour un objet constant peut toujours sappliquer agrave

un objet variable la reacuteciproque eacutetant naturellement fausse)

3 Nous avons deacutejagrave rencontreacute des situations de recopie dans le cas de laffectation Mais

alors les deux objets concerneacutes existaient deacutejagrave laffectation nest donc pas une situation

dinitialisation par recopie telle que nous venons de la deacutefinir Bien que les deux opeacutera-

tions possegravedent un traitement par deacutefaut semblable (copie superficielle) la prise en

compte dune copie profonde passe par des meacutecanismes diffeacuterents deacutefinition dun

constructeur de recopie pour lrsquoinitialisation surdeacutefinition de lopeacuterateur = pour laffec-

tation (ce que nous apprendrons agrave faire dans le chapitre consacreacute agrave la surdeacutefinition des

opeacuterateurs)

3 - Le constructeur de recopie121

4 Nous verrons que si une classe est destineacutee agrave donner naissance agrave des objets susceptibles

drsquoecirctre introduits dans des conteneurs il ne sera plus possible drsquoen deacutesactiver la reco-

pie (pas plus que lrsquoaffectation)

En Java

Les objets sont manipuleacutes non par valeur mais par reacutefeacuterence La notion de constructeur

de recopie nrsquoexiste pas En cas de besoin il reste possible de creacuteer explicitement une

copie profonde drsquoun objet nommeacutee clone

32 Exemple 1 objet transmis par valeurNous vous proposons de comparer les deux situations que nous venons deacutevoquer constructeur

de recopie par deacutefaut constructeur de recopie deacutefini dans la classe Pour ce faire nous allons

utiliser une classe vect permettant de geacuterer des tableaux dentiers de taille variable (on devrait

plutocirct dire de taille deacutefinissable lors de lexeacutecution car une fois deacutefinie cette taille ne changera

plus) Nous souhaitons que lutilisateur de cette classe deacuteclare un tableau sous la forme

vect t (dim)

dim eacutetant une expression entiegravere repreacutesentant sa taille

Il paraicirct alors naturel de preacutevoir pour vect

bull comme membres donneacutees la taille du tableau et un pointeur sur ses eacuteleacutements lesquels ver-

ront leurs emplacements alloueacutes dynamiquement

bull un constructeur recevant un argument entier chargeacute de cette allocation dynamique

bull un destructeur libeacuterant lemplacement alloueacute par le constructeur

Cela nous conduit agrave une premiegravere eacutebauche

class vect int nelem double adr public vect (int n) ~vect ( )

321 Emploi du constructeur de recopie par deacutefaut

Voici un exemple dutilisation de la classe vect preacuteceacutedente (nous avons ajouteacute des affichages

de messages pour suivre agrave la trace les constructions et destructions dobjets) Ici nous nous

contentons de transmettre par valeur un objet de type vect agrave une fonction ordinaire nommeacutee

fct qui ne fait rien dautre que dafficher un message indiquant son appel

include ltiostreamgtusing namespace std

Construction destruction et initialisation des objetsCHAPITRE 7

122

class vect

int nelem nombre deacuteleacutements

double adr pointeur sur ces eacuteleacutements

public

vect (int n) constructeur usuel

adr = new double [nelem = n]

cout ltlt + const usuel - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

~vect () destructeur

cout ltlt - Destr objet - adr objet

ltlt this ltlt - adr vecteur ltlt adr ltlt n

delete adr

void fct (vect b)

cout ltlt appel de fct n

main()

vect a(5)

fct (a)

+ const usuel - adr objet 006AFDE4 - adr vecteur 007D0320

appel de fct

- Destr objet - adr objet 006AFD90 - adr vecteur 007D0320

- Destr objet - adr objet 006AFDE4 - adr vecteur 007D0320

Lorsquaucun constructeur de recopie na eacuteteacute deacutefini

Comme vous pouvez le constater lappel

fct (a)

a creacuteeacute un nouvel objet dans lequel on a recopieacute les valeurs des membres nelem et adr de a

La situation peut ecirctre scheacutematiseacutee ainsi (b est le nouvel objet ainsi creacuteeacute)

a

b

5

5

3 - Le constructeur de recopie123

A la fin de lexeacutecution de la fonction fct le destructeur ~point est appeleacute pour b ce qui libegravere

lemplacement pointeacute par adr agrave la fin de lrsquoeacutexeacutecution de la fonction main le destructeur est

appeleacute pour a ce qui libegravere le mecircme emplacement Cette tentative constitue une erreur

dexeacutecution dont les conseacutequences varient avec lrsquoimpleacutementation

322 Deacutefinition dun constructeur de recopie

On peut eacuteviter ce problegraveme en faisant en sorte que lappel

fct (a)

conduise agrave creacuteer inteacutegralement un nouvel objet de type vect avec ses membres donneacutees

nelem et adr mais aussi son propre emplacement de stockage des valeurs du tableau Autre-

ment dit nous souhaitons aboutir agrave cette situation

Pour ce faire nous deacutefinissons au sein de la classe vect un constructeur par recopie de la

forme

vect (const vect amp) ou a la rigueur vect (vect amp)

dont nous savons quil sera appeleacute dans toute situation dinitialisation donc en particulier

lors de lappel de fct

Ce constructeur (appeleacute apregraves la creacuteation dun nouvel objet1) doit

bull creacuteer dynamiquement un nouvel emplacement dans lequel il recopie les valeurs correspon-

dant agrave lrsquoobjet reccedilu en argument

bull renseigner convenablement les membres donneacutees du nouvel objet (nelem = valeur du mem-

bre nelem de lrsquoobjet reccedilu en argument adr = adresse du nouvel emplacement)

1 Notez bien que le constructeur na pas agrave creacuteer lrsquoobjet lui-mecircme cest-agrave-dire ici les membres int et adr mais

simplement les parties soumises agrave la gestion dynamique

a

b

5

5

Construction destruction et initialisation des objetsCHAPITRE 7

124

Introduisons ce constructeur de recopie dans lrsquoexemple preacuteceacutedent

include ltiostreamgt

using namespace std

class vect

int nelem nombre deacuteleacutements

double adr pointeur sur ces eacuteleacutements

public

vect (int n) constructeur usuel

adr = new double [nelem = n]

cout ltlt + const usuel - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

vect (const vect amp v) constructeur de recopie

adr = new double [nelem = vnelem] creacuteation nouvel objet

int i for (i=0 iltnelem i++) adr[i]=vadr[i] recopie de lancien

cout ltlt + const recopie - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

~vect () destructeur

cout ltlt - Destr objet - adr objet

ltlt this ltlt - adr vecteur ltlt adr ltlt n

delete adr

void fct (vect b)

cout ltlt appel de fct n

main()

vect a(5) fct (a)

+ const usuel - adr objet 006AFDE4 - adr vecteur 007D0320

+ const recopie - adr objet 006AFD88 - adr vecteur 007D0100

appel de fct

- Destr objet - adr objet 006AFD88 - adr vecteur 007D0100

- Destr objet - adr objet 006AFDE4 - adr vecteur 007D0320

Deacutefinition et utilisation dun constructeur de recopie

Vous constatez cette fois que chaque objet posseacutedant son propre emplacement meacutemoire les

destructions successives se deacuteroulent sans problegraveme

3 - Le constructeur de recopie125

Remarques

1 Si nous avons reacutegleacute le problegraveme de lrsquoinitialisation dun objet de type vect par un autre

objet du mecircme type nous navons pas pour autant reacutegleacute celui qui se poserait en cas

drsquoaffectation entre objets de type vect Comme nous lavons deacutejagrave signaleacute agrave plusieurs repri-

ses ce dernier point ne peut se reacutesoudre que par la surdeacutefinition de lopeacuterateur =

2 Nous avons choisi pour notre constructeur par recopie la deacutemarche la plus naturelle

consistant agrave effectuer une copie profonde en dupliquant la partie dynamique du vecteur

Dans certains cas on pourra chercher agrave eacuteviter cette duplication en la dotant drsquoun comp-

teur de reacutefeacuterences comme lrsquoexplique lrsquoAnnexe E

3 Si notre constructeur de recopie eacutetait deacuteclareacute priveacute lrsquoappel fct(a) entraicircnerait une erreur

de compilation preacutecisant qursquoun constructeur de recopie nrsquoest pas disponible Si le but

est de deacutefinir une classe dans laquelle la recopie est interdite il suffit alors de ne fournir

aucune deacutefinition On notera cependant qursquoil reste neacutecessaire de srsquoassurer qursquoaucune

fonction membre nrsquoaura besoin de ce constructeur ce qui serait par exemple le cas si

notre fonction membre f de la classe vect se preacutesentait ainsi

void f()

void fct (vect) deacuteclaration de la fonction ordinaire fct

vect v1(5)

fct (v1) appel de fct --gt appel contsructeur de recopie

vect v2 = v1 initialisation par appel constructeur de recopie

33 Exemple 2 objet en valeur de retour dune fonctionLorsque la transmission dun argument ou dune valeur de retour dune fonction a lieu par

valeur elle met en œuvre une recopie Lorsqursquoelle concerne un objet cette recopie est

comme nous lavons dit reacutealiseacutee soit par le constructeur de recopie par deacutefaut soit par le

constructeur de recopie preacutevu pour lobjet

Si un objet comporte une partie dynamique lemploi de la recopie par deacutefaut conduit agrave une

copie superficielle ne concernant que les membres de lobjet Les risques de double libeacutera-

tion dun emplacement meacutemoire sont alors les mecircmes que ceux eacutevoqueacutes au paragraphe 32

Mais pour la partie dynamique de lrsquoobjet on perd en outre le beacuteneacutefice de la protection contre

des modifications quoffre la transmission par valeur En effet dans ce cas la fonction con-

cerneacutee reccediloit bien une copie de ladresse de lemplacement mais par le biais de ce pointeur

elle peut tout agrave fait modifier le contenu de lemplacement lui-mecircme (revoyez le scheacutema du

paragraphe 321 dans lequel a jouait le rocircle dun argument et b celui de sa recopie)

Voici un exemple de programme faisant appel agrave une classe point doteacutee dune fonction mem-

bre nommeacutee symetrique fournissant en retour un point symeacutetrique de celui layant appeleacute

Notez bien quici contrairement agrave lexemple preacuteceacutedent le constructeur de recopie nest pas

Construction destruction et initialisation des objetsCHAPITRE 7

126

indispensable au bon fonctionnement de notre classe (qui ne comporte aucune partie

dynamique) il ne sert quagrave illustrer le meacutecanisme de son appel

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur usuel

x=abs y=ord

cout ltlt ++ Appel Const usuel ltlt this ltlt ltlt x ltlt ltlt y ltlt n

point (const point amp p) constructeur de recopie

x=px y=py

cout ltlt ++ Appel Const recopie ltlt this ltlt ltlt x ltlt ltlt y ltlt n

~point ()

cout ltlt -- Appel Destr ltlt this ltlt ltlt x ltlt ltlt y ltlt n

point symetrique ()

point pointsymetrique ()

point res resx = -x resy = -y return res

main()

point a(13) b

cout ltlt avant appel de symetriquen

b = asymetrique ()

cout ltlt apres appel de symetriquen

++ Appel Const usuel 006AFDE4 1 3

++ Appel Const usuel 006AFDDC 0 0

avant appel de symetrique

++ Appel Const usuel 006AFD60 0 0

++ Appel Const recopie 006AFDD4 -1 -3

-- Appel Destr 006AFD60 -1 -3

-- Appel Destr 006AFDD4 -1 -3

apres appel de symetrique

-- Appel Destr 006AFDDC -1 -3

-- Appel Destr 006AFDE4 1 3

Appel du constructeur de recopie en cas de transmission par valeur

4 - Initialisation dun objet lors de sa deacuteclaration127

4 Initialisation dun objet lors de sa deacuteclarationNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

En langage C on peut initialiser une variable au moment de sa deacuteclaration comme dans

int n = 12

En theacuteorie C++ permet de faire de mecircme avec les objets en ajoutant un initialiseur lors de

leur deacuteclaration Mais si le rocircle dun tel initialiseur va de soi dans le cas de variables classi-

ques (il ne sagit que den fournir la ou les valeurs) il nen va plus de mecircme dans le cas dun

objet en effet il ne sagit plus de se contenter dinitialiser simplement ses membres mais

plutocirct de fournir sous une forme peu naturelle des arguments pour un constructeur De plus

C++ nimpose aucune restriction sur le type de linitialiseur qui pourra donc ecirctre du mecircme

type que lrsquoobjet initialiseacute le constructeur utiliseacute sera alors le constructeur de recopie preacute-

senteacute preacuteceacutedemment

Consideacuterons dabord cette classe (munie dun constructeur usuel)

class point

int x y

public

point (int abs) x = abs y = 0

Nous avons deacutejagrave vu quel serait le rocircle dune deacuteclaration telle que

point a(3)

C++ nous autorise eacutegalement agrave eacutecrire

point a = 3

Cette deacuteclaration entraicircne

bull la creacuteation dun objet a

bull lappel du constructeur auquel on transmet en argument la valeur de linitialiseur ici 3

En deacutefinitive les deux deacuteclarations

point a(3)

point a = 3

sont eacutequivalentes

Dune maniegravere geacuteneacuterale lorsque lon deacuteclare un objet avec un initialiseur ce dernier peut

ecirctre une expression dun type quelconque agrave condition quil existe un constructeur agrave un seul

argument de ce type

Cela sapplique donc aussi agrave une situation telle que

point a

point b = a on initialise b avec lrsquoobjet a de mecircme type

Manifestement on aurait obtenu le mecircme reacutesultat en deacuteclarant

point b(a) on creacutee lobjet b en utilisant le constructeur par recopie

de la classe point auquel on transmet lobjet a

Construction destruction et initialisation des objetsCHAPITRE 7

128

Quoi quil en soit ces deux deacuteclarations (point b=a et point b(a)) entraicircnent effectivement la

creacuteation dun objet de type point suivie de lappel du constructeur par recopie de point (celui

par deacutefaut ou le cas eacutecheacuteant celui quon y a deacutefini) auquel on transmet en argument

lobjet a

Remarques

1 Il ne faut pas confondre linitialiseur dune classe avec celui employeacute en C pour donner

des valeurs initiales agrave un tableau

int t[5] = 3 5 11 2 0

ou agrave une structure Celui-ci est toujours utilisable en C++ y compris pour les structures

comportant des fonctions membres Il est mecircme applicable agrave des classes ne disposant

pas de constructeur et dans lesquelles tous les membres sont publics en pratique cette

possibiliteacute ne preacutesente guegravere dinteacuterecirct

2 Supposons quune classe point soit munie dun constructeur agrave deux arguments entiers et

consideacuterons la deacuteclaration

point a = point (1 5)

Il sagit bien dune deacuteclaration comportant un initialiseur constitueacute dune expression de

type point On pourrait logiquement penser quelle entraicircne lappel dun constructeur de

recopie (par deacutefaut ou effectif) en vue dinitialiser lobjet a nouvellement creacuteeacute avec

lrsquoexpression temporaire point (15)

En fait dans ce cas preacutecis dinitialisation dun objet par appel explicite du constructeur

C++ a preacutevu de traiter cette deacuteclaration comme

point a(1 5)

Autrement dit il y a creacuteation dun seul objet a et appel du constructeur (usuel) pour

cet objet Aucun constructeur de recopie nest appeleacute

Cette deacutemarche est assez naturelle et simplificatrice Elle nen demeure pas moins une

exception par opposition agrave celle qui sera mise en œuvre dans

point a = b

ou dans

point a = b + point (1 5)

lorsque nous aurons appris agrave donner un sens agrave une expression telle que b + point (1 5)

(qui suppose la surdeacutefinition de lopeacuterateur + pour la classe point)

5 - Objets membres129

5 Objets membres

51 IntroductionIl est tout agrave fait possible quune classe possegravede un membre donneacutee lui-mecircme de type classe

Par exemple ayant deacutefini

class point

int x y

public

int init (int int)

void affiche ( )

nous pouvons deacutefinir

class cercle

point centre

int rayon

public

void affrayon ( )

Si nous deacuteclarons alors

cercle c

lobjet c possegravede un membre donneacutee priveacute centre de type point Lobjet c peut acceacuteder classi-

quement agrave la meacutethode affrayon par caffrayon En revanche il ne pourra pas acceacuteder agrave la

meacutethode init du membre centre car centre est priveacute Si centre eacutetait public on pourrait acceacuteder

aux meacutethodes de centre par ccentreinit () ou ccentreaffiche ()

Dune maniegravere geacuteneacuterale la situation dobjets membres correspond agrave une relation entre classes

du type relation de possession (on dit aussi relation a ndash du verbe avoir) Effectivement on

peut bien dire ici quun cercle possegravede (a) un centre (de type point) Ce type de relation

soppose agrave la relation qui sera induite par lrsquoheacuteritage de type relation est (du verbe ecirctre)

Voyons maintenant comment sont mis en œuvre les constructeurs des diffeacuterents objets

lorsquils existent

52 Mise en œuvre des constructeurs et des destructeursSupposons cette fois que notre classe point ait eacuteteacute deacutefinie avec un constructeur

class point

int x y

public

point (int int)

Construction destruction et initialisation des objetsCHAPITRE 7

130

Nous ne pouvons plus deacutefinir la classe cercle preacuteceacutedente sans constructeur En effet si nous

le faisions son membre centre se verrait certes attribuer un emplacement (lors dune creacuteation

dun objet de type cercle) mais son constructeur ne pourrait ecirctre appeleacute (quelles valeurs

pourrait-on lui transmettre )

Il faut donc

bull dune part deacutefinir un constructeur pour cercle

bull dautre part speacutecifier les arguments agrave fournir au constructeur de point ceux-ci doivent ecirctre

choisis obligatoirement parmi ceux fournis agrave cercle

Voici ce que pourrait ecirctre la deacutefinition de cercle et de son constructeur

class cercle point centre int rayon public cercle (int int int) cerclecercle (int abs int ord int ray) centre (abs ord)

Vous voyez que len-tecircte de cercle speacutecifie apregraves les deux-points la liste des arguments qui

seront transmis agrave point

Les constructeurs seront appeleacutes dans lordre suivant point cercle Sil existe des destruc-

teurs ils seront appeleacutes dans lordre inverse

Voici un exemple complet

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord cout ltlt Constr point ltlt x ltlt ltlt y ltlt n class cercle point centre int rayon public cercle (int int int) cerclecercle (int abs int ord int ray) centre(abs ord) rayon = ray cout ltlt Constr cercle ltlt rayon ltlt n main() cercle a (139)

5 - Objets membres131

Constr point 1 3Constr cercle 9

Appel des diffeacuterents constructeurs dans le cas dobjets membres

Remarques

1 Si point dispose dun constructeur sans argument le constructeur de cercle peut ne pas

speacutecifier dargument agrave destination du constructeur de centre qui sera appeleacute automatique-

ment

2 On pourrait eacutecrire ainsi le constructeur de cercle

cerclecercle (int abs int ord int ray) rayon = ray centre = point (abs ord) cout ltlt Constr cercle ltlt rayon ltlt n

Mais dans ce cas on creacuteerait un objet temporaire de type point suppleacutementaire comme

le montre lrsquoexeacutecution du mecircme programme ainsi modifieacute

Constr point 0 0Constr point 1 3Constr cercle 9

3 Dans le cas dobjets comportant plusieurs objets membres la seacutelection des arguments

destineacutes aux diffeacuterents constructeurs se fait en seacuteparant chaque liste par une virgule En

voici un exemple

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(xq) a2(r)

Ici pour simplifier leacutecriture nous avons supposeacute que le constructeur de C eacutetait en

ligne Parmi les arguments n p x q et r quil reccediloit p sera transmis au constructeur A

de a1 x et q au constructeur B de b puis r au constructeur A de a2 Notez bien que

lordre dans lequel ces trois constructeurs sont exeacutecuteacutes est en theacuteorie celui de leur

Construction destruction et initialisation des objetsCHAPITRE 7

132

deacuteclaration dans la classe et non pas celui des initialiseurs En pratique on eacutevitera des

situtations ougrave cet ordre pourrait avoir de lrsquoimportance

En revanche comme on peut srsquoy attendre le constructeur C ne sera exeacutecuteacute quapregraves les

trois autres (lordre des imbrications est toujours respecteacute)

53 Le constructeur de recopieNous avons vu que pour toute classe il est preacutevu un constructeur de recopie par deacutefaut qui

est appeleacute en labsence de constructeur de recopie effectif Son rocircle est simple dans le cas

dobjets ne comportant pas dobjets membres puisquil sagit alors de recopier les valeurs des

diffeacuterents membres donneacutees

Lorsque lobjet comporte des objets membres la recopie (par deacutefaut) se fait membre par

membre1 autrement dit si lun des membres est lui-mecircme un objet on le recopiera en appe-

lant son propre constructeur de recopie (qui pourra ecirctre soit un constructeur par deacutefaut

soit un constructeur deacutefini dans la classe correspondante)

Cela signifie que la construction par recopie (par deacutefaut) dun objet sera satisfaisante degraves lors

quil ne contient pas de pointeurs sur des parties dynamiques mecircme si certains de ses objets

membres en comportent (agrave condition quils soient quant agrave eux munis des constructeurs par

recopie approprieacutes)

En revanche si lobjet contient des pointeurs il faudra le munir dun constructeur de recopie

approprieacute Ce dernier devra alors prendre en charge linteacutegraliteacute de la recopie de lobjet

Cependant on pourra pour cela transmettre les informations neacutecessaire aux constructeurs par

recopie (par deacutefaut ou non) de certains de ses membres en utilisant la technique deacutecrite au

paragraphe 52

6 Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur

La syntaxe que nous avons deacutecrite au paragraphe 52 pour transmettre des arguments agrave un

constructeur dun objet membre peut en fait sappliquer agrave nimporte quel membre mecircme sil

ne sagit pas dun objet Par exemple

class point int x y public point (int abs=0 int ord=0) x(abs) y(ord)

1 En anglais on parle de memberwise copy Avant la version 20 de C++ la copie se faisait bit agrave bit (bitwise copy)

ce qui neacutetait pas toujours satisfaisant

7 - Les tableaux drsquoobjets133

Lappel du constructeur point provoquera lrsquoinitialisation des membres x et y avec respective-

ment les valeurs abs et ord Son corps est vide ici puisquil ny a rien de plus agrave faire pour

remplacer notre constructeur classique

point (int abs=0 int ord=0) x=abs y=ord

Cette possibiliteacute peut devenir indispensable en cas

bull drsquoinitialisation dun membre donneacutee constant Par exemple avec cette classe

class truc const int n public truc ()

il nrsquoest pas possible de proceacuteder ainsi pour initialiser n dans le constructeur de truc

tructruc() n = 12 interdit n est constant

En revanche on pourra proceacuteder ainsi

tructruc() n(12)

bull drsquoinitialisation dun membre donneacutee qui est une reacutefeacuterence En effet on ne peut quinitialiser

une telle reacutefeacuterence jamais lui affecter une nouvelle valeur (revoyez eacuteventuellement le para-

graphe 35 du chapitre 4)

7 Les tableaux drsquoobjetsNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

En C++ un tableau peut posseacuteder des eacuteleacutements de nimporte quel type y compris de type

classe ce qui conduit alors agrave des tableaux dobjets Ce concept ne preacutesente pas de difficulteacutes

particuliegraveres au niveau des notations que nous allons nous contenter de rappeler agrave partir drsquoun

exemple En revanche il nous faudra preacuteciser certains points relatifs agrave lappel des construc-

teurs et aux initialiseurs

71 NotationsSoit une classe point sans constructeur deacutefinie par

class point int x y public void init (int int) void affiche ( )

Construction destruction et initialisation des objetsCHAPITRE 7

134

Nous pouvons deacuteclarer un tableau courbe de vingt objets de type point par

point courbe [20]

Si i est un entier la notation courbe[i] deacutesignera un objet de type point Linstruction

courbe[i]affiche ()

appellera le membre init pour le point courbe[i] (les prioriteacutes relatives des opeacuterateurs et []

permettent de saffranchir de parenthegraveses) De mecircme on pourra afficher tous les points par

for (i = 0 i lt 20 i++) courbe[i]affiche()

Remarque

Un tableau dobjets nest pas un objet Dans lesprit de la POO pure ce concept

nexiste pas puisquon ne manipule que des objets En revanche il reste toujours possible

de deacutefinir une classe dont un des membres est un tableau dobjets Ainsi nous pourrions

deacutefinir un type courbe par

class courbe point p[20]

Notez que la classe vector de la bibliothegraveque standard permettra de deacutefinir des tableaux

dynamiques (dont la taille pourra varier au fil de lrsquoexeacutecution) qui seront de vrais objets

En Java

Non seulement un tableau drsquoobjet est un objet mais mecircme un simple tableau drsquoeacuteleacutements

drsquoun type de base est aussi un objet

72 Constructeurs et initialiseursNous venons de voir la signification de la deacuteclaration

point courbe[20]

dans le cas ougrave point est une classe sans constructeur

Si la classe comporte un constructeur sans argument celui-ci sera appeleacute successivement

pour chacun des eacuteleacutements (de type point) du tableau courbe En revanche si aucun des cons-

tructeurs de point nest un constructeur sans argument la deacuteclaration preacuteceacutedente conduira agrave

une erreur de compilation Dans ce cas en effet C++ nest plus en mesure de garantir le pas-

sage par un constructeur degraves lors que la classe concerneacutee (point) en comporte au moins un

Il est cependant possible de compleacuteter une telle deacuteclaration par un initialiseur comportant une

liste de valeurs chaque valeur sera transmise agrave un constructeur approprieacute (les valeurs peu-

vent donc ecirctre de types quelconques eacuteventuellement diffeacuterents les uns des autres dans la

mesure ougrave il existe le constructeur correspondant) Pour les tableaux de classe automatique

les valeurs de linitialiseur peuvent ecirctre une expression quelconque (pour peu quelle soit cal-

7 - Les tableaux drsquoobjets135

culable au moment ougrave on en a besoin) En outre linitialiseur peut comporter moins de

valeurs que le tableau na deacuteleacutements1 Dans ce cas il y a appel du constructeur sans argument

(qui doit donc exister) pour les eacuteleacutements auxquels ne correspond aucune valeur

Voici un exemple illustrant ces possibiliteacutes (nous avons choisi un constructeur disposant

drsquoarguments par deacutefaut il remplace trois constructeurs agrave zeacutero un et deux arguments)

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur (0 1 ou 2 arguments) x=abs y =ord cout ltlt ++ Constr point ltlt x ltlt ltlt y ltlt n ~point () cout ltlt -- Destr point ltlt x ltlt ltlt y ltlt n main() int n = 3 point courbe[5] = 7 n 2n+5 cout ltlt fin programme n

++ Constr point 7 0++ Constr point 3 0++ Constr point 11 0++ Constr point 0 0++ Constr point 0 0 fin programme -- Destr point 0 0-- Destr point 0 0-- Destr point 11 0-- Destr point 3 0-- Destr point 7 0

Construction et initialisation dun tableau dobjets (version 20)

73 Cas des tableaux dynamiques dobjetsSi lon dispose dune classe point on peut creacuteer dynamiquement un tableau de points en fai-

sant appel agrave lopeacuterateur new Par exemple

point adcourbe = new point[20]

1 Mais pour linstant les eacuteleacutements manquants doivent obligatoirement ecirctre les derniers

Construction destruction et initialisation des objetsCHAPITRE 7

136

alloue lemplacement meacutemoire neacutecessaire agrave vingt objets (conseacutecutifs) de type point et place

ladresse du premier de ces objets dans adcourbe

Lagrave encore si la classe point comporte un constructeur sans argument ce dernier sera appeleacute

pour chacun des vingt objets En revanche si aucun des constructeurs de point nest un cons-

tructeur sans argument linstruction preacuteceacutedente conduira agrave une erreur de compilation Bien

entendu aucun problegraveme particulier ne se posera si la classe point ne comporte aucun cons-

tructeur

Par contre il nexiste ici aucune possibiliteacute de fournir un initialiseur alors que cela est possi-

ble dans le cas de tableaux automatiques ou statiques (voir paragraphe 62)

Pour deacutetruire notre tableau dobjets il suffira de linstruction (notez la preacutesence des crochets

[] qui preacutecisent que lon a affaire agrave un tableau dobjets)

delete [] adcourbe

Celle-ci provoquera lappel du destructeur de point et la libeacuteration de lespace correspondant

pour chacun des eacuteleacutements du tableau

8 Les objets temporairesNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Lorsquune classe dispose dun constructeur ce dernier peut ecirctre appeleacute explicitement (avec

la liste drsquoarguments neacutecessaires) Il y a alors creacuteation dun objet temporaire Par exemple si

nous supposons quune classe point possegravede le constructeur

point (int int)

nous pouvons si a est un objet de type point eacutecrire une affectation telle que

a = point (1 2)

Dans une telle instruction leacutevaluation de lexpression

point (1 2)

conduit agrave

bull la creacuteation dun objet temporaire de type point (il a une adresse preacutecise mais il nest pas ac-

cessible au programme)1

bull lappel du constructeur point pour cet objet temporaire avec transmission des arguments

speacutecifieacutes (ici 1 et 2)

bull la recopie de cet objet temporaire dans a (affectation dun objet agrave un autre de mecircme type)

Quant agrave lobjet temporaire ainsi creacuteeacute il na plus drsquointeacuterecirct degraves que linstruction daffectation est

exeacutecuteacutee La norme preacutevoit qursquoil soit deacutetruit degraves que possible

1 En fait il en va de mecircme lorsque lon reacutealise une affectation telle que y = a x + b Il y a bien creacuteation dun

emplacement temporaire destineacute agrave recueillir le reacutesultat de leacutevaluation de lexpression a x + b

8 - Les objets temporaires137

Voici un exemple de programme montrant lemploi dobjets temporaires Remarquez quici

nous avons preacutevu dans le constructeur et le destructeur de notre classe point dafficher non

seulement les valeurs de lobjet mais eacutegalement son adresse

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) constructeur (inline) x = abs y = ord cout ltlt ++ Constr point ltlt x ltlt ltlt y ltlt a ladresse ltlt this ltlt n ~point () destructeur (inline) cout ltlt -- Destr point ltlt x ltlt ltlt y ltlt a ladresse ltlt this ltlt n

main() point a(00) un objet automatique de classe point a = point (1 2) un objet temporaire a = point (3 5) un autre objet temporaire cout ltlt Fin main n

+ Constr point 0 0 a ladresse 006AFDE4+ Constr point 1 2 a ladresse 006AFDDC- Destr point 1 2 a ladresse 006AFDDC+ Constr point 3 5 a ladresse 006AFDD4- Destr point 3 5 a ladresse 006AFDD4 Fin main - Destr point 3 5 a ladresse 006AFDE4

Exemple de creacuteation dobjets temporaires

On voit clairement que les deux affectations de la fonction main entraicircnent la creacuteation dun

objet temporaire distinct de a qui se trouve deacutetruit tout de suite apregraves La derniegravere destruc-

tion reacutealiseacutee apregraves la fin de lrsquoexeacutecution concerne lrsquoobjet automatique a

Remarques

1 Reacutepeacutetons que dans une affectation telle que

a = point (1 2)

lobjet a existe deacutejagrave Il na donc pas agrave ecirctre creacuteeacute et il ny a pas dappel de constructeur agrave ce

niveau pour a

Construction destruction et initialisation des objetsCHAPITRE 7

138

2 Les remarques sur les risques que preacutesente une affectation entre objets notamment srsquoils

comportent des parties dynamiques1 restent valables ici On pourra utiliser la mecircme

solution agrave savoir la surdeacutefinition de lopeacuterateur daffectation

3 Il existe dautres circonstances dans lesquelles sont creacuteeacutes des objets temporaires agrave

savoir

ndash transmission de la valeur dun objet en argument dune fonction il y a creacuteation dun

objet temporaire au sein de la fonction concerneacutee

ndash transmission dun objet en valeur de retour dune fonction il y a creacuteation dun objet

temporaire au sein de la fonction appelante

Dans les deux cas lobjet temporaire est initialiseacute par appel du constructeur de recopie

4 La preacutesence dobjets temporaires (dont le moment de destruction nest pas parfaitement

imposeacute par la norme) peut rendre difficile le deacutenombrement exact dobjets dune classe

donneacutee

5 La norme ANSI autorise les compilateurs agrave supprimer certaines creacuteations drsquoobjets tem-

poraires notamment dans des situations telles que

f (point(12) appel drsquoune fonction attendant un point avec un argument qui est un objet temporaire lrsquoimpleacutementation peut ne pas creacuteer point(12) dans la fonction appelantereturn point(35) renvoi de la valeur drsquoun point lrsquoimpleacutementation peut ne pas creacuteer point(35) dans la fonction

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 Comme le suggegravere la remarque du paragraphe 13 eacutecrivez une fonction main qui bien

que ne contenant que des deacuteclarations (voire une seule deacuteclaration) nen effectue pas

moins un certain traitement (par exemple affichage)

2 Expeacuterimentez le programme du paragraphe 2 pour voir comment sont traiteacutes les objets

temporaires dans votre impleacutementation

3 Cherchez agrave mettre en eacutevidence les problegravemes poseacutes par laffectation dobjets du type

vect tel quil est deacutefini dans lexemple du paragraphe 322

4 Ecrivez un programme permettant de mettre en eacutevidence lordre dappel des construc-

teurs et des destructeurs dans la situation du paragraphe 52 (objets membres) ainsi

que dans celle de la seconde remarque (objet comportant plusieurs objets membres)

Expeacuterimentez eacutegalement la situation dobjets membres dobjets membres

1 Nous incluons dans ce cas les objets dont un membre (lui-mecircme objet) comporte une partie dynamique

8 - Les objets temporaires139

5 (C) Ecrivez une classe nommeacutee pile_entier permettant de geacuterer une pile dentiers Ces der-

niers seront conserveacutes dans un tableau dentiers alloueacutes dynamiquement La classe

comportera les fonctions membres suivantes

bull pile_entier (int n) constructeur allouant dynamiquement un emplacement de n en-

tiers

bull pile_entier ( ) constructeur sans argument allouant par deacutefaut un emplacement de

vingt entiers

bull ~pile_entier ( ) destructeur

bull void empile (int p) ajoute lentier p sur la pile

bull int depile ( ) fournit la valeur de lentier situeacute en haut de la pile en le supprimant

de la pile

bull int pleine ( ) fournit 1 si la pile est pleine 0 sinon

bull int vide ( ) fournit 1 si la pile est vide 0 sinon

6 (C) Ecrivez une fonction main utilisant des objets automatiques et dynamiques du type

pile_entier deacutefini preacuteceacutedemment

7 Mettez en eacutevidence les problegravemes poseacutes par des deacuteclarations de la forme

pile_entier a(10) pile_entier b = a

8 (C) Ajoutez agrave la classe pile_entier le constructeur de recopie permettant de reacutegler les pro-

blegravemes preacuteceacutedents

8

Les fonctions amies

La POO pure impose lrsquoencapsulation des donneacutees Nous avons vu comment la mettre en

œuvre en C++ les membres priveacutes (donneacutees ou fonctions) ne sont accessibles quaux fonc-

tions membres (publiques ou priveacutees1) et seuls les membres publics sont accessibles de

lexteacuterieur

Nous avons aussi vu quen C++ luniteacute de protection est la classe cest-agrave-dire quune mecircme

fonction membre peut acceacuteder agrave tous les objets de sa classe Crsquoest ce qui se produisait dans la

fonction coincide (examen de la coiumlncidence de deux objets de type point) preacutesenteacutee au para-

graphe 4 du chapitre 6

En revanche ce mecircme principe dencapsulation interdit agrave une fonction membre dune classe

dacceacuteder agrave des donneacutees priveacutees dune autre classe Or cette contrainte savegravere gecircnante dans

certaines circonstances Supposez par exemple que vous ayez deacutefini une classe vecteur (de

taille fixe ou variable peu importe ) et une classe matrice Il est probable que vous souhaite-

rez alors deacutefinir une fonction permettant de calculer le produit dune matrice par un vecteur

Or avec ce que nous connaissons actuellement de C++ nous ne pourrions deacutefinir cette fonc-

tion ni comme fonction membre de la classe vecteur ni comme fonction membre de la classe

matrice et encore moins comme fonction indeacutependante (cest-agrave-dire membre daucune

classe)

Bien entendu vous pourriez toujours rendre publiques les donneacutees de vos deux classes mais

vous perdriez alors le beacuteneacutefice de leur protection Vous pourriez eacutegalement introduire dans

1 Le statut proteacutegeacute (protected) nrsquointervient qursquoen cas drsquoheacuteritage nous en parlerons au chapitre 13 Pour lrsquoinstant

vous pouvez consideacuterer que les membres proteacutegeacutes sont traiteacutes comme les membres priveacutes

Les fonctions amiesCHAPITRE 8

142

les deux classes des fonctions publiques permettant dacceacuteder aux donneacutees mais vous seriez

alors peacutenaliseacute en temps dexeacutecution

En fait la notion de fonction amie1 propose une solution inteacuteressante sous la forme dun

compromis entre encapsulation formelle des donneacutees priveacutees et des donneacutees publiques Lors

de la deacutefinition dune classe il est en effet possible de deacuteclarer quune ou plusieurs fonctions

(exteacuterieures agrave la classe) sont des amies une telle deacuteclaration damitieacute les autorise alors agrave

acceacuteder aux donneacutees priveacutees au mecircme titre que nimporte quelle fonction membre

Lavantage de cette meacutethode est de permettre le controcircle des accegraves au niveau de la classe

concerneacutee on ne peut pas simposer comme fonction amie dune classe si cela na pas eacuteteacute

preacutevu dans la classe Nous verrons toutefois quen pratique la protection est un peu moins

efficace quil ny paraicirct dans la mesure ougrave une fonction peut parfois se faire passer pour une

autre

Il existe plusieurs situations damitieacutes

bull fonction indeacutependante amie dune classe

bull fonction membre dune classe amie dune autre classe

bull fonction amie de plusieurs classes

bull toutes les fonctions membres dune classe amies dune autre classe

La premiegravere nous servira agrave preacutesenter les principes geacuteneacuteraux de deacuteclaration deacutefinition et utili-

sation dune fonction amie Nous examinerons ensuite en deacutetail chacune de ces situations

damitieacute Enfin nous verrons lincidence de lexistence de fonctions amies sur lexploitation

dune classe

1 Exemple de fonction indeacutependante amie drsquoune classe

Au paragraphe 4 du chapitre 6 nous avons introduit une fonction coincide examinant la

coiumlncidence de deux objets de type point pour ce faire nous en avons fait une fonction

membre de la classe point Nous vous proposons ici de reacutesoudre le mecircme problegraveme en fai-

sant cette fois de la fonction coincide une fonction indeacutependante amie de la classe point

Tout dabord il nous faut introduire dans la classe point la deacuteclaration damitieacute approprieacutee agrave

savoir

friend int coincide (point point)

Il sagit preacuteciseacutement du prototype de la fonction coincide preacuteceacutedeacute du mot cleacute friend Naturel-

lement nous avons preacutevu que coincide recevrait deux arguments de type point (cette fois il

1 Friend en anglais

1 - Exemple de fonction indeacutependante amie drsquoune classe143

ne sagit plus dune fonction membre elle ne recevra donc pas dargument implicite this cor-

respondant agrave lobjet layant appeleacute)

Leacutecriture de la fonction coincide ne pose aucun problegraveme particulier

Voici un exemple de programme

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) un constructeur (inline) x=abs y=ord deacuteclaration fonction amie (indeacutependante) nommeacutee coincide friend int coincide (point point) int coincide (point p point q) deacutefinition de coincide if ((px == qx) ampamp (py == qy)) return 1 else return 0 main() programme dessai point a(10) b(1) c if (coincide (ab)) cout ltlt a coincide avec b n else cout ltlt a et b sont differents n if (coincide (ac)) cout ltlt a coincide avec c n else cout ltlt a et c sont differents n

a coincide avec b a et c sont differents

Exemple de fonction indeacutependante (coincide) amie de la classe point

Remarques

1 Lemplacement de la deacuteclaration damitieacute au sein de la classe point est absolument indiffeacute-

rent

2 Il nest pas neacutecessaire de deacuteclarer la fonction amie dans la fonction ou dans le fichier

source ougrave on lutilise car elle est deacutejagrave obligatoirement deacuteclareacutee dans la classe concer-

neacutee Cela reste valable dans le cas (usuel) ougrave la classe a eacuteteacute compileacutee seacutepareacutement

puisquil faudra alors en introduire la deacuteclaration (geacuteneacuteralement par include) Neacutean-

moins une deacuteclaration superflue de la fonction amie ne constituerait pas une erreur

3 Comme nous lavons deacutejagrave fait remarquer nous navons plus ici dargument implicite

(this) Ainsi contrairement agrave ce qui se produisait au paragraphe 4 du chapitre 6 notre

fonction coincide est maintenant parfaitement symeacutetrique Nous retrouverons le mecircme

Les fonctions amiesCHAPITRE 8

144

pheacutenomegravene lorsque pour surdeacutefinir un opeacuterateur binaire nous pourrons choisir entre

une fonction membre (dissymeacutetrique) ou une fonction amie (symeacutetrique)

4 Ici les deux arguments de coincide sont transmis par valeur Ils pourraient lecirctre par

reacutefeacuterence notez que dans le cas dune fonction membre lobjet appelant la fonction

est doffice transmis par reacutefeacuterence (sous la forme de this)

5 Geacuteneacuteralement une fonction amie dune classe posseacutedera un ou plusieurs arguments ou

une valeur de retour du type de cette classe (cest ce qui justifiera son besoin daccegraves

aux membres priveacutes des objets correspondants) Ce nest toutefois pas une obligation1

on pourrait imaginer une fonction ayant besoin dacceacuteder aux membres priveacutes dobjets

locaux agrave cette fonction

6 Lorsquune fonction amie dune classe fournit une valeur de retour du type de cette

classe il est freacutequent que cette valeur soit celle dun objet local agrave la fonction Il est alors

impeacuteratif que sa transmission ait lieu par valeur dans le cas dune transmission par

reacutefeacuterence (ou par adresse) la fonction appelante recevrait ladresse dun emplacement

meacutemoire qui aurait eacuteteacute libeacutereacute agrave la sortie de la fonction Ce pheacutenomegravene a deacutejagrave eacuteteacute eacutevoqueacute

au paragraphe 6 du chapitre 6

2 Les diffeacuterentes situations drsquoamitieacuteNous venons dexaminer le cas dune fonction indeacutependante amie dune classe Celle-ci peut

ecirctre reacutesumeacutee par le scheacutema suivant

class point

int coincide (point point )

partie priveacutee on a accegraves ici aux membres pri-

veacutes de tout objet de type point

partie publique

friend int coincide (point point)

Fonction indeacutependante (coincide) amie drsquoune classe (point)

Bien que nous layons placeacutee ici dans la partie publique de point nous vous rappelons que la

deacuteclaration damitieacute peut figurer nimporte ougrave dans la classe

Dautres situations damitieacute sont possibles fondeacutees sur le mecircme principe elles peuvent con-

duire agrave des deacuteclarations damitieacute tregraves leacutegegraverement diffeacuterentes Nous allons maintenant les pas-

ser en revue

1 Mais ce sera obligatoire dans le cas des opeacuterateurs surdeacutefinis

2 - Les diffeacuterentes situations drsquoamitieacute145

21 Fonction membre dune classe amie dune autre classeIl sagit un peu dun cas particulier de la situation preacuteceacutedente En fait il suffit simplement de

preacuteciser dans la deacuteclaration damitieacute la classe agrave laquelle appartient la fonction concerneacutee agrave

laide de lopeacuterateur de reacutesolution de porteacutee ()

Par exemple supposons que nous ayons agrave deacutefinir deux classes nommeacutees A et B et que nous

ayons besoin dans B dune fonction membre f de prototype

int f(char A)

Si comme il est probable f doit pouvoir acceacuteder aux membres priveacutes de A elle sera deacuteclareacutee

amie au sein de la classe par

friend int Bf(char A)

Voici un scheacutema reacutecapitulatif de la situation

class A class B partie priveacutee int f (char A)

partie publique friend int Bf (char A) int Bf (char A )

on a accegraves ici aux membres priveacutes de tout objet de type A

Fonction (f) drsquoune classe (B) amie drsquoune autre classe (A)

Remarques

1 Pour compiler convenablement les deacuteclarations dune classe A contenant une deacuteclaration

damitieacute telle que

friend int Bf(char A)

le compilateur a besoin de connaicirctre les caracteacuteristiques de B cela signifie que la

deacuteclaration de B (mais pas neacutecessairement la deacutefinition de ses fonctions membres)

devra avoir eacuteteacute compileacutee avant celle de A

En revanche pour compiler convenablement la deacuteclaration

int f(char A)

figurant au sein de la classe B le compilateur na pas besoin de connaicirctre preacuteciseacutement

les caracteacuteristiques de A Il lui suffit de savoir quil sagit dune classe Comme dapregraves

ce qui vient drsquoecirctre dit la deacuteclaration de B na pu apparaicirctre avant on fournira linforma-

tion voulue au compilateur en faisant preacuteceacuteder la deacuteclaration de A de

class A

Les fonctions amiesCHAPITRE 8

146

Bien entendu la compilation de la deacutefinition de la fonction f neacutecessite (en geacuteneacuteral1) la

connaissance des caracteacuteristiques des classes A et B leurs deacuteclarations devront donc

apparaicirctre avant

A titre indicatif voici une faccedilon de compiler nos deux classes A et B et la fonction f

class A class B int f(char A) class A friend int Bf(char A) int Bf(char A)

2 Si lon a besoin de deacuteclarations damitieacutes croiseacutees entre fonctions de deux classes dif-

feacuterentes la seule faccedilon dy parvenir consiste agrave deacuteclarer au moins une des classes amie

de lautre (comme nous apprendrons agrave le faire au paragraphe 23)

22 Fonction amie de plusieurs classesRien nempecircche quune mecircme fonction (quelle soit indeacutependante ou fonction membre) fasse

lobjet de deacuteclarations damitieacute dans diffeacuterentes classes Voici un exemple dune fonction

amie de deux classes A et B

class A class B

partie priveacutee partie priveacutee

partie publique partie publique

friend void f(A B) friend void f(A B)

void f(A B)

on a accegraves ici aux membres priveacutes

de nrsquoimporte quel objet de type A ou B

Fonction indeacutependante (f) amie de deux classes (A et B)

1 Une exception aurait lieu pour B si f nacceacutedait agrave aucun de ses membres (ce qui serait surprenant) Il en irait de

mecircme pour A si aucun argument de ce type napparaissait dans f et si cette derniegravere nacceacutedait agrave aucun membre de A

(ce qui serait tout aussi surprenant)

3 - Exemple147

Remarque

Ici la deacuteclaration de A peut ecirctre compileacutee sans celle de B en la faisant preacuteceacuteder de la

deacuteclaration

class B

De mecircme la deacuteclaration de B peut ecirctre compileacutee sans celle de A en la faisant preacuteceacuteder

de la deacuteclaration

class A

Si lon compile en mecircme temps les deux deacuteclarations de A et B il faudra utiliser lune

des deux deacuteclarations citeacutees (class A si B figure avant A class B sinon)

Bien entendu la compilation de la deacutefinition de f neacutecessitera geacuteneacuteralement les deacuteclara-

tions de A et de B

23 Toutes les fonctions dune classe amies dune autre classeCest une geacuteneacuteralisation du cas eacutevoqueacute au paragraphe 21 On pourrait dailleurs effectuer

autant de deacuteclarations damitieacute quil y a de fonctions concerneacutees Mais il est plus simple

deffectuer une deacuteclaration globale Ainsi pour dire que toutes les fonctions membres de la

classe B sont amies de la classe A on placera dans la classe A la deacuteclaration

friend class B

Remarques

1 Cette fois pour compiler la deacuteclaration de la classe A il suffira de la faire preacuteceacuteder de

class B

2 Ce type de deacuteclaration damitieacute eacutevite de fournir les en-tecirctes des fonctions concerneacutees

3 ExempleNous vous proposons ici de reacutesoudre le problegraveme eacutevoqueacute en introduction agrave savoir reacutealiser

une fonction permettant de deacuteterminer le produit dun vecteur (objet de classe vect) par une

matrice (objet de classe matrice) Par souci de simpliciteacute nous avons limiteacute les fonctions

membres agrave

bull un constructeur pour vect et pour matrice

bull une fonction daffichage (affiche) pour matrice

Nous vous fournissons deux solutions fondeacutees sur lemploi dune fonction amie nommeacutee

prod

bull prod est indeacutependante et amie des deux classes vect et matrice

bull prod est membre de matrice et amie de la classe vect

Les fonctions amiesCHAPITRE 8

148

31 Fonction amie indeacutependante

include ltiostreamgtusing namespace std class matrice pour pouvoir compiler la deacuteclaration de vect La classe vect class vect double v[3] vecteur agrave 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 indeacutependante void affiche () int i for (i=0 ilt3 i++) cout ltlt v[i] ltlt cout ltlt n La classe matrice class matrice double mat[3] [3] matrice 3 X 3 public matrice (double t[3][3]) constructeur agrave partir dun tableau 3 x 3 int i int j for (i=0 ilt3 i++) for (j=0 jlt3 j++) mat[i] [j] = t[i] [j] friend vect prod (matrice vect) prod = fonction amie indeacutependante La fonction prod vect prod (matrice m vect x) int i j double som vect res pour le reacutesultat du produit for (i=0 ilt3 i++) for (j=0 som=0 jlt3 j++) som += mmat[i] [j] xv[j] resv[i] = som return res Un petit programme de test main() vect w (123) vect res double tb [3][3] = 1 2 3 4 5 6 7 8 9 matrice a = tb res = prod(a w) resaffiche ()

3 - Exemple149

14 32 50

Produit dune matrice par un vecteur agrave laide dune fonction indeacutependante amie des deux classes

32 Fonction amie membre dune classe

include ltiostreamgtusing namespace std Deacuteclaration de la classe matrice class vect pour pouvoir compiler correctementclass matrice double mat[3] [3] matrice 3 X 3 public matrice (double t[3][3]) constructeur agrave partir dun tableau 3 x 3 int i int j for (i=0 ilt3 i++) for (j=0 jlt3 j++) mat[i] [j] = t[i] [j] vect prod (vect) prod = fonction membre (cette fois) Deacuteclaration de la classe vect class vect double v[3] vecteur agrave 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 matriceprod (vect) prod = fonction amie void affiche () int i for (i=0 ilt3 i++) cout ltlt v[i] ltlt cout ltlt n Deacutefinition de la fonction prod vect matriceprod (vect x) int i j double som vect res pour le reacutesultat du produit for (i=0 ilt3 i++) for (j=0 som=0 jlt3 j++) som += mat[i] [j] xv[j] resv[i] = som return res

Les fonctions amiesCHAPITRE 8

150

Un petit programme de test main() vect w (123) vect res double tb [3][3] = 1 2 3 4 5 6 7 8 9 matrice a = tb res = aprod (w) resaffiche ()

14 32 50

Produit dune matrice par un vecteur agrave laide dune fonction membre amie dune autre classe

4 Exploitation de classes disposant de fonctions amies

Comme nous lavons deacutejagrave mentionneacute au chapitre 5 les classes seront geacuteneacuteralement compileacutees

seacutepareacutement Leur utilisation se fera agrave partir dun module objet contenant leurs fonctions

membres et dun fichier en-tecircte contenant leur deacuteclaration Bien entendu il est toujours possi-

ble de regrouper plusieurs classes dans un mecircme module objet et eacuteventuellement dans un

mecircme fichier en-tecircte

Dans tous les cas cette compilation seacutepareacutee des classes permet den assurer la reacuteutilisabiliteacute

le client (qui peut eacuteventuellement ecirctre le concepteur de la classe) ne peut pas intervenir sur

le contenu des objets de cette classe

Que deviennent ces possibiliteacutes lorsque lon utilise des fonctions amies En fait sil sagit de

fonctions amies membres dune classe rien nest changeacute (en dehors des eacuteventuelles deacuteclara-

tions de classes neacutecessaires agrave son emploi) En revanche sil sagit dune fonction indeacutepen-

dante il faudra bien voir que si lon souhaite en faire un module objet seacutepareacute on court le

risque de voir lutilisateur de la classe violer le principe dencapsulation

En effet dans ce cas lutilisateur dune classe disposant dune fonction amie peut toujours ne

pas incorporer la fonction amie agrave leacutedition de liens et fournir lui-mecircme une autre fonction de

mecircme en-tecircte puis acceacuteder comme il lentend aux donneacutees priveacutees

Ce risque drsquoeffet cameacuteleacuteon doit ecirctre nuanceacute par le fait quil sagit dune action deacutelibeacutereacutee

(demandant un certain travail) et non pas dune simple eacutetourderie

9

La surdeacutefinition drsquoopeacuterateurs

Nous avons vu au chapitre 4 que C++ autorise la surdeacutefinition de fonctions quil sagisse de

fonctions membres ou de fonctions indeacutependantes Rappelons que cette technique consiste agrave

attribuer le mecircme nom agrave des fonctions diffeacuterentes lors dun appel le choix de la bonne

fonction est effectueacute par le compilateur suivant le nombre et le type des arguments

Mais C++ permet eacutegalement dans certaines conditions de surdeacutefinir des opeacuterateurs En fait

le langage C comme beaucoup dautres reacutealise deacutejagrave la surdeacutefinition de certains opeacuterateurs

Par exemple dans une expression telle que

a + b

le symbole + peut deacutesigner suivant le type de a et b

bull laddition de deux entiers

bull lrsquoaddition de deux reacuteels (float)

bull lrsquoaddition de deux reacuteels double preacutecision (double)

bull etc

De la mecircme maniegravere le symbole peut suivant le contexte repreacutesenter la multiplication

dentiers ou de reacuteels ou une indirection (comme dans a = adr)

En C++ vous pourrez surdeacutefinir nimporte quel opeacuterateur existant (unaire ou binaire) pour

peu qursquoil porte sur au moins un objet1 Il sagit lagrave dune technique fort puissante puisquelle va

1 Cette restriction signifie simplement quil ne sera pas possible de surdeacutefinir les opeacuterateurs portant sur les diffeacuterents

types de base

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

152

vous permettre de creacuteer par le biais des classes des types agrave part entiegravere cest-agrave-dire munis

comme les types de base dopeacuterateurs parfaitement inteacutegreacutes La notation opeacuteratoire qui en

deacutecoulera aura lavantage drsquoecirctre beaucoup plus concise et (du moins si lon sy prend

intelligemment ) lisible qursquoune notation fonctionnelle (par appel de fonction)

Par exemple si vous deacutefinissez une classe complexe destineacutee agrave repreacutesenter des nombres com-

plexes il vous sera possible de donner une signification agrave des expressions telles que

a + b a - b a b ab

a et b eacutetant des objets de type complexe1 Pour cela vous surdeacutefinirez les opeacuterateurs + - et

en speacutecifiant le rocircle exact que vous souhaitez leur attribuer Cette deacutefinition se deacuteroulera

comme celle dune fonction agrave laquelle il suffira simplement dattribuer un nom speacutecial per-

mettant de speacutecifier quil sagit en fait dun opeacuterateur Autrement dit la surdeacutefinition dopeacutera-

teurs en C++ consistera simplement en leacutecriture de nouvelles fonctions surdeacutefinies

Apregraves vous avoir preacutesenteacute la surdeacutefinition dopeacuterateurs ses possibiliteacutes et ses limites nous

lrsquoappliquerons aux opeacuterateurs = et [] Certes il ne sagira que dexemples mais ils montreront

quagrave partir du moment ougrave lon souhaite donner agrave ces opeacuterateurs une signification naturelle et

acceptable dans un contexte de classe un certain nombre de preacutecautions doivent ecirctre prises

En particulier nous verrons comment la surdeacutefinition de laffectation permet de reacutegler le pro-

blegraveme deacutejagrave rencontreacute agrave savoir celui des objets comportant des pointeurs sur des emplace-

ments dynamiques

Enfin nous examinerons comment prendre en charge la gestion de la meacutemoire en surdeacutefinis-

sant les opeacuterateurs new et delete

1 Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs

Consideacuterons une classe point

class point int x y

et supposons que nous souhaitions deacutefinir lopeacuterateur + afin de donner une signification agrave une

expression telle que a + b lorsque a et b sont de type point Ici nous conviendrons que la

somme de deux points est un point dont les coordonneacutees sont la somme de leurs coordon-

neacutees2

1 Une notation fonctionnelle conduirait agrave des choses telles que somme (ab) ou asomme(b) suivant que lon utilise

une fonction amie ou une fonction membre

2 Nous aurions pu tout aussi bien prendre lexemple de la classe complexe eacutevoqueacutee en introduction Nous preacutefeacuterons

cependant choisir un exemple dans lequel la signification de lopeacuterateur na pas un caractegravere aussi eacutevident En effet

noubliez pas que nimporte quel symbole opeacuterateur peut se voir attribuer nimporte quelle signification

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs153

La convention adopteacutee par C++ pour surdeacutefinir cet opeacuterateur + consiste agrave deacutefinir une fonc-

tion de nom

operator +

Le mot cleacute operator est suivi de lopeacuterateur concerneacute (dans le cas preacutesent il ne serait pas obli-

gatoire de preacutevoir un espace car en C + sert de seacuteparateur)

Ici notre fonction operator + doit disposer de deux arguments de type point et fournir une

valeur de retour du mecircme type En ce qui concerne sa nature cette fonction peut agrave notre greacute

ecirctre une fonction membre de la classe concerneacutee ou une fonction indeacutependante dans ce der-

nier cas il sagira geacuteneacuteralement dune fonction amie car elle devra pouvoir acceacuteder aux

membres priveacutes de la classe

Examinons ici les deux solutions en commenccedilant par celle qui est la plus naturelle agrave

savoir la fonction amie

11 Surdeacutefinition dopeacuterateur avec une fonction amieLe prototype de notre fonction operator + sera

point operator + (point point)

Ses deux arguments correspondront aux opeacuterandes de lopeacuterateur + lorsquil sera appliqueacute agrave

des valeurs de type point

Le reste du travail est classique

bull deacuteclaration damitieacute au sein de la classe point

bull deacutefinition de la fonction

Voici un exemple de programme montrant la deacutefinition et lutilisation de notre opeacuterateur

daddition de points

include ltiostreamgtusing namespace std

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 ltlt coordonnees ltlt x ltlt ltlt y ltlt n

point operator + (point a point b) point p px = ax + bx py = ay + by return p

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

154

main() point a(12) aaffiche()

point b(25) baffiche()

point c c = a+b caffiche()

c = a+b+c caffiche()

coordonnees 1 2

coordonnees 2 5

coordonnees 3 7coordonnees 6 14

Surdeacutefinition de lopeacuterateur + pour des objets de type point en employant une fonction amie

Remarques

1 Une expression telle que a + b est en fait interpreacuteteacutee par le compilateur comme lappel

operator + (a b)

Bien que cela ne preacutesente guegravere dinteacuterecirct nous pourrions eacutecrire

c = operator + (a b)

au lieu de c = a + b

2 Une expression telle que a + b + c est eacutevalueacutee en tenant compte des regravegles de prioriteacute

et dassociativiteacute habituelles de lopeacuterateur + Nous reviendrons plus loin sur ce point

Pour linstant notez simplement que cette expression est eacutevalueacutee comme

(a + b) + c

cest-agrave-dire en utilisant la notation fonctionnelle

operator + (operator + (a b) c)

12 Surdeacutefinition dopeacuterateur avec une fonction membreCette fois le premier opeacuterande de notre opeacuterateur correspondant au premier argument de la

fonction operator + preacuteceacutedente va se trouver transmis implicitement ce sera lobjet ayant

appeleacute la fonction membre Par exemple une expression telle que a + b sera alors interpreacuteteacutee

par le compilateur comme

aoperator + (b)

Le prototype de notre fonction membre operator + sera donc

point operator + (point)

Voici comment lrsquoexemple preacuteceacutedent pourrait ecirctre adapteacute

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs155

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord constructeur point operator + (point) void affiche () cout ltlt coordonnees ltlt x ltlt ltlt y ltlt n point pointoperator + (point a) point p px = x + ax py = y + ay return p main() point a(12) aaffiche() point b(25) baffiche() point c c = a+b caffiche() c = a+b+c caffiche()

coordonnees 1 2coordonnees 2 5coordonnees 3 7coordonnees 6 14

Surdeacutefinition de lopeacuterateur + pour des objets de type point en employant une fonction membre

Remarques

1 Cette fois la deacutefinition de la fonction operator + fait apparaicirctre une dissymeacutetrie entre les

deux opeacuterandes Par exemple le membre x est noteacute x pour le premier opeacuterande (argument

implicite) et ax pour le second Cette dissymeacutetrie peut parfois inciter lutilisateur agrave choisir

une fonction amie plutocirct quune fonction membre Il faut toutefois se garder de deacutecider

trop vite dans ce domaine Nous y reviendrons un peu plus loin

2 Ici laffectation

c = a + b

est interpreacuteteacutee comme

c = aoperator + (b)

Quant agrave laffectation

c = a + b + c

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

156

le langage C++ ne preacutecise pas exactement son interpreacutetation Certains compilateurs

creacuteeront un objet temporaire t

t = aoperator + (b) c = toperator + (c)

Dautres proceacutederont ainsi en transmettant comme adresse de lobjet appelant operator

+ celle de lobjet renvoyeacute par lappel preacuteceacutedent

c = (aoperator + (b))operator + (c)

On peut deacutetecter le choix fait par un compilateur en affichant toutes les creacuteations

dobjets (en noubliant pas dintroduire un constructeur de recopie prenant la place du

constructeur par deacutefaut)

13 Opeacuterateurs et transmission par reacutefeacuterenceDans les deux exemples preacuteceacutedents la transmission des arguments (deux pour une fonction

amie un pour une fonction membre) et de la valeur de retour de operator + se faisait par

valeur1

Bien entendu on peut envisager de faire appel au transfert par reacutefeacuterence en particulier dans

le cas dobjets de grande taille Par exemple le prototype de la fonction amie operator +

pourrait ecirctre

point operator + (point amp a point amp b)

En revanche la transmission par reacutefeacuterence poserait un problegraveme si on cherchait agrave lappliquer

agrave la valeur de retour En effet le point p est creacuteeacute localement dans la fonction il sera donc

deacutetruit degraves la fin de son exeacutecution Dans ces conditions employer la transmission par reacutefeacute-

rence reviendrait agrave transmettre ladresse dun emplacement de meacutemoire libeacutereacute

Certes nous utilisons ici immeacutediatement la valeur de p degraves le retour dans la fonction main

(ce qui est geacuteneacuteralement le cas avec un opeacuterateur) Neacuteanmoins nous ne pouvons faire aucune

hypothegravese sur la maniegravere dont une impleacutementation donneacutee libegravere un emplacement meacutemoire

elle peut simplement se contenter de noter quil est disponible auquel cas son contenu reste

valable pendant un certain temps elle peut au contraire le mettre agrave zeacutero La premiegravere

situation est certainement la pire puisquelle peut donner lillusion que cela marche

Pour eacuteviter la recopie de cette valeur de retour on pourrait songer agrave allouer dynamiquement

lemplacement de p Geacuteneacuteralement cela prendra plus de temps que sa recopie ulteacuterieure et de

plus compliquera quelque peu le programme (il faudra libeacuterer convenablement lemplace-

ment en question et on ne pourra le faire quen dehors de la fonction )

Si lon cherche agrave proteacuteger contre deacuteventuelles modifications un argument transmis par reacutefeacute-

rence on pourra toujours faire appel au mot cleacute const par exemple len-tecircte de operator +

pourrait ecirctre2

point operator + (const pointamp a const pointamp b)

1 Rappelons que la transmission de lobjet appelant une fonction membre se fait par reacutefeacuterence

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral157

Naturellement si lon utilise const dans le cas dobjets comportant des pointeurs sur des par-

ties dynamiques seuls ces pointeurs seront proteacutegeacutes les parties dynamiques resteront

modifiables

2 La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteralNous venons de voir un exemple de surdeacutefinition de lopeacuterateur binaire + lorsquil reccediloit deux

opeacuterandes de type point et ce de deux faccedilons comme fonction amie comme fonction mem-

bre Examinons maintenant ce quil est possible de faire dune maniegravere geacuteneacuterale

21 Se limiter aux opeacuterateurs existantsLe symbole suivant le mot cleacute operator doit obligatoirement ecirctre un opeacuterateur deacutejagrave deacutefini

pour les types de base Il nest donc pas possible de creacuteer de nouveaux symboles Nous ver-

rons dailleurs que certains opeacuterateurs ne peuvent pas ecirctre redeacutefinis du tout (cest le cas de )

et que dautres imposent quelques contraintes suppleacutementaires

Il faut conserver la pluraliteacute (unaire binaire) de lopeacuterateur initial Ainsi vous pourrez surdeacute-

finir un opeacuterateur + unaire ou un opeacuterateur + binaire mais vous ne pourrez pas deacutefinir de =

unaire ou de ++ binaire

Lorsque plusieurs opeacuterateurs sont combineacutes au sein dune mecircme expression (quils soient sur-

deacutefinis ou non) ils conservent leur prioriteacute relative et leur associativiteacute Par exemple si vous

surdeacutefinissez les opeacuterateurs binaires + et pour le type complexe lexpression suivante (a b

et c eacutetant supposeacutes du type complexe)

a b + c

sera interpreacuteteacutee comme

(a b) + c

De telles regravegles peuvent vous paraicirctre restrictives En fait vous verrez agrave lusage quelles sont

encore tregraves larges et quil est facile de rendre un programme incompreacutehensible en abusant de

la surdeacutefinition dopeacuterateurs

Le tableau ci-apregraves preacutecise les opeacuterateurs surdeacutefinissables (en fait tous sauf et )

et rappelle leur prioriteacute relative et leur associativiteacute Notez la preacutesence

bull de lopeacuterateur de cast nous verrons au chapitre 10 quil peut sappliquer agrave la conversion

dune classe dans un type de base ou agrave la conversion dune classe dans une autre classe

bull des opeacuterateurs new et delete avant la version 20 ils ne pouvaient pas ecirctre surdeacutefinis pour

une classe particuliegravere on ne pouvait en modifier la signification que dune faccedilon globale

Depuis la version 20 ils sont surdeacutefinissables au mecircme titre que les autres Nous en parle-

rons au paragraphe 7

2 Cependant comme on le verra au chapitre 10 la preacutesence de cet attribut const pourra autoriser certaines

conversions de lrsquoargument

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

158

bull des opeacuterateurs -gt et introduits par la norme ils sont drsquoun usage restreint et ils srsquoappli-

quent aux pointeurs sur des membres Leur rocircle est deacutecrit en Annexe F

Les opeacuterateurs surdeacutefinissables en C++ (classeacutes par prioriteacute deacutecroissante)

(1) Srsquoil nrsquoest pas surdeacutefini il possegravede une signification par deacutefaut

(2) Depuis la version 20 seulement

(3) Doit ecirctre deacutefini comme fonction membre

(4) Soit agrave un niveau global (fonction indeacutependante) avant la version 20 Depuis la version 20 il peut en outre ecirctre

surdeacutefini pour une classe dans ce cas il doit lrsquoecirctre comme fonction membre

(5) Jusqursquoagrave la version 3 on ne pouvait pas distinguer entre les notations preacute et post Depuis la version 3 lorsqursquoils

sont deacutefinis de faccedilon unaire ces opeacuterateurs correspondent agrave la notation preacute mais il en existe une deacutefinition binaire

(avec deuxiegraveme opeacuterande fictif de type int) qui correspond agrave la notation post

(6) On distingue bien new de new[] et delete de delete[]

22 Se placer dans un contexte de classeOn ne peut surdeacutefinir un opeacuterateur que sil comporte au moins un argument (implicite ou

non) de type classe Autrement dit il doit sagir

Pluraliteacute Opeacuterateurs Associativiteacute

Binaire ()(3) [](3) -gt(1) (2) (3) -gt

Unaire + - ++(5) --(5) ~ amp(1)

new(1)(4)(6) new[](1)(4)(6) delete(1)(4)(6) delete[](1)(4)(6)

(cast)

lt-

Binaire -gt

Binaire -gt(1) (1) -gt

Binaire + - -gt

Binaire ltlt gtgt -gt

Binaire lt lt= gt gt= -gt

Binaire == = -gt

Binaire amp -gt

Binaire ^ -gt

Binaire || -gt

Binaire ampamp -gt

Binaire | -gt

Binaire =(1)(3) += -= = = =

amp= ^= |= ltlt= gtgt=

lt-

Binaire (2) -gt

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral159

bull Soit dune fonction membre dans ce cas elle comporte agrave coup sucircr un argument (implicite)

de type classe agrave savoir lobjet layant appeleacute Sil sagit dun opeacuterateur unaire elle ne com-

portera aucun argument explicite Sil sagit dun opeacuterateur binaire elle comportera un argu-

ment explicite auquel aucune contrainte de type nest imposeacutee (dans les exemples

preacuteceacutedents il sagissait du mecircme type que la classe elle-mecircme mais il pourrait sagir dun

autre type classe ou mecircme dun type de base)

bull Soit dune fonction indeacutependante ayant au moins un argument de type classe En geacuteneacuteral il

sagira dune fonction amie

Cette regravegle garantit limpossibiliteacute de surdeacutefinir un opeacuterateur portant sur des types de base

(imaginez ce que serait un programme dans lequel on pourrait changer la signification de

3 + 5 ou de adr ) Une exception a lieu cependant pour les seuls opeacuterateurs new et delete

dont la signification peut ecirctre modifieacutee de maniegravere globale (pour tous les objets et les types

de base) nous en reparlerons au paragraphe 7

De plus certains opeacuterateurs doivent obligatoirement ecirctre deacutefinis comme membres dune

classe Il sagit de [] ( ) -gt1 ainsi que de new et delete (dans le seul cas ougrave ils portent sur une

classe particuliegravere)

23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateurComme nous avons deacutejagrave eu loccasion de lindiquer vous ecirctes totalement libre dattribuer agrave un

opeacuterateur surdeacutefini la signification que vous deacutesirez Cette liberteacute nest limiteacutee que par le bon

sens qui doit vous inciter agrave donner agrave un symbole une signification relativement naturelle

par exemple + pour la somme de deux complexes plutocirct que - ou []

Cela dit vous ne retrouverez pas pour les opeacuterateurs surdeacutefinis les liens qui existent entre

certains opeacuterateurs de base Par exemple si a et b sont de type int

a += b

est eacutequivalent agrave

a = a + b

Autrement dit le rocircle de lopeacuterateur de base += se deacuteduit du rocircle de lopeacuterateur + et de celui

de lopeacuterateur = En revanche si vous surdeacutefinissez lopeacuterateur + et lopeacuterateur = lorsque leurs

deux opeacuterandes sont de type complexe vous naurez pas pour autant deacutefini la signification de

+= lorsquil aura deux opeacuterandes de type complexe De plus vous pourrez tregraves bien surdeacutefinir

+= pour quil ait une signification diffeacuterente de celle attendue naturellement cela nest pas

conseilleacute

De mecircme et de faccedilon peut-ecirctre plus surprenante C++ ne fait aucune hypothegravese sur la com-

mutativiteacute eacuteventuelle dun opeacuterateur surdeacutefini (contrairement agrave ce qui se passe pour sa prio-

riteacute relative ou son associativiteacute) Cette remarque est lourde de conseacutequences Supposez par

1 Il nest surdeacutefinissable que depuis la version 20

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

160

exemple que vous ayez surdeacutefini lopeacuterateur + lorsquil a comme opeacuterandes un complexe et

un double (dans cet ordre) son prototype pourrait ecirctre

complexe operator + (complexe double)

Si ceci vous permet de donner un sens agrave une expression telle que (a eacutetant complexe)

a + 35

cela ne permet pas pour autant dinterpreacuteter

35 + a

Pour ce faire il aurait fallu surdeacutefinir lopeacuterateur + lorsquil a comme opeacuterandes un double et

un complexe avec par exemple1 comme prototype

complexe operator + (double complexe)

Nous verrons cependant au chapitre 10 que les possibiliteacutes de conversions deacutefinies par lutili-

sateur permettront de simplifier quelque peu les choses Par exemple il suffira dans ce cas

preacutecis de deacutefinir lopeacuterateur + lorsquil porte sur deux complexes ainsi que la conversion de

double en complexe pour que les expressions de lune de ces formes aient un sens

double + complexecomplexe + doublefloat + complexecomplexe + float

24 Cas des opeacuterateurs ++ et --Jusquagrave la version 20 de C++ on ne pouvait pas distinguer lopeacuterateur ++ en notation preacute-

fixeacutee (comme dans ++a) de ce mecircme opeacuterateur en notation postfixeacutee (comme dans a++)

Autrement dit pour un type classe donneacute on ne pouvait deacutefinir quun seul opeacuterateur ++ (ope-

rator ++) qui eacutetait utiliseacute dans les deux cas

Depuis la version 3 on peut deacutefinir agrave la fois un opeacuterateur ++ utilisable en notation preacutefixeacutee et

un autre utilisable en notation postfixeacutee Pour ce faire on utilise une convention qui consiste

agrave ajouter un argument fictif suppleacutementaire agrave la version postfixeacutee Par exemple si T deacutesigne

un type classe et que ++ est deacutefini sous la forme drsquoune fonction membre

bull lopeacuterateur (usuel) den-tecircte T operator ++ () est utiliseacute en cas de notation preacutefixeacutee

bull lopeacuterateur den-tecircte T operator ++ (int) est utiliseacute en cas de notation postfixeacutee Notez bien

la preacutesence dun second opeacuterande de type int Celui-ci est totalement fictif en ce sens quil

permet au compilateur de choisir lopeacuterateur agrave utiliser mais quaucune valeur ne sera reacuteelle-

ment transmise lors de lappel

De mecircme si ++ est deacutefini sous forme de fonction amie

bull lrsquoopeacuterateur (usuel) drsquoen-tecircte T operator (T) est utiliseacute en cas de notation preacutefixeacutee

bull lrsquoopeacuterateur drsquoen-tecircte T operator (T int) est utiliseacute en cas de notation postfixeacutee

1 Nous verrons dailleurs un peu plus loin que dans ce cas on ne pourra pas surdeacutefinir cet opeacuterateur comme une

fonction membre (puisque son premier opeacuterande nest plus de type classe)

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral161

Les mecircmes consideacuterations sappliquent agrave lopeacuterateur --

Voici un exemple dans lequel nous avons deacutefini ++ pour quil increacutemente dune uniteacute les deux

coordonneacutees dun point et fournisse comme valeur soit celle du point avant increacutementation

dans le cas de la notation postfixeacutee soit celle du point apregraves increacutementation dans le cas de la

notation preacutefixeacutee

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord point operator ++ () notation preacutefixeacutee x++ y++ return this point operator ++ (int n) notation postfixeacutee point p = this x++ y++ return p void affiche () cout ltlt x ltlt ltlt y ltlt n

main() point a1 (2 5) a2(2 5) b b = ++a1 cout ltlt a1 a1affiche () affiche a1 3 6 cout ltlt b baffiche () affiche b 3 6 b = a2++ cout ltlt a2 a2affiche () affiche a2 3 6 cout ltlt b baffiche () affiche b 2 5

Exemple de surdeacutefinition de ++ en notation preacutefixeacutee et postfixeacutee

Remarque

Theacuteoriquement depuis la version 3 et donc depuis la norme ANSI il nrsquoest plus possible

de ne deacutefinir quun seul opeacuterateur ++ quon utiliserait agrave la fois en notation preacutefixeacutee et post-

fixeacutee En fait la plupart des compilateurs acceptent que lrsquoon ne fournisse que la version

preacutefixeacutee qui se trouve alors utiliseacutee dans les deux cas

25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinieDans notre exemple drsquointroduction nous avions surdeacutefini lrsquoopeacuterateur + pour des opeacuterandes

de type point Comme on srsquoen doute en lrsquoabsence drsquoune telle surdeacutefinition lrsquoopeacuterateur

nrsquoaurait aucun sens dans ce contexte et son utilisation conduirait agrave une erreur de compilation

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

162

Il en va ainsi pour la plupart des opeacuterateurs qui nrsquoont donc pas de signification preacutedeacutefinie

pour un type classe Il existe toutefois quelques exceptions qui vont geacuteneacuteralement de soi (par

exemple on srsquoattend bien agrave ce que amp repreacutesente lrsquoadresse drsquoun objet )

Lrsquoopeacuterateur = fait lui aussi exception Nous avons deacutejagrave eu lrsquooccasion de lrsquoemployer avec

deux opeacuterandes du mecircme type classe et nous nrsquoavions pas eu besoin de le surdeacutefinir Effecti-

vement en lrsquoabsence de surdeacutefinition explicite cet opeacuterateur correspond agrave la recopie des

valeurs de son second opeacuterande dans le premier Nous avons drsquoailleurs constateacute que cette

simple recopie pouvait srsquoaveacuterer insatisfaisante degraves lors que les objets concerneacutes comportaient

des pointeurs sur des emplacements dynamiques Il srsquoagit lagrave typiquement drsquoune situation qui

neacutecessite la surdeacutefinition de lrsquoopeacuterateur = dont nous donnerons un exemple dans le paragra-

phe suivant

On notera la grande analogie existant entre

bull le constructeur de recopie srsquoil nrsquoen existe pas drsquoexplicite il y a appel drsquoun constructeur de

recopie par deacutefaut

bull lrsquoopeacuterateur drsquoaffectation srsquoil nrsquoen existe pas drsquoexplicite il y a emploi drsquoun opeacuterateur drsquoaf-

fectation par deacutefaut

Constructeur de recopie par deacutefaut et opeacuterateur drsquoaffectation par deacutefaut effectuent le mecircme

travail la recopie des valeurs de lrsquoobjet Au chapitre 7 nous avons signaleacute que dans le cas

drsquoobjets dont certains membres sont eux-mecircmes des objets le constructeur de recopie par

deacutefaut travaillait membre par membre La mecircme remarque srsquoapplique agrave lrsquoopeacuterateur drsquoaffecta-

tion par deacutefaut il opegravere membre par membre1 ce qui laisse la possibiliteacute drsquoappeler un opeacutera-

teur drsquoaffectation explicite dans le cas ougrave lrsquoun des membres en posseacutederait un Cela peut

eacuteviter drsquoavoir agrave eacutecrire explicitement un opeacuterateur drsquoaffectation pour des objets sans pointeurs

(apparents) mais dont un ou plusieurs membres possegravedent quant agrave eux des parties dynami-

ques

26 Les conversionsC et C++ autorisent freacutequemment les conversions entre types de base de faccedilon explicite ou

implicite Ces possibiliteacutes seacutetendent aux objets Par exemple comme nous lavons deacutejagrave eacutevo-

queacute si a est de type complexe et si lopeacuterateur + a eacuteteacute surdeacutefini pour deux complexes une

expression telle que a + 35 pourra prendre un sens

bull soit si lon a surdeacutefini lopeacuterateur + lorsquil a un opeacuterande de type complexe et un opeacuterande

de type double

bull soit si lon a deacutefini une conversion de type double en complexe

Nous avons toutefois preacutefeacutereacute regrouper au chapitre 10 tout ce qui concerne les problegravemes de

conversion cest lagrave que nous parlerons de la surdeacutefinition dun opeacuterateur de cast

1 Lagrave encore depuis la version 20 de C++ Auparavant il opeacuterait de faccedilon globale (memberwise copy)

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =163

27 Choix entre fonction membre et fonction amieC++ vous laisse libre de surdeacutefinir un opeacuterateur agrave laide dune fonction membre ou dune

fonction indeacutependante (en geacuteneacuteral amie) Vous pouvez donc parfois vous demander sur quels

critegraveres effectuer le choix Certes il semble qursquoon puisse eacutennoncer la regravegle suivante si un

opeacuterateur doit absolument recevoir un type de base en premier argument il ne peut pas

ecirctre deacutefini comme fonction membre (puisque celle-ci reccediloit implicitement un premier argu-ment du type de sa classe)

Mais il faudra tenir compte des possibliteacutes exposeacutees au prochain chapitre de conversion en unobjet drsquoun opeacuterande drsquoun type de base Par exemple lrsquoaddition dun double (type de base) etdun complexe (type classe) dans cet ordre1 semble correspondre agrave la situation eacutevoqueacutee (pre-mier opeacuterande drsquoun type de base) et donc imposer le recours agrave une fonction amie de la classecomplexe En fait nous verrons qursquoil peut aussi se traiter par surdeacutefinition drsquoune fonctionmembre de la classe complexe effectuant laddition de deux complexes compleacuteteacutee par ladeacutefinition de la conversion double -gt complexe

3 Exemple de surdeacutefinition de lrsquoopeacuterateur =

31 Rappels concernant le constructeur par recopie Nous avons deacutejagrave eu loccasion dutiliser une classe vect correspondant agrave des vecteurs dyna-miques (voir au paragraphe 3 du chapitre 7)

class vect int nelem nombre deacuteleacutements int adr adresse public vect (int n) constructeur

Si fct eacutetait une fonction agrave un argument de type vect les instructions suivantes vect a(5) fct (a)

1 Il ne suffira pas davoir surdeacutefini laddition dun complexe et dun double (qui peut se faire par une fonction

membre) En effet comme nous lavons dit aucune hypothegravese nest faite par C++ sur lopeacuterateur surdeacutefini en

particulier sur sa commutativiteacute

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

164

posaient problegraveme lappel de fct conduisait agrave la creacuteation par recopie de a dun nouvel objetb Nous eacutetions alors en preacutesence de deux objets a et b comportant un pointeur (adr) vers lemecircme emplacement

En particulier si la classe vect posseacutedait (comme cest souhaitable ) un destructeur chargeacute delibeacuterer lemplacement dynamique associeacute on risquait daboutir agrave deux demandes de libeacuterationdu mecircme emplacement meacutemoire

Une solution consistait agrave deacutefinir un constructeur de recopie chargeacute deffectuer non seulementla recopie de lobjet lui-mecircme mais aussi celle de sa partie dynamique dans un nouvel empla-cement (ou agrave interdire la recopie)

32 Cas de lrsquoaffectationLaffectation dobjets de type vect pose les mecircmes problegravemes Ainsi avec cette deacuteclaration

vect a(5) b(3)

qui correspond au scheacutema

a

b

5

5

a

b

5

3

x

y

z

t

u

f

g

h

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =165

Laffectation b = a

conduit agrave

Le problegraveme est effectivement voisin de celui de la construction par recopie Voisin maisnon identique car quelques difffeacuterences apparaissent

bull On peut se trouver en preacutesence dune affectation dun objet agrave lui-mecircme

bull Avant affectation il existe ici deux objets complets (cest-agrave-dire avec leur partie dynami-que) Dans le cas de la construction par recopie il nexistait quun seul emplacement dyna-mique le second eacutetant agrave creacuteer On va donc se retrouver ici avec lancien emplacementdynamique de b Or srsquoil nest plus reacutefeacuterenceacute par b est-on sucircr quil nest pas reacutefeacuterenceacute parailleurs

33 Algorithme proposeacuteNous pouvons reacutegler les diffeacuterents points en surdeacutefinissant lopeacuterateur daffectation demaniegravere que chaque objet de type vect comporte son propre emplacement dynamique Dansce cas on est sucircr quil nest reacutefeacuterenceacute quune seule fois et son eacuteventuelle libeacuteration peut sefaire sans problegraveme Notez cependant que cette deacutemarche ne convient totalement que si elleest associeacutee agrave la deacutefinition conjointe du constructeur de recopie

Voici donc comment nous pourrions traiter une affectation telle que b = a lorsque a est dif-feacuterent de b

bull libeacuteration de lemplacement pointeacute par b

bull creacuteation dynamique dun nouvel emplacement dans lequel on recopie les valeurs de lempla-cement pointeacute par a

bull mise en place des valeurs des membres donneacutees de b

a

b

5

3

x

y

z

t

u

f

g

h

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

166

Voici un scheacutema illustrant la situation agrave laquelle on aboutit

Il reste agrave reacutegler le cas ougrave a et b correspondent au mecircme objet

Si la transmission de a agrave lrsquoopeacuterateur drsquoaffectation a lieu par valeur et si le constructeur parrecopie a eacuteteacute redeacutefini de faccedilon approprieacutee (par creacuteation drsquoun nouvel emplacement dynami-que) lrsquoalgorithme proposeacute fonctionnera sans problegraveme

En revanche si la transmission de a a lieu par reacutefeacuterence on abordera lrsquoalgorithme avec cettesituation

Lrsquoemplacement dynamique associeacute agrave b (donc aussi agrave a) sera libeacutereacute avant qursquoon tente de lrsquouti-liser pour le recopier dans un nouvel emplacement La situation sera alors catastrophique1

a

b

5

5

x

y

z

t

u

x

y

z

t

u

5z

t

ua et b

y

1 Dans beaucoup drsquoenvironnements les valeurs drsquoun emplacement libeacutereacute ne sont pas modifieacutees Lrsquoalgorithme peut

alors donner lrsquoillusion qursquoil fonctionne

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =167

34 Valeur de retourEnfin il faut deacutecider de la valeur de retour fournie par lrsquoopeacuterateur Agrave ce niveau tout deacutependde lrsquousage que nous souhaitons en faire

bull Si nous nous contentons drsquoaffectations simples (b=a) nous nrsquoavons besoin drsquoaucune va-leur de retour (void)

bull En revanche si nous souhaitons pouvoir traiter une affectation multiple ou plus geacuteneacuterale-ment faire en sorte que (comme on peut srsquoy attendre ) lrsquoexpression b=a ait une valeur(probablement celle de b ) il est neacutecessaire que lrsquoopeacuterateur fournisse une valeur de retour

Nous choisissons ici la seconde possibiliteacute qui a le meacuterite drsquoecirctre plus geacuteneacuterale1

35 En deacutefinitiveVoici finalement ce que pourrait ecirctre la deacutefinition de lrsquoopeacuterateur = (C++ impose de le deacutefinircomme une fonction membre) b devient le premier opeacuterande ndash ici this ndash et a devient lesecond opeacuterande ndash ici v De plus nous preacutevoyons de transmettre le second opeacuterande parreacutefeacuterence

vect vectoperator = (const vect amp v) notez const if (this = ampv) delete adr adr = new int [nelem = vnelem] for (int i=0 iltnelem i++) adr[i] = vadr[i] return this

Comme lrsquoargument de la fonction membre operator= est transmis par reacutefeacuterence il est neacuteces-saire de lui associer le qualificatif const si lrsquoon souhaite pouvoir affecter un vecteur constantagrave un vecteur quelconque2

36 Exemple de programme completNous vous proposons dinteacutegrer cette deacutefinition dans un programme complet servant agrave illus-trer le fonctionnement de lopeacuterateur Pour ce faire nous ajoutons comme dhabitude un cer-tain nombre dinstructions daffichage (en particulier nous suivons les adresses des objets etdes emplacements dynamiques qui leur sont associeacutes) Mais pour que le programme ne soitpas trop long nous avons reacuteduit la classe vect au strict minimum en particulier nousnrsquoavons pas preacutevu de constructeur de recopie or celui-ci deviendrait naturellement

indispensable dans une application reacuteelle

1 Bien entendu C++ vous laisse libre de faire ce que vous voulez y compris de renvoyer une valeur autre que celle

de b (avec tous les risques de manque de lisibiliteacute que cela suppose )

2 Cependant comme on le verra au chapitre 10 la preacutesence de cet attribut const pourra autoriser certaines

conversions de lrsquoargument

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

168

En outre bien qursquoici notre fonction main se limite agrave lemploi de lopeacuterateur = nous avons ducircpreacutevoir une transmission par reacutefeacuterence pour largument et la valeur de retour de operator=En effet si nous ne lavions pas fait lappel de cet opeacuterateur ndash traiteacute comme une fonction ndashaurait entraicircneacute un appel de constructeur de recopie (a = b est eacutequivalent ici agrave aoperator =

(b)) il se serait alors agi du constructeur de recopie par deacutefaut ce qui aurait entraicircneacute les pro-

blegravemes deacutejagrave eacutevoqueacutes de double libeacuteration dun emplacement1

include ltiostreamgtusing namespace std class vect int nelem nombre deacuteleacutements int adr pointeur sur ces eacuteleacutements public vect (int n) constructeur adr = new int [nelem = n] for (int i=0 iltnelem i++) adr[i] = 0 cout ltlt ++ obj taille ltlt nelem ltlt en ltlt this ltlt - v dyn en ltlt adr ltlt n ~vect () destructeur cout ltlt -- obj taille ltlt nelem ltlt en ltlt this ltlt - v dyn en ltlt adr ltlt n delete adr vect amp operator = (const vect amp) surdeacutefinition opeacuterateur = vect amp vectoperator = (const vect amp v) cout ltlt == appel operateur = avec adresses ltlt this ltlt ltlt ampv ltlt n if (this = ampv) cout ltlt effacement vecteur dynamique en ltlt adr ltlt n delete adr adr = new int [nelem = vnelem] cout ltlt nouveau vecteur dynamique en ltlt adr ltlt n for (int i=0 iltnelem i++) adr[i] = vadr[i] else cout ltlt on ne fait rien n return this main() vect a(5) b(3) c(4) cout ltlt affectation a=b n a = b cout ltlt affectation c=c n c = c cout ltlt affectation a=b=c n a = b = c

1 Un des exercices de ce chapitre vous propose de le veacuterifier

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =169

++ obj taille 5 en 006AFDE4 - v dyn en 007D0340

++ obj taille 3 en 006AFDDC - v dyn en 007D00D0

++ obj taille 4 en 006AFDD4 - v dyn en 007D0090

affectation a=b

== appel operateur = avec adresses 006AFDE4 006AFDDC

effacement vecteur dynamique en 007D0340

nouveau vecteur dynamique en 007D0340

affectation c=c

== appel operateur = avec adresses 006AFDD4 006AFDD4

on ne fait rien

affectation a=b=c

== appel operateur = avec adresses 006AFDDC 006AFDD4

effacement vecteur dynamique en 007D00D0

nouveau vecteur dynamique en 007D00D0

== appel operateur = avec adresses 006AFDE4 006AFDDC

effacement vecteur dynamique en 007D0340

nouveau vecteur dynamique en 007D0340

-- obj taille 4 en 006AFDD4 - v dyn en 007D0090

-- obj taille 4 en 006AFDDC - v dyn en 007D00D0

-- obj taille 4 en 006AFDE4 - v dyn en 007D0340

Exemple dutilisation dune classe vect avec un opeacuterateur daffectation surdeacutefini

37 Lorsqursquoon souhaite interdire lrsquoaffectationNous avons deacutejagrave vu (paragraphe 313 du chapitre 7) que dans certains cas on pouvait avoir

inteacuterecirct agrave interdire la recopie dobjets Les mecircmes consideacuterations sappliquent agrave laffectation

Ainsi une redeacutefinition de laffectation sous forme priveacutee en interdit lemploi par des fonc-

tions autres que les fonctions membres de la classe concerneacutee On peut eacutegalement exploiter la

possibiliteacute quoffre C++ de deacuteclarer une fonction sans en fournir de deacutefinition dans ce cas

toute tentative daffectation (mecircme au sein dune fonction membre) sera rejeteacutee par leacutediteur

de liens Dune maniegravere geacuteneacuterale il peut ecirctre judicieux de combiner les deux possibiliteacutes

cest-agrave-dire deffecteur une deacuteclaration priveacutee sans deacutefinition dans ces cas les tentatives

daffectation de la part de lutilisateur seront deacutetecteacutees en compilation et seules les tentatives

daffectation par une fonction membre produiront une erreur de leacutedition de liens (et ce point

ne concerne que le concepteur de la classe et non son utilisateur)

Remarques

1 Comme dans le cas de la deacutefinition du constructeur de recopie nous avons utiliseacute la

deacutemarche la plus naturelle consistant agrave effectuer une copie profonde en dupliquant la par-

tie dynamique de lobjet Dans certains cas on pourra chercher agrave eacuteviter cette duplication

en la dotant dun compteur de reacutefeacuterences comme lexplique lAnnexe E

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

170

2 Nous verrons plus tard que si une classe est destineacutee agrave donner naissance agrave des objets

susceptibles drsquoecirctre introduits dans des conteneurs il nrsquoest plus possible de deacutesactiver

lrsquoaffectation (pas plus que la recopie)

En Java

Java ne permet pas la surdeacutefinition dopeacuterateur On ne peut donc pas modifier la seacutemanti-

que de laffectation qui rappelons-le est tregraves diffeacuterente de celle agrave laquelle on est habitueacute

en C++ (les objets eacutetant manipuleacutes par reacutefeacuterence on aboutit apregraves affectation agrave deux reacutefeacute-

rences eacutegales agrave un unique objet)

4 La forme canonique dune classeDegraves lors quune classe dispose de pointeurs sur des parties dynamiques la copie dobjets de la

classe (aussi bien par le constructeur de recopie par deacutefaut que par lopeacuterateur daffectation

par deacutefaut) nest pas satisfaisante Dans ces conditions si lon souhaite que cette recopie fonc-

tionne convenablement il est neacutecessaire de munir la classe des quatre fonctions membres

suivantes au moins

bull constructeur (il sera geacuteneacuteralement chargeacute de lallocation de certaines parties de lobjet)

bull destructeur (il devra libeacuterer correctement tous les emplacements dynamiques creacuteeacutes par lobjet)

bull constructeur de recopie

bull opeacuterateur daffectation

Voici un canevas reacutecapitulatif correspondant agrave ce minimum quon nomme souvent classe

canonique

class T public

T () constructeurs autres que par recopie

T (const T amp) constructeur de recopie (forme conseilleacutee)

(deacuteclaration priveacutee pour lrsquointerdire) ~T () destructeur

T amp operator = (const T amp) affectation (forme conseilleacutee)

(deacuteclaration priveacutee pour lrsquointerdire)

La forme canonique dune classe

Bien que ce ne soit pas obligatoire nous vous conseillons

bull demployer le qualificatif const pour largument du constructeur de recopie et celui de laffec-

tation dans la mesure ougrave ces fonctions membres nont aucune raison de modifier les valeurs

5 - Exemple de surdeacutefinition de lopeacuterateur [ ]171

des objets correspondants On verra toutefois au chapitre 10 que cette faccedilon de proceacuteder peut

autoriser lintroduction de certaines conversions de lopeacuterande de droite de laffectation

bull de preacutevoir (agrave moins davoir de bonnes raisons de faire le contraire) une valeur de retour agrave

lopeacuterateur daffectation seul moyen de geacuterer correctement les affectations multiples

En revanche largument de lopeacuterateur daffectation et sa valeur de retour peuvent ecirctre indif-

feacuteremment transmis par reacutefeacuterence ou par valeur Cependant on ne perdra pas de vue que les

transmissions par valeur entraicircnent lappel du constructeur de recopie Dautre part degraves lors

que les objets sont de taille respectable la transmission par reacutefeacuterence savegravere plus efficace

Si vous creacuteez une classe comportant des pointeurs sans la doter de ce minimum vital et sans

prendre de preacutecautions particuliegraveres lutilisateur ne se verra nullement interdire la recopie ou

laffectation dobjets

Il peut arriver de creacuteer une classe qui nrsquoa pas besoin de disposer de ces possibiliteacutes de recopie

et drsquoaffectation par exemple parce qursquoelles nrsquoont pas de sens (cas drsquoune classe fenecirctre drsquoun

systegraveme graphique) Il se peut aussi que vous souhaitiez tout simplement ne pas offrir ces

possibliteacutes agrave lrsquoutilisateur de la classe Dans ce cas plutocirct que de compter sur la bonne

volonteacute de lrsquoutilisateur il est preacutefeacuterable drsquoutiliser quand mecircme la forme canonique en

srsquoarrangeant pour interdire ces actions Nous vous avons fourni des pistes dans ce sens au

paragraphe 37 ainsi qursquoau paragraphe 313 du chapitre 7 et nous avons vu qursquoune solution

simple agrave mettre en place consistait agrave fournir des deacuteclarations priveacutees de ces deux meacutethodes

sans en fournir de deacutefinition

Remarque

Ce scheacutema sera compleacuteteacute au chapitre 13 afin de prendre en compte la situation dheacuteritage

5 Exemple de surdeacutefinition de lopeacuterateur [ ] Consideacuterons agrave nouveau notre classe vect

class vect int nelem int adr

Cherchons agrave la munir doutils permettant dacceacuteder agrave un eacuteleacutement de lemplacement pointeacute par

adr agrave partir de sa position que lon repeacuterera par un entier compris entre 0 et nelem-1

Nous pourrions bien sucircr eacutecrire des fonctions membres comme

void range (int valeur int position)

pour introduire une valeur agrave une position donneacutee et

int trouve (int position)

pour fournir la valeur situeacutee agrave une position donneacutee

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

172

La manipulation de nos vecteurs ne serait alors guegravere aiseacutee Elle ressemblerait agrave ceci

vect a(5) arange (15 0) place 15 en position 0 de aarange (25 1) 25 en position 1for (int i = 2 i lt 5 i++) arange (0 i) et O ailleursfor i = 0 i lt 5 i++) pour afficher les valeurs de a cout ltlt atrouve (i)

En fait nous pouvons chercher agrave surdeacutefinir lopeacuterateur [] de maniegravere que a[i] deacutesigne leacuteleacute-

ment demplacement i de a La seule preacutecaution agrave prendre consiste agrave faire en sorte que cette

notation puisse ecirctre utiliseacutee non seulement dans une expression (cas qui ne preacutesente aucune

difficulteacute) mais eacutegalement agrave gauche dune affectation cest-agrave-dire comme lvalue Notez que

le problegraveme ne se posait pas dans lexemple ci-dessus puisque chaque cas eacutetait traiteacute par une

fonction membre diffeacuterente

Pour que a[i] soit une lvalue il est donc neacutecessaire que la valeur de retour fournie par lopeacute-

rateur [] soit transmise par reacutefeacuterence

Par ailleurs C++ impose de surdeacutefinir cet opeacuterateur sous la forme dune fonction membre ce

qui implique que son premier opeacuterande (le premier opeacuterande de a[i] est a) soit de type classe

(ce qui semble raisonnable ) Son prototype sera donc

int amp operator [] (int)

Si nous nous contentons de renvoyer leacuteleacutement chercheacute sans effectuer de controcircle sur la vali-

diteacute de la position le corps de la fonction operator[] peut se reacuteduire agrave

return adr[i]

Voici un exemple simple dutilisation dune classe vect reacuteduite agrave son strict minimum cons-

tructeur destructeur et opeacuterateur [] Bien entendu en pratique il faudrait au moins lui ajouter

un constructeur de recopie et un opeacuterateur daffectation

include ltiostreamgtusing namespace std class vect int nelem int adr public vect (int n) adr = new int [nelem=n] ~vect () delete adr int amp operator [] (int) int amp vectoperator [] (int i) return adr[i] main() int i vect a(3) b(3) c(3) for (i=0 ilt3 i++) a[i] = i b[i] = 2i for (i=0 ilt3 i++) c[i] = a[i]+b[i] for (i=0 ilt3 i++) cout ltlt c[i] ltlt

6 - Surdeacutefinition de lopeacuterateur ()173

0 3 6

Exemple de surdeacutefinition de lopeacuterateur[]

Remarques

1 Nous pourrions bien sucircr transmettre le second opeacuterande par reacutefeacuterence mais cela ne preacute-

senterait guegravere dinteacuterecirct compte tenu de la petite taille des variables du type int

2 C++ interdit de deacutefinir lopeacuterateur [] sous la forme dune fonction amie il en allait deacutejagrave

de mecircme pour lopeacuterateur = De toute faccedilon nous verrons au prochain chapitre quil

nest pas conseilleacute de deacutefinir par une fonction amie un opeacuterateur susceptible de modifier

un objet compte tenu des conversions implicites pouvant apparaicirctre

3 Seules les fonctions membres doteacutees du qualificatif const peuvent ecirctre appliqueacutees agrave un

objet constant Tel que nous lavons conccedilu lopeacuterateur [] ne permet donc pas dacceacuteder

agrave un objet constant mecircme sil ne sagit que drsquoutiliser la valeur de ses eacutelements sans la

modifier Certes on pourrait ajouter ce qualificatif const agrave lrsquoopeacuterateur [] mais il la

modification des valeurs drsquoun objet constant deviendrait alors possible ce qui nest

guegravere souhaitable En geacuteneacuteral on preacutefeacuterera deacutefinir un second opeacuterateur destineacute unique-

ment aux objets constants en faisant en sorte quil puisse consulter lobjet en question

mais non le modifier Dans notre cas voici ce que pourrait ecirctre ce second opeacuterateur

int vectoperator [] (int i) const return adr[i]

Une affectation telle que v[i] = v eacutetant un vecteur constant sera bien rejeteacutee en com-

pilation puisque notre opeacuterateur transmet son reacutesultat par valeur et non plus par reacutefeacute-

rence

4 Lopeacuterateur [] eacutetait ici dicteacute par le bon sens mais nullement imposeacute par C++ Nous

aurions pu tout aussi bien utiliser

ndash lopeacuterateur () la notation a(i) aurait encore eacuteteacute compreacutehensible

ndash lopeacuterateur lt que penser alors de la notation a lt i

ndash lopeacuterateur notation a i

ndash etc

6 Surdeacutefinition de lopeacuterateur ()Lorsquune classe surdeacutefinit lopeacuterateur () on dit que les objets auxquels elle donne naissance

sont des objets fonctions car ils peuvent ecirctre utiliseacutes de la mecircme maniegravere quune fonction

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

174

ordinaire En voici un exemple simple dans lequel nous surdeacutefinissons lopeacuterateur () pour

quil corresponde agrave une fonction agrave deux arguments de type int et renvoyant un int

class cl_fct public cl_fct(float x) constructeur int operator() (int n int p ) opeacuterateur ()

Dans ces conditions une deacuteclaration telle que

cl_fct obj_fct1(25)

construit bien sucircr un objet nommeacute obj_fct1 de type cl_fct en transmettant le paramegravetre 25 agrave

son constructeur En revanche la notation suivante reacutealise lappel de lopeacuterateur ( ) de lobjet

obj_fct1 en lui transmettant les valeurs 3 et 5

obj_fct1(3 5)

Ces possibiliteacutes peuvent servir lorsquil est neacutecessaire deffectuer certaines opeacuterations dini-

tialisation dune fonction ou de parameacutetrer son travail (par le biais des arguments passeacutes agrave son

constructeur) Mais elles saveacutereront encore plus inteacuteressantes dans le cas des fonctions dites

de rappel crsquoest-agrave-dire transmises en argument agrave une autre fonction

7 Surdeacutefinition des opeacuterateurs new et deleteNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Tout drsquoabord il faut bien noter que les opeacuterateurs new et delete peuvent srsquoappliquer agrave des

types de base agrave des structures usuelles ou agrave des objets Par ailleurs il existe drsquoautres opeacutera-

teurs new[] et delete[] srsquoappliquant agrave des tableaux (drsquoeacuteleacutements de type de base structure ou

objet) Cette remarque a des conseacutequences au niveau de leur redeacutefinition

bull Vous pourrez redeacutefinir new et delete seacutelectivement pour une classe donneacutee bien entendu

vous pourrez toujours redeacutefinir ces opeacuterateurs dans autant de classes que vous le

souhaiterez dans ce cas les opeacuterateurs preacutedeacutefinis (on parle aussi drsquoopeacuterateurs globaux)

continueront drsquoecirctre utiliseacutes pour les classes ougrave aucune surdeacutefinition nrsquoaura eacuteteacute preacutevue

bull Vous pourrez eacutegalement redeacutefinir ces opeacuterateurs de faccedilon globale il seront alors utiliseacutes

pour les types de base pour les structures usuelles et pour les types classe nrsquoayant opeacutereacute

aucune surdeacutefinition

bull Enfin il ne faudra pas perdre de vue que les surdeacutefinitions de new drsquoune part et de new[]

drsquoautre part sont deux choses diffeacuterentes lrsquoune nrsquoentraicircnant pas automatiquement lrsquoautre

la mecircme remarque srsquoapplique agrave delete et delete[]

Voyons cela plus en deacutetail en commenccedilant par la situation la plus usuelle agrave savoir la surdeacute-

finition de new et delete au sein drsquoune classe

7 - Surdeacutefinition des opeacuterateurs new et delete175

71 Surdeacutefinition de new et delete pour une classe donneacuteeLa surdeacutefinition de new se fait obligatoirement par une fonction membre qui doit

bull Posseacuteder un argument de type size_t correspondant agrave la taille en octets de lrsquoobjet agrave allouer

Bien qursquoil figure dans la deacutefinition de new il nrsquoa pas agrave ecirctre speacutecifieacute lors de son appel car

crsquoest le compilateur qui le geacuteneacuterera automatiquement en fonction de la taille de lrsquoobjet con-

cerneacute (Rappelons que size_t est un synonyme drsquoun type entier deacutefini dans le fichier en-

tecircte cstddef)

bull Fournir en retour une valeur de type void correspondant agrave lrsquoadresse de lrsquoemplacement al-

loueacute pour lrsquoobjet

Quant agrave la deacutefinition de la fonction membre correspondant agrave lrsquoopeacuterateur delete elle doit

bull Recevoir un argument du type pointeur sur la classe correspondante il repreacutesente lrsquoadresse

de lrsquoemplacement alloueacute agrave lrsquoobjet agrave deacutetruire

bull Ne fournir aucune valeur de retour (void)

Remarques

1 Mecircme lorsque lrsquoopeacuterateur new a eacuteteacute surdeacutefini pour une classe il reste possible de faire

appel agrave lrsquoopeacuterateur preacutedeacutefini en utilisant lrsquoopeacuterateur de reacutesolution de porteacutee il en va de

mecircme pour delete

2 Les opeacuterateurs new et delete sont des fonctions membres statiques de leur classe (voir

le paragraphe 8 du chapitre 6) En tant que tels ils nrsquoont donc accegraves qursquoaux membres

statiques de la classe ougrave ils sont deacutefinis et ne reccediloivent pas drsquoargument implicite (this)

72 ExempleVoici un programme dans lequel la classe point surdeacutefinit les opeacuterateurs new et delete dans

le seul but drsquoen comptabiliser les appels1 Ils font drsquoailleurs appel aux opeacuterateurs preacutedeacutefinis

(par emploi de ) pour ce qui concerne la gestion de la meacutemoire

include ltiostreamgtinclude ltcstddefgt pour size_tusing namespace std

class point static int npt nombre total de points static int npt_dyn nombre de points dynamiques int x y

1 Bien entendu dans un programme reacuteel lrsquoopeacuterateur new accomplira en geacuteneacuteral une tacircche plus eacutelaboreacutee

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

176

public point (int abs=0 int ord=0) constructeur x=abs y=ord npt++ cout ltlt ++ nombre total de points ltlt npt ltlt n ~point () destructeur npt-- cout ltlt -- nombre total de points ltlt npt ltlt n void operator new (size_t sz) new surdeacutefini npt_dyn++ cout ltlt il y a ltlt npt_dyn ltlt points dynamiques sur un n return new char[sz] void operator delete (void dp) npt_dyn-- cout ltlt il y a ltlt npt_dyn ltlt points dynamiques sur un n delete (dp) int pointnpt = 0 initialisation membre statique nptint pointnpt_dyn = 0 initialisation membre statique npt_dynmain() point ad1 ad2 point a(35) ad1 = new point (13) point b ad2 = new point (20) delete ad1 point c(2) 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

Exemple de surdeacutefinition de lrsquoopeacuterateur new pour la classe point

7 - Surdeacutefinition des opeacuterateurs new et delete177

Remarques

1 Comme le montre cet exemple et comme on peut srsquoy attendre la surdeacutefinition des opeacutera-

teurs new et delete nrsquoa drsquoincidence que sur les objets alloueacutes dynamiquement Les objets

statiques (alloueacutes agrave la compilation) et les objets dynamiques (alloueacutes lors de lrsquoexeacutecution

mais sur la pile) ne sont toujours pas concerneacutes

2 Que new soit surdeacutefini ou preacutedeacutefini son appel est toujours (heureusement) suivi de

celui du constructeur (lorsqursquoil existe) De mecircme que delete soit surdeacutefini ou preacutedeacutefini

son appel est toujours preacuteceacutedeacute de celui du destructeur (lorsqursquoil existe)

3 Nrsquooubliez pas qursquoil est neacutecessaire de distinguer new de new[] delete de delete[] Ainsi

dans lrsquoexemple de programme preacuteceacutedent une instruction telle que

point ad = new point [50]

ferait appel agrave lrsquoopeacuterateur new preacutedeacutefini (et 50 fois agrave lrsquoappel du constructeur sans argu-

ment) En geacuteneacuteral on surdeacutefinira eacutegalement new[] et delete[] comme nous allons le

voir ci-apregraves

73 Drsquoune maniegravere geacuteneacuteralePour surdeacutefinir new[] au sein drsquoune classe il suffit de proceacuteder comme pour new le nom

mecircme de lrsquoopeacuterateur (new[] au lieu de new) servant agrave effectuer la distinction Par exemple

dans notre classe point de lrsquoexemple preacuteceacutedent nous pourrons ajouter

void operator new [](size_t sz)

return new char[sz]

La valeur fournie en argument correspondra bien agrave la taille totale agrave allouer pour le tableau (et

non agrave la taille drsquoun seul eacuteleacutement) Cette fois dans notre preacuteceacutedent exemple de programme

lrsquoinstruction

point adp = new point[50]

effectuera bien un appel de lrsquoopeacuterateur new[] ainsi surdeacutefini (et toujours les 50 appels du

constructeur sans arguments de point)

De mecircme on surdeacutefinira delete[] de cette faccedilon

void operator delete (void dp) dp adresse de lrsquoemplacement agrave libeacuterer

Enfin pour surdeacutefinir les opeacuterateurs new et delete de maniegravere globale il suffit de deacutefinir

lrsquoopeacuterateur correspondant sous la forme drsquoune fonction indeacutependante comme dans cet

exemple

void operator new (size_t sz)

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

178

Notez bien qursquoalors

bull Cet opeacuterateur sera appeleacute pour tous les types pour lesquels aucun opeacuterateur new nrsquoa eacuteteacute sur-

deacutefini y compris pour les types de base Crsquoest le cas de la deacuteclaration suivante

int adi = new int

bull Dans la surdeacutefinition de cet opeacuterateur il nrsquoest plus possible de faire appel agrave lrsquoopeacuterateur new

preacutedeacutefini Toute tentative drsquoappel de new ou mecircme de new fera entrer dans un processus

reacutecursif

Ce dernier point limite lrsquointeacuterecirct de la surdeacutefinition globale de new de delete puisque le pro-

grammeur doit prendre complegravetement agrave sa charge la gestion dynamique de meacutemoire (par

exemple en reacutealisant les appels au systegraveme neacutecessaires)

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1) Dans les deux exemples de programme des paragraphes 11 et 12 mettez en eacutevidence

les appels dun constructeur de recopie Pour ce faire introduisez un constructeur sup-

pleacutementaire de la forme point (pointamp) dans la classe point Voyez ce qui se produit

lorsque vous employez la transmission par reacutefeacuterence pour le ou les arguments de ope-

rator+

2) Dans lexemple du paragraphe 3 introduisez un constructeur de recopie pour la classe

vect Constatez que le remplacement de la transmission par reacutefeacuterence par une trans-

mission par valeur entraicircne la creacuteation de nombreux objets suppleacutementaires

3 (C) Dans une classe point de la forme

class point

int x y

public

point (int abs = 0 int ord = 0)

introduisez un opeacuterateur == tel que si a et b sont deux points a==b fournisse la

valeur 1 lorsque a et b ont les mecircmes coordonneacutees et la valeur 0 dans le cas contraire

On preacutevoira les deux situations

a) fonction membre

b) fonction amie

7 - Surdeacutefinition des opeacuterateurs new et delete179

4 (C) Dans une classe pile_entier de la forme1

class pile_entier int dim nombre maxi deacuteleacutements de la pile int adr adresse du tableau repreacutesentant la pile int nelem nombre deacuteleacutements courant de la pile public pile_entier (int n) ~pile_entier ()

introduisez les opeacuterateurs gt et lt tels que si p est un objet de type pile_entier et n une

variable entiegravere

p lt n ajoute la valeur de n sur la pile p (en ne renvoyant aucune valeur)

p gt n supprime la valeur du haut de la pile et la place dans n

On preacutevoira les deux situations

a) fonctions membres

b) fonctions amies

5 Veacuterifiez si votre impleacutementation accepte qursquoon ne deacutefinisse que la version preacute de

lrsquoopeacuterateur ++ en vous inspirant de lrsquoexemple du paragraphe 24

6 (C) En langage C il nexiste pas de veacuteritable type chaicircne mais simplement une conven-

tion de repreacutesentation des chaicircnes (suite de caractegraveres termineacutee par un caractegravere de

code nul) Un certain nombre de fonctions utilisant cette convention permettent les

manipulations classiques (copie concateacutenation)

Cet exercice vous demande de deacutefinir une classe nommeacutee chaine offrant des possibili-

teacutes plus proches dun veacuteritable type chaicircne (tel que celui du Basic ou du Pascal) Pour

ce faire on preacutevoira comme membres donneacutees

bull la longueur courante de la chaicircne

bull ladresse dune zone alloueacutee dynamiquement destineacutee agrave recevoir la suite de carac-

tegraveres (il ne sera pas neacutecessaire dy ranger le caractegravere nul de fin puisque la longueur

de la chaicircne est deacutefinie par ailleurs)

Le contenu dun objet de type chaine pourra donc eacutevoluer par un simple jeu de gestion

dynamique

On munira la classe chaine des constructeurs suivants

bull chaine() initialise une chaicircne vide

bull chaine (char) initialise la chaicircne avec la chaicircne (au sens du C) dont on fournit

ladresse en argument

bull chaine (chaineamp) constructeur de recopie

1 Revoyez eacuteventuellement lexercice 5 du chapitre 7

On deacutefinira les opeacuterateurs

bull = pour laffectation entre objets de type chaine (penser agrave laffectation multiple)

bull == pour examiner leacutegaliteacute de deux chaicircnes

bull + pour reacutealiser la concateacutenation de deux chaicircnes Si a et b sont de type chaine a + b

sera une (nouvelle) chaicircne formeacutee de la concateacutenation de a et b (les chaicircnes a et b

devront ecirctre inchangeacutees)

bull [] pour acceacuteder agrave un caractegravere de rang donneacute dune chaicircne (les affectations de la for-

me a[i] = x devront pouvoir fonctionner

On pourra ajouter une fonction daffichage On ne preacutevoira pas demployer de comp-

teur par reacutefeacuterence ce qui signifie quon acceptera de dupliquer les chaicircnes identiques

NB On trouvera dans la bibliothegraveque standard preacutevue par la norme une classe string

offrant entre autres les fonctionnaliteacutes eacutevoqueacutees ici Pour conserver son inteacuterecirct agrave

lrsquoexercice il ne faut pas lrsquoutiliser ici

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

180

10

Les conversions de typedeacutefinies par lrsquoutilisateur

En matiegravere de conversion dun type de base en un autre type de base C++ offre naturellement

les mecircmes possibiliteacutes que le langage C qui rappelons-le fait intervenir des conversions

explicites et des conversions implicites

Les conversions sont explicites lorsque lon fait appel agrave un opeacuterateur de cast comme dans

int n double z

z = double(n) conversion de int en double

ou dans

n = int(z) conversion de double en int

Les conversions implicites ne sont pas mentionneacutees par lutilisateur1 mais elles sont mises

en place par le compilateur en fonction du contexte elles se rencontrent agrave diffeacuterents

niveaux

bull dans les affectations il y a alors conversion forceacutee dans le type de la variable reacuteceptrice

bull dans les appels de fonction comme le prototype est obligatoire en C++ il y a eacutegalement

conversion forceacutee dun argument dans le type deacuteclareacute dans le prototype

1 Cest-agrave-dire en fait lauteur du programme Nous avons toutefois conserveacute le terme reacutepandu dutilisateur qui

soppose ici agrave compilateur

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

182

bull dans les expressions pour chaque opeacuterateur il y a conversion eacuteventuelle de lun des opeacute-

randes dans le type de lautre suivant des regravegles preacutecises1 qui font intervenir

ndash des conversions systeacutematiques char et short en int

ndash des conversions dajustement de type par exemple int en long pour une addition de

deux valeurs de type long

Mais C++ permet aussi de deacutefinir des conversions faisant intervenir des types classe creacuteeacutes

par lutilisateur Par exemple pour un type complexe on pourra en eacutecrivant des fonctions

approprieacutees donner une signification aux conversions

complexe -gt doubledouble -gt complexe

Qui plus est nous verrons que lexistence de telles conversions permettra de donner un sens agrave

laddition dun complexe et dun double ou mecircme celle dun complexe et dun int

Cependant sil paraicirct logique de disposer de conversions entre une classe complexe et les

types numeacuteriques il nen ira plus neacutecessairement de mecircme pour des classes nayant pas une

connotation matheacutematique aussi forte ce qui nempecircchera pas le compilateur de mettre en

place le mecircme genre de conversions

Ce chapitre fait le point sur ces diffeacuterentes possibiliteacutes Consideacutereacutees comme assez dangereu-

ses il est bon de ne les employer qursquoen toute connaissance de cause Pour vous eacuteviter une

conclusion hacirctive nous avons volontairement utiliseacute des exemples de conversions tantocirct

signifiantes (agrave connotation matheacutematique) tantocirct non signifiantes

Au passage nous en profiterons pour insister sur le rocircle important du qualificatif const appli-

queacute agrave un argument muet transmis par reacutefeacuterence

1 Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur

Consideacuterons une classe point posseacutedant un constructeur agrave un argument comme

point (int abs) x = abs y = 0

On peut dire que ce constructeur reacutealise une conversion dun int en un objet de type point

Nous avons dailleurs deacutejagrave vu comment appeler explicitement ce constructeur par exemple

point a a = point(3)

Comme nous le verrons agrave moins de linterdire au moment de la deacutefinition de la classe ce

constructeur peut ecirctre appeleacute implicitement dans des affectations des appels de fonction ou

1 Ces regravegles sont deacutetailleacutees dans La reacutefeacuterence du C norme ANSIISO du mecircme auteur

1 - Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur183

des calculs dexpression au mecircme titre quune conversion usuelle (on parle aussi de con-

version standard)

Plus geacuteneacuteralement si lon considegravere deux classes nommeacutees point et complexe on peut dire

qursquoun constructeur de la classe complexe agrave un argument de type point

complexe (point)

permet de convertir un point en complexe Nous verrons que cette conversion pourra elle

aussi ecirctre utiliseacutee implicitement dans les diffeacuterentes situations eacutevoqueacutees (agrave moins quon lait

interdit explicitement)

En revanche un constructeur (qui fournit un objet du type de sa classe) ne peut en aucun cas

permettre de reacutealiser une conversion dun objet en une valeur dun type simple (type de base

ou pointeur) par exemple un point en int ou un complexe en double Comme nous le verrons

ce type de conversion pourra ecirctre traiteacute en deacutefinissant au sein de la classe concerneacutee un opeacute-

rateur de cast approprieacute par exemple pour les deux cas citeacutes

operator int()

au sein de la classe point

operator double()

au sein de la classe complexe

Cette derniegravere deacutemarche de deacutefinition dun opeacuterateur de cast pourra aussi ecirctre employeacutee pour

deacutefinir une conversion dun type classe en un autre type classe Par exemple avec

operator complexe()

au sein de la classe point on deacutefinira la conversion dun point en complexe au mecircme titre

quavec le constructeur

complexe (point)

situeacute cette fois dans la classe complexe

Voici un scheacutema reacutecapitulant les diffeacuterentes possibiliteacutes que nous venons deacutevoquer A et B

deacutesignent deux classes b un type de base quelconque

Les quatre sortes de conversions deacutefinies par lrsquoutilisateur

Constructeur agrave un argument

A(b)

Opeacuterateur de cast dans A

operator (b)

Constructeur de D agrave un argument

D(C)

Opeacuterateur de cast dans C

operator D()

b A

C D

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

184

Parmi les diffeacuterentes possibiliteacutes de conversion que nous venons deacutevoquer seul lopeacuterateur

de cast appliqueacute agrave une classe apparaicirct comme nouveau Nous allons donc le preacutesenter mais

aussi expliquer quand et comment les diffeacuterentes conversions implicites sont mises en œuvre

et examiner les cas rejeteacutes par le compilateur

2 Lopeacuterateur de cast pour la conversion type classe ndashgt type de base

21 Deacutefinition de lopeacuterateur de castConsideacuterons une classe point

class point int x y

Supposez que nous souhaitions la munir dun opeacuterateur de cast permettant la conversion de

point en int Nous le noterons simplement

operator int()

Il sagit lagrave du meacutecanisme habituel de surdeacutefinition dopeacuterateur eacutetudieacute au chapitre preacuteceacutedent

lopeacuterateur se nomme ici int il est unaire (un seul argument) et comme il sagit dune fonc-

tion membre aucun argument napparaicirct dans son en-tecircte ou son prototype Reste la valeur de

retour en principe cet opeacuterateur fournit un int de sorte quon aurait pu penser agrave len-tecircte

int operator int()

En fait en C++ un opeacuterateur de cast doit toujours ecirctre deacutefini comme une fonction mem-

bre et le type de la valeur de retour (qui est alors celui deacutefini par le nom de lopeacuterateur) ne

doit pas ecirctre mentionneacute

En deacutefinitive voici comment nous pourrions deacutefinir notre opeacuterateur de cast (ici en ligne) en

supposant que le reacutesultat souhaiteacute pour la conversion en int soit labscisse du point

operator int() return x

Bien entendu pour ecirctre utilisable agrave lrsquoexteacuterieur de la classe cet opeacuterateur devra ecirctre public

22 Exemple dutilisationVoici un premier exemple de programme montrant agrave la fois un appel explicite de lopeacuterateur

int que nous venons de deacutefinir et un appel implicite entraicircneacute par une affectation1 Comme agrave

1 Srsquoil nrsquoeacutetait pas deacuteclareacute public on obtiendrait une erreur de compilation dans les deux appels

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base185

laccoutumeacutee nous avons introduit une instruction daffichage dans lopeacuterateur lui-mecircme

pour obtenir une trace de son appel

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x main() point a(34) b(57) int n1 n2 n1 = int(a) ou n1 = (int) a appel explicite de int () on peut aussi eacutecrire n1 = (int) a ou n1 = static_castltintgt (a) cout ltlt n1 = ltlt n1 ltlt n n2 = b appel implicite de int() cout ltlt n2 = ltlt n2 ltlt n

++ construction point 3 4++ construction point 5 7== appel int() pour le point 3 4n1 = 3== appel int() pour le point 5 7n2 = 5

Exemple dutilisation dun opeacuterateur de cast pour la conversion point -gt int

Nous voyons clairement que laffectation

n2 = b

a eacuteteacute traduite par le compilateur en

bull une conversion du point b en int

bull une affectation (classique) de la valeur obtenue agrave n2

23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonctionDeacutefinissons une fonction fct recevant un argument de type entier que nous appelons

bull une premiegravere fois avec un argument entier (6)

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

186

bull une deuxiegraveme fois avec un argument de type point (a)

En outre nous introduisons (artificiellement) dans la classe point un constructeur de recopie

afin de montrer quici il nest pas appeleacute

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n point (const point amp p) constructeur de recopie cout ltlt appel constructeur de recopie n x = px y = py operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x void fct (int n) fonction cout ltlt appel fct avec argument ltlt n ltlt n

main() void fct (int) point a(34) fct (6) appel normal de fct 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

Appel de lopeacuterateur de cast lors dun appel de fonction

On voit que lappel

fct(a)

a eacuteteacute traduit par le compilateur en

bull une conversion de a en int

bull un appel de fct agrave laquelle on fournit en argument la valeur ainsi obtenue

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base187

Comme on pouvait sy attendre la conversion est bien reacutealiseacutee avant lappel de la fonction et

il ny a pas de creacuteation par recopie dun objet de type point

24 Appel implicite de lopeacuterateur de cast dans leacutevaluation dune expression

Les reacutesultats de ce programme illustrent la maniegravere dont sont eacutevalueacutees des expressions telles

que a + 3 ou a + b lorsque a et b sont de type point

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x main() point a(34) b(57) int n1 n2 n1 = a + 3 cout ltlt n1 = ltlt n1 ltlt n n2 = a + b cout ltlt n2 = ltlt n2 ltlt n

double z1 z2 z1 = a + 3 cout ltlt z1 = ltlt z1 ltlt n z2 = a + b cout ltlt z2 = ltlt z2 ltlt n

++ construction point 3 4++ construction point 5 7== appel int() pour le point 3 4n1 = 6== appel int() pour le point 3 4== appel int() pour le point 5 7n2 = 8== appel int() pour le point 3 4z1 = 6== appel int() pour le point 3 4== appel int() pour le point 5 7z2 = 8

Utilisation de lopeacuterateur de cast dans leacutevaluation dune expression

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

188

Lorsquil rencontre une expression comme a + 3 avec un opeacuterateur portant sur un eacuteleacutement de

type point et un entier le compilateur recherche tout dabord sil existe un opeacuterateur + surdeacute-

fini correspondant agrave ces types dopeacuterandes Ici il nen trouve pas Il cherche alors agrave mettre en

place des conversions des opeacuterandes permettant daboutir agrave une opeacuteration existante Dans

notre cas il preacutevoit la conversion de a en int de maniegravere agrave se ramener agrave la somme de deux

entiers suivant le scheacutema

point int | | int | |___ + ___| | int

Certes une telle deacutemarche peut choquer Quelques remarques srsquoimposent

bull Ici aucune autre conversion nest envisageable Il nen irait pas de mecircme sil existait un opeacute-

rateur (surdeacutefini) daddition de deux points

bull La deacutemarche paraicirct moins choquante si lon ne cherche pas agrave donner une veacuteritable significa-

tion agrave lopeacuteration a + 3

bull Nous cherchons agrave preacutesenter les diffeacuterentes situations que lon risque de rencontrer non pas

pour vous encourager agrave les employer toutes mais plutocirct pour vous mettre en garde

Quant agrave leacutevaluation de a + b elle se fait suivant le scheacutema suivant

point point | | int int |___ + ___| | int

Pour chacune des deux expressions nous avons preacutevu deux sortes drsquoaffectation

bull agrave une variable entiegravere

bull agrave une variable de type double dans ce cas il y a conversion forceacutee du reacutesultat de lexpres-

sion en double

Notez bien que le type de la variable reacuteceptrice nagit aucunement sur la maniegravere dont

lexpression est eacutevalueacutee pas plus que sur son type final

25 Conversions en chaicircneConsideacuterez cet exemple

include ltiostreamgtusing namespace std

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base189

class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x void fct (double v) cout ltlt appel fct avec argument ltlt v ltlt n

main() point a(34) int n1 double z1 z2 n1 = a + 385 cout ltlt n1 = ltlt n1 ltlt n z1 = a + 385 cout ltlt z1 = ltlt z1 ltlt n z2 = a cout ltlt z2 = ltlt z2 ltlt n fct (a)

++ construction point 3 4== appel int() pour le point 3 4n1 = 6== appel int() pour le point 3 4z1 = 685== appel int() pour le point 3 4z2 = 3== appel int() pour le point 3 4 appel fct avec argument 3

Conversions en chaicircne

Cette fois nous avons agrave eacutevaluer agrave deux reprises la valeur de lexpression

a + 385

La diffeacuterence avec les situations preacuteceacutedentes est que la constante 385 est de type double et

non plus de type int Par analogie avec ce qui preacutecegravede on pourrait supposer que le compila-

teur preacutevoie la conversion de 385 en int Or il sagirait dune conversion dun type de base

double en un autre type de base int qui risquerait drsquoecirctre deacutegradante et qui comme dhabi-

tude nest jamais mise en œuvre de maniegravere implicite dans un calcul dexpression1

1 Elle pourrait lecirctre dans une affectation ou un appel de fonction en tant que conversion forceacutee

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

190

En fait leacutevaluation se fera suivant le scheacutema

point double | | int | | | double | |___ + ___| | double

La valeur afficheacutee pour z1 confirme le type double de lexpression

La valeur de ai a donc eacuteteacute soumise agrave deux conversions successives avant drsquoecirctre transmise agrave

un opeacuterateur Ceci est indeacutependant de lusage qui doit ecirctre fait ulteacuterieurement de la valeur de

lexpression agrave savoir

bull conversion en int pour affectation agrave n1 dans le premier cas

bull affectation agrave z2 dans le second cas

Quant agrave laffectation z2 = a elle entraicircne une double conversion de point en int puis de int en

double

Il en va de mecircme pour lappel

fct (a)

Dune maniegravere geacuteneacuterale

Remarque

Nous avons deacutejagrave rencontreacute ce meacutecanisme dans le cas des fonctions surdeacutefinies Ici il

sagit dun meacutecanisme comparable appliqueacute agrave un opeacuterateur preacutedeacutefini et non plus agrave une

fonction deacutefinie par lutilisateur Nous retrouverons des situations semblables par la

suite relatives cette fois agrave un opeacuterateur deacutefini par lutilisateur (donc agrave une fonction)

les regravegles appliqueacutees seront alors bien celles que nous avons eacutevoqueacutees dans la recher-

che de la bonne fonction surdeacutefinie

26 En cas dambiguiumlteacuteA partir du moment ougrave le compilateur accepte de mettre en place une chaicircne de conversions

certaines ambiguiumlteacutes peuvent apparaicirctre Reprenons lexemple de la classe point en suppo-

sant cette fois que nous lavons munie de deux opeacuterateurs de cast

En cas de besoin C++ peut ainsi mettre en œuvre une chaicircne de conver-sions agrave condition toutefois que celle-ci ne fasse intervenir qursquoune seule CDU (Conversion Deacutefinie par lrsquoUtilisateur) Plus preacuteciseacutement cette chaicircne peut ecirctre formeacutee drsquoau maximum trois conversions agrave savoir une conversion standard suivie drsquoune CDU suivie drsquoune conversion standard

3 - Le constructeur pour la conversion type de base -gt type classe191

operator int()operator double()

Supposons que nous utilisions de nouveau une expression telle que (a eacutetant de type point)

a + 385

Dans ce cas le compilateur se trouve en preacutesence de deux scheacutemas possibles de conversion

point double point double | | | | double | int | |____+____| | | | double | double |___ + ___| | double

Ici il refuse lexpression en fournissant un diagnostic dambiguiumlteacute

Cette ambiguiumlteacute reacuteside dans le fait que deux chaicircnes de conversions permettent de passer du

type point au type double Sil sagissait dune ambiguiumlteacute concernant le choix de lopeacuterateur agrave

appliquer (ce qui neacutetait pas le cas ici) le compilateur appliquerait alors les regravegles habituelles

de choix dune fonction surdeacutefinie1

3 Le constructeur pour la conversion type de base -gt type classe

31 ExempleNous avons deacutejagrave vu comment appeler explicitement un constructeur Par exemple avec la

classe point preacuteceacutedente si a est de type point nous pouvons eacutecrire

a = point (12)

Cette instruction provoque

bull la creacuteation dun objet temporaire de type point

bull lrsquoaffectation de cet objet agrave a

On peut donc dire que lexpression

point (12)

exprime la conversion de lentier 12 en un point

Dune maniegravere geacuteneacuterale tout constructeur agrave un seul argument dun type de base2 reacutealise une

conversion de ce type de base dans le type de sa classe

1 En toute rigueur il faudrait consideacuterer que les opeacuterateurs sur les types de base correspondent eux aussi agrave des

fonctions de la forme operator +

2 Ou eacuteventuellement comme cest le cas ici agrave plusieurs arguments ayant des valeurs par deacutefaut agrave partir du moment

ougrave il peut ecirctre appeleacute avec un seul argument

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

192

Or tout comme lopeacuterateur de cast ce constructeur peut eacutegalement ecirctre appeleacute implicitement

Ainsi laffectation

a = 12

provoque exactement le mecircme reacutesultat que

a = point (12)

A sa rencontre en effet le compilateur cherche sil existe une conversion (voire une chaicircne de con-

versions) unique permettant de passer du type int au type point Ici le constructeur fait laffaire

De la mecircme faccedilon si fct a pour prototype

void fct (point)

un appel tel que

fct (4)

entraicircne une conversion de lentier 4 en un point temporaire qui est alors transmis agrave fct

Voici un petit programme illustrant ces premiegraveres possibiliteacutes de conversion par un constructeur

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments

x = abs y = ord

cout ltlt ++ construction point ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

point (const point amp p) constructeur de recopie

x = px y = py

cout ltlt constr recopie de ltlt ampp ltlt en ltlt this ltlt n

void fct (point p) fonction simple

cout ltlt appel fct ltlt n

main()

void fct (point)

point a(34)

a = point (12) appel explicite constructeur

a = 12 appel implicite

fct(4)

++ construction point 3 4 en 006AFDF0

++ construction point 12 0 en 006AFDE8

++ construction point 12 0 en 006AFDE0

3 - Le constructeur pour la conversion type de base -gt type classe193

++ construction point 4 0 en 006AFD88

appel fct

Utilisation dun constructeur pour reacutealiser des conversions int ndashgt point

Remarques

1 Bien entendu si fct est surdeacutefinie le choix de la bonne fonction se fera suivant les regravegles

deacutejagrave rencontreacutees au chapitre 4 Cette fonction devra ecirctre unique de mecircme que les chaicircnes

de conversions mises en œuvre pour chaque argument

2 Si nous avions deacuteclareacute fct sous la forme void fct (point amp) lrsquoappel fct(4) serait rejeteacute

En revanche avec la deacuteclaration void fct (const point amp) ce mecircme appel serait

accepteacute il conduirait agrave la creacuteation drsquoun point temporaire obtenu par conversion de 4 en

point et agrave la transmission de sa reacutefeacuterence agrave la fonction fct Lrsquoexeacutecution se preacutesenterait

exactement comme ci-dessus

32 Le constructeur dans une chaicircne de conversionsSupposons que nous disposions dune classe complexe

class complexe

double reel imag

public

complexe (double r = 0 double i = 0)

Son constructeur permet des conversions double -gt complexe Mais compte tenu des possibi-

liteacutes de conversion implicite int -gt double ce constructeur peut intervenir dans une chaicircne de

conversions

int -gt double -gt complexe

Ce sera le cas dans une affectation telle que (c eacutetant de type complexe)

c = 3

Cette possibiliteacute de chaicircne de conversions rejoint ici les regravegles concernant les conversions

habituelles agrave propos des fonctions (surdeacutefinies ou non) En effet on peut consideacuterer ici que

lentier 3 est converti en double compte tenu du prototype de complexe Cette double inter-

preacutetation dune mecircme possibiliteacute nest pas gecircnante dans la mesure ougrave elle conduit dans les

deux cas agrave la mecircme conclusion concernant la faisabiliteacute de la conversion

33 Choix entre constructeur ou opeacuterateur daffectationDans lexemple daffectation

a = 12

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

194

du paragraphe 31 il nexistait pas dopeacuterateur drsquoaffectation dun int agrave un point Si tel est le

cas on peut penser que le compilateur doit alors choisir entre

bull utiliser la conversion int -gt point offerte par le constructeur suivie drsquoune affectation point -

gt point

bull sup2utiliser lopeacuterateur daffectation int -gt point

En fait une regravegle permet de trancher

Cest donc la seconde solution qui sera choisie ici par le compilateur comme le montre le

programme suivant Nous avons surdeacutefini lopeacuterateur drsquoaffectation non seulement dans le cas

intndashgt point mais aussi dans le cas point -gt point afin de bien montrer que cette derniegravere ver-

sion nest pas employeacutee dans laffectation a = 12

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments

x = abs y = ord

cout ltlt ++ construction point ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

point amp operator = (const point amp p) surdeacutef affectation point -gt point

x = px y = py

cout ltlt == affectation point --gt point de ltlt ampp ltlt en ltlt this

return this

point amp operator = (const int n) surdeacutef affectation int -gt point

x = n y = 0

cout ltlt == affectation int --gt point de ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

return this

main()

point a(34)

a = 12

++ construction point 3 4 en 006AFDF0

== affectation int --gt point de 12 0 en 006AFDF0

Les conversions deacutefinies par lutilisateur ne sont mises en œuvre que si neacutecessaire

Les conversions deacutefinies par lrsquoutilisateur (cast ou constructeur) ne sont mises en œuvre que lorsque cela est neacutecessaire

3 - Le constructeur pour la conversion type de base -gt type classe195

34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur

Consideacuterons une classe point munie dun constructeur agrave un argument entier et dun opeacuterateur

daddition fourni sous la forme dune fonction amie (nous verrons un peu plus loin ce qui se

passerait dans le cas dune fonction membre)

class point int x y public point (int) friend point operator + (point point)

Dans ces conditions si a est de type point une expression telle que

a + 3

a une signification En effet dans ce cas le compilateur met en œuvre

bull une conversion de lentier 3 en point (par appel du constructeur)

bull laddition de la valeur obtenue avec celle de a (par appel de operator +)

Le reacutesultat sera du type point Le scheacutema suivant reacutecapitule la situation

point int | | | point |___ + ___| | point

On peut dire eacutegalement que notre expression a + 3 est eacutequivalente agrave

operator + (a point (3))

Le mecircme meacutecanisme sapplique agrave une expression telle que

5 + a

qui sera donc eacutequivalente agrave

operator + (5 a)

Toutefois dans ce dernier cas il nen serait pas alleacute de mecircme si notre opeacuterateur + avait eacuteteacute

deacutefini par une fonction membre En effet son premier opeacuterande aurait alors ducirc ecirctre de type

point aucune conversion implicite naurait pu ecirctre mise en place1

Voici un petit programme illustrant les possibiliteacutes que nous venons deacutevoquer

include ltiostreamgtusing namespace std class point int x y

1 Des appels tels que 5operator + (a) ou noperator + (a) (n eacutetant de type int) seront rejeteacutes

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

196

public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n friend point operator + (point point) point + point --gt point void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n point operator+ (point a point b) point r rx = ax + bx ry = ay + by return r

main() point a b(94) a = b + 5 aaffiche() a = 2 + b baffiche()

++ construction point 0 0++ construction point 9 4++ construction point 5 0++ construction point 0 0Coordonneacutees 14 4++ construction point 2 0++ construction point 0 0Coordonneacutees 9 4

Elargissement de la signification de lopeacuterateur +

Remarques

1 On peut envisager de transmettre par reacutefeacuterence les arguments de operator Dans ce cas il

est neacutecessaire de preacutevoir le qualificatif const pour autoriser la conversion de 5 en un point

temporaire dans lrsquoaffectation a = b + 5 ou de 2 en un point temporaire dans a = 2 + b

2 Lrsquoutilisation du constructeur dans une chaicircne de conversions peut rendre de grands ser-

vices dans une situation reacuteelle puisquelle permet de donner un sens agrave des expressions

mixtes Lexemple le plus caracteacuteristique est celui dune classe de nombres complexes

(supposeacutes constitueacutes ici de deux valeurs de type double) Il suffit en effet de deacutefinir la

somme de deux complexes et un constructeur agrave un argument de type double

3 - Le constructeur pour la conversion type de base -gt type classe197

class complexe double reel imag public complexe (double v) reel = v imag = 0 friend complexe operator + (complexe complexe)

Les expressions de la forme

ndash complexe + double

ndash double + complexe

auront alors une signification (et ici ce sera bien celle que lon souhaite)

Compte tenu des possibiliteacutes de conversions il en ira de mecircme de nimporte quelle

addition dun complexe et dun float dun long dun short ou dun char

Ici encore ces conversions ne seront plus possibles si les opeacuterandes sont transmis par

reacutefeacuterence Elles le redeviendront avec des reacutefeacuterences agrave des constantes

3 Si nous avions deacutefini

class complexe float reel imag public complexe (float v) friend complexe operator + (complexe complexe)

laddition dun complexe et dun double ne serait pas possible Elle le deviendrait en

remplaccedilant le constructeur par

complexe (double v)

(ce qui ne signifie pas pour autant que le reacutesultat de la conversion forceacutee de double en

float qui y figurera sera acceptable )

35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit

La norme ANSI de C++ preacutevoit quon puisse interdire lutilisation du constructeur dans des

conversions implicites (simples ou en chaicircne) en utilisant le mot cleacute explicit lors de sa deacutecla-

ration Par exemple avec

class point public explicit point (int) friend operator + (point point)

les instructions suivantes seraient rejeteacutees (a et b eacutetant de type point)

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

198

a = 12 illeacutegal car le constructeur possegravede le qualificatif explicita = b + 5 idem

En revanche la conversion pourrait toujours se faire par un appel explicite comme dans

a = point (3) OK conversion explicite par le constructeura = b + point (5) idem

4 Les conversions drsquoun type classe en un autre type classe

Les possibiliteacutes de conversions dun type de base en un type classe que nous venons drsquoeacutetudier

se geacuteneacuteralisent ainsi

bull Au sein dune classe A on peut deacutefinir un opeacuterateur de cast reacutealisant la conversion dans le

type A dun autre type de classe B

bull Un constructeur de la classe A recevant un argument de type B reacutealise une conversion de B

en A

41 Exemple simple dopeacuterateur de castLe programme suivant illustre la premiegravere situation lopeacuterateur complexe de la classe point

permet des conversions dun objet de type point en un objet de type complexe

include ltiostreamgtusing namespace std class complexe

class point int x y public point (int abs=0 int ord=0) x=abs y=ord operator complexe () conversion point --gt complexe

class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i friend pointoperator complexe () void affiche () cout ltlt reel ltlt + ltlt imag ltltin pointoperator complexe () complexe r rreel=x rimag=y cout ltlt cast ltltxltlt ltltyltlt en ltltrreelltlt + ltltrimagltltin return r

4 - Les conversions drsquoun type classe en un autre type classe199

main() point a(25) complexe c c = (complexe) a caffiche () conversion explicite point b (912) c = b caffiche () conversion implicite

cast 2 5 en 2 + 5i2 + 5icast 9 12 en 9 + 12i9 + 12i

Exemple dutilisation dun opeacuterateur de cast pour des conversions point -gt complexe

Remarque

La conversion point ndashgt complexe eacutequivalente ici agrave la conversion de deux entiers en reacuteel

est assez naturelle et de toute faccedilon non deacutegradante Mais bien entendu C++ vous laisse

seul juge de la qualiteacute des conversions que vous pouvez deacutefinir de cette maniegravere

42 Exemple de conversion par un constructeurLe programme suivant illustre la seconde situation le constructeur complexe (point) repreacute-

sente une autre faccedilon de reacutealiser des conversions dun objet de type point en un objet de type

complexe

include ltiostreamgtusing namespace std class point class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i complexe (point) void affiche () cout ltlt reel ltlt + ltlt imag ltlt in class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend complexecomplexe (point) complexecomplexe (point p) reel = px imag = py

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

200

main()

point a(35)

complexe c (a) caffiche ()

3 + 5i

Exemple dutilisation dun constructeur pour des conversions point ndashgt complexe

Remarques

1 La remarque faite preacuteceacutedemment agrave propos de la qualiteacute des conversions sapplique tout

aussi bien ici Par exemple nous aurions pu introduire dans la classe point un construc-

teur de la forme point (complexe)

2 En ce qui concerne les conversions dun type de base en une classe la seule possibiliteacute

qui nous eacutetait offerte consistait agrave preacutevoir un constructeur approprieacute au sein de la classe

En revanche pour les conversions A ndashgt B (ougrave A et B sont deux classes) nous avons le

choix entre placer dans B un constructeur B(A) ou placer dans A un opeacuterateur de cast

B()

3 Il nest pas possible de deacutefinir simultaneacutement la mecircme conversion A ndashgt B en preacutevoyant

agrave la fois un constructeur B(A) dans B et un cast B() dans A En effet cela conduirait le

compilateur agrave deacuteceler une ambiguiumlteacute degraves quune conversion de A en B serait neacutecessaire

Il faut signaler cependant quune telle anomalie peut rester cacheacutee tant que le besoin

dune telle conversion ne se fait pas sentir (en particulier les classes A et B seront com-

pileacutees sans problegraveme y compris si elles figurent dans le mecircme fichier source)

43 Pour donner une signification agrave un opeacuterateur deacutefini dans une autre classe

Consideacuterons une classe complexe pour laquelle lopeacuterateur + a eacuteteacute surdeacutefini par une fonction

amie1 ainsi quune classe point munie dun opeacuterateur de cast complexe() Supposons a de

type point x de type complexe et consideacuterons lexpression

x + a

Compte tenu des regravegles habituelles relatives aux fonctions surdeacutefinies (mise en œuvre dune

chaicircne unique de conversions ne contenant pas plus dune CDU) le compilateur est conduit

agrave eacutevaluer cette expression suivant le scheacutema

1 Nous verrons que ce point est important on nobtiendrait pas les mecircmes possibiliteacutes avec une fonction membre

4 - Les conversions drsquoun type classe en un autre type classe201

complexe point | | | complexe |___ + ___| | complexe

Celui-ci fait intervenir lopeacuterateur + surdeacutefini par la fonction indeacutependante operator+ On

peut dire que lrsquoexpression x + a est en fait eacutequivalente agrave

operator + (x a)

Le mecircme raisonnement sapplique agrave lexpression a + x Quant agrave lexpression

a + b

ougrave a et b sont de type point elle est eacutequivalente agrave

operator + (a b)

et eacutevalueacutee suivant le scheacutema

point point | | complexe complexe |____ + ____| | complexe

Voici un exemple complet de programme illustrant ces possibiliteacutes

include ltiostreamgtusing namespace std class complexe class point int x y public point (int abs=0 int ord=0) x=abs y=ord operator complexe () void affiche () cout ltlt point ltlt x ltlt ltlt y ltlt n class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i void affiche () cout ltlt reel ltlt + ltlt imag ltlt i n friend pointoperator complexe () friend complexe operator + (complexe complexe) pointoperator complexe () complexe r rreel = x rimag = y return r complexe operator + (complexe a complexe b) complexe r rreel = areel + breel rimag = aimag + bimag return r

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

202

main() point a(34) b(79) c complexe x(3528) y y = x + a yaffiche () marcherait encore si + eacutetait fct membre y = a + x yaffiche () ne marcherait pas si + eacutetait fonction membre y = a + b yaffiche () ne marcherait pas si + eacutetait fonction membre (voir remarque) NB c = a + b naurait pas de sens ici

65 + 68i 65 + 68i 10 + 13i

Elargissement de la signification de lopeacuterateur + de la classe complexe

Remarques

1 Sil est effectivement possible ici deacutecrire

y = a + b

il nest pas possible deacutecrire

c = a + b

car il nexiste pas de conversion de complexe (type de lexpression a + b) en point

Pour que cela soit possible il suffirait par exemple dintroduire dans la classe point un

constructeur de la forme point (complexe) Bien entendu cela ne preacutejuge nullement de

la signification dune telle opeacuteration et en particulier de son aspect deacutegradant

2 Si lopeacuterateur + de la classe complexe avait eacuteteacute deacutefini par une fonction membre de

prototype

complexe complexeoperator + (complexe)

lexpression a + x naurait pas eu de sens pas plus que a + b En effet dans le premier

cas lappel de operator + naurait pu ecirctre que

aoperator + (x)

Cela naurait pas eacuteteacute permis En revanche lexpression x + a aurait pu correctement ecirctre

eacutevalueacutee comme

xoperator + (a)

3 Il nest pas toujours aussi avantageux que dans cet exemple de deacutefinir un opeacuterateur sous

la forme dune fonction amie En particulier si un opeacuterateur modifie son premier opeacute-

rande (supposeacute ecirctre un objet) il est preacutefeacuterable den faire une fonction membre Dans le

cas contraire en effet on risque de voir cet opeacuterateur agir non pas sur lobjet concerneacute

mais sur un objet (ou une variable) temporaire dun autre type creacuteeacute par une conversion

5 - Quelques conseils203

implicite1 Crsquoest dailleurs pour cette raison que C++ impose que les opeacuterateurs = [] ()

et -gt soient toujours surdeacutefinis par des fonctions membres

4 On peut envisager de transmettre les arguments de operator+ par reacutefeacuterence Dans ce

cas si lrsquoon nrsquoa pas preacutevu le qualificatif const dans leur deacuteclaration dans lrsquoen-tecircte les

trois expressions x+a a+x et a+b conduisent agrave une erreur de compilation

5 Quelques conseilsLes possibiliteacutes de conversions implicites ne sont certes pas infinies puisquelles sont limi-

teacutees agrave une chaicircne dau maximum trois conversions (standard CDU standard) et que la

CDU nest mise en œuvre que si elle est utile

Elles nen restent pas moins tregraves (trop ) riches Une telle richesse peut laisser craindre que

certaines conversions soient mises en place sans que le concepteur des classes concerneacutees ne

lait souhaiteacute

En fait il faut bien voir que

bull lopeacuterateur de cast doit ecirctre introduit deacutelibeacutereacutement par le concepteur de la classe

bull le concepteur dune classe peut interdire lusage implicite du constructeur dans une conver-

sion en faisant appel au mot cleacute explicit

Il est donc possible de se proteacuteger totalement contre lusage des conversions implicites relati-

ves aux classes il suffira de qualifier tous les constructeurs avec explicit et de ne pas intro-

duire dopeacuterateur de cast

Dune maniegravere geacuteneacuterale on aura inteacuterecirct agrave reacuteserver ces possibiliteacutes de conversions implicites agrave

des classes ayant une forte connotation matheacutematique dans lesquelles on aura probable-

ment surdeacutefini un certain nombre dopeacuterateurs (+ - etc)

Lexemple le plus classique est certainement celui de la classe complexe (que nous avons ren-

contreacutee dans ce chapitre) Dans ce cas il paraicirct naturel de disposer de conversions de com-

plexe en float de float en complexe de int en complexe (par le biais de float) etc

De mecircme il paraicirct naturel de pouvoir reacutealiser aussi bien la somme dun complexe et dun float

que celle de deux complexes et donc de profiter des possibiliteacutes de conversions implicites

pour ne deacutefinir quun seul opeacuterateur daddition (celle de deux complexes)

1 Aucune conversion implicite ne peut avoir lieu sur lobjet appelant une fonction membre

11

Les patrons de fonctions

Nous avons deacutejagrave vu que la surdeacutefinition de fonctions permettait de donner un nom unique agrave

plusieurs fonctions reacutealisant un travail diffeacuterent La notion de patron de fonction (on parle

aussi de fonction geacuteneacuterique ou de modegravele de fonction) introduite par la version 3 est agrave la

fois plus puissante et plus restrictive plus puissante car il suffit deacutecrire une seule fois la

deacutefinition dune fonction pour que le compilateur puisse automatiquement ladapter agrave

nimporte quel type plus restrictive puisque toutes les fonctions ainsi fabriqueacutees par le com-

pilateur doivent correspondre agrave la mecircme deacutefinition donc au mecircme algorithme

Nous commencerons par vous preacutesenter cette nouvelle notion agrave partir drsquoun exemple simple

ne faisant intervenir quun seul paramegravetre de type Nous verrons ensuite quelle se geacuteneacutera-

lise agrave un nombre quelconque de paramegravetres et quon peut eacutegalement faire intervenir des

paramegravetres expressions Puis nous montrerons comment un patron de fonctions peut agrave son

tour ecirctre surdeacutefini Enfin nous verrons que toutes ces possibiliteacutes peuvent encore ecirctre affi-

neacutees en speacutecialisant une ou plusieurs des fonctions dun patron

NB On rencontre souvent le terme anglais template au lieu de celui de patron On parle alors

de fonctions template ou de classes template mais dans ce cas il est difficile de distin-

guer comme nous serons ameneacutes agrave le faire un patron de fonctions drsquoune fonction patron ou

un patron de classes drsquoune classe patron

Les patrons de fonctionsCHAPITRE 11

206

1 Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions

11 Creacuteation dun patron de fonctionsSupposons que nous ayons besoin deacutecrire une fonction fournissant le minimum de deux valeurs

de mecircme type reccedilues en arguments Nous pourrions eacutecrire une deacutefinition pour le type int

int min (int a int b) if (a lt b) return a ou return a lt b a b else return b

Bien entendu il nous faudrait probablement eacutecrire une autre deacutefinition pour le type float

cest-agrave-dire (en supposant que nous lui donnions le mecircme nom min ce que nous avons tout

inteacuterecirct agrave faire)

float min (float a float b) if (a lt b) return a ou return a lt b a b else return b

Nous aurions ainsi agrave eacutecrire de nombreuses deacutefinitions tregraves proches les unes des autres En

effet seul le type concerneacute serait ameneacute agrave ecirctre modifieacute

En fait nous pouvons simplifier consideacuterablement les choses en deacutefinissant un seul patron

de fonctions de la maniegravere suivante

creacuteation dun patron de fonctionstemplate ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

Creacuteation dun patron de fonctions

Comme vous le constatez seul len-tecircte de notre fonction a changeacute (il nen ira pas toujours

ainsi)

template ltclass Tgt T min (T a T b)

La mention template ltclass Tgt preacutecise que lon a affaire agrave un patron (template) dans lequel

apparaicirct un paramegravetre1 de type nommeacute T Notez que C++ a deacutecideacute demployer le mot cleacute

1 Ou argument ici nous avons convenu demployer le terme paramegravetre pour les patrons et le terme argument pour

les fonctions mais il ne sagit aucunement dune convention universelle

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions207

class pour preacuteciser que T est un paramegravetre de type (on aurait preacutefeacutereacute le mot cleacute type ) Autre-

ment dit dans la deacutefinition de notre fonction T repreacutesente un type quelconque

Le reste de len-tecircte

T min (T a T b)

preacutecise que min est une fonction recevant deux arguments de type T et fournissant un reacutesultat

du mecircme type

Remarque

Dans la deacutefinition drsquoun patron on utilise le mot cleacute class pour indiquer en fait un type

quelconque classe ou non La norme a introduit le mot cleacute typename qui peut se subtituer

agrave class dans la deacutefinition

template lttypename Tgt T min (T a T b) idem template ltclass Tgt

Cependant son arriveacutee tardive fait que la plupart des programmes continuent drsquoutiliser

le mot cleacute class dans ce cas

12 Premiegraveres utilisations du patron de fonctionsPour utiliser le patron min que nous venons de creacuteer il suffit dutiliser la fonction min dans

des conditions approprieacutees (cest-agrave-dire ici deux arguments de mecircme type) Ainsi si dans un

programme dans lequel n et p sont de type int nous faisons intervenir lexpression min (n p)

le compilateur fabriquera (on dit aussi instanciera) automatiquement la fonction min (dite

fonction patron1) correspondant agrave des arguments de type int Si nous appelons min avec

deux arguments de type float le compilateur fabriquera automatiquement une autre fonc-

tion patron min correspondant agrave des arguments de type float et ainsi de suite

Comme on peut sy attendre il est neacutecessaire que le compilateur dispose de la deacutefinition du

patron en question autrement dit que les instructions preacuteceacutedentes apparaissent avant une

quelconque utilisation de min Voici un exemple complet illustrant cela

include ltiostreamgtusing namespace std creacuteation dun patron de fonctionstemplate ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

1 Attention au vocabulaire patron de fonction pour la fonction geacuteneacuterique fonction patron pour une instance

donneacutee

Les patrons de fonctionsCHAPITRE 11

208

exemple dutilisation du patron de fonctions minmain() int n=4 p=12 float x=25 y=325 cout ltlt min (n p) = ltlt min (n p) ltlt n int min(int int) cout ltlt min (x y) = ltlt min (x y) ltlt n float min (float float)

min (n p) = 4min (x y) = 25

Deacutefinition et utilisation dun patron de fonctions

13 Autres utilisations du patron de fonctionsLe patron min peut ecirctre utiliseacute pour des arguments de nimporte quel type quil sagisse dun

type preacutedeacutefini (short char double int char int etc) ou dun type deacutefini par lutilisa-

teur (notamment structure ou classe)

Par exemple si n et p sont de type int un appel tel que min (ampn ampp) conduit le compilateur

agrave instancier une fonction int min (int int )

Examinons plus en deacutetail deux situations preacutecises

bull arguments de type char

bull arguments de type classe

131 Application au type char Voici un premier exemple dans lequel nous exploitons le patron min pour fabriquer une fonc-

tion portant sur des chaicircnes de caractegraveres

include ltiostreamgtusing namespace std template ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b main() char adr1 = monsieur adr2 = bonjour cout ltlt min (adr1 adr2) = ltlt min (adr1 adr2)

min (adr1 adr2) = monsieur

Application du patron min au type char

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions209

Le reacutesultat peut surprendre si vous vous attendiez agrave ce que min fournisse la chaicircne bon-

jour En fait agrave la rencontre de lexpression min (adr1 adr2) le compilateur a geacuteneacutereacute la fonc-

tion suivante

char min (char a char b)

if (a lt b) return a

else return b

La comparaison altb porte donc sur les valeurs des pointeurs reccedilus en argument (ici a eacutetait

infeacuterieur agrave b mais il peut en aller autrement dans dautres impleacutementations) En revanche

laffichage obtenu par lopeacuterateur ltlt porte non plus sur ces adresses mais sur les chaicircnes

situeacutees agrave ces adresses

132 Application agrave un type classe

Pour pouvoir appliquer le patron min agrave une classe il est bien sucircr neacutecessaire que lopeacuterateur lt

puisse sappliquer agrave deux opeacuterandes de ce type classe Voici un exemple dans lequel nous

appliquons min agrave deux objets de type vect classe munie drsquoun opeacuterateur lt fournissant un

reacutesultat baseacute sur le module des vecteurs

include ltiostreamgt

using namespace std

le patron de fonctions mintemplate ltclass Tgt T min (T a T b)

if (a lt 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 ltlt x ltlt ltlt y friend int operator lt (vect vect)

int operator lt (vect a vect b) return axax + ayay lt bxbx + byby

un exemple dutilisation de minmain()

vect u (3 2) v (4 1) w w = min (u v)

cout ltlt min (u v) = waffiche()

Les patrons de fonctionsCHAPITRE 11

210

min (u v) = 3 2

Utilisation du patron min pour la classe vect

Naturellement si nous cherchons agrave appliquer notre patron min agrave une classe pour laquelle

lopeacuterateur lt nest pas deacutefini le compilateur le signalera exactement de la mecircme maniegravere que

si nous avions eacutecrit nous-mecircme la fonction min pour ce type

Remarque

Un patron de fonctions pourra sappliquer agrave des classes patrons cest-agrave-dire agrave un type de

classe instancieacute par un patron de classe Nous en verrons des exemples dans le prochain

chapitre

14 Contraintes drsquoutilisation drsquoun patronLes instructions de deacutefinition dun patron ressemblent agrave des instructions exeacutecutables de deacutefi-

nition de fonction Neacuteanmoins le meacutecanisme mecircme des patrons fait que ces instructions sont

utiliseacutees par le compilateur pour fabriquer (instancier) chaque fois quil est neacutecessaire les ins-

tructions correspondant agrave la fonction requise en ce sens ce sont donc des deacuteclarations leur

preacutesence est toujours neacutecessaire et il nest pas possible de creacuteer un module objet correspon-

dant agrave un patron de fonctions

Tout se passe en fait comme si avec la notion de patron de fonctions apparaissaient deux

niveaux de deacuteclarations On retrouvera le mecircme pheacutenomegravene pour les patrons de classes Par

la suite nous continuerons agrave parler de deacutefinition dun patron

En pratique on placera les deacutefinitions de patron dans un fichier approprieacute dextension h

Remarque

Les consideacuterations preacuteceacutedentes doivent en fait ecirctre pondeacutereacutees par le fait que la norme a

introduit le mot cleacute export Appliqueacute agrave la deacutefinition drsquoun patron il preacutecise que celle-ci

sera accessible depuis un autre fichier source Par exemple en eacutecrivant ainsi notre patron

de fonctions min du paragraphe 11

export template ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

on peut alors utiliser ce patron depuis un autre fichier source en se contentant de men-

tionner sa deacuteclaration (cette fois il srsquoagit bien drsquoune veacuteritable deacuteclaration et non plus

drsquoune deacutefinition)

2 - Les paramegravetres de type drsquoun patron de fonctions211

template ltclass Tgt T min (T a T b) deacuteclaration seule de min

min (x y)

En pratique on aura alors inteacuterecirct agrave preacutevoir deux fichiers en-tecirctes distincts un pour la

deacuteclaration un pour la deacutefinition On pourra agrave volonteacute inclure le premier dans la deacutefi-

nition du patron ou dans son utilisation

Ce meacutecanisme met en jeu une sorte de preacutecompilation des deacutefinitions de patrons

2 Les paramegravetres de type drsquoun patron de fonctions

Ce paragraphe fait le point sur la maniegravere dont les paramegravetres de type peuvent intervenir dans

un patron de fonctions sur lalgorithme qui permet au compilateur dinstancier la fonction

voulue et sur les problegravemes particuliers quil peut poser

Notez quun patron de fonctions peut eacutegalement comporter ce que lon nomme des paramegrave-

tres expressions qui correspondent en fait agrave la notion usuelle dargument dune fonction Ils

seront eacutetudieacutes au paragraphe suivant

21 Utilisation des paramegravetres de type dans la deacutefinition dun patron

Un patron de fonctions peut donc comporter un ou plusieurs paramegravetres de type chacun

devant ecirctre preacuteceacutedeacute du mot cleacute class par exemple

template ltclass T class Ugt fct (T a T b U c)

Ces paramegravetres peuvent intervenir agrave nimporte quel endroit de la deacutefinition dun patron1

bull dans len-tecircte (ceacutetait le cas des exemples preacuteceacutedents)

bull dans des deacuteclarations2 de variables locales (de lun des types des paramegravetres)

bull dans les instructions exeacutecutables3 (par exemple new sizeof ())

1 De la mecircme maniegravere quun nom de type peut intervenir dans la deacutefinition dune fonction

2 Il sagit alors de deacuteclarations au sein de la deacutefinition du patron cest-agrave-dire finalement de deacuteclarations au sein de

deacuteclarations

3 Nous parlons dinstructions exeacutecutables bien quil sagisse toujours de deacuteclarations (puisque la deacutefinition dun

patron est une deacuteclaration) En toute rigueur ces instructions donneront naissance agrave des instructions exeacutecutables agrave

chaque instanciation dune nouvelle fonction

Les patrons de fonctionsCHAPITRE 11

212

En voici un exemple

template ltclass T class Ugt 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 eacuteleacutements de type T

n = sizeof (T)

Dans tous les cas il est neacutecessaire que chaque paramegravetre de type apparaisse au moins une

fois dans len-tecircte du patron comme nous le verrons cette condition est parfaitement logi-

que puisque cest preacuteciseacutement gracircce agrave la nature de ces arguments que le compilateur est en

mesure dinstancier correctement la fonction neacutecessaire

22 Identification des paramegravetres de type dune fonction patronLes exemples preacuteceacutedents eacutetaient suffisamment simples pour que lon devine quelle eacutetait la

fonction instancieacutee pour un appel donneacute Mais reprenons le patron min

template ltclass Tgt T min (T a T b)

if (a lt b) return a else return b

avec ces deacuteclarations

int n char c

Que va faire le compilateur en preacutesence dun appel tel que min (nc) ou min(cn) En fait la

regravegle preacutevue par C++ dans ce cas est quil doit y avoir correspondance absolue des types

Cela signifie que nous ne pouvons utiliser le patron min que pour des appels dans lesquels les

deux arguments ont le mecircme type Manifestement ce nest pas le cas dans nos deux appels

qui aboutiront agrave une erreur de compilation On notera que dans cette correspondance abso-

lue les eacuteventuels qualifieurs const ou volatile interviennent

Voici quelques exemples dappels de min qui preacutecisent quelle sera la fonction instancieacutee lors-

que lappel est correct

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) erreurmin (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

2 - Les paramegravetres de type drsquoun patron de fonctions213

Il est cependant possible drsquointervenir sur ce meacutecanisme drsquoidentification de type En effet

C++ vous autorise agrave speacutecifier un ou plusieurs paramegravetres de type au moment de lrsquoappel du

patron Voici quelques exemples utilisant les deacuteclarations preacuteceacutedentes

minltintgt (c n) force lutilisation de minltintgt et donc la conversion

de c en int le reacutesultat sera de type int

minltchargt (q n) force lutilisation de minltchargt et donc la conversion de q et de n en char le reacutesultat sera de type char

Voici un autre exemple faisant intervenir plusieurs paramegravetres de type

template ltclass T class Ugt T fct (T x U y T z) return x + y + z

main () int n = 1 p = 2 q = 3

float x = 25 y = 50

cout ltlt fct (n x p) ltlt n affiche la valeur (int) 5 cout ltlt fct (x n y) ltlt n affiche la valeur (float) 85

cout ltlt fct (n p q) ltlt n affiche la valeur (int) 6

cout ltlt fct (n p x) ltlt n erreur pas de correspondance

Ici encore on peut forcer certains des paramegravetres de type comme dans ces exemples

fctltintfloatgt (n p x) force lutilisation de fctltintfloatgt et donc la conversion de p en float et de x en int

fctltfloatgt (n p x ) force lutilisation de float pour T U est deacutetermineacute par les regravegles habituelles

crsquoest-agrave-dire int (type de p)

n sera converti en float

Remarque

Le mode de transmission drsquoun paramegravetre (par valeur ou par reacutefeacuterence) ne joue aucun rocircle

dans lrsquoidentification des paramegravetres de type Cela va de soi puisque

bull drsquoune part ce mode ne peut pas ecirctre deacuteduit de la forme de lrsquoappel

bull drsquoautre part la notion de conversion nrsquoa aucune signfication ici elle ne peut donc pas in-

tervenir pour trancher entre une reacutefeacuterence et une reacutefeacuterence agrave une constante

23 Nouvelle syntaxe dinitialisation des variables des types standard

Dans un patron de fonctions un paramegravetre de type est susceptible de correspondre tantocirct agrave un

type standard tantocirct agrave un type classe Un problegraveme apparaicirct donc si lon doit deacuteclarer au sein

du patron un objet de ce type en transmettant un ou plusieurs arguments agrave son constructeur

Les patrons de fonctionsCHAPITRE 11

214

Consideacuterons cet exemple

template ltclass Tgt fct (T a)

T x (3) x est un objet local de type T quon construit

en transmettant la valeur 3 agrave son constructeur

Tant que lon utilise une fonction fct pour un type classe tout va bien En revanche si lon

cherche agrave lrsquoutiliser pour un type standard par exemple int le compilateur geacuteneacutere la fonction

suivante

fct (int a)

int x (3)

Pour que linstruction int x(3) ne pose pas de problegraveme C++ a preacutevu quelle soit simplement

interpreacuteteacutee comme une initialisation de x avec la valeur 3 cest-agrave-dire comme

int x = 3

En theacuteorie cette possibiliteacute est utilisable dans nimporte quelle instruction C++ de sorte que

vous pouvez tregraves bien eacutecrire

double x(35) au lieu de double x = 35

char c(e) au lieu de char c = e

En pratique cela sera rarement utiliseacute de cette faccedilon

24 Limitations des patrons de fonctionsLorsque lon deacutefinit un patron de classe agrave un paramegravetre de type peut theacuteoriquement corres-

pondre nimporte quel type effectif (standard ou classe) Il nexiste a priori aucun meacutecanisme

intrinsegraveque permettant dinterdire linstanciation pour certains types

Ainsi si un patron a un en-tecircte de la forme

template ltclass Tgt void fct (T)

on pourra appeler fct avec un argument de nimporte quel type int float int int t t ou

mecircme t (t deacutesignant un type classe quelconque)

Cependant un certain nombre deacuteleacutements peuvent intervenir indirectement pour faire

eacutechouer linstanciation

Tout dabord on peut imposer quun paramegravetre de type corresponde agrave un pointeur Ainsi avec

un patron den-tecircte

template ltclass Tgt void fct (T )

on ne pourra appeler fct quavec un pointeur sur un type quelconque int int t ou t

Dans les autres cas on aboutira agrave une erreur de compilation

Par ailleurs dans la deacutefinition dun patron peuvent apparaicirctre des instructions qui saveacutereront

incorrectes lors de la tentative dinstanciation pour certains types

3 - Les paramegravetres expressions drsquoun patron de fonctions215

Par exemple le patron min

template ltclass Tgt T min (T a T b) if (a lt b) return a else return b

ne pourra pas sappliquer si T correspond agrave un type classe dans lequel lopeacuterateur lt na pas eacuteteacute

surdeacutefini

De mecircme un patron comme

template ltclass Tgt void fct (T) T x (2 5) objet local de type T initialiseacute par un constructeur agrave 2 arguments

ne pourra pas sappliquer agrave un type classe pour lequel nexiste pas un constructeur agrave deux

arguments

En deacutefinitive bien quil nexiste pas de meacutecanisme formel de limitation les patrons de fonc-

tions peuvent neacuteanmoins comporter dans leur deacutefinition mecircme un certain nombre deacuteleacutements

qui en limiteront la porteacutee

3 Les paramegravetres expressions drsquoun patron de fonctions

Comme nous lavons deacutejagrave eacutevoqueacute un patron de fonctions peut comporter des paramegravetres

expressions1 crsquoest-agrave-dire des paramegravetres (muets) ordinaires analogues agrave ceux quon

trouve dans la deacutefinition dune fonction Consideacuterons cet exemple dans lequel nous deacutefinis-

sons un patron nommeacute compte permettant de fabriquer des fonctions comptabilisant le nom-

bre deacuteleacutements nuls dun tableau de type et de taille quelconques

include ltiostreamgtusing namespace std template ltclass Tgt int compte (T tab int n) int i nz=0 for (i=0 iltn i++) if (tab[i]) nz++ return nz

main () int t [5] = 5 2 0 2 0 char c[6] = 0 12 0 0 0 5 cout ltlt compte (t) = ltlt compte (t 5) ltlt n cout ltlt compte (c) = ltlt compte (c 6) ltlt n

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

Les patrons de fonctionsCHAPITRE 11

216

compte (t) = 2

compte (c) = 4

Exemple de patron de fonctions comportant un paramegravetre expression (n)

On peut dire que le patron compte deacutefinit une famille de fonctions compte dans laquelle le

type du premier argument est variable (et donc deacutefini par lappel) tandis que le second est de

type imposeacute (ici int) Comme on peut sy attendre dans un appel de compte seul le type du

premier argument intervient dans le code de la fonction instancieacutee

Dune maniegravere geacuteneacuterale un patron de fonctions peut disposer dun ou de plusieurs paramegravetres

expressions Lors de lappel leur type na plus besoin de correspondre exactement agrave celui

attendu il suffit quil soit acceptable par affectation comme dans nimporte quel appel dune

fonction ordinaire

4 Surdeacutefinition de patronsDe mecircme quil est possible de surdeacutefinir une fonction classique il est possible de surdeacutefinir

un patron de fonctions cest-agrave-dire de deacutefinir plusieurs patrons posseacutedant des arguments dif-

feacuterents On notera que cette situation conduit en fait agrave deacutefinir plusieurs familles de fonc-

tions (il y a bien plusieurs deacutefinitions de familles et non plus simplement plusieurs

deacutefinitions de fonctions) Elle ne doit pas ecirctre confondue avec la speacutecialisation dun patron de

fonctions qui consiste agrave surdeacutefinir une ou plusieurs des fonctions de la famille et que nous

eacutetudierons au paragraphe suivant

41 Exemples ne comportant que des paramegravetres de typeConsideacuterons cet exemple dans lequel nous avons surdeacutefini deux patrons de fonctions min de

faccedilon agrave disposer

bull dune premiegravere famille de fonctions agrave deux arguments de mecircme type quelconque (comme

dans les exemples preacuteceacutedents)

bull dune seconde famille de fonctions agrave trois arguments de mecircme type quelconque

include ltiostreamgt

using namespace std

patron numero I

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

4 - Surdeacutefinition de patrons217

patron numero IItemplate ltclass Tgt T min (T a T b T c) return min (min (a b) c) main() int n=12 p=15 q=2 float x=35 y=425 z=025 cout ltlt min (n p) ltlt n patron I int min (int int) cout ltlt min (n p q) ltlt n patron II int min (int int int) cout ltlt min (x y z) ltlt n patron II float min (float float float)

122025

Exemple de surdeacutefinition de patron de fonctions (1)

Dune maniegravere geacuteneacuterale on peut surdeacutefinir des patrons posseacutedant un nombre diffeacuterent de

paramegravetres de type (dans notre exemple il ny en avait quun dans chaque patron min) les

en-tecirctes des fonctions correspondantes peuvent donc ecirctre aussi varieacutes quon le deacutesire Mais il

est souhaitable quil ny ait aucun recoupement entre les diffeacuterentes familles de fonctions cor-

respondant agrave chaque patron Si tel nest pas le cas une ambiguiumlteacute risque dapparaicirctre avec cer-

tains appels

Voici un autre exemple dans lequel nous avons deacutefini plusieurs patrons de fonctions min agrave

deux arguments afin de traiter convenablement les trois situations suivantes

bull deux valeurs de mecircme type (comme dans les paragraphes preacuteceacutedents)

bull un pointeur sur une valeur dun type donneacute et une valeur de ce mecircme type

bull une valeur dun type donneacute et un pointeur sur une valeur de ce mecircme type

include ltiostreamgtusing namespace std

patron numeacutero Itemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

patron numeacutero IItemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

Les patrons de fonctionsCHAPITRE 11

218

patron numeacutero III

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

main()

int n=12 p=15

float x=25 y=52

cout ltlt min (n p) ltlt n patron numeacutero I int min (int int)

cout ltlt min (ampn p) ltlt n patron numeacutero II int min (int int)

cout ltlt min (x ampy) ltltn patron numeacutero III float min (float float )

cout ltlt min (ampn ampp) ltlt n patron numeacutero I int min (int int )

12

12

25

006AFDF0

Exemple de surdeacutefinition de patron de fonctions (2)

Les trois premiers appels ne posent pas de problegraveme En revanche un appel tel que min (ampn

ampp) conduit agrave instancier agrave laide du patron numeacutero I la fonction

int min (int int )

La valeur fournie alors par lappel est la plus petite des deux valeurs (de type int ) ampn et ampp

Il est probable que ce ne soit pas le reacutesultat attendu par lutilisateur (nous avons deacutejagrave rencon-

treacute ce genre de problegraveme dans le paragraphe 1 en appliquant min agrave des chaicircnes1)

Pour linstant notez quil ne faut pas espeacuterer ameacuteliorer la situation en deacutefinissant un patron

suppleacutementaire de la forme

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

En effet les quatre familles de fonctions ne seraient plus totalement indeacutependantes Plus preacute-

ciseacutement si les trois premiers appels fonctionnent toujours convenablement lappel min (ampn

ampp) conduit agrave une ambiguiumlteacute puisque deux patrons conviennent maintenant (celui que nous

venons dintroduire et le premier)

1 Mais ce problegraveme pourra se reacutegler convenablement avec la speacutecialisation de patron ce qui nest pas le cas du

problegraveme que nous exposons ici

4 - Surdeacutefinition de patrons219

Remarque

Nous avons deacutejagrave vu que le mode de transmission drsquoun paramegravetre de type (par valeur ou

par expression) ne jouait aucun rocircle dans lrsquoidentification des paramegravetres de type drsquoun

patron Il en va de mecircme pour le choix du bon patron en cas de surdeacutefinition La raison en

est la mecircme ce mode de transmission nrsquoest pas deacutefini par lrsquoappel de la fonction mais uni-

quement suivant la fonction choisie pour satisfaire agrave lrsquoappel Comme dans le cas des

patrons la correspondance de type doit ecirctre exacte il nrsquoest mecircme plus question de trou-

ver deux patrons lrsquoun correspondant agrave une transmission par valeur lrsquoautre agrave une trans-

mission par reacutefeacuterence1

template ltclass Tgt f(T a) template ltclass Tgt f(T amp a) main() int n f(n) ambiguiumlteacute f(T) avec T=int ou f(Tamp) avec T=int

Cela restait possible dans le cas des fonctions surdeacutefinies dans la mesure ougrave la reacutefeacute-

rence ne pouvait ecirctre employeacutee qursquoavec une correspondance exacte la transmission par

valeur autorisant des conversions (mais lrsquoambiguiumlteacute existait quand mecircme en cas de cor-

respondance exacte)

42 Exemples comportant des paramegravetres expressionsLa preacutesence de paramegravetres expressions donne agrave la surdeacutefinition de patron un caractegravere plus

geacuteneacuteral Dans lexemple suivant nous avons deacutefini deux familles de fonctions min

bull lune pour deacuteterminer le minimum de deux valeurs de mecircme type quelconque

bull lautre pour deacuteterminer le minimum des valeurs dun tableau de type quelconque et de taille

quelconque (fournie en argument sous la forme dun entier)include ltiostreamgt

using namespace std patron Itemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b patron IItemplate ltclass Tgt T min (T t int n) int i T min = t[0] for (i=1 iltn i++) if (t[i] lt min) min=t[i] return min

1 Nous reviendrons au paragraphe 5 sur la distinction entre f(Tamp) et f(const Tamp)

Les patrons de fonctionsCHAPITRE 11

220

main() long n=2 p=12

float t[6] = 25 32 15 38 11 28 cout ltlt min (n p) ltlt n patron I long min (long long)

cout ltlt min (t 6) ltlt n patron II float min (float int)

211

Exemple de surdeacutefinition de patrons comportant un paramegravetre expression

Notez que si plusieurs patrons sont susceptibles drsquoecirctre employeacutes et quils ne se distinguent

que par le type de leurs paramegravetres expressions ce sont alors les regravegles de choix dune fonc-

tion surdeacutefinie ordinaire qui sappliquent

5 Speacutecialisation de fonctions de patron

51 GeacuteneacuteraliteacutesUn patron de fonctions deacutefinit une famille de fonctions agrave partir dune seule deacutefinition Autre-

ment dit toutes les fonctions de la famille reacutealisent le mecircme algorithme Dans certains cas

cela peut saveacuterer peacutenalisant Nous lavons dailleurs deacutejagrave remarqueacute dans le cas du patron min

du paragraphe 1 le comportement obtenu lorsquon lappliquait au type char ne nous satis-

faisait pas

La notion de speacutecialisation offre une solution agrave ce problegraveme En effet C++ vous autorise agrave

fournir outre la deacutefinition dun patron la deacutefinition dune ou de plusieurs fonctions pour cer-

tains types darguments Voici par exemple comment ameacuteliorer notre patron min du paragra-

phe 1 en fournissant une version speacutecialiseacutee pour les chaicircnes

include ltiostreamgt

using namespace std include ltcstringgt pour strcmp (ancien stringh)

patron mintemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

fonction min pour les chaineschar min (char cha char chb)

if (strcmp (cha chb) lt 0) return cha else return chb

5 - Speacutecialisation de fonctions de patron221

main() int n=12 p=15 char adr1 = monsieur adr2 = bonjour cout ltlt min (n p) ltlt n patron int min (int int) cout ltlt min (adr1 adr2) fonction char min (char char )

12bonjour

Exemple de speacutecialisation dune fonction dun patron

52 Les speacutecialisations partiellesIl est theacuteoriquement possible deffectuer ce que lon nomme des speacutecialisations partielles1

crsquoest-agrave-dire de deacutefinir des familles de fonctions certaines eacutetant plus geacuteneacuterales que dautres

comme dans

template ltclass T class Ugt void fct (T a U b) template ltclass Tgt void fct (T a T b)

Manifestement la seconde deacutefinition est plus speacutecialiseacutee que la premiegravere et devrait ecirctre utili-

seacutee dans des appels de fct dans lesquels les deux arguments sont de mecircme type

Ces possibiliteacutes de speacutecialisation partielle srsquoavegraverent tregraves utiles dans les situations suivantes

bull traitement particulier pour un pointeur en speacutecialisant partiellement T en T

template ltclass Tgt void f(T t) patron I template ltclass Tgt void f(T t) patron II int n int adc f(n) f(int) en utilisant patron I avec T = int f(adi) f(int ) en utilisant patron II avec T = int car il est plus speacutecialiseacute que patron I (avec T = int )

bull distinction entre pointeur ou reacutefeacuterence sur une variable de pointeur ou reacutefeacuterence sur une

constante

template ltclass Tgt void f(T amp t) patron I template ltclass Tgt void f(const T amp t) patron II int n const int cn=12 f(n) f(int amp) en utilisant patron I avec T = int f(cn) f(const int amp) en utilisant patron II avec T = int car il est plus speacutecialiseacute que patron I (avec T = const int)

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

Les patrons de fonctionsCHAPITRE 11

222

Drsquoune maniegravere geacuteneacuterale la norme deacutefinit une relation drsquoordre partiel permettant de dire

qursquoun patron est plus speacutecialiseacute qursquoun autre Comme on peut srsquoy attendre il existe des situa-

tions ambigueumls dans lesquelles aucun patron nrsquoest plus speacutecialiseacute qursquoun autre

6 Algorithme drsquoinstanciation drsquoune fonction patron

Nous avons donc vu qursquoon peut deacutefinir un ou plusieurs patrons de mecircme nom (surdeacutefinition)

chacun posseacutedant ses propres paramegravetres de type et eacuteventuellement des paramegravetres expres-

sions De plus il est possible de fournir des fonctions ordinaires portant le mecircme nom quun

patron (speacutecialisation dune fonction de patron)

Lorsque lrsquoon combine ces diffeacuterentes possibiliteacutes le choix de la fonction agrave instancier peut

srsquoaveacuterer moins eacutevident que dans nos preacuteceacutedents exemples Nous allons donc preacuteciser ici

lrsquoalgorithme utiliseacute par le compilateur dans linstanciation de la fonction correspondant agrave un

appel donneacute

Dans un premier temps on examine toutes les fonctions ordinaires ayant le nom voulu et on

sinteacuteresse aux correspondances exactes Si une seule convient le problegraveme est reacutesolu Sil en

existe plusieurs il y a ambiguiumlteacute une erreur de compilation est deacutetecteacutee et la recherche est

interrompue

Si aucune fonction ordinaire ne reacutealise de correspondance exacte on examine alors tous les

patrons ayant le nom voulu en ne consideacuterant que les paramegravetres de type Si une seule

correspondance exacte est trouveacutee on cherche agrave instancier la fonction correspondante1 agrave

condition que cela soit possible Cela signifie que si cette derniegravere dispose de paramegravetres

expressions il doit exister des conversions valides des arguments correspondants dans le type

voulu Si tel est le cas le problegraveme est reacutesolu

Si plusieurs patrons assurent une correspondance exacte de type on examine tout dabord si

lon est en preacutesence dune speacutecialisation partielle auquel cas on choisit le patron le plus speacute-

cialiseacute2 Si cela ne suffit pas agrave lever lrsquoambiguiumlteacute on examine les eacuteventuels paramegravetres expres-

sions qursquoon traite de la mecircme maniegravere que pour une surdeacutefinition usuelle Si plusieurs

fonctions restent utilisables on aboutit agrave une erreur de compilation et la recherche est inter-

rompue

En revanche si aucun patron de fonctions ne convient3 on examine agrave nouveau toutes les

fonctions ordinaires en les traitant cette fois comme de simples fonctions surdeacutefinies (promo-

tions numeacuteriques conversions standard4)

1 Du moins si elle na pas deacutejagrave eacuteteacute instancieacutee

2 Rappelons que la possibiliteacute de speacutecialisation partielle des patrons de fonctions nest pas correctement geacutereacutee par

toutes les impleacutementations

3 Y compris si un seul reacutealisait les correspondances exactes des paramegravetres de type sans qursquoil existe de conversions

leacutegales pour les eacuteventuels paramegravetres expressions

4 Voir au paragraphe 5 du chapitre 4

6 - Algorithme drsquoinstanciation drsquoune fonction patron223

Voici quelques exemples

Exemple 1template ltclass Tgt void f(T t int n) cout ltlt f(Tint)n template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n main() double y f(y 10) OK f(T int) avec T=double f(y 125) ambiguiumlteacute f(Tint) ou f(Tfloat) car 125 est de type double les conversions standard double--gtint et double--gtfloat conviennent f(y 125f) Ok f(T float) avec T=double

Exemple 2template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n template ltclass T class Ugt void f(T t U u) cout ltlt f(TU)n main() double y float x f(x y) OK f(TU) avec T=float U=double f(y x) ambiguiumlteacute f(TU) avec T=double U=float ou f(Tfloat) avec U=double

Exemple 3template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n main() double y float x f(x y) OK avec T=double et conversion de y en float f(y x) OK avec T=float f(x hello) T=double convient mais char ne peut pas ecirctre converti en float

Les patrons de fonctionsCHAPITRE 11

224

Remarque

Il est tout agrave fait possible que la deacutefinition dun patron fasse intervenir agrave son tour une fonc-

tion patron (cest-agrave-dire une fonction susceptible decirctre instancieacutee agrave partir dun autre

patron)

12

Les patrons de classes

Le preacuteceacutedent chapitre a montreacute comment C++ permettait gracircce agrave la notion de patron de fonc-

tions de deacutefinir une famille de fonctions parameacutetreacutees par un ou plusieurs types et eacuteventuelle-

ment des expressions Dune maniegravere comparable C++ permet de deacutefinir des patrons de

classes Lagrave encore il suffira drsquoeacutecrire une seule fois la deacutefinition de la classe pour que le

compilateur puisse automatiquement ladapter agrave diffeacuterents types

Comme nous lavons fait pour les patrons de fonctions nous commencerons par vous preacutesen-

ter cette notion de patron de classes agrave partir drsquoun exemple simple ne faisant intervenir quun

paramegravetre de type Nous verrons ensuite quelle se geacuteneacuteralise agrave un nombre quelconque de

paramegravetres de type et de paramegravetres expressions Puis nous examinerons la possibiliteacute de speacute-

cialiser un patron de classes soit en speacutecialisant certaines de ses fonctions membres soit en

speacutecialisant toute une classe Nous ferons alors le point sur linstanciation de classes patrons

notamment en ce qui concerne lidentiteacute de deux classes Nous verrons ensuite comment se

geacuteneacuteralisent les deacuteclarations damitieacutes dans le cas de patrons de classes Nous terminerons par

un exemple dutilisation de classes patrons imbriqueacutees en vue de manipuler des tableaux

(dobjets) agrave deux indices

Signalons degraves maintenant que malgreacute leurs ressemblances les notions de patron de fonctions

et de patron de classes preacutesentent des diffeacuterences assez importantes Comme vous le consta-

terez ce chapitre nest nullement lextrapolation aux classes du preacuteceacutedent chapitre consacreacute

aux fonctions

Les patrons de classesCHAPITRE 12

226

1 Exemple de creacuteation et drsquoutilisation drsquoun patron de classes

11 Creacuteation dun patron de classesNous avons souvent eacuteteacute ameneacute agrave creacuteer une classe point de ce genre (nous ne fournissons pas

ici la deacutefinition des fonctions membres)

class point int x int y public point (int abs=0 int ord=0) void affiche ()

Lorsque nous proceacutedons ainsi nous imposons que les coordonneacutees dun point soient des

valeurs de type int Si nous souhaitons disposer de points agrave coordonneacutees dun autre type

(float double long unsigned int) nous devons deacutefinir une autre classe en remplaccedilant sim-

plement dans la classe preacuteceacutedente le mot cleacute int par le nom de type voulu

Ici encore nous pouvons simplifier consideacuterablement les choses en deacutefinissant un seul patron

de classe de cette faccedilon

template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) void affiche ()

Comme dans le cas des patrons de fonctions la mention template ltclass Tgt preacutecise que lon

a affaire agrave un patron (template) dans lequel apparaicirct un paramegravetre de type nommeacute T rappe-

lons que C++ a deacutecideacute demployer le mot cleacute class pour preacuteciser que T est un argument de

type (pas forceacutement classe)

Bien entendu la deacutefinition de notre patron de classes nest pas encore complegravete puisquil y

manque la deacutefinition des fonctions membres agrave savoir le constructeur point et la fonction affi-

che Pour ce faire la deacutemarche va leacutegegraverement diffeacuterer selon que la fonction concerneacutee est en

ligne ou non

Pour une fonction en ligne les choses restent naturelles il suffit simplement dutiliser le

paramegravetre T agrave bon escient Voici par exemple comment pourrait ecirctre deacutefini notre

constructeur

point (T abs=0 T ord=0) x = abs y = ord

En revanche lorsque la fonction est deacutefinie en dehors de la deacutefinition de la classe il est

neacutecessaire de rappeler au compilateur

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes227

bull que dans la deacutefinition de cette fonction vont apparaicirctre des paramegravetres de type pour ce

faire on fournira agrave nouveau la liste de paramegravetre sous la forme

template ltclass Tgt

bull le nom du patron concerneacute (de mecircme quavec une classe ordinaire il fallait preacutefixer le nom

de la fonction du nom de la classe) par exemple si nous deacutefinissons ainsi la fonction af-

fiche son nom sera

pointltTgtaffiche ()

En deacutefinitive voici comment se preacutesenterait len-tecircte de la fonction affiche si nous le deacutefinis-

sions ainsi en dehors de la classe

template ltclass Tgt void pointltTgtaffiche ()

En toute rigueur le rappel du paramegravetre T agrave la suite du nom de patron (point) est redondant1

puisqursquoil a deacutejagrave eacuteteacute speacutecifieacute dans la liste de paramegravetres suivant le mot cleacute template

Voici ce que pourrait ecirctre finalement la deacutefinition de notre patron point

include ltiostreamgtusing namespace std creacuteation dun patron de classetemplate ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () template ltclass Tgt void pointltTgtaffiche () cout ltlt Coordonneacutees ltlt x ltlt ltlt y ltlt n

Creacuteation dun patron de classes

Remarque

Comme on lrsquoa deacutejagrave fait remarquer agrave propos de la deacutefinition de patrons de fonctions

depuis la norme le mot cleacute class peut ecirctre remplaceacute par typename2

1 Stroustrup le concepteur du langage C++ se contente de mentionner cette redondance sans la justifier

2 En toute rigueur ce mot cleacute peut eacutegalement servir agrave lever une ambiguiumlteacute pour le compilateur en lrsquoajoutant en

preacutefixe agrave un identificateur afin qursquoil soit effectivement interpreacuteteacute comme un nom de type Par exemple avec cette

deacuteclaration

typename Atruc a eacutequivalent agrave Atruc a si aucune ambiguiteacute nrsquoexiste

on preacutecise que Atruc est bien un nom de type on deacuteclare donc a comme eacutetant de type Atruc

Il est rare que lrsquoon ait besoin de recourir agrave cette possibiliteacute

Les patrons de classesCHAPITRE 12

228

12 Utilisation dun patron de classes

Apregraves avoir creacuteeacute ce patron une deacuteclaration telle que

point ltintgt ai

conduit le compilateur agrave instancier la deacutefinition dune classe point dans laquelle le paramegravetre

T prend la valeur int Autrement dit tout se passe comme si nous avions fourni une deacutefinition

complegravete de cette classe

Si nous deacuteclarons

point ltdoublegt ad

le compilateur instancie la deacutefinition dune classe point dans laquelle le paramegravetre T prend la

valeur double exactement comme si nous avions fourni une autre deacutefinition complegravete de

cette classe

Si nous avons besoin de fournir des arguments au constructeur nous proceacutederons de faccedilon

classique comme dans

point ltintgt ai (3 5) point ltdoublegt ad (35 23)

13 Contraintes drsquoutilisation drsquoun patron de classes

Comme on peut sy attendre les instructions deacutefinissant un patron de classes sont des deacutecla-

rations au mecircme titre que les instructions deacutefinissant une classe (y compris les instructions de

deacutefinition de fonctions en ligne)

Mais il en va de mecircme pour les fonctions membres qui ne sont pas en ligne leurs instruc-

tions sont neacutecessaires au compilateur pour instancier chaque fois que neacutecessaire les instruc-

tions requises On retrouve ici la mecircme remarque que celle que nous avons formuleacutee pour les

patrons de fonctions (voir paragraphe 14 du chapitre 11)

Aussi nest-il pas possible de livrer agrave un utilisateur une classe patron toute compileacutee il faut

lui fournir les instructions source de toutes les fonctions membres (alors que pour une classe

ordinaire il suffit de lui fournir la deacuteclaration de la classe et un module objet correspondant

aux fonctions membres)

Tout se passe encore ici comme srsquoil existait deux niveaux de deacuteclarations Par la suite nous

continuerons cependant agrave parler de deacutefinition dun patron

En pratique on placera les deacutefinitions de patron dans un fichier approprieacute dextension h

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes229

Remarque

Ici encore les consideacuterations preacuteceacutedentes doivent en fait ecirctre pondeacutereacutees par le fait que la

norme a introduit le mot cleacute export Appliqueacute agrave la deacutefinition drsquoun patron de classes il preacute-

cise que celle-ci sera accessible depuis un autre fichier source Par exemple on pourra

deacutefinir un patron de classes point de cette faccedilon

export template ltclass Tgt class point

T x T y

public

point ()

void afiche ()

template ltclass Tgt pointltTgtpoint() deacutefinition constructeur

template ltclass Tgt void pointltTgtaffiche() deacutefinition affiche

On peut alors utiliser ce patron depuis un autre fichier source en se contentant de men-

tionner sa seule deacuteclaration (comme avec les patrons de fonctions on distingue alors

deacuteclaration et deacutefinition)

template ltclass Tgt pointltTgt deacuteclaration seule de pointltTgt

T x T y

point ()

void afiche ()

Ici encore on aura inteacuterecirct agrave preacutevoir deux fichiers en-tecirctes distincts un pour la deacuteclara-

tion un pour la deacutefinition Le premier sera inclus dans la deacutefinition du patron et dans

son utilisation

Rappelons que ce meacutecanisme met en jeu une sorte de preacutecompilation des deacutefinitions

de patrons

14 Exemple reacutecapitulatifVoici un programme complet comportant

bull la creacuteation dun patron de classes point doteacutee drsquoun constructeur en ligne et drsquoune fonction

membre (affiche) non en ligne

bull un exemple dutilisation (main)

include ltiostreamgt

using namespace std

Les patrons de classesCHAPITRE 12

230

creacuteation dun patron de classetemplate ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () template ltclass Tgt void pointltTgtaffiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

main () point ltintgt ai (3 5) aiaffiche () point ltchargt ac (d y) acaffiche () point ltdoublegt ad (35 23) adaffiche ()

coordonnees 3 5coordonnees d ycoordonnees 35 23

Creacuteation et utilisation dun patron de classes

Remarques

1 Le comportement de pointltchargt est satisfaisant si nous souhaitons effectivement dispo-

ser de points repeacutereacutes par de vrais caractegraveres En revanche si nous avons utiliseacute le type

char pour disposer de petits entiers le reacutesultat est moins satisfaisant En effet nous

pourrons toujours deacuteclarer un point de cette faccedilon

point ltchargt pc (4 9)

Mais le comportement de la fonction affiche ne nous conviendra plus (nous obtiendrons

les caractegraveres ayant pour code les coordonneacutees du point )

Nous verrons quil reste toujours possible de modifier cela en speacutecialisant notre

classe point pour le type char ou encore en speacutecialisant la fonction affiche pour la

classe pointltchargt

2 A priori on a plutocirct envie dappliquer notre patron point agrave des types T standard Toute-

fois rien ninterdit de lappliquer agrave un type classe T quelconque mecircme srsquoil peut alors

srsquoaveacuterer difficile dattribuer une signification agrave la classe patron ainsi obtenue Il faut

cependant quil existe une conversion de int en T utile pour convertir la valeur 0 dans le

2 - Les paramegravetres de type drsquoun patron de classes231

type T lors de linitialisation des arguments du constructeur de point (sinon on obtien-

dra une erreur de compilation) De plus il est neacutecessaire que la recopie et laffectation

dobjets de type T soient correctement prises en compte (dans le cas contraire aucun

diagnostic ne sera fourni agrave la compilation les conseacutequences nrsquoen seront perccedilues qursquoagrave

lrsquoexeacutecution)

2 Les paramegravetres de type drsquoun patron de classes

Tout comme les patrons de fonctions les patrons de classes peuvent comporter des paramegrave-

tres de type et des paramegravetres expressions Ce paragraphe eacutetudie les premiers les seconds

seront eacutetudieacutes au paragraphe suivant Une fois de plus notez bien que malgreacute leur ressem-

blance avec les patrons de fonctions les contraintes relatives agrave ces diffeacuterents types de para-

megravetres ne seront pas les mecircmes

21 Les paramegravetres de type dans la creacuteation dun patron de classes

Les paramegravetres de type peuvent ecirctre en nombre quelconque et utiliseacutes comme bon vous sem-

ble dans la deacutefinition du patron de classes En voici un exemple

template ltclass T class U class Vgt liste de trois param de nom (muet) T U et Vclass essai T x un membre x de type T U t[5] un tableau t de 5 eacuteleacutements de type U V fm1 (int U) deacuteclaration dune fonction membre recevant 2 arguments de type int et U et renvoyant un reacutesultat de type V

22 Instanciation dune classe patronRappelons que nous nommons classe patron une instance particuliegravere dun patron de clas-

ses

Une classe patron se deacuteclare simplement en fournissant agrave la suite du nom de patron un nom-

bre drsquoarguments effectifs (noms de types) eacutegal au nombre de paramegravetres figurant dans la liste

(template lt gt) du patron Voici des deacuteclarations de classes patron obtenues agrave partir du

patron essai preacuteceacutedent (il ne sagit que de simples exemples deacutecole auxquels il ne faut pas

chercher agrave attribuer une signification preacutecise)

essai ltint float intgt ce1 essai ltint int double gt ce2 essai ltchar int objgt ce3

Les patrons de classesCHAPITRE 12

232

La derniegravere suppose bien sucircr que le type obj a eacuteteacute preacutealablement deacutefini (il peut sagir dun

type classe)

Il est mecircme possible dutiliser comme paramegravetre de type effectif un type instancieacute agrave laide

dun patron de classes Par exemple si nous disposons du patron de classes nommeacute point tel

quil a eacuteteacute deacutefini dans le paragraphe preacuteceacutedent nous pouvons deacuteclarer

essai ltfloat pointltintgt doublegt ce4 essai ltpointltintgt pointltfloatgt char gt ce5

Remarques

1 Les problegravemes de correspondance exacte rencontreacutes avec les patrons de fonctions nexis-

tent plus pour les patrons de classes (du moins pour les paramegravetres de types eacutetudieacutes ici)

En effet dans le cas des patrons de fonctions linstanciation se fondait non pas sur la liste

des paramegravetres indiqueacutes agrave la suite du mot cleacute template mais sur la liste des paramegravetres de

len-tecircte de la fonction un mecircme nom (muet) pouvait apparaicirctre deux fois et il y avait

donc risque dabsence de correspondance

2 Il est tout agrave fait possible quun argument formel (figurant dans len-tecircte) dune fonction

patron soit une classe patron En voici un exemple dans lequel nous supposons deacutefini

le patron de classes nommeacute point (ce peut ecirctre le preacuteceacutedent)

template ltclass Tgt void fct (pointltTgt)

Lorsquil devra instancier une fonction fct pour un type T donneacute le compilateur instan-

ciera eacutegalement (si cela na pas encore eacuteteacute fait) la classe patron pointltTgt

3 Comme dans le cas des patrons de fonctions on peut rencontrer des difficulteacutes lorsque

lon doit initialiser (au sein de fonctions membres) des variables dont le type figure en

paramegravetre En effet il peut sagir dun type de base ou au contraire dun type classe Lagrave

encore la nouvelle syntaxe dinitialisation des types standard (preacutesenteacutee au paragraphe

23 du chapitre 11) permet de reacutesoudre le problegraveme

4 Un patron de classes peut comporter des membres (donneacutees ou fonctions) statiques

Dans ce cas il faut savoir que chaque instance de la classe dispose de son propre jeu de

membres statiques on est en quelque sorte statique au niveau de linstance et non au

niveau du patron Crsquoest logique puisque le patron de classes nest quun moule utiliseacute

pour instancier diffeacuterentes classes plus preacuteciseacutement un patron de classes peut toujours

ecirctre remplaceacute par autant de deacutefinitions diffeacuterentes de classes que de classes instancieacutees

3 - Les paramegravetres expressions drsquoun patron de classes233

3 Les paramegravetres expressions drsquoun patron de classes

Un patron de classes peut comporter des paramegravetres expressions Bien quil sagisse ici

encore dune notion voisine de celle preacutesenteacutee pour les patrons de fonctions certaines diffeacute-

rences importantes existent En particulier les valeurs effectives dun paramegravetre expression

devront obligatoirement ecirctre constantes dans le cas des classes

31 Exemple Supposez que nous souhaitions deacutefinir une classe tableau susceptible de manipuler des

tableaux dobjets dun type quelconque Lrsquoideacutee vient tout naturellement agrave lesprit den faire

une classe patron posseacutedant un paramegravetre de type On peut aussi preacutevoir un second paramegravetre

permettant de preacuteciser le nombre deacuteleacutements du tableau

Dans ce cas la creacuteation de la classe se preacutesentera ainsi

template ltclass T int ngt class tableau

T tab [n]

public

La liste de paramegravetres (template ltgt) comporte deux paramegravetres de nature totalement

diffeacuterente

bull un paramegravetre (deacutesormais classique) de type introduit par le mot cleacute class

bull un paramegravetre expression de type int on preacutecisera sa valeur lors de la deacuteclaration dune

instance particuliegravere de la classe tableau

Par exemple avec la deacuteclaration

tableau ltint 4gt ti

nous deacuteclarerons une classe nommeacutee ti correspondant finalement agrave la deacuteclaration suivante

class ti

int tab [4]

public

Voici un exemple complet de programme deacutefinissant un peu plus complegravetement une telle

classe patron nommeacutee tableau nous lavons simplement doteacutee de lopeacuterateur [] et dun cons-

tructeur (sans arguments) qui ne se justifie que par le fait quil affiche un message approprieacute

Nous avons instancieacute des tableaux dobjets de type point (ici point est agrave nouveau une classe

ordinaire et non une classe patron)

Les patrons de classesCHAPITRE 12

234

include ltiostreamgtusing namespace std template ltclass T int ngt class tableau T tab [n] public tableau () cout ltlt construction tableau n T amp operator [] (int i) return tab[i] class point int x y public point (int abs=1 int ord=1 ) ici init par deacutefaut agrave 1 x=abs y=ord cout ltlt constr point ltlt x ltlt ltlt y ltlt n void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n main() tableau ltint4gt ti int i for (i=0 ilt4 i++) ti[i] = i cout ltlt ti for (i=0 ilt4 i++) cout ltlt ti[i] ltlt cout ltlt n tableau ltpoint 3gt tp for (i=0 ilt3 i++) tp[i]affiche()

construction tableauti 0 1 2 3const point 1 1const point 1 1const point 1 1construction tableaucoordonneacutees 1 1coordonneacutees 1 1coordonneacutees 1 1

Exemple de classe patron comportant un paramegravetre expression

Remarque

La classe tableau telle quelle est preacutesenteacutee ici na pas veacuteritablement dinteacuterecirct pratique En

effet on obtiendrait le mecircme reacutesultat en deacuteclarant de simples tableaux dobjets par exem-

ple int ti[4] au lieu de tableau ltint4gt ti En fait il ne sagit que dun cadre initial quon

4 - Speacutecialisation drsquoun patron de classes235

peut compleacuteter agrave loisir Par exemple on pourrait facilement y ajouter un controcircle dindice

en adaptant la deacutefinition de lopeacuterateur [] on pourrait eacutegalement preacutevoir dinitialiser les

eacuteleacutements du tableau Cest dailleurs ce que nous aurons loccasion de faire au paragraphe

9 ougrave nous utiliserons le patron tableau pour manipuler des tableaux agrave plusieurs indices

32 Les proprieacuteteacutes des paramegravetres expressionsOn peut faire apparaicirctre autant de paramegravetres expressions quon le deacutesire dans une liste de

paramegravetres dun patron de classes Ces paramegravetres peuvent intervenir nimporte ougrave dans la

deacutefinition du patron au mecircme titre que nimporte quelle expression constante peut apparaicirctre

dans la deacutefinition dune classe

Lors de linstanciation dune classe comportant des paramegravetres expressions les paramegravetres

effectifs correspondants doivent obligatoirement ecirctre des expressions constantes1 dun type

rigoureusement identique agrave celui preacutevu dans la liste drsquoarguments (aux conversions triviales

pregraves) autrement dit aucune conversion nest possible

Contrairement agrave ce qui passait pour les patrons de fonctions il nest pas possible de surdeacutefinir

un patron de classes cest-agrave-dire de creacuteer plusieurs patrons de mecircme nom mais comportant

une liste de paramegravetres (de type ou expressions) diffeacuterents En conseacutequence les problegravemes

dambiguiumlteacute eacutevoqueacutes lors de linstanciation dune fonction patron ne peuvent plus se poser

dans le cas de linstanciation dune classe patron

Sur un plan meacutethodologique on pourra souvent heacutesiter entre lemploi de paramegravetres expres-

sions et la transmission drsquoarguments au constructeur Ainsi dans lrsquoexemple de classe tableau

nous aurions pu ne pas preacutevoir le paramegravetre expression n mais en revanche transmettre au

constructeur le nombre deacuteleacutements souhaiteacutes Une diffeacuterence importante serait alors apparue

au niveau de la gestion des emplacements meacutemoire correspondant aux diffeacuterents eacuteleacutements du

tableau

bull attribution demplacement agrave la compilation (statique ou automatique suivant la classe dal-

location de lobjet de type tableaultgt correspondant) dans le premier cas

bull allocation dynamique par le constructeur dans le second cas

4 Speacutecialisation drsquoun patron de classesNous avons vu quil eacutetait possible de speacutecialiser certaines fonctions dun patron de fonc-

tions Si la mecircme possibiliteacute existe pour les patrons de classes elle prend toutefois un aspect

leacutegegraverement diffeacuterent agrave la fois au niveau de sa syntaxe et de ses possibiliteacutes comme nous le

verrons apregraves un exemple dintroduction

1 Cette contrainte nexistait pas pour les paramegravetres expressions des patrons de fonctions mais leur rocircle neacutetait pas

le mecircme

Les patrons de classesCHAPITRE 12

236

41 Exemple de speacutecialisation dune fonction membreUn patron de classes deacutefinit une famille de classes dans laquelle chaque classe comporte agrave la

fois sa deacutefinition et la deacutefinition de ses fonctions membres Ainsi toutes les fonctions mem-

bres de nom donneacute reacutealisent le mecircme algorithme Si lon souhaite adapter une fonction mem-

bre agrave une situation particuliegravere il est possible den fournir une nouvelle

Voici un exemple qui reprend le patron de classes point deacutefini dans le premier paragraphe

Nous y avons speacutecialiseacute la fonction affiche dans le cas du type char afin quelle affiche non

plus des caractegraveres mais des nombres entiers

include ltiostreamgt

using namespace std

creacuteation dun patron de classe

template ltclass Tgt class point

T x T y

public

point (T abs=0 T ord=0)

x = abs y = ord

void affiche ()

deacutefinition de la fonction affiche

template ltclass Tgt void pointltTgtaffiche ()

cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

ajout dune fonction affiche speacutecialiseacutee pour les caractegraveres

void pointltchargtaffiche ()

cout ltlt Coordonnees ltlt (int)x ltlt ltlt (int)y ltlt n

main ()

point ltintgt ai (3 5) aiaffiche ()

point ltchargt ac (d y) acaffiche ()

point ltdoublegt ad (35 23) adaffiche ()

coordonneacutees 3 5

coordonneacutees 100 121

coordonneacutees 35 23

Exemple de speacutecialisation dune fonction membre dune classe patron

Notez quil nous a suffi deacutecrire len-tecircte de affiche sous la forme

void pointltchargtaffiche ()

pour preacuteciser au compilateur quil devait utiliser cette fonction agrave la place de la fonction affi-

che du patron point cest-agrave-dire agrave la place de linstance pointltchargt

4 - Speacutecialisation drsquoun patron de classes237

42 Les diffeacuterentes possibiliteacutes de speacutecialisation

421 On peut speacutecialiser une fonction membre pour tous les paramegravetres

Dans notre exemple la classe patron point ne comportait quun paramegravetre de type Il est pos-

sible de speacutecialiser une fonction membre en se basant sur plusieurs paramegravetres de type ainsi

que sur des valeurs preacutecises drsquoun ou plusieurs paramegravetres expressions (bien que cette der-

niegravere possibiliteacute nous paraisse dun inteacuterecirct limiteacute) Par exemple consideacuterons le patron tableau

deacutefini au paragraphe 31

template ltclass T int ngt class tableau T tab [n] public tableau () cout ltlt construction tableau n

Nous pouvons eacutecrire une version speacutecialiseacutee de son constructeur pour les tableaux de

10 eacuteleacutements de type point (il ne sagit vraiment que dun exemple deacutecole ) en proceacutedant

ainsi

tableaultpoint10gttableau ()

422 On peut speacutecialiser une fonction membre ou une classe

Dans les exemples preacuteceacutedents nous avons speacutecialiseacute une fonction membre dun patron En

fait on peut indiffeacuteremment

bull speacutecialiser une ou plusieurs fonctions membres sans modifier la deacutefinition de la classe elle-

mecircme (ce sera la situation la plus freacutequente)

bull speacutecialiser la classe elle-mecircme en en fournissant une nouvelle deacutefinition cette seconde

possibiliteacute peut saccompagner de la speacutecialisation de certaines fonctions membres

Par exemple apregraves avoir deacutefini le patron template ltclass Tgt class point (comme au paragra-

phe 41) nous pourrions deacutefinir une version speacutecialiseacutee de la classe point pour le type char

cest-agrave-dire une version approprieacutee de linstance pointltchargt en proceacutedant ainsi

class point ltchargt nouvelle deacutefinition

Nous pourrions aussi deacutefinir des versions speacutecialiseacutees de certaines des fonctions membre de

pointltchargt en proceacutedant comme preacuteceacutedemment ou ne pas en deacutefinir auquel cas on ferait

appel aux fonctions membres du patron

423 On peut preacutevoir des speacutecialisations partielles de patrons de classes

Nous avons deacutejagrave parleacute de speacutecialisation partielle dans le cas de patrons de fonctions (voir au

paragraphe 5 du chapitre 11) La norme ANSI autorise eacutegalement la speacutecialisation partielle

drsquoun patron de classes1 En voici un exemple

1 Cette possibiliteacute nrsquoexistait pas dans la version 3 Elle a eacuteteacute introduite par la norme ANSI et elle nrsquoest pas encore

reconnue de tous les compilateurs

Les patrons de classesCHAPITRE 12

238

template ltclass T class Ugt class A patron Itemplate ltclass Tgt class A ltT Tgt patron II

Une deacuteclaration telle que A ltint floatgt a1 utilisera le patron I tandis qursquoune deacuteclaration

telle que Altint int gt a2 utilisera le patron II plus speacutecialiseacute

5 Paramegravetres par deacutefautDans la deacutefinition dun patron de classes il est possible de speacutecifier des valeurs par deacutefaut

pour certains paramegravetres1 suivant un meacutecanisme semblable agrave celui utiliseacute pour les paramegrave-

tres de fonctions usuelles Voici quelques exemples

template ltclass T class U=floatgt class A template ltclass T int n=3gt class B Altintlonggt a1 instanciation usuelle Altintgt a2 eacutequivaut agrave Altint floatgt a2 Bltint 3gt b1 instanciation usuelle Bltintgt b2 eacutequivaut agrave Bltint 3gt b2

Remarque

La notion de paramegravetres par deacutefaut na pas de signification pour les patrons de fonctions

6 Patrons de fonctions membresLe meacutecanisme de deacutefinition de patrons de fonctions peut sappliquer agrave une fonction membre

dune classe ordinaire comme dans cet exemple

class A

template ltclass Tgt void fct (T a)

Cette possibiliteacute peut srsquoappliquer agrave une fonction membre dune classe patron comme dans cet

exemple2

template ltclass Tgt class A

template ltclass Ugt void fct (U x T y) ici le type T est utiliseacute mais

il pourrait ne pas lecirctre

Dans ce dernier cas linstanciation de la bonne fonction fct se fondera agrave la fois sur la classe agrave

laquelle elle appartient et sur la nature de son premier argument

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

2 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

7 - Identiteacute de classes patrons239

7 Identiteacute de classes patronsNous avons deacutejagrave vu que lopeacuterateur drsquoaffectation pouvait sappliquer agrave deux objets dun mecircme

type Lrsquoexpression mecircme type est parfaitement deacutefinie tant que lon nutilise pas dinstan-

ces de patron de classes deux objets sont de mecircme type sils sont deacuteclareacutes avec le mecircme

nom de classe Mais que devient cette deacutefinition dans le cas dobjets dont le type est une ins-

tance particuliegravere dun patron de classes

En fait deux classes patrons correspondront agrave un mecircme type si leurs paramegravetres de type cor-

respondent exactement au mecircme type et si leurs paramegravetres expressions ont la mecircme valeur

Ainsi en supposant que nous disposions du patron tableau deacutefini au paragraphe 31 avec ces

deacuteclarations

tableau ltint 12gt t1 tableau ltfloat 12gt t2

vous naurez pas le droit deacutecrire

t2 = t1 incorrect car valeurs diffeacuterentes du premier paramegravetre (float et int)

De mecircme avec ces deacuteclarations

tableau ltint 15gt ta

tableau ltint 20gt tb

vous naurez pas le droit deacutecrire

ta = tb incorrect car valeurs diffeacuterentes du second paramegravetre (15 et 20)

Ces regravegles apparemment restrictives ne servent en fait quagrave assurer un bon fonctionnement

de laffectation quil sagisse de laffectation par deacutefaut (membre agrave membre il faut donc bien

disposer exactement des mecircmes membres dans les deux objets) ou de laffectation surdeacutefinie

(pour que cela fonctionne toujours il faudrait que le concepteur du patron de classe preacutevoie

toutes les combinaisons possibles et de plus ecirctre sucircr quune eacuteventuelle speacutecialisation ne ris-

que pas de perturber les choses)

Certes dans le premier cas (t2=t1) une conversion int-gtfloat nous aurait peut-ecirctre convenu

Mais pour que le compilateur puisse la mettre en œuvre il faudrait quil sache quune classe

tableaultint 10gt ne comporte que des membres de type int quune classe tableaultfloat

10gt ne comporte que des membres de type float que les deux classes ont le mecircme nombre de

membres donneacutees

8 Classes patrons et deacuteclarations drsquoamitieacuteLexistence des patrons de classes introduit de nouvelles possibiliteacutes de deacuteclaration damitieacute

81 Deacuteclaration de classes ou fonctions ordinaires amiesLa deacutemarche reste celle que nous avons rencontreacutee dans le cas des classes ordinaires Par

exemple si A est une classe ordinaire et fct une fonction ordinaire

Les patrons de classesCHAPITRE 12

240

template ltclass Tgtclass 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

82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons

En fait cette possibiliteacute peut prendre deux aspects diffeacuterents selon que les paramegravetres utiliseacutes

pour deacutefinir linstance concerneacutee sont effectifs ou muets (deacutefinis dans la liste de paramegravetres

du patron de classe)

Supposons que point est une classe patron ainsi deacutefinie

template ltclass Tgt class point

et fct une fonction patron ainsi deacutefinie

template ltclass Tgt int fct (T x)

Voici un exemple illustrant le premier aspect

template ltclass T class Ugt

class essai1

int x

public

friend class pointltintgt la classe patron pointltintgt 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 exemple illustrant le second aspect

template ltclass T class Ugt

class essai2

int x

public

friend class pointltTgt

friend int fct (U)

Notez bien que dans le second cas on eacutetablit un couplage entre la classe patron geacuteneacutereacutee

par le patron essai2 et les deacuteclarations damitieacute correspondantes Par exemple pour lintance

essai2 ltint doublegt les deacuteclarations damitieacute porteront sur pointltintgt et int fct (double)

9 - Exemple de classe tableau agrave deux indices241

83 Deacuteclaration drsquoun autre patron de fonctions ou de classesVoici un exemple faisant appel aux mecircmes patrons point et fct que ci-dessus

template ltclass T class Ugt

class essai2

int x

public

template ltclass Xgt friend class point ltXgt

template ltclass Xgt friend class int fct (point ltXgt)

Cette fois toutes les instances du patron point sont amies de nrsquoimporte quelle instance du

patron essai2 De mecircme toutes les instances du patron de fonctions fct sont amies de

nrsquoimporte quelle instance du patron essai2

9 Exemple de classe tableau agrave deux indices Nous avons vu agrave plusieurs reprises comment surdeacutefinir lopeacuterateur [] au sein dune classe

tableau Neacuteanmoins nous nous sommes toujours limiteacute agrave des tableaux agrave un indice

Ici nous allons voir qursquoil est tregraves facile une fois qursquoon a deacutefini un patron de tableau agrave un

indice de lappliquer agrave un tableau agrave deux indices (ou plus) par le simple jeu de la composition

des patrons

Si nous consideacuterons pour linstant la classe tableau deacutefinie de cette faccedilon simplifieacutee

template ltclass T int ngt class tableau

T tab [n]

public

T amp operator [] (int i) opeacuterateur []

return tab[i]

nous pouvons tout agrave fait deacuteclarer

tableau lttableaultint2gt3gt t2d

En effet t2d est un tableau de 3 eacuteleacutements ayant chacun le type tableau ltint2gt autrement

dit chacun de ces 3 eacuteleacutements est lui-mecircme un tableau de 2 entiers

Une notation telle que t2d [1] [2] a un sens elle repreacutesente la reacutefeacuterence au troisiegraveme eacuteleacutement

de t2d [1] cest-agrave-dire au troisiegraveme eacuteleacutement du deuxiegraveme tableau de deux entiers de t2d

Voici un exemple complet (mais toujours simplifieacute) illustrant cela Nous avons simplement

ajouteacute artificiellement un constructeur afin dobtenir une trace des diffeacuterentes constructions

impleacutementation dun tableau agrave deux dimensions

include ltiostreamgt

using namespace std

Les patrons de classesCHAPITRE 12

242

template ltclass T int ngt class tableau

T tab [n]

public

tableau () constructeur

cout ltlt construction tableau a ltlt n ltlt elementsn

T amp operator [] (int i) opeacuterateur []

return tab[i]

main()

tableau lttableaultint2gt3gt t2d

t2d [1] [2] = 15

cout ltlt t2d [1] [2] = ltlt t2d [1] [2] ltlt n

cout ltlt t2d [0] [1] = ltlt t2d [0] [1] ltlt n

construction tableau a 2 elements

construction tableau a 2 elements

construction tableau a 2 elements

construction tableau a 3 elements

t2d [1] [2] = 15

t2d [0] [1] = -858993460

Utilisation du patron tableau pour manipuler des tableaux agrave deux indices (1)

On notera bien que notre patron tableau est a priori un tableau agrave un indice Seule la maniegravere

dont on lutilise permet de lappliquer agrave des tableaux agrave un nombre quelconque dindices

Manifestement cet exemple est trop simpliste dailleurs tel quel il napporte rien de plus

quun banal tableau Pour le rendre plus reacutealiste nous allons preacutevoir

bull de geacuterer les deacutebordements dindices ici nous nous contenterons dafficher un message et

de faire comme si lutilisateur avait fourni un indice nul1

bull dinitialiser tous les eacuteleacutements du tableau lors de sa construction nous utiliserons pour ce fai-

re la valeur 0 Mais encore faut-il que la chose soit possible cest-agrave-dire que quel que soit

le type T des eacuteleacutements du tableau on puisse leur affecter la valeur 0 Cela signifie quil doit

exister une conversion de T en int Il est facile de la reacutealiser avec un constructeur agrave un eacuteleacute-

ment de type int Du mecircme coup cela permettra de preacutevoir une valeur initiale lors de la deacute-

claration dun tableau (par seacutecuriteacute nous preacutevoirons la valeur 0 par deacutefaut)

Voici la classe ainsi modifieacutee et un exemple dutilisation

1 Il pourrait eacutegalement ecirctre judicieux de deacuteclencher une exception comme nous apprendrons agrave le faire sur ce

mecircme exemple au paragraphe 1 du chapitre 17

9 - Exemple de classe tableau agrave deux indices243

impleacutementation dun tableau 2d avec test deacutebordement dindicesinclude ltiostreamgtusing namespace std template ltclass T int ngt class tableau T tab [n] int limite nombre deacuteleacutements du tableau public tableau (int init=0) int i for (i=0 iltn i++) tab[i] = init il doit exister un constructeur agrave un argument pour le cas ougrave tab[i] est un objet limite = n-1 cout ltlt appel constructeur tableau de taille ltlt n ltlt init = ltlt init ltlt n T amp operator [] (int i) if (ilt0 || igtlimite) cout ltlt --debordement ltlt i ltlt n i=0 choix arbitraire return tab[i] main() tableau lttableaultint3gt2gt ti pas dinitialisation tableau lttableaultfloat4gt2gt td (10) initialisation agrave 10 ti [1] [6] = 15 ti [8] [-1] = 20 cout ltlt ti [1] [2] ltlt n eacuteleacutement initialiseacute agrave valeur par deacutefaut (0) cout ltlt td [1] [0] ltlt n eacuteleacutement initialiseacute explicitement

appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 2 init = 0appel constructeur tableau de taille 4 init = 0appel constructeur tableau de taille 4 init = 0appel constructeur tableau de taille 4 init = 10appel constructeur tableau de taille 4 init = 10appel constructeur tableau de taille 2 init = 10--debordement 6--debordement 8--debordement -1010

Utilisation du patron tableau pour manipuler des tableaux agrave deux indices (2)

Les patrons de classesCHAPITRE 12

244

Remarque

Si vous examinez bien les messages de construction des diffeacuterents tableaux vous obser-

verez que lon obtient deux fois plus de messages que preacutevu pour les tableaux agrave un indice

Lexplication reacuteside dans linstruction tab[i] = init du constructeur tableau En effet lors-

que tab[i] deacutesigne un eacuteleacutement de type de base il y a simplement conversion de la valeur

entiegravere init dans ce type de base En revanche lorsque lon a affaire agrave un objet de type T

(ici T est de la forme tableaultgt) cette instruction provoque lappel du constructeur

tableau(int) pour creacuteer un objet temporaire de ce type Cela se voit tregraves clairement dans le

cas du tableau td pour lequel on trouve une construction dun tableau temporaire initialiseacute

avec la valeur 0 et une construction dun tableau initialiseacute avec la valeur 10

13

Lrsquoheacuteritage simple

On sait que le concept dheacuteritage (on parle eacutegalement de classes deacuteriveacutees) constitue lun des

fondements de la POO En particulier il est agrave la base des possibiliteacutes de reacuteutilisation de

composants logiciels (en loccurrence de classes) En effet il vous autorise agrave deacutefinir une nou-

velle classe dite deacuteriveacutee agrave partir dune classe existante dite de base La classe deacuteriveacutee

heacuteritera des potentialiteacutes de la classe de base tout en lui en ajoutant de nouvelles et cela

sans quil soit neacutecessaire de remettre en question la classe de base Il ne sera pas utile de la

recompiler ni mecircme de disposer du programme source correspondant (exception faite de sa

deacuteclaration)

Cette technique permet donc de deacutevelopper de nouveaux outils en se fondant sur un certain

acquis ce qui justifie le terme dheacuteritage Bien entendu plusieurs classes pourront ecirctre deacuteri-

veacutees dune mecircme classe de base En outre lrsquoheacuteritage nest pas limiteacute agrave un seul niveau une

classe deacuteriveacutee peut devenir agrave son tour classe de base pour une autre classe On voit ainsi

apparaicirctre la notion dheacuteritage comme outil de speacutecialisation croissante

Qui plus est nous verrons que C++ (depuis la version 20) autorise lrsquoheacuteritage multiple gracircce

auquel une classe peut ecirctre deacuteriveacutee de plusieurs classes de base

Nous commencerons par vous preacutesenter la mise en œuvre de lrsquoheacuteritage en C++ agrave partir drsquoun

exemple tregraves simple Nous examinerons ensuite comment agrave limage de ce qui se passait dans

le cas dobjets membres C++ offre un meacutecanisme inteacuteressant de transmission dinformations

entre constructeurs (de la classe deacuteriveacutee et de la classe de base) Puis nous verrons la sou-

plesse que preacutesente le C++ en matiegravere de controcircle des accegraves de la classe deacuteriveacutee aux membres

de la classe de base (aussi bien au niveau de la conception de la classe de base que de celle de

la classe deacuteriveacutee)

Lrsquoheacuteritage simpleCHAPITRE 13

246

Nous aborderons ensuite les problegravemes de compatibiliteacute entre une classe de base et une classe

deacuteriveacutee tant au niveau des objets eux-mecircmes que des pointeurs sur ces objets ou des reacutefeacuteren-

ces agrave ces objets Ces aspects deviendront fondamentaux dans la mise en œuvre du polymor-

phisme par le biais des meacutethodes virtuelles Nous examinerons alors ce quil advient du

constructeur de recopie de lopeacuterateur drsquoaffectation et des patrons de classes

Enfin apregraves avoir examineacute les situations de deacuterivations successives nous apprendrons agrave

exploiter concregravetement une classe deacuteriveacutee

Quant agrave lheacuteritage multiple il fera lobjet du chapitre suivant

1 La notion drsquoheacuteritageExposons tout drsquoabord les bases de la mise en œuvre de lrsquoheacuteritage en C++ agrave partir drsquoun exem-

ple simple ne faisant pas intervenir de constructeur ou de destructeur et ougrave le controcircle des

accegraves est limiteacute

Consideacuterons la premiegravere classe point deacutefinie au chapitre 5 dont nous rappelons la

deacuteclaration

------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration drsquoune classe de base (point)

Supposons que nous ayons besoin de deacutefinir un nouveau type classe nommeacute pointcol destineacute

agrave manipuler des points coloreacutes dun plan Une telle classe peut manifestement disposer des

mecircmes fonctionnaliteacutes que la classe point auxquelles on pourrait adjoindre par exemple

une meacutethode nommeacutee colore chargeacutee de deacutefinir la couleur Dans ces conditions nous pou-

vons ecirctre tenteacutes de deacutefinir pointcol comme une classe deacuteriveacutee de point Si nous preacutevoyons

(pour linstant) une fonction membre speacutecifique agrave pointcol nommeacutee colore et destineacutee agrave attri-

buer une couleur agrave un point coloreacute voici ce que pourrait ecirctre la deacuteclaration de pointcol (la

fonction colore est ici en ligne)

1 - La notion drsquoheacuteritage247

class pointcol public point pointcol deacuterive de point short couleur public void colore (short cl) couleur = cl

Une classe pointcol deacuteriveacutee de point

Notez la deacuteclaration

class pointcol public point

Elle speacutecifie que pointcol est une classe deacuteriveacutee de la classe de base point De plus le mot

public signifie que les membres publics de la classe de base (point) seront des membres

publics de la classe deacuteriveacutee (pointcol) cela correspond agrave lideacutee la plus freacutequente que lon

peut avoir de lrsquoheacuteritage sur le plan geacuteneacuteral de la POO Nous verrons plus loin dans le para-

graphe consacreacute au controcircle des accegraves agrave quoi conduirait lomission du mot public

La classe pointcol ainsi deacutefinie nous pouvons deacuteclarer des objets de type pointcol de maniegravere

usuelle

pointcol p q

Chaque objet de type pointcol peut alors faire appel

bull aux meacutethodes publiques de pointcol (ici colore)

bull aux meacutethodes publiques de la classe de base point (ici init deplace et affiche)

Voici un programme illustrant ces possibiliteacutes Vous nrsquoy trouverez pas la liste de la classe

point car nous nous sommes placeacute dans les conditions habituelles drsquoutilisation drsquoune classe

deacutejagrave au point Plus preacuteciseacutement nous supposons que nous disposons

bull drsquoun module objet relatif agrave la classe point qursquoil est neacutecessaire drsquoincorporer au moment de

lrsquoeacutedition de liens

bull drsquoun fichier nommeacute ici pointh contenant la deacuteclaration de la classe point

include ltiostreamgtinclude pointh incorporation des deacuteclarations de pointusing namespace std --- Deacuteclaration et deacutefinition de la classe pointcol ----- class pointcol public point pointcol deacuterive de point short couleur public void colore (short cl) couleur = cl main() pointcol p pinitialise (1020) pcolore (5) paffiche ()

Lrsquoheacuteritage simpleCHAPITRE 13

248

pdeplace (24) paffiche ()

Je suis en 10 20Je suis en 12 24

Exemple dutilisation dune classe pointcol deacuteriveacutee de point

2 Utilisation des membres de la classe de base dans une classe deacuteriveacutee

Lrsquoexemple preacuteceacutedent destineacute agrave montrer comment sexprime lrsquoheacuteritage en C++ ne cherchait

pas agrave en explorer toutes les possibiliteacutes notamment en matiegravere de controcircle des accegraves Pour

lrsquoinstant nous savons simplement que gracircce agrave lemploi du mot public les membres publics

de point sont eacutegalement membres publics de pointcol Cest ce qui nous a permis de les utili-

ser au sein de la fonction main par exemple dans linstruction pinitialise (10 20)

Or la classe pointcol telle que nous lavons deacutefinie preacutesente des lacunes Par exemple lorsque

nous appelons affiche pour un objet de type pointcol nous nobtenons aucune information sur

sa couleur Une premiegravere faccedilon dameacuteliorer cette situation consiste agrave eacutecrire une nouvelle

fonction membre publique de pointcol censeacutee afficher agrave la fois les coordonneacutees et la couleur

Appelons-la pour linstant affichec (nous verrons plus tard quil est possible de lappeler eacutega-

lement affiche)

A ce niveau vous pourriez penser deacutefinir affichec de la maniegravere suivante

void affichec ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n cout ltlt et ma couleur est ltlt couleur ltlt n

Mais alors cela signifierait que la fonction affichec membre de pointcol aurait accegraves aux

membres priveacutes de point ce qui serait contraire au principe dencapsulation En effet il

deviendrait alors possible deacutecrire une fonction acceacutedant directement1 aux donneacutees priveacutees

dune classe simplement en creacuteant une classe deacuteriveacutee Dougrave la regravegle adopteacutee par C++

En revanche une meacutethode drsquoune classse deacuteriveacutee a accegraves aux membres publics de sa classe de

base Ainsi dans le cas qui nous preacuteoccupe si notre fonction membre affichec ne peut pas

1 Cest-agrave-dire sans passer par linterface obligatoire constitueacutee par les fonctions membres publiques

Une meacutethode drsquoune classe deacuteriveacutee nrsquoa pas accegraves aux membres priveacutes de sa classe de base

2 - Utilisation des membres de la classe de base dans une classe deacuteriveacutee249

acceacuteder directement aux donneacutees priveacutees x et y de la classe point elle peut neacuteanmoins faire

appel agrave la fonction affiche de cette mecircme classe Dougrave une deacutefinition possible de affichec

void pointcolaffichec () affiche () cout ltlt et ma couleur est ltlt couleur ltlt n

Une fonction daffichage pour un objet de type pointcol

Notez bien que au sein de affichec nous avons fait directement appel agrave affiche sans avoir agrave

speacutecifier agrave quel objet cette fonction devait ecirctre appliqueacutee par convention il sagit de

celui ayant appeleacute affichec Nous retrouvons la mecircme regravegle que pour les fonctions membres

dune mecircme classe En fait il faut deacutesormais consideacuterer que affiche est une fonction membre

de pointcol1

Dune maniegravere analogue nous pouvons deacutefinir dans pointcol une nouvelle fonction dinitiali-

sation nommeacutee initialisec chargeacutee dattribuer des valeurs aux donneacutees x y et couleur agrave partir

de trois valeurs reccedilues en argument

void pointcolinitialisec (int abs int ord short cl)

initialise (abs ord) couleur = cl

Une fonction dinitialisation pour un objet de type pointcol

Voici un exemple complet de programme reprenant la deacutefinition de la classe pointcol (nous

supposons que la deacutefinition de la classe point est fournie seacutepareacutement et que sa deacuteclaration

figure dans pointh

include ltiostreamgtinclude pointh deacuteclaration de la classe point (neacutecessaire pour compiler la deacutefinition de pointcol) using namespace std class pointcol public point short couleur

public void colore (short cl) couleur = cl void affichec ()

1 Mais ce ne serait pas le cas si affiche neacutetait pas une fonction publique de point

Lrsquoheacuteritage simpleCHAPITRE 13

250

void initialisec (int int short) void pointcolaffichec () affiche () cout ltlt et ma couleur est ltlt couleur ltlt n void pointcolinitialisec (int abs int ord short cl) initialise (abs ord) couleur = cl main() pointcol p pinitialisec (1020 5) paffichec () paffiche () pdeplace (24) paffichec () pcolore (2) paffichec ()

Je suis en 10 20 et ma couleur est 5Je suis en 10 20Je suis en 12 24 et ma couleur est 5Je suis en 12 24 et ma couleur est 2

Une nouvelle classe pointcol et son utilisation

En Java

La notion drsquoheacuteritage existe bien sucircr en Java Elle fait appel au mot cleacute extends agrave la place

de public On peut interdire agrave une classe de donner naissance agrave une classe deacuteriveacutee en la

qualifiant avec le mot cleacute final une telle possibiliteacute nrsquoexiste pas en C++

3 Redeacutefinition des membres drsquoune classe deacuteriveacutee

31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacuteeDans le dernier exemple de classe pointcol nous disposions agrave la fois

bull dans point dune fonction membre nommeacutee affiche

bull dans pointcol dune fonction membre nommeacutee affichec

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee251

Or ces deux meacutethodes font le mecircme travail agrave savoir afficher les valeurs des donneacutees de leur

classe Dans ces conditions on pourrait souhaiter leur donner le mecircme nom Ceci est effecti-

vement possible en C++ moyennant une petite preacutecaution En effet au sein de la fonction

affiche de pointcol on ne peut plus appeler la fonction affiche de point comme auparavant

cela provoquerait un appel reacutecursif de la fonction affiche de pointcol Il faut alors faire appel

agrave lopeacuterateur de reacutesolution de porteacutee () pour localiser convenablement la meacutethode voulue

(ici on appellera pointaffiche)

De maniegravere comparable si pour un objet p de type pointcol on appelle la fonction paffiche

il sagira de la fonction redeacutefinie dans pointcol Si lon tient absolument agrave utiliser la fonction

affiche de la classe point on appellera ppointaffiche

Voici comment nous pouvons transformer lrsquoexemple du paragraphe preacuteceacutedent en nommant

affiche et initialise les nouvelles fonctions membres de pointcol

include ltiostreamgtinclude pointhusing namespace std class pointcol public point short couleur public void colore (short cl) couleur = cl void affiche () redeacutefinition de affiche de point void initialise (int int short) redeacutefinition de initialise de point void pointcolaffiche () pointaffiche () appel de affiche de la classe point cout ltlt et ma couleur est ltlt couleur ltlt n void pointcolinitialise (int abs int ord short cl) pointinitialise (abs ord) appel de initialise de la classe point couleur = cl main() pointcol p pinitialise (1020 5) paffiche () ppointaffiche () pour forcer lappel de affiche de point pdeplace (24) paffiche () pcolore (2) paffiche ()

Je suis en 10 20 et ma couleur est 5Je suis en 10 20Je suis en 12 24 et ma couleur est 5Je suis en 12 24 et ma couleur est 2

Une classe pointcol dans laquelle les meacutethodes initialise et affiche sont redeacutefinies

Lrsquoheacuteritage simpleCHAPITRE 13

252

En Java

On a deacutejagrave dit que Java permettait drsquointerdire agrave une classe de donner naissance agrave des clas-

ses deacuteriveacutees Ce langage permet eacutegalement drsquointerdire la redeacutefinition drsquoune fonction

membre en la deacuteclarant avec le mot cleacute final dans la classe de base

32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacuteeBien que cela soit dun emploi moins courant ce que nous avons dit agrave propos de la redeacutefini-

tion des fonctions membres sapplique tout aussi bien aux membres donneacutees Plus preacuteciseacute-

ment si une classe A est deacutefinie ainsi

class A int a char b

une classe B deacuteriveacutee de A pourra par exemple deacutefinir un autre membre donneacutee nommeacute a

class B public A float a

Dans ce cas si lobjet b est de type B ba fera reacutefeacuterence au membre a de type float de b Il

sera toujours possible dacceacuteder au membre donneacutee a de type int (heacuteriteacute de A) par bAa1

Notez bien que le membre a deacutefini dans B sajoute au membre a heacuteriteacute de A il ne le rem-

place pas

33 Redeacutefinition et surdeacutefinitionIl va de soi que lorsqursquoune fonction est redeacutefinie dans une classe deacuteriveacutee elle masque une

fonction de mecircme signature de la classe de base En revanche comme on va le voir les cho-

ses sont moins naturelles en cas de surdeacutefinition ou mecircme de mixage entre ces deux possibi-

liteacutes Consideacuterez

class A public void f(int n) f est surdeacutefinie void f(char c) dans A class B public A public void f(float x) on ajoute une troisegraveme deacutefinition dans B

1 En supposant bien sucircr que les accegraves en question soient autoriseacutes

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee253

main()

int n char c A a B b

af(n) appelle Af(int) (regravegles habituelles)

af(c) appelle Af(char) (regravegles habituelles)

bf(n) appelle Bf(float) (alors que peut-ecirctre Af(int) conviendrait)

bf(c) appelle Bf(float) (alors que peut-ecirctre Af(char) conviendrait)

Ici on a ajouteacute dans B une troisiegraveme version de f pour le type float Pour reacutesoudre les appels

bf(n) et bf(c) le compilateur nrsquoa consideacutereacute que la fonction f de B qui srsquoest trouveacutee appeleacutee

dans les deux cas Si aucune fonction f nrsquoavait eacuteteacute deacutefinie dans B on aurait utiliseacute les fonc-

tions f(int) et (char) de A

Le mecircme pheacutenomegravene se produirait si lrsquoon effectuait dans B une redeacutefinition de lrsquoune des

fonctions f de A comme dans

class A

public

void f(int n) f est surdeacutefinie

void f(char c) dans A

class B public A

public

void f(int n) on redeacutefinit f(int) dans B

main()

int n char c B b

bf(n) appelle B(int)

bf(c) appelle Bf(int)

Dans ce dernier cas on voit qursquoune redeacutefinition drsquoune meacutethode dans une classe deacuteriveacutee cache

en quelque sorte les autres Voici un dernier exemple

class A

public

void f(int n)

void f(char c)

class B public A

public

void f(int int)

main()

int n char c B b

bf(n) erreur de compilation

bf(c) erreur de compilation

Ici pour les appels bf(n) et bf(c) le compilateur nrsquoa consideacutereacute que lrsquounique fonction

f(int int) de B laquelle ne convient manifestement pas

Lrsquoheacuteritage simpleCHAPITRE 13

254

En reacutesumeacute

On voit drsquoailleurs que cette particulariteacute peut ecirctre employeacutee pour interdire lrsquoemploi dans une

classe deacuteriveacutee drsquoune fonction membre drsquoune classe de base il suffit drsquoy deacutefinir une fonction

priveacutee de mecircme nom (peu importent ses arguments et sa valeur de retour)

Remarque

Il est possible drsquoimposer que la recherche drsquoune fonction surdeacutefinie se fassse dans plu-

sieurs classes en utilisant une directive using Par exemple si dans la classe A preacuteceacutedente

on introduit (agrave un niveau public) lrsquoinstruction

using Af on reacuteintroduit les fonctions f de A

lrsquoinstruction bf(c) conduira alors agrave lrsquoappel de Af(char) (le comportement des autres

appels restant ici le mecircme)

En Java on considegravere toujours lrsquoensemble des meacutethodes de nom donneacute agrave la fois dans la

classe concerneacutee et dans toutes ses ascendantes

4 Appel des constructeurs et des destructeurs

41 RappelsRappelons lessentiel des regravegles concernant lappel dun constructeur ou du destructeur dune

classe (dans le cas ougrave il ne sagit pas dune classe deacuteriveacutee)

bull Sil existe au moins un constructeur toute creacuteation dun objet (par deacuteclaration ou par new)

entraicircnera lappel dun constructeur choisi en fonction des informations fournies en argu-

ments Si aucun constructeur ne convient il y a erreur de compilation Il est donc impossible

dans ce cas de creacuteer un objet sans qursquoun constructeur ne soit appeleacute

bull Sil nexiste aucun constructeur il nest pas possible de preacuteciser des informations lors de la

creacuteation dun objet Cette fois il devient possible de creacuteer un objet sans qursquoun constructeur

ne soit appeleacute1 (crsquoest mecircme la seule faccedilon de le faire )

bull Sil existe un destructeur il sera appeleacute avant la destruction de lobjet

Lorsqursquoune fonction membre est deacutefinie dans une classe elle masque toutes les fonctions membres de mecircme nom de la classe de base (et des classes ascendan-tes) Autrement dit la recherche drsquoune fonction (surdeacutefinie ou non) se fait dans une seule porteacutee soit celle de la classe concerneacutee soit celle de la classe de base (ou drsquoune classe ascendante) mais jamais dans plusieurs classes agrave la fois

1 On dit aussi parfois qursquoil y a appel du constructeur par deacutefaut

4 - Appel des constructeurs et des destructeurs255

42 La hieacuterarchisation des appelsCes regravegles se geacuteneacuteralisent au cas des classes deacuteriveacutees en tenant compte de laspect hieacuterarchi-

que quelles introduisent Pour fixer les ideacutees supposons que chaque classe possegravede un cons-

tructeur et un destructeur

class A class B public A public public A () B () ~A () ~B ()

Pour creacuteer un objet de type B il faut tout dabord creacuteer un objet de type A donc faire appel au

constructeur de A puis le compleacuteter par ce qui est speacutecifique agrave B et faire appel au construc-

teur de B Ce meacutecanisme est pris en charge par C++ il ny aura pas agrave preacutevoir dans le cons-

tructeur de B lappel du constructeur de A

La mecircme deacutemarche sapplique aux destructeurs lors de la destruction dun objet de type B il

y aura automatiquement appel du destructeur de B puis appel de celui de A (les destructeurs

sont appeleacutes dans lordre inverse de lappel des constructeurs)

43 Transmission dinformations entre constructeursToutefois un problegraveme se pose lorsque le constructeur de A neacutecessite des arguments En

effet les informations fournies lors de la creacuteation dun objet de type B sont a priori destineacutes agrave

son constructeur En fait C++ a preacutevu la possibiliteacute de speacutecifier dans la deacutefinition dun

constructeur dune classe deacuteriveacutee les informations que lon souhaite transmettre agrave un cons-

tructeur de la classe de base Le meacutecanisme est le mecircme que celui que nous vous avons

exposeacute dans le cas des objets membres (au paragraphe 5 du chapitre 7) Par exemple si lon a

ceci

class point class pointcol public point public public point (int int) pointcol (int int char)

et que lon souhaite que pointcol retransmette agrave point les deux premiegraveres informations reccedilues

on eacutecrira son en-tecircte de cette maniegravere

pointcol (int abs int ord char cl) point (abs ord)

Le compilateur mettra en place la transmission au constructeur de point des informations abs

et ord correspondant (ici) aux deux premiers arguments de pointcol Ainsi la deacuteclaration

pointcol a (10 15 3)

entraicircnera

bull lappel de point qui recevra les arguments 10 et 15

bull lappel de pointcol qui recevra les arguments 10 15 et 3

Lrsquoheacuteritage simpleCHAPITRE 13

256

En revanche la deacuteclaration

pointcol q (5 2)

sera rejeteacutee par le compilateur puisquil nexiste aucun constructeur pointcol agrave deux argu-

ments

Bien entendu il reste toujours possible de mentionner des arguments par deacutefaut dans point-

col par exemple

pointcol (int abs = 0 int ord = 0 char cl = 1) point (abs ord)

Dans ces conditions la deacuteclaration

pointcol b (5)

entraicircnera

bull lappel de point avec les arguments 5 et 0

bull lappel de pointcol avec les arguments 5 0 et 1

Notez que la preacutesence eacuteventuelle darguments par deacutefaut dans point na aucune incidence ici

(mais on peut les avoir preacutevus pour les objets de type point)

En Java

La transmission drsquoinformations entre un constructeur drsquoune classe deacuteriveacutee et un construc-

teur drsquoune classe de base reste possible mais elle srsquoexprime de faccedilon diffeacuterente Dans un

constructeur drsquoune classe deacuteriveacutee il est neacutecessaire de preacutevoir lrsquoappel explicite drsquoun cons-

tructeur drsquoune classe de base on utilise alors le mot super pour deacutesigner la classe de

base

44 ExempleVoici un exemple complet de programme illustrant cette situation les classes point et point-

col ont eacuteteacute limiteacutees agrave leurs constructeurs et destructeurs (ce qui leur enlegraveverait bien sucircr tout

inteacuterecirct en pratique)

include ltiostreamgtsing namespace std classe point class point int x y public point (int abs=0 int ord=0) constructeur de point (inline) cout ltlt ++ constr point ltlt abs ltlt ltlt ord ltlt n x = abs y =ord ~point () destructeur de point (inline) cout ltlt -- destr point ltlt x ltlt ltlt y ltlt n

4 - Appel des constructeurs et des destructeurs257

classe pointcol class pointcol public point short couleur public pointcol (int int short) deacuteclaration constructeur pointcol ~pointcol () destructeur de pointcol (inline) cout ltlt -- dest pointcol - couleur ltlt couleur ltlt n pointcolpointcol (int abs=0 int ord=0 short cl=1) point (abs ord) cout ltlt ++ constr pointcol ltlt abs ltlt ltlt ord ltlt ltlt cl ltlt n couleur = cl programme dessai main() pointcol a(10153) objets pointcol b (23) automatiques pointcol c (12) pointcol adr adr = new pointcol (1225) 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 12 25++ constr pointcol 12 25 1-- dest pointcol - couleur 1-- destr point 12 25-- dest pointcol - couleur 1-- destr point 12 0-- dest pointcol - couleur 1-- destr point 2 3-- dest pointcol - couleur 3-- destr point 10 15

Appel des constructeurs et destructeurs de la classe de base et de la classe deacuteriveacutee

Remarque

Dans le message afficheacute par ~pointcol vous auriez peut ecirctre souhaiteacute voir apparaicirctre les

valeurs de x et de y Or cela nest pas possible du moins telle que la classe point a eacuteteacute con-

ccedilue En effet un membre dune classe deacuteriveacutee na pas accegraves aux membres priveacutes de la

classe de base Nous reviendrons sur cet aspect fondamental dans la conception de classes

reacuteutilisables

Lrsquoheacuteritage simpleCHAPITRE 13

258

45 CompleacutementsNous venons dexaminer la situation la plus usuelle la classe de base et la classe deacuteriveacutee

posseacutedaient au moins un constructeur

Si la classe de base ne possegravede pas de constructeur aucun problegraveme particulier ne se pose Il

en va de mecircme si elle ne possegravede pas de destructeur

En revanche si la classe deacuteriveacutee ne possegravede pas de constructeur alors que la classe de base

en comporte le problegraveme de la transmission des informations attendues par le constructeur

de la classe de base se pose de nouveau Comme celles-ci ne peuvent plus provenir du cons-

tructeur de la classe deacuteriveacutee on comprend que la seule situation acceptable soit celle ougrave la

classe de base dispose dun constructeur sans argument Dans les autres cas on aboutit agrave une

erreur de compilation

Par ailleurs lorsque lon mentionne les informations agrave transmettre agrave un constructeur de la

classe de base on nest pas obligeacute de se limiter comme nous lavons fait jusquici agrave des noms

darguments On peut employer nimporte quelle expression Par exemple bien que cela nait

guegravere de sens ici nous pourrions eacutecrire

pointcol (int abs int ord char cl) point (abs + ord abs - ord)

Remarque

Le cas du constructeur de recopie sera examineacute un peu plus loin car sa bonne mise en

œuvre neacutecessite la connaissance des possibiliteacutes de conversion implicite dune classe deacuteri-

veacutee en une classe de base

5 Controcircle des accegravesNous navons examineacute jusquici que la situation drsquoheacuteritage la plus naturelle cest-agrave-dire celle

dans laquelle

bull la classe deacuteriveacutee1 a accegraves aux membres publics de la classe de base

bull les utilisateurs2 de la classe deacuteriveacutee ont accegraves agrave ses membres publics ainsi quaux mem-

bres publics de sa classe de base

Comme nous allons le voir maintenant C++ permet dintervenir en partie sur ces deux sortes

dautorisation daccegraves et ce agrave deux niveaux

Lors de la conception de la classe de base en plus des statuts publics et priveacutes que nous

connaissons il existe un troisiegraveme statut dit proteacutegeacute (mot cleacute protected) Les membre pro-

1 Crsquoest-agrave-dire toute fonction membre dune classe deacuteriveacutee

2 Crsquoest-agrave-dire tout objet du type de la classe deacuteriveacutee

5 - Controcircle des accegraves259

teacutegeacutes se comportent comme des membres priveacutes pour lutilisateur de la classe deacuteriveacutee mais

comme des membres publics pour la classe deacuteriveacutee elle-mecircme

Lors de la conception de la classe deacuteriveacutee on peut restreindre les possibiliteacutes daccegraves aux

membres de la classe de base

51 Les membres proteacutegeacutesJusquici nous avons consideacutereacute quil nexistait que deux statuts possibles pour un membre

de classe

bull priveacute le membre nest accessible quaux fonctions membres (publiques ou priveacutees) et aux

fonctions amies de la classe

bull public le membre est accessible non seulement aux fonctions membres ou aux fonctions

amies mais eacutegalement agrave lutilisateur de la classe (cest-agrave-dire agrave nimporte quel objet du type

de cette classe)

Nous avons vu que lemploi des mots cleacutes public et private permettait de distinguer les mem-

bres priveacutes des membres publics

Le troisiegraveme statut ndash proteacutegeacute ndash est deacutefini par le mot cleacute protected qui semploie comme les

deux mots cleacutes preacuteceacutedents Par exemple la deacutefinition dune classe peut prendre lallure

suivante

class X private partie priveacutee protected partie proteacutegeacutee public partie publique

Les membres proteacutegeacutes restent inaccessibles agrave lutilisateur de la classe pour qui ils apparais-

sent comme des membres priveacutes Mais ils seront accessibles aux membres dune eacuteventuelle

classe deacuteriveacutee tout en restant dans tous les cas inaccessibles aux utilisateurs de cette classe

52 ExempleAu deacutebut du paragraphe 2 nous avons eacutevoqueacute limpossibiliteacute pour une fonction membre

dune classe pointcol deacuteriveacutee de point dacceacuteder aux membres priveacutes x et y de point Si nous

deacutefinissons ainsi notre classe point

class point protected int x y public point ( ) affiche ()

Lrsquoheacuteritage simpleCHAPITRE 13

260

il devient possible de deacutefinir dans pointcol une fonction membre affiche de la maniegravere

suivante

class pointcol public point short couleur public void affiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n cout ltlt et ma couleur est ltlt couleur ltlt n

53 Inteacuterecirct du statut proteacutegeacuteLes membres priveacutes dune classe sont deacutefinitivement inaccessibles depuis ce que nous

appellerons lexteacuterieur de la classe (objets de cette classe fonctions membres dune classe

deacuteriveacutee objets de cette classe deacuteriveacutee) Cela peut poser des problegravemes au concepteur dune

classe deacuteriveacutee notamment si ces membres sont des donneacutees dans la mesure ougrave il est con-

traint comme un banal utilisateur de passer par linterface obligatoire De plus cette

faccedilon de faire peut nuire agrave lefficaciteacute du code geacuteneacutereacute

Lintroduction du statut proteacutegeacute constitue donc un progregraves manifeste les membres proteacutegeacutes

se preacutesentent comme des membres priveacutes pour lutilisateur de la classe mais ils sont compa-

rables agrave des membres publics pour le concepteur dune classe deacuteriveacutee (tout en restant compa-

rables agrave des membres priveacutes pour lutilisateur de cette derniegravere) Neacuteanmoins il faut

reconnaicirctre qursquoon offre du mecircme coup les moyens de violer (consciemment) le principe

dencapsulation des donneacutees En effet rien nempecircche un utilisateur dune classe comportant

une partie proteacutegeacutee de creacuteer une classe deacuteriveacutee contenant les fonctions approprieacutees permet-

tant dacceacuteder aux donneacutees correspondantes Bien entendu il sagit dun viol conccedilu deacutelibeacutereacute-

ment par lutilisateur cela na plus rien agrave voir avec des risques de modifications

accidentelles des donneacutees

Remarques

1 Lorsquune classe deacuteriveacutee possegravede des fonctions amies ces derniegraveres disposent exacte-

ment des mecircmes autorisations daccegraves que les fonctions membres de la classe deacuteriveacutee En

particulier les fonctions amies dune classe deacuteriveacutee auront bien accegraves aux membres deacutecla-

reacutes proteacutegeacutes dans sa classe de base

2 En revanche les deacuteclarations damitieacute ne sheacuteritent pas Ainsi si f a eacuteteacute deacuteclareacutee amie

dune classe A et si B deacuterive de A f nest pas automatiquement amie de B (il est bien sucircr

possible de preacutevoir une deacuteclaration drsquoamitieacute approprieacutee dans B)

5 - Controcircle des accegraves261

En Java

Le statut proteacutegeacute existe aussi en Java mais avec une signification un peu difeacuterente les

membres proteacutegeacutes sont accessibles non seulement aux classes deacuteriveacutees mais aussi aux

classes appartenant au mecircme package (la notion de package nrsquoexiste pas en C++)

54 Deacuterivation publique et deacuterivation priveacutee

541 Rappels concernant la deacuterivation publiqueLes exemples preacuteceacutedents faisaient intervenir la forme la plus courante de deacuterivation dite

publique car introduite par le mot cleacute public dans la deacuteclaration de la classe deacuteriveacutee

comme dans

class pointcol public point

Rappelons que dans ce cas

bull Les membres publics de la classe de base sont accessibles agrave tout le monde cest-agrave-dire agrave

la fois aux fonctions membres et aux fonctions amies de la classe deacuteriveacutee ainsi quaux utili-

sateurs de la classe deacuteriveacutee

bull Les membres proteacutegeacutes de la classe de base sont accessibles aux fonctions membres et aux

fonctions amies de la classe deacuteriveacutee mais pas aux utilisateurs de cette classe deacuteriveacutee

bull Les membres priveacutes de la classe de base sont inaccessibles agrave la fois aux fonctions membres

ou amies de la classe deacuteriveacutee et aux utilisateurs de cette classe deacuteriveacutee

De plus tous les membres de la classe de base conservent dans la classe deacuteriveacutee le statut

quils avaient dans la classe de base Cette remarque nintervient quen cas de deacuterivation dune

nouvelle classe de la classe deacuteriveacutee

Voici un tableau reacutecapitulant la situation

La deacuterivation publique

Ces possibiliteacutes peuvent ecirctre restreintes en deacutefinissant ce que lon nomme des deacuterivations pri-

veacutees ou proteacutegeacutees

Statut dans la classe

de base

Accegraves aux fonctions

membres et amies de

la classe deacuteriveacutee

Accegraves agrave un utilisateur

de la classe deacuteriveacutee

Nouveau statut dans la

classe deacuteriveacutee en cas

de nouvelle deacuterivation

public oui oui public

proteacutegeacute oui non proteacutegeacute

priveacute non non priveacute

Lrsquoheacuteritage simpleCHAPITRE 13

262

542 Deacuterivation priveacuteeEn utilisant le mot cleacute private au lieu du mot cleacute public il est possible dinterdire agrave un utilisa-

teur dune classe deacuteriveacutee laccegraves aux membres publics de sa classe de base Par exemple avec

ces deacuteclarations

class point class pointcol private point public public point () pointcol () void affiche () void colore () void deplace ()

Si p est de type pointcol les appels suivants seront rejeteacutes par le compilateur1

paffiche () ou mecircme ppointaffiche () pdeplace () ou mecircme ppointdeplace ()

alors que naturellement celui-ci sera accepteacute

pcolore ()

On peut agrave juste titre penser que cette technique limite linteacuterecirct de lheacuteritage Plus preacuteciseacutement

le concepteur de la classe deacuteriveacutee peut quant agrave lui utiliser librement les membres publics de

la classe de base (comme un utilisateur ordinaire) en revanche il deacutecide de fermer totale-

ment cet accegraves agrave lutilisateur de la classe deacuteriveacutee On peut dire que lutilisateur connaicirctra tou-

tes les fonctionnaliteacutes de la classe en lisant sa deacuteclaration sans quil nait aucunement besoin

de lire celle de sa classe de base (il nen allait pas de mecircme dans la situation usuelle dans les

exemples des paragraphes preacuteceacutedents pour connaicirctre lexistence de la fonction membre

deplace pour la classe pointcol il fallait connaicirctre la deacuteclaration de point)

Cela montre que cette technique de fermeture des accegraves agrave la classe de base ne sera employeacutee

que dans des cas bien preacutecis par exemple

bull lorsque toutes les fonctions utiles de la classe de base sont redeacutefinies dans la classe deacuteriveacutee

et quil ny a aucune raison de laisser lutilisateur acceacuteder aux anciennes

bull lorsque lon souhaite adapter linterface dune classe de maniegravere agrave reacutepondre agrave certaines

exigences dans ce cas la classe deacuteriveacutee peut agrave la limite ne rien apporter de plus (pas de

nouvelles donneacutees pas de nouvelles fonctionnaliteacutes) elle agit comme la classe de base

seule son utilisation est diffeacuterente

1 A moins que lune des fonctions membres affiche ou deplace nrsquoait eacuteteacute redeacutefinie dans pointcol

5 - Controcircle des accegraves263

55 Les possibiliteacutes de deacuterivation proteacutegeacutee Depuis sa version 3 C++ dispose drsquoune possibiliteacute suppleacutementaire de deacuterivation dite deacuteriva-

tion proteacutegeacutee intermeacutediaire entre la deacuterivation publique et la deacuterivation priveacutee Dans ce cas

les membres publics de la classe de base seront consideacutereacutes comme proteacutegeacutes lors de deacuteriva-

tions ulteacuterieures

On prendra garde agrave ne pas confondre le mode de deacuterivation dune classe par rapport agrave sa

classe de base (publique proteacutegeacutee ou priveacutee) deacutefini par lun des mots public protected ou

private avec le statut des membres dune classe (public proteacutegeacute ou priveacute) deacutefini eacutegalement

par lun de ces trois mots

Remarques

1 Dans le cas dune deacuterivation priveacutee les membres proteacutegeacutes de la classe de base restent

accessibles aux fonctions membres et aux fonctions amies de la classe deacuteriveacutee En revan-

che ils seront consideacutereacutes comme priveacutes pour une deacuterivation future

2 Les expressions deacuterivation publique et deacuterivation priveacutee seront ambigueumls dans le cas

dheacuteritage multiple Plus preacuteciseacutement il faudra alors dire pour chaque classe de base

quel est le type de deacuterivation (publique ou priveacutee)

3 En toute rigueur il est possible dans une deacuterivation priveacutee ou proteacutegeacutee de laisser

public un membre de la classe de base en le redeacuteclarant explicitement comme dans cet

exemple

class pointcol private point deacuterivation priveacutee public pointaffiche() la meacutethode affiche de la classe de base point sera publique dans pointcol

Depuis la norme cette deacuteclaration peut eacutegalement se faire agrave lrsquoaide du mot cleacute using1

class pointcol private point deacuterivation priveacutee public using pointaffiche() la meacutethode affiche de la classe de base point sera publique dans pointcol

1 Dont la vocation premiegravere reste cependant lrsquoutilisation de symboles deacuteclareacutes dans des espaces de noms comme

nous le verrons au chapitre 24

Lrsquoheacuteritage simpleCHAPITRE 13

264

56 ReacutecapitulationVoici un tableau reacutecapitulant les proprieacuteteacutes des diffeacuterentes sortes de deacuterivation (la mention

Accegraves FMA signifie accegraves aux fonctions membres ou amies de la classe la mention

nouveau statut signifie statut quaura ce membre dans une eacuteventuelle classe deacuteriveacutee)

Les diffeacuterentes sortes de deacuterivation

Remarque

On voit clairement quune deacuterivation proteacutegeacutee ne se distingue dune deacuterivation priveacutee que

lorsque lon est ameneacute agrave deacuteriver de nouvelles classes de la classe deacuteriveacutee en question

En Java

Alors que Java dispose des trois statuts public proteacutegeacute (avec une signification plus large

qursquoen C++) et priveacute il ne dispose que drsquoun seul mode de deacuterivation correspondant agrave la

deacuterivation publique du C++

6 Compatibiliteacute entre classe de base et classe deacuteriveacutee

Dune maniegravere geacuteneacuterale en POO on considegravere quun objet dune classe deacuteriveacutee peut rem-

placer un objet dune classe de base ou encore que lagrave ougrave un objet de classe A est attendu tout

objet dune classe deacuteriveacutee de A peut faire laffaire

Cette ideacutee repose sur le fait que tout ce que lon trouve dans une classe de base (fonctions ou

donneacutees) se trouve eacutegalement dans la classe deacuteriveacutee De mecircme toute action reacutealisable sur

une classe de base peut toujours ecirctre reacutealiseacutee sur une classe deacuteriveacutee (ce qui ne veut pas dire

pour autant que le reacutesultat sera aussi satisfaisant dans le cas de la classe deacuteriveacutee que dans

celui de la classe de base ndash on affirme seulement quune telle action est possible ) Par exem-

ple un point coloreacute peut toujours ecirctre traiteacute comme un point il possegravede des coordonneacutees on

peut les afficher en proceacutedant comme pour celles dun point

Bien entendu les reacuteciproques de ces deux propositions sont fausses par exemple on ne peut

pas colorer un point ou sinteacuteresser agrave sa couleur

Classe de base Deacuteriveacutee publique Deacuteriveacutee proteacutegeacutee Deacuteriveacutee priveacutee

Statut initial

Accegraves FMA

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

public

proteacutegeacute

priveacute

O

O

O

O

N

N

public

proteacutegeacute

priveacute

O

N

N

proteacutegeacute

proteacuteg

priveacute

N

N

N

priveacute

priveacute

priveacute

N

N

N

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee265

On traduit souvent ces proprieacuteteacutes en disant que lrsquoheacuteritage reacutealise une relation est entre la

classe deacuteriveacutee et la classe de base1 tout objet de type pointcol est un point mais tout objet de

type point nrsquoest pas un pointcol

Cette compatibiliteacute entre une classe deacuteriveacutee et sa classe de base2 se retrouve en C++ avec

une leacutegegravere nuance elle ne sapplique que dans le cas de deacuterivation publique3 Concregravetement

cette compatibiliteacute se reacutesume agrave lexistence de conversions implicites

bull dun objet dun type deacuteriveacute dans un objet dun type de base

bull dun pointeur (ou dune reacutefeacuterence) sur une classe deacuteriveacutee en un pointeur (ou une reacutefeacuterence)

sur une classe de base

Nous allons voir lincidence de ces conversions sur les affectations entre objets dabord entre

pointeurs ensuite La derniegravere situation au demeurant la plus reacutepandue nous permettra de

mettre en eacutevidence

bull le typage statique des objets qui en deacutecoule ce point constituera en fait une introduction agrave

la notion de meacutethode virtuelle permettant le typage dynamique sur lequel repose le polymor-

phisme (qui fera lobjet du chapitre 15)

bull les risques de violation du principe dencapsulation qui en deacutecoulent

61 Conversion dun type deacuteriveacute en un type de baseSoit nos deux classes habituelles

class point class pointcol public point

Avec les deacuteclarations

point a pointcol b

laffectation

a = b

est leacutegale Elle entraicircne une conversion de b dans le type point4 et laffectation du reacutesultat agrave a

Cette affectation se fait suivant les cas

bull par appel de lopeacuterateur daffectation (de la classe point) si celui-ci a eacuteteacute surdeacutefini

bull par emploi de laffectation par deacutefaut dans le cas contraire

En revanche laffectation suivante serait rejeteacutee

b = a

1 Lrsquoappartenance drsquoun objet agrave un autre objet sous forme drsquoobjets membres reacutealisait une relation de type a (du verbe

avoir)

2 Ou lune de ses classes de base dans le cas de lrsquoheacuteritage multiple que nous aborderons au chapitre suivant

3 Ce qui se justifie par le fait que dans le cas contraire il suffirait de convertir un objet dune classe deacuteriveacutee dans le

type de sa classe de base pour passer outre la privatisation des membres publics du type de base

4 Cette conversion revient agrave ne conserver de b que ce qui est du type point Geacuteneacuteralement elle nrsquoentraicircne pas la

creacuteation drsquoun nouvel objet

Lrsquoheacuteritage simpleCHAPITRE 13

266

62 Conversion de pointeursConsideacuterons agrave nouveau une classe point et une classe pointcol deacuteriveacutee de point chacune

comportant une fonction membre affiche

class point class pointcol public point int x y short couleur public public void affiche () void affiche ()

Soit ces deacuteclarations

point adp pointcol adpc

Lagrave encore C++ autorise laffectation

adp = adpc

qui correspond agrave une conversion du type pointcol dans le type point

Laffectation inverse

adpc = adp

serait naturellement rejeteacutee Elle est cependant reacutealisable en faisant appel agrave lopeacuterateur de

cast Ainsi bien que sa signification soit discutable1 il vous sera toujours possible deacutecrire

linstruction

adpc = (pointcol ) adp

Remarque

Sil est possible de convertir explicitement un pointeur de type point en un pointeur de

type pointcol il est impossible de convertir un objet de type point en un objet de type

pointcol La diffeacuterence vient de ce que lon a affaire agrave une conversion preacutedeacutefinie dans le

premier cas2 alors que dans le second le compilateur ne peut imaginer ce que vous sou-

haitez faire

63 Limitations lieacutees au typage statique des objetsConsideacuterons les deacuteclarations du paragraphe preacuteceacutedent accompagneacutees de3

point p (3 5) pointcol pc (8 6 2) adp = amp p adpc = amp pc

1 Et mecircme dangereuse comme nous le verrons au paragraphe 64

2 Laquelle se borne en fait agrave un changement de type (sur le plan syntaxique) accompagneacute eacuteventuellement dun

alignement dadresse (attention rien ne garantit que lapplication successive des deux conversions reacuteciproques

(point ndashgt pointcol puis pointcol ndashgt point ) fournisse exactement ladresse initiale )

3 En supposant quil existe des constructeurs approprieacutes

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee267

La situation est alors celle-ci

A ce niveau linstruction

adp -gt affiche ()

appellera la meacutethode pointaffiche tandis que linstruction

adpc -gt affiche ()

appellera la meacutethode pointcolaffiche

Nous aurions obtenu les mecircmes reacutesultats avec

paffiche ()

pcaffiche ()

Si nous exeacutecutons alors laffectation

adp = adpc

nous aboutissons agrave cette situation

A ce niveau que va faire une instruction telle que

adp -gt affiche ()

Y aura-t-il appel de pointaffiche ou de pointcolaffiche

En effet adp est du type point mais lobjet pointeacute par adp est du type pointcol En fait le

choix de la meacutethode appeleacutee est reacutealiseacute par le compilateur ce qui signifie qursquoelle est deacutefinie

une fois pour toutes et ne pourra eacutevoluer au fil des changements eacuteventuels de type de lobjet

pointeacute Bien entendu dans ces conditions on comprend que le compilateur ne peut que deacuteci-

der de mettre en place lappel de la meacutethode correspondant au type deacutefini par le pointeur Ici

il sagira donc de pointaffiche puisque adp est du type point

adp

3

5

8

6

2

adpc

adp

3

5

8

6

2

adpc

Lrsquoheacuteritage simpleCHAPITRE 13

268

Notez bien que si pointcol dispose dune meacutethode colore (nexistant pas dans point) un appel

tel que

adp -gt colore (8)

sera rejeteacute par le compilateur

On peut donc dire pour linstant que le type des objets pointeacutes par adp et adpc est deacutecideacute et

figeacute au moment de la compilation On peut alors consideacuterer comme un leurre le fait que C++

tolegravere certaines conversions de pointeurs Drsquoailleurs il tolegravere celles qui au bout du compte

ne poseront pas de problegraveme vis-agrave-vis du choix fait au moment de la compilation (comme

nous lavons dit on pourra toujours afficher un pointcol comme sil sagissait dun point) En

effet nous pouvons deacutesigner agrave laide dun mecircme pointeur des objets de type diffeacuterent mais

nous navons pour linstant aucun moyen de tenir reacuteellement compte du type de lobjet pointeacute

(par exemple affiche traite un pointcol comme un point mais ne peut pas savoir sil sagit

dun point ou dun pointcol)

En reacutealiteacute nous verrons que C++ permet deffectuer cette identification dun objet au moment

de lexeacutecution (et non plus arbitrairement agrave la compilation) et de reacutealiser ce que lon nomme

le polymorphisme ou le typage dynamique (alors que jusquici nous navions affaire quagrave

du typage statique) Cela neacutecessitera lemploi de fonctions virtuelles que nous aborderons

au chapitre 15

Voici un exemple de programme illustrant les limitations que nous venons deacutevoquer Remar-

quez que dans la meacutethode affiche de pointcol nous navons pas fait appel agrave la meacutethode affi-

che de point pour quelle puisse acceacuteder aux membres x et y de point nous avons preacutevu de

leur donner le statut proteacutegeacute

include ltiostreamgtusing namespace std class point protected pour que x et y soient accessibles agrave pointcol int x y public point (int abs=0 int ord=0) x=abs y=ord void affiche () cout ltlt Je suis un point n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y cout ltlt et ma couleur est ltlt couleur ltlt n

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee269

main() point p(35) point adp = ampp pointcol pc (862) pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche () cout ltlt -----------------n adp = adpc adpc = adp serait rejeteacute adp-gtaffiche () adpc-gtaffiche ()

Je suis un point mes coordonnees sont 3 5Je suis un point colore mes coordonnees sont 8 6 et ma couleur est 2-----------------Je suis un point mes coordonnees sont 8 6Je suis un point colore mes coordonnees sont 8 6 et ma couleur est 2

Les limitations lieacutees au typage statique des objets

En Java

En Java comme en C++ il y a bien compatibiliteacute entre classe de base et classe deacuteriveacutee en

ce qui concerne lrsquoaffectation drsquoobjets (les pointeurs nrsquoexistent pas en Java) Mais il ne

faut pas oublier qursquoil srsquoagit drsquoaffectation de reacutefeacuterences (et non de copie effective) Par

ailleurs les problegravemes eacutevoqueacutes agrave propos du typage statique nrsquoexistent pas en Java la liga-

ture eacutetant toujours dynamique tout se passe en fait comme si tout objet posseacutedait des

fonctions virtuelles

64 Les risques de violation des protections de la classe de baseNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Nous avons vu quil eacutetait possible dans une classe deacuteriveacutee de rendre priveacutes les membres

publics heacuteriteacutes de la classe de base en recourrant agrave une deacuterivation priveacutee En voici un

exemple

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 lobjet a aura accegraves aux membres z et fa de A On pourra eacutecrire par exemple

Lrsquoheacuteritage simpleCHAPITRE 13

270

az = 525 afa ()

Par contre lobjet b naura pas accegraves agrave ces membres compte tenu du mot private figurant

dans la deacuteclaration de la classe B Dans ces conditions les instructions

bz = 83 bfa ()

seront rejeteacutees par le compilateur (agrave moins bien sucircr que les membres z et fa ne soient redeacutefi-

nis dans la classe B)

Neacuteanmoins lutilisateur de la classe B peut passer outre cette protection mise en place par le

concepteur de la classe en proceacutedant ainsi

A ada B adb adb = ampb ada = (A ) adb

ou encore plus briegravevement

A ada = (A ) amp b

Dans ces conditions ada contient effectivement ladresse de b (nous avons ducirc employer le

cast car noubliez pas que sinon la conversion deacuteriveacutee -gt base serait rejeteacutee) mais ada a

toujours le type A On peut donc maintenant acceacuteder aux membres publics de la classe A

alors qursquoils sont priveacutes pour la classe B Ces instructions seront accepteacutees

ada -gt z = 83 ada -gt fa ()

7 Le constructeur de recopie et lrsquoheacuteritageQuil sagisse de celui par deacutefaut ou de celui fourni explicitement nous savons que le cons-

tructeur de recopie est appeleacute en cas

bull dinitialisation dun objet par un objet de mecircme type

bull de transmission de la valeur dun objet en argument ou en retour dune fonction

Les regravegles que nous avons eacutenonceacutees au paragraphe 4 srsquoappliquent agrave tous les constructeurs

donc au constructeur de recopie Toutefois il faut aussi tenir compte de lexistence dun cons-

tructeur de recopie par deacutefaut Examinons les diverses situations possibles en supposant que

lon ait affaire aux instructions suivantes (B deacuterive de A)

class A class B public A void fct (B) fct est une fonction recevant un argument de type B B b1 () arguments eacuteventuels pour un constructeur usuelfct (b1) appel de fct agrave qui on doit transmettre b1 par valeur ce qui implique lappel dun constructeur de recopie de la classe B

Bien entendu tout ce que nous allons dire sappliquerait eacutegalement aux autres situations dini-

tialisation par recopie cest-agrave-dire au cas ougrave une fonction renverrait par valeur un reacutesultat de

type B ou encore agrave celui ougrave lon initialiserait un objet de type B avec un autre objet de type B

7 - Le constructeur de recopie et lrsquoheacuteritage271

comme dans B b2 = b1 ou encore B b2 (b1) (voir eacuteventuellement au paragraphe 3 du chapitre

7 et au paragraphe 4 du chapitre 7)

71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopieIl y a donc appel du constructeur de recopie par deacutefaut de B Rappelons que la recopie se fait

membre par membre Nous avons vu ce que cela signifiait dans le cas des objets membres

Ici cela signifie que la partie de b1 appartenant agrave la classe A sera traiteacutee comme un mem-

bre de type A On cherchera donc agrave appeler le constructeur de recopie de A pour les membres

donneacutees correspondants Rappelons que

bull si A a deacutefini un tel constructeur sous forme publique il sera appeleacute

bull srsquoil nrsquoexiste aucune deacuteclaration et aucune deacutefinition drsquoun tel constructeur on fera appel agrave la

construction par deacutefaut

Drsquoautre part il existe des situations intermeacutediaires (revoyez eacuteventuellement le paragraphe

313 du chapitre 7) Notamment si A deacuteclare un constructeur priveacute sans le deacutefinir en vue

drsquointerdire la recopie drsquoobjets de type A dans ce cas la recopie drsquoobjets de type B srsquoen trou-

vera eacutegalement interdite

Remarque

Cette geacuteneacuteralisation de la recopie membre par membre aux classes deacuteriveacutees pourrait lais-

ser supposer qursquoil en ira de mecircme pour lrsquoopeacuterateur drsquoaffectation (dont nous avons vu qursquoil

fonctionnait de faccedilon semblable agrave la recopie) En fait ce ne sera pas le cas nous y

reviendrons au paragraphe 8

72 La classe deacuteriveacutee deacutefinit un constructeur de recopieLe constructeur de recopie de B est alors naturellement appeleacute Mais la question qui se pose

est de savoir srsquoil y a appel drsquoun constructeur de A En fait C++ a deacutecideacute de ne preacutevoir aucun

appel automatique de constructeur de la classe de base dans ce cas (mecircme srsquoil existe un cons-

tructeur de recopie dans A ) Cela signifie que

Mais il reste possible drsquoutiliser le meacutecanisme de transmission drsquoinformations entre construc-

teurs (eacutetudieacutee au paragraphe 43) Ainsi si le constructeur de B preacutevoit des informations pour

un constructeur de A avec un en-tecircte de la forme

B (B amp x) A ()

il y aura appel du constructeur correspondant de A

Le constructeur de recopie de la classe deacuteriveacutee doit prendre en charge lrsquointeacutegra-liteacute de la recopie de lrsquoobjet et non seulement de sa partie heacuteriteacutee

Lrsquoheacuteritage simpleCHAPITRE 13

272

En geacuteneacuteral on souhaitera que le constructeur de A appeleacute agrave ce niveau soit le constructeur de

recopie de A1 Dans ces conditions on voit que ce constructeur doit recevoir en argument

non pas lrsquoobjet x tout entier mais seulement ce qui dans x est de type A Crsquoest lagrave qursquointer-

vient la possibiliteacute de conversion implicite drsquoune classe deacuteriveacutee dans une classe de base (eacutetu-

dieacutee au paragraphe 6) Il nous suffira de deacutefinir ainsi notre constructeur pour aboutir agrave une

recopie satisfaisante

B (B amp x) A (x) x de type B est converti dans le type A pour ecirctre

transmis au constructeur de recopie de A

recopie de la partie de x speacutecifique agrave B (non heacuteriteacutee de A)

Voici un programme illustrant cette possibiliteacute Nous deacutefinissons simplement nos deux clas-

ses habituelles point et pointcol en les munissant toutes les deux dun constructeur de reco-

pie2 et nous provoquons lappel de celui de pointcol en appelant une fonction fct agrave un

argument de type pointcol transmis par valeur

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur usuel

x = abs y = ord

cout ltlt ++ point ltlt x ltlt ltlt y ltlt n

point (point amp p) constructeur de recopie

x = px y = py

cout ltlt CR point ltlt x ltlt ltlt y ltlt n

class pointcol public point

char coul

public

pointcol (int abs=0 int ord=0 int cl=1) point (abs ord) constr usuel

coul = cl

cout ltlt ++ pointcol ltlt int(coul) ltlt n

1 Bien entendu en theacuteorie il reste possible au constructeur par recopie de la classe deacuteriveacutee B drsquoappeler nrsquoimporte

quel constructeur de A autre que son constructeur par recopie Il faut alors ecirctre en mesure de reporter convenable-

ment dans lrsquoobjet les valeurs de la partie de x qui est un A Dans certains cas on pourra encore y parvenir par le

meacutecanisme de transmission drsquoinformations entre constructeurs Sinon il faudra effectuer le travail au sein du cons-

tructeur de recopie de B ce qui peut srsquoaveacuterer deacutelicat compte tenu drsquoeacuteventuels problegravemes de droits drsquoaccegraves

2 Ce qui dans ce cas preacutecis de classe ne comportant pas de pointeurs nest pas utile la recopie par deacutefaut deacutecrite

preacuteceacutedemment saveacuterant suffisante dans tous les cas Mais ici lobjectif est simplement dillustrer le meacutecanisme de

transmission drsquoinformations entre constructeurs

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage273

pointcol (pointcol amp p) point (p) constructeur de recopie

il y aura conversion implicite

de p dans le type point

coul = pcoul

cout ltlt CR pointcol ltlt int(coul) ltlt n

void fct (pointcol pc)

cout ltlt entree dans fct n

main()

void fct (pointcol)

pointcol a (234)

fct (a) appel de fct agrave qui on transmet a par valeur

++ point 2 3

++ pointcol 4

CR point 2 3

CR pointcol 4

entree dans fct

Pour forcer lappel dun constructeur de recopie de la classe de base

8 Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritageNous avons expliqueacute comment C++ deacutefinit laffectation par deacutefaut entre deux objets de

mecircme type Dautre part nous avons montreacute qursquoil eacutetait possible de surdeacutefinir cet opeacuterateur

drsquoaffectation (obligatoirement sous la forme dune fonction membre)

Voyons ce que deviennent ces possibiliteacutes en cas dheacuteritage Supposons que la classe B heacuterite

(publiquement) de A et consideacuterons comme nous lavons fait pour le constructeur de recopie

(paragraphe 7) les diffeacuterentes situations possibles

81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur =Lrsquoaffectation de deux objets de type B se deacuteroule membre agrave membre en consideacuterant que la

partie heacuteriteacutee de A constitue un membre Ainsi les membres propres agrave B sont traiteacutes par

lrsquoaffectation preacutevue pour leur type (par deacutefaut ou surdeacutefinie) La partie heacuteriteacutee de A est traiteacutee

par lrsquoaffectation preacutevue dans la classe A crsquoest-agrave-dire

bull par lrsquoopeacuterateur = surdeacutefini dans A srsquoil existe et qursquoil est public

bull par lrsquoaffectation par deacutefaut de A si lrsquoopeacuterateur = nrsquoa pas eacuteteacute redeacutefini du tout

Lrsquoheacuteritage simpleCHAPITRE 13

274

On notera bien que si lrsquoopeacuterateur = a eacuteteacute surdeacutefini sous forme priveacutee dans A son appel ne

pourra pas se faire pour un objet de type B (en dehors des fonctions membres de B) Lrsquointer-

diction de lrsquoaffectation dans A entraicircne donc drsquooffice celle de lrsquoaffectation dans B

On retrouve un comportement tout agrave fait analogue agrave celui deacutecrit dans le cas du constructeur

de recopie

82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur =Laffectation de deux objets de type B fera alors neacutecessairement appel agrave lopeacuterateur = deacutefini

dans B Celui de A ne sera pas appeleacute mecircme sil a eacuteteacute surdeacutefini Il faudra donc que lopeacutera-

teur = de B prenne en charge tout ce qui concerne laffectation dobjets de type B y

compris pour ce qui est des membres heacuteriteacutes de A

Voici un premier exemple de programme illustrant cela la classe pointcol deacuterive de point

Les deux classes ont surdeacutefini lopeacuterateur =

include ltiostreamgtusing namespace std class point protected int x y public point (int abs=0 int ord=0) x=abs y=ord point amp operator = (point amp a) x = ax y = ay cout ltlt operateur = 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 amp operator = (pointcol amp b) coul = bcoul cout ltlt operateur = de pointcoln return this void affiche () cout ltlt pointcol ltlt x ltlt ltlt y ltlt ltlt coul ltlt n main() pointcol p(1 3 10) q(4 9 20) cout ltlt p = paffiche () cout ltlt q avant = qaffiche () q = p cout ltlt q apres = qaffiche ()

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage275

p = pointcol 1 3 10

q avant = pointcol 4 9 20

operateur = de pointcol

q apres = pointcol 4 9 10

Quand la classe de base et la classe deacuteriveacutee surdeacutefinissent lopeacuterateur =

On voit clairement que lopeacuterateur = deacutefini dans la classe point na pas eacuteteacute appeleacute lors dune

affectation entre objets de type pointcol

Le problegraveme est voisin de celui rencontreacute agrave propos du constructeur de recopie avec cette dif-

feacuterence quon ne dispose plus ici du meacutecanisme de transfert drsquoarguments qui en permettait un

appel (presque) implicite Si lon veut pouvoir profiter de lopeacuterateur = deacutefini dans A il fau-

dra lappeler explicitement Le plus simple pour ce faire est dutiliser les possibiliteacutes de con-

versions de pointeurs examineacutees au paragraphe preacuteceacutedent

Voici comment nous pourrions modifier en ce sens lopeacuterateur = de pointcol

pointcol amp operator = (pointcol amp b)

point ad1 ad2

cout ltlt opeacuterateur = de pointcoln

ad1 = this conversion pointeur sur pointcol en pointeur sur point

ad2 = amp b idem

ad1 = ad2 affectation de la partie point de b

coul = bcoul affectation de la partie propre agrave pointcol

return this

Nous convertissons les pointeurs (this et ampb) sur des objets de pointcol en des pointeurs sur

des objets de type point Il suffit ensuite de reacutealiser une affectation entre les nouveaux objets

pointeacutes ( ad1 et ad2) pour entraicircner lappel de lopeacuterateur = de la classe point Voici le nou-

veau programme complet ainsi modifieacute Cette fois les reacutesultats montrent que laffectation

entre objets de type pointcol est satisfaisante

include ltiostreamgt

using namespace std

class point

protected

int x y

public

point (int abs=0 int ord=0) x=abs y=ord

point amp operator = (point amp a)

x = ax y = ay

cout ltlt operateur = de point n

return this

Lrsquoheacuteritage simpleCHAPITRE 13

276

class pointcol public point

protected

int coul

public

pointcol (int abs=0 int ord=0 int cl=1) point (abs ord) coul=cl

pointcol amp operator = (pointcol amp b)

point ad1 ad2

cout ltlt operateur = de pointcoln

ad1 = this conversion pointeur sur pointcol en pointeur sur point

ad2 = amp b idem

ad1 = ad2 affectation de la partie point de b

coul = bcoul affectation de la partie propre agrave pointcol

return this

void affiche ()

cout ltlt pointcol ltlt x ltlt ltlt y ltlt ltlt coul ltlt n

main()

pointcol p(1 3 10) q(4 9 20)

cout ltlt p = paffiche ()

cout ltlt q avant = qaffiche ()

q = p

cout ltlt q apres = qaffiche ()

p = pointcol 1 3 10

q avant = pointcol 4 9 20

operateur = de pointcol

operateur = de point

q apres = pointcol 1 3 10

Comment forcer dans une classe deacuteriveacutee lutilisation de lopeacuterateur = surdeacutefini dans la classe de base

Remarque

On dit souvent quen C++ lopeacuterateur drsquoaffectation nest pas heacuteriteacute Une telle affirmation

est en fait source de confusions En effet on peut consideacuterer quelle est exacte car lorsque

B na pas deacutefini lopeacuterateur = on ne se contente pas de faire appel agrave celui deacutefini (eacuteventuel-

lement) dans A (ce qui reviendrait agrave reacutealiser une affectation partielle ne concernant que la

partie heacuteriteacutee de A ) En revanche on peut consideacuterer que cette affirmation est fausse

puisque lorsque B ne surdeacutefinit pas lopeacuterateur = cette classe peut quand mecircme profi-

ter (automatiquement) de lopeacuterateur deacutefini dans A

9 - Heacuteritage et forme canonique dune classe277

9 Heacuteritage et forme canonique dune classeAu paragraphe 4 du chapitre 9 nous avons deacutefini ce que lon nomme la forme canonique

dune classe cest-agrave-dire le canevas selon lequel devrait ecirctre construite toute classe disposant

de pointeurs

En tenant compte de ce qui a eacuteteacute preacutesenteacute aux paragraphes 7 et 8 de ce chapitre voici com-

ment ce scheacutema pourrait ecirctre geacuteneacuteraliseacute dans le cadre de lrsquoheacuteritage (par souci de briegraveveteacute

certaines fonctions ont eacuteteacute placeacutees en ligne) On trouve

bull une classe de base nommeacutee T respectant la forme canonique deacutejagrave preacutesenteacutee

bull une classe deacuteriveacutee nommeacutee U respectant elle aussi la forme canonique mais sappuyant sur

certaines des fonctionnaliteacutes de sa classe de base (constructeur par recopie et opeacuterateur drsquoaf-

fectation)

class T public T () constructeurs de T autres que par recopie T (const T amp) constructeur de recopie de T (forme conseilleacutee) ~T () destructeur T amp Toperator = (const T amp) opeacuterateur daffectation (forme conseilleacutee)

class U public T public U () constructeurs autres que recopie U (const U amp x) T (x) constructeur recopie de U utilise celui de T preacutevoir ici la copie de la partie de x speacutecifique agrave T (qui nest pas un T) ~U () U amp Uoperator = (const U amp x) opeacuterateur daffectation (forme conseilleacutee) T ad1 = this ad2 = ampx ad1 = ad2 affectation (agrave lobjet courant) de la partie de x heacuteriteacutee de T preacutevoir ici laffectation (agrave lobjet courant) de la partie de x speacutecifique agrave U (non heacuteriteacutee de T)

Forme canonique dune classe deacuteriveacutee

Remarque

Rappelons que si T deacutefinit un constructeur de recopie priveacute la recopie drsquoobjets de type U

sera eacutegalement interdite agrave moins bien sucircr de deacutefinir dans U un constructeur par recopie

public prenant en charge lrsquointeacutegraliteacute de lrsquoobjet (il pourra eacuteventuellement srsquoappuyer sur

Lrsquoheacuteritage simpleCHAPITRE 13

278

un constructeur par recopie priveacute de T agrave condition qursquoil nrsquoait pas eacuteteacute preacutevu de corps

vide )

De mecircme si T deacutefinit un opeacuterateur drsquoaffectation priveacute lrsquoaffectation drsquoobjets de type U

sera eacutegalement interdite si lrsquoon ne redeacutefinit pas un opeacuterateur drsquoaffectation public dans

U

Ainsi drsquoune maniegravere geacuteneacuterale proteacuteger une classe contre les recopies et les affectations

protegravege du mecircme coup ses classes deacuteriveacutees

10 Lrsquoheacuteritage et ses limitesNous avons vu comment une classe deacuteriveacutee peut tirer parti des possibiliteacutes dune classe de

base Si lrsquoon dit parfois quelle heacuterite de ses fonctionnaliteacutes lrsquoexpression peut precircter agrave con-

fusion en laissant croire que lrsquoheacuteritage est plus geacuteneacuteral quil ne lest en reacutealiteacute

Prenons lexemple dune classe point qui a surdeacutefini lopeacuterateur + (point + point -gt point) et

dune classe pointcol qui heacuterite publiquement de point (et qui ne redeacutefinit pas +) Pourra-t-

elle utiliser cette fonctionnaliteacute de la classe point quest lopeacuterateur + En fait un certain

nombre de choses sont floues La somme de deux points coloreacutes sera-t-elle un point coloreacute

Si oui quelle pourrait bien ecirctre sa couleur Sera-t-elle simplement un point Dans ce cas on

ne peut pas vraiment dire que pointcol a heacuteriteacute des possibiliteacutes daddition de point

Prenons maintenant un autre exemple celui de la classe point munie dune fonction (mem-

bre ou amie) coincide telle que nous lavions consideacutereacutee au paragraphe 1 du chapitre 8 et une

classe pointcol heacuteritant de point Cette fonction coincide pourra-t-elle (telle quelle est) ecirctre

utiliseacutee pour tester la coiumlncidence de deux points coloreacutes

Nous vous proposons dapporter des eacuteleacutements de reacuteponse agrave ces diffeacuterentes questions Pour ce

faire nous allons preacuteciser ce quest lrsquoheacuteritage ce qui nous permettra de montrer que les situa-

tions deacutecrites ci-dessus ne relegravevent pas (uniquement) de cette notion Nous verrons ensuite

comment la conjugaison de lrsquoheacuteritage et des regravegles de compatibiliteacute entre objets deacuteriveacutes (dont

nous avons parleacute ci-dessus) permet de donner un sens agrave certaines des situations eacutevoqueacutees les

autres neacutecessiteront le recours agrave des moyens suppleacutementaires (conversions par exemple)

101La situation dheacuteritageConsideacuterons ce canevas (t deacutesignant un type quelconque)

class A class B public A

public

t f()

10 - Lrsquoheacuteritage et ses limites279

La classe A possegravede une fonction membre f (dont nous ne preacutecisons pas ici les arguments)

fournissant un reacutesultat de type t (type de base ou deacutefini par lutilisateur) La classe B heacuterite

des membres publics de A donc de f Soient deux objets a et b

A a B b

Bien entendu lappel

af ()

a un sens et fournit un reacutesultat de type t

Le fait que B heacuterite publiquement de A permet alors daffirmer que lappel

bf ()

a lui aussi un sens autrement dit que f agira sur b (ou avec b) comme sil eacutetait du type A Son

reacutesultat sera toujours de type t et ses arguments auront toujours le type imposeacute par son proto-

type

Tout lheacuteritage est contenu dans cette affirmation agrave laquelle il faut absolument se tenir Expli-

quons-nous

1011 Le type du reacutesultat de lappelGeacuteneacuteralement tant que t est un type usuel laffirmation ci-dessus semble eacutevidente Mais des

doutes apparaissent degraves que t est un type objet surtout sil sagit du type de la classe dont f est

membre Ainsi avec le prototype

A f()

le reacutesultat de lappel bf() sera bien de type A (et non de type B comme on pourrait parfois

le souhaiter)

Cette limitation se trouvera toutefois leacutegegraverement atteacutenueacutee dans le cas de fonctions renvoyant

des pointeurs ou des reacutefeacuterences comme on le verra au paragraphe 43 du chapitre 15 On y

apprendra en effet que les fonctions virtuelles pourront alors disposer de valeurs de retours

covariantes crsquoest-agrave-dire susceptibles de deacutependre du type de lrsquoobjet concerneacute

1012 Le type des arguments de fLa remarque faite agrave propos de la valeur de retour sapplique aux arguments de f Par exemple

supposons que f ait pour prototype

t f(A)

et que nous ayons deacuteclareacute

A a1 a2 B b1 b2

Lheacuteritage (public) donne effectivement une signification agrave

b1f(a1)

Quant agrave lappel

b1f(b2)

sil a un sens cest gracircce agrave lexistence de conversions implicites

bull de lobjet b1 de type B en un objet du type A si f reccediloit son argument par valeur noubliez

pas qualors il y aura appel dun constructeur de recopie (par deacutefaut ou surdeacutefini)

bull dune reacutefeacuterence agrave b1 de type B en une reacutefeacuterence agrave un objet de type A si f reccediloit ses arguments

par reacutefeacuterence

Lrsquoheacuteritage simpleCHAPITRE 13

280

102ExemplesRevenons maintenant aux exemples eacutevoqueacutes en introduction de ce paragraphe

1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point

En fait que lopeacuterateur + soit deacutefini sous la forme dune fonction membre ou dune fonction

amie la somme de deux objets a et b de type pointcol sera de type point En effet dans le

premier cas lexpression

a + b

sera eacutevalueacutee comme

aoperator+ (b)

Il y aura appel de la fonction membre operator+1 pour lobjet a (dont on ne consideacuterera que

ce qui est du type point) agrave laquelle on transmettra en argument le reacutesultat de la conversion de

b en un point2 Son reacutesultat sera de type point

Dans le second cas lexpression sera eacutevalueacutee comme

operator+ (a b)

Il y aura appel de la fonction amie3 operator+ agrave laquelle on transmettra le reacutesultat de la con-

version de a et b dans le type point Le reacutesultat sera toujours de type point

Dans ces conditions vous voyez que si c est de type pointcol une banale affectation telle

que

c = a + b

sera rejeteacutee faute de disposer de la conversion de point en pointcol On peut dailleurs logi-

quement se demander quelle couleur une telle conversion pourrait attribuer agrave son reacutesultat Si

maintenant on souhaite deacutefinir la somme de deux points coloreacutes il faudra redeacutefinir lopeacutera-

teur + au sein de pointcol quitte agrave ce quil fasse appel agrave celui deacutefini dans point pour la somme

des coordonneacutees

1022 Heacuteritage dans pointcol de la fonction coincide de point

Cette fois il est facile de voir quaucun problegraveme particulier ne se pose4 agrave partir du moment

ougrave lon considegravere que la coiumlncidence de deux points coloreacutes correspond agrave leacutegaliteacute de leurs

seules coordonneacutees (la couleur nintervenant pas)

A titre indicatif voici un exemple de programme complet dans lequel coincide est deacutefini

comme une fonction membre de point

1 Fonction membre de pointcol mais heacuteriteacutee de point

2 Selon les cas il y aura conversion dobjets ou conversion de reacutefeacuterences

3 Amie de point et de pointcol par heacuteritage mais ici cest seulement la relation damitieacute avec point qui est

employeacutee

4 Mais ici le reacutesultat fourni par coincide nest pas dun type classe

11 - Exemple de classe deacuteriveacutee281

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend int coincide (point amp point amp) int coincide (point amp p point amp q) if ((px == qx) ampamp (py == qy)) return 1 else return 0 class pointcol public point short couleur public pointcol (int abs=0 int ord=0 short cl=1) point (abs ord) couleur = cl main() programme dessai pointcol a(253) b(259) c if (coincide (ab)) cout ltlt a coincide avec b n else cout ltlt a et b sont diffeacuterents n if (coincide (ac)) cout ltlt a coincide avec c n else cout ltlt a et c sont differents n

a coincide avec b a et c sont differents

Heacuteritage dans pointcol de la fonction coincide de point

11 Exemple de classe deacuteriveacuteeSupposons que nous disposions de la classe vect telle que nous lavons deacutefinie au paragraphe

5 du chapitre 9 Cette classe est munie dun constructeur dun destructeur et dun opeacuterateur

dindiccedilage [] (notez bien que pour ecirctre exploitable cette classe qui contient des parties dyna-

miques devrait comporter eacutegalement un constructeur par recopie et la surdeacutefinition de lopeacute-

rateur daffectation)

class vect int nelem int adr public vect (int n) adr = new int [nelem=n] ~vect () delete adr int amp operator [] (int) int amp vectoperator [] (int i) return adr[i]

Lrsquoheacuteritage simpleCHAPITRE 13

282

Supposons maintenant que nous ayons besoin de vecteurs dans lesquels on puisse fixer non

seulement le nombre deacuteleacutements mais les bornes (minimum et maximum) des indices (sup-

poseacutes ecirctre toujours de type entier) Par exemple nous pourrions deacuteclarer (si vect1 est le nom

de la nouvelle classe)

vect1 t (15 24)

ce qui signifierait que t est un tableau de dix entiers dindices variant de 15 agrave 24

Il semble alors naturel dessayer de deacuteriver une classe de vect Il faut preacutevoir deux membres

suppleacutementaires pour conserver les bornes de lindice dougrave le deacutebut de la deacuteclaration de notre

nouvelle classe

class vect1 public vect int debut fin

Manifestement vect1 neacutecessite un constructeur agrave deux arguments entiers correspondant aux

bornes de lindice Son en-tecircte sera de la forme

vect1 (int d int f)

Mais lappel de ce constructeur entraicircnera automatiquement celui du constructeur de vect Il

nest donc pas question de faire dans vect1 lallocation dynamique de notre vecteur Au con-

traire nous reacuteutilisons le travail effectueacute par vect il nous suffit de lui transmettre le nombre

deacuteleacutements souhaiteacutes dougrave len-tecircte complet de vect1

vect1 (int d int f) vect (f-d+1)

Quant agrave la tacircche speacutecifique de vect1 elle se limite agrave renseigner les valeurs de debut et fin

A priori la classe vect1 na pas besoin de destructeur puisqursquoelle nalloue aucun emplace-

ment dynamique autre que celui deacutejagrave alloueacute par vect

Nous pourrions aussi penser que vect1 na pas besoin de surdeacutefinir lopeacuterateur [] dans la

mesure ougrave elle heacuterite de celui de vect Quen est-il exactement Dans vect la fonction

membre operator[] reccediloit un argument implicite et un argument de type int elle fournit une

valeur de type int Sur ce plan lrsquoheacuteritage fonctionnera donc correctement et C++ acceptera

quon fasse appel agrave operator[] pour un objet de type deacuteriveacute vect1 Ainsi avec

vect1 t (15 24)

la notation

t[i]

qui signifiera

toperator[] (i)

aura bien une signification

Le seul ennui est que cette notation deacutesignera toujours le iegraveme eacuteleacutement du tableau dynamique

de lobjet t Et ce nest plus ce que nous voulons Il nous faut donc surdeacutefinir lopeacuterateur []

pour la classe vect1

A ce niveau deux solutions au moins soffrent agrave nous

bull utiliser lopeacuterateur existant dans vect ce qui nous conduit agrave

int amp operator[] (int i) return vectoperator[] (i-debut)

11 - Exemple de classe deacuteriveacutee283

bull ne pas utiliser lopeacuterateur existant dans vect ce qui nous conduirait agrave

int amp operator [] (int i)

return adr [i-debut]

(agrave condition que adr soit accessible agrave la fonction operator [] donc deacuteclareacute public ou plus

raisonnablement priveacute)

Cette derniegravere solution paraicirct peut-ecirctre plus seacuteduisante1

Voici un exemple complet faisant appel agrave la premiegravere solution Nous avons fait figurer la

classe vect elle-mecircme pour faciliter son examen et introduit comme agrave lrsquoaccoutumeacutee quel-

ques affichages dinformation au sein de certaines fonctions membres de vect et de vect1

include ltiostreamgt

using namespace std la classe vect

class vect int nelem nombre deacuteleacutements int adr pointeur sur ces eacuteleacutements

public vect (int n) constructeur vect

adr = new int [nelem = n] cout ltlt + Constr vect de taille ltlt n ltlt n

~vect () destructeur vect

cout ltlt - Destr vect delete adr

int amp operator [] (int)

int amp vectoperator [] (int i) return adr[i]

la classe deacuteriveacutee vect1

class vect1 public vect int debut fin

public vect1 (int d int f) vect (f - d + 1) constructeur vect1

cout ltlt ++ Constr vect1 - bornes ltlt d ltlt ltlt f ltlt n debut = d fin = f

int amp operator [] (int)

int amp vect1operator [] (int i) return vectoperator [] (i-debut)

1 Du moins ici car le travail agrave effectuer eacutetait simple En pratique on cherchera plutocirct agrave reacutecupeacuterer le travail deacutejagrave

effectueacute en se contentant de le compleacuteter si neacutecessaire

Lrsquoheacuteritage simpleCHAPITRE 13

284

un programme dessai

main()

const int MIN=15 MAX = 24

vect1 t(MIN MAX)

int i

for (i=MIN ilt=MAX i++) t[i] = i

for (i=MIN ilt=MAX i++) cout ltlt t[i] ltlt

cout ltlt n

+ Constr vect de taille 10

++ Constr vect1 - bornes 15 24

15 16 17 18 19 20 21 22 23 24

- Destr vect

Remarque

Bien entendu lagrave encore pour ecirctre exploitable la classe vect1 devrait deacutefinir un construc-

teur par recopie et lopeacuterateur daffectation A ce propos on peut noter quil reste possible

de deacutefinir ces deux fonctions dans vect1 mecircme si elles nont pas eacuteteacute deacutefinies correctement

dans vect

12 Patrons de classes et heacuteritageIl est tregraves facile de combiner la notion dheacuteritage avec celle de patron de classes Cette combi-

naison peut revecirctir plusieurs aspects

bull Classe ordinaire deacuteriveacutee dune classe patron (cest-agrave-dire dune instance particuliegravere

dun patron de classes) Par exemple si A est une classe patron deacutefinie par template ltclass

Tgt A

class B public A ltintgt B deacuterive de la classe patron Altintgt

on obtient une seule classe nommeacutee B

bull Patron de classes deacuteriveacute dune classe ordinaire Par exemple A eacutetant une classe

ordinaire

template ltclass Tgt class B public A

on obtient une famille de classes (de paramegravetre de type T) Laspect patron a eacuteteacute introduit

ici au moment de la deacuterivation

12 - Patrons de classes et heacuteritage285

bull Patron de classes deacuteriveacute dun patron de classes Cette possibiliteacute peut revecirctir deux aspects

selon que lon introduit ou non de nouveaux paramegravetres lors de la deacuterivation Par exemple

si A est une classe patron deacutefinie par template ltclass Tgt A on peut

ndash deacutefinir une nouvelle famille de fonctions deacuteriveacutees par

template ltclass Tgt class B public A ltTgt

Dans ce cas il existe autant de classes deacuteriveacutees possibles que de classes de base possi-

bles

ndash deacutefinir une nouvelle famille de fonctions deacuteriveacutees par

template ltclass T class Ugt class B public A ltTgt

Dans ce cas on peut dire que chaque classe de base possible peut engendrer une famille

de classes deacuteriveacutees (de paramegravetre de type U)

Dune maniegravere geacuteneacuterale vous pouvez jouer agrave votre greacute avec les paramegravetres crsquoest-agrave-dire en

introduire ou en supprimer agrave volonteacute

Voici trois exemples correspondant agrave certaines des situations que nous venons deacutevoquer

121Classe ordinaire deacuterivant dune classe patronIci nous avons deacuteriveacute de la classe patron pointltintgt une classe ordinaire nommeacutee

point_int

include ltiostreamgtusing namespace std template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

class pointcol_int public point ltintgt int coul public pointcol_int (int abs=0 int ord=0 int cl=1) point ltintgt (abs ord) coul = cl void affiche ()

pointltintgtaffiche () cout ltlt couleur ltlt coul ltlt n main () point ltfloatgt pf (35 28) pfaffiche () instanciation classe patron pointcol_int p (3 5 9) paffiche () emploi (classique) de la classe pointcol_int

Lrsquoheacuteritage simpleCHAPITRE 13

286

Coordonnees 35 28Coordonnees 3 5 couleur 9

122Deacuterivation de patrons avec les mecircmes paramegravetresA partir du patron template ltclass Tgt class point nous deacuterivons un patron nommeacute pointcol

dans lequel le nouveau membre introduit est du mecircme type T que les coordonneacutees du point

include ltiostreamgtusing namespace std

template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

template ltclass Tgt class pointcol public point ltTgt T coul public pointcol (T abs=0 T ord=0 T cl=1) point ltTgt (abs ord) coul = cl void affiche () pointltTgtaffiche () cout ltlt couleur ltlt coul

main () point ltlonggt p (34 45) paffiche () pointcol ltshortgt q (12 45 5) qaffiche ()

Coordonnees 34 45Coordonnees 12 45couleur 5

123Deacuterivation de patrons avec introduction drsquoun nouveau paramegravetre

A partir du patron template ltclass Tgt class point nous deacuterivons un patron nommeacute pointcol

dans lequel le nouveau membre introduit est dun type U diffeacuterent de celui des coordonneacutees

du point

include ltiostreamgtusing namespace std

13 - Lrsquoheacuteritage en pratique287

template ltclass Tgt class point

T x T y public

point (T abs=0 T ord=0) x = abs y = ord

void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

template ltclass T class Ugt class pointcol public point ltTgt U coul

public

pointcol (T abs=0 T ord=0 U cl=1) point ltTgt (abs ord) coul = cl

void affiche ()

pointltTgtaffiche () cout ltlt couleur ltlt coul ltlt n

main ()

un point agrave coordonneacutees de type float et couleur de type int pointcol ltfloat intgt p (35 28 12) paffiche ()

un point agrave coordonneacutees de type unsigned long et couleur de type short

pointcol ltunsigned long shortgt q (295467 345789 8) qaffiche ()

Coordonnees 35 28

couleur 12Coordonnees 295467 345789

couleur 8

13 Lrsquoheacuteritage en pratiqueCe paragraphe examine quelques points qui interviennent dans la mise en application de

lrsquoheacuteritage Tout drsquoabord nous montrerons que la technique peut ecirctre iteacutereacutee autant de fois

qursquoon le souhaite en utilisant des deacuterivations successives Puis nous verrons que lrsquoheacuteritage

peut ecirctre utiliseacute dans des buts relativement diffeacuterents Enfin nous examinerons la maniegravere de

mettre en oeuvre les diffeacuterentes compilations et eacuteditions de liens rendues geacuteneacuteralement

neacutecessaires dans le cadre de lrsquoheacuteritage

131Deacuterivations successivesNous venons drsquoexposer les principes de base de lrsquoheacuteritage en nous limitant agrave des situations ne

faisant intervenir que deux classes agrave la fois une classe de base et une classe deacuteriveacutee

En fait ces notions de classe de base et de classe deacuteriveacutee sont relatives puisque

bull drsquoune mecircme classe peuvent ecirctre deacuteriveacutees plusieurs classes diffeacuterentes (eacuteventuellement uti-

liseacutees au sein dun mecircme programme)

bull une classe deacuteriveacutee peut agrave son tour servir de classe de base pour une autre classe deacuteriveacutee

Lrsquoheacuteritage simpleCHAPITRE 13

288

Autrement dit les diffeacuterentes classes deacuteriveacutees dune mecircme classe de base peuvent ecirctre repreacute-

senteacutees par une arborescence telle que

Ici D est deacuteriveacutee de B elle-mecircme deacuteriveacutee de A (on dit aussi que D heacuterite de B qui elle-

mecircme heacuterite de A) Pour traduire la relation existant entre A et D on dira que D est une des-

cendante de A ou encore que A est une ascendante de D Naturellement D est aussi une des-

cendante de B lorsquon aura besoin drsquoecirctre plus preacutecis on dira que D est une descendante

directe de B

Par ailleurs depuis la version 2 C++ eacutelargit les possibiliteacutes dheacuteritage en introduisant ce que

lon nomme lrsquoheacuteritage multiple une classe donneacutee peut heacuteriter simultaneacutement de plusieurs

classes Dans ces conditions on na plus affaire agrave une arborescence de classes mais agrave un gra-

phe qui peut eacuteventuellement devenir complexe

En voici un exemple simple

Tout ce qui a eacuteteacute dit jusquagrave maintenant srsquoeacutetend sans aucun problegraveme agrave toutes les situations

dheacuteritage simple (syntaxe appel des constructeurs) Dune maniegravere geacuteneacuterale lorsque nous

parlerons dune classe deacuteriveacutee dune classe de base il pourra sagir dune descendante quel-

conque (directe ou non) De mecircme lorsque nous parlerons de deacuterivation publique il faudra

comprendre que la classe concerneacutee sobtient par une ou plusieurs deacuterivations successives

publiques de sa classe de base Notez quil suffit quune seule de ces deacuterivations soit priveacutee

pour quau bout du compte on parle globalement de deacuterivation priveacutee

A

B C

D E F G

13 - Lrsquoheacuteritage en pratique289

En ce qui concerne les situations drsquoheacuteritage multiple leur mise en œuvre neacutecessite quelques

connaissances suppleacutementaires Nous avons preacutefeacutereacute les regrouper au chapitre 14 notamment

parce que leur usage est peu reacutepandu

132Diffeacuterentes utilisations de lrsquoheacuteritageLrsquoheacuteritage peut ecirctre utiliseacute dans deux buts tregraves diffeacuterents

Par exemple face agrave un problegraveme donneacute il se peut qursquoon dispose deacutejagrave drsquoune classe qui le

reacutesolve partiellement On peut alors creacuteer une classe deacuteriveacutee qursquoon complegravete de faccedilon agrave

reacutepondre agrave lrsquoensemble du problegraveme On gagne alors du temps de programmation puisquon

reacuteutilise une partie de logiciel Mecircme si lon nexploite pas toutes les fonctions de la classe de

deacutepart on ne sera pas trop peacutenaliseacute dans la mesure ougrave les fonctions non utiliseacutees ne seront pas

incorporeacutees agrave leacutedition de liens Le seul risque encouru sera celui dune perte de temps drsquoexeacute-

cution dans des appels imbriqueacutes que lon aurait pu limiter en reacuteeacutecrivant totalement la classe

En revanche les membres donneacutees non utiliseacutes (sil y en a) occuperont de lespace dans tous

les objets du type

Dans cet esprit de reacuteutilisation on trouve aussi le cas ougrave disposant dune classe on souhaite

en modifier linterface utilisateur pour quelle reacuteponde agrave des critegraveres donneacutes On creacutee alors

une classe deacuteriveacutee qui agit comme la classe de base seule la faccedilon de lrsquoutiliser est diffeacuterente

Dans un tout autre esprit on peut en ne partant de rien chercher agrave reacutesoudre un problegraveme en

lexprimant sous forme dun graphe de classes1 On peut mecircme creacuteer ce que lon nomme des

classes abstraites cest-agrave-dire dont la vocation nest pas de donner naissance agrave des objets

mais simplement drsquoecirctre utiliseacutees comme classes de base pour dautres classes deacuteriveacutees

133 Exploitation drsquoune classe deacuteriveacuteeEn ce qui concerne lutilisation (compilation eacutedition de liens) dune classe deacuteriveacutee au sein

dun programme les choses sont tregraves simples si la classe de base et la classe deacuteriveacutee sont

creacuteeacutees dans le programme lui-mecircme (un seul fichier source un module objet) Mais il en va

rarement ainsi Au paragraphe 2 nous avons deacutejagrave vu comment proceacuteder lorsqursquoon utilise une

classe de base deacutefinie dans un fichier seacutepareacute Vous trouverez ci-dapregraves un scheacutema geacuteneacuteral

montrant les opeacuterations mises en jeu lorsqursquoon compile successivement et seacutepareacutement

bull une classe de base

bull une classe deacuteriveacutee

bull un programme utilisant cette classe deacuteriveacutee

La plupart des environnements de programmation permettent de tenir compte des deacutependan-

ces entre ces diffeacuterents fichiers et de faire en sorte que les compilations correspondantes

nrsquoaient lieu que si neacutecessaire On retrouve ce meacutecanisme dans la notion de projet (dans bon

nombre drsquoenvironnements PC) ou de fichier make (dans les environnements UNIX ou

LINUX)

1 Ou dun arbre si lon ne dispose pas de lrsquoheacuteritage multiple

Lrsquoheacuteritage simpleCHAPITRE 13

290

Deacuteclaration

classe de

base

Deacutefinition

classe de

base

Deacuteclaration

classe

deacuteriveacutee

Deacutefinition

classe

deacuteriveacutee

Programme

utilisant la

classe deacuteriveacutee

Module objet

classe de

base

Compilation

Module objet

classe

deacuteriveacutee

Module objet

programme

utilisateur

Edtion

de

liens

Programme

exeacutecutable

Compilation

Compilation

Exploitation drsquoune classe deacuteriveacutee

14

Lheacuteritage multiple

Comme nous lavons signaleacute au chapitre preacuteceacutedent C++ dispose de possibiliteacutes dheacuteritage

multiple Il sagit lagrave dune geacuteneacuteralisation conseacutequente dans la mesure ougrave elle permet de

saffranchir de la contrainte hieacuterarchique imposeacutee par lrsquoheacuteritage simple

Malgreacute tout son usage reste assez peu reacutepandu La principale raison reacuteside certainement dans

les difficulteacutes quil implique au niveau de la conception des logiciels Il est en effet plus

facile de structurer un ensemble de classes selon un ou plusieurs arbres (cas de lrsquoheacuteritage

simple) que selon un simple graphe orienteacute sans circuit (cas de lrsquoheacuteritage multiple)

Bien entendu la plupart des choses que nous avons dites agrave propos de lrsquoheacuteritage simple srsquoeacuteten-

dent agrave lrsquoheacuteritage multiple Neacuteanmoins un certain nombre dinformations suppleacutementaires

doivent ecirctre introduites pour reacutepondre aux questions suivantes

bull Comment exprimer cette deacutependance multiple au sein dune classe deacuteriveacutee

bull Comment sont appeleacutes les constructeurs et destructeurs concerneacutes ordre transmission din-

formations etc

bull Comment reacutegler les conflits qui risquent dapparaicirctre dans des situations telles que celle-ci

ougrave D heacuterite de B et C qui heacuteritent toutes deux de A

Lheacuteritage multipleCHAPITRE 14

292

1 Mise en œuvre de lheacuteritage multipleConsideacuterons une situation simple celle ougrave une classe que nous nommerons pointcoul heacuterite

de deux autres classes nommeacutees point et coul

Supposons pour fixer les ideacutees que les classes point et coul se preacutesentent ainsi (nous les

avons reacuteduites agrave ce qui eacutetait indispensable agrave la deacutemonstration)

class point class coul int x y short couleur public public point () coul () ~point () ~coul () affiche () affiche ()

Nous pouvons deacutefinir une classe pointcoul heacuteritant de ces deux classes en la deacuteclarant ainsi

(ici nous avons choisi public pour les deux classes mais nous pourrions employer private ou

protected1)

class pointcoul public point public coul

Notez que nous nous sommes contenteacute de remplacer la mention dune classe de base par une

liste de mentions de classes de base

A

B C

D

point coul

pointcoul

1 Depuis la version 3

1 - Mise en œuvre de lheacuteritage multiple293

Au sein de cette classe nous pouvons deacutefinir de nouveaux membres Ici nous nous limitons

agrave un constructeur un destructeur et une fonction daffichage

Dans le cas de lrsquoheacuteritage simple le constructeur devait pouvoir retransmettre des informa-

tions au constructeur de la classe de base Il en va de mecircme ici avec cette diffeacuterence quil y a

deux classes de base Len-tecircte du constructeur se preacutesente ainsi

pointcoul ( ) point () coul ()

| | |

arguments arguments arguments

de pointcoul agrave transmettre agrave transmettre

agrave point agrave coul

Lordre dappel des constructeurs est le suivant

bull constructeurs des classes de base dans lordre ougrave les classes de base sont deacuteclareacutees dans la

classe deacuteriveacutee (ici point puis coul)

bull constructeur de la classe deacuteriveacutee (ici pointcoul)

Les destructeurs eacuteventuels seront lagrave encore appeleacutes dans lordre inverse lors de la destruc-

tion dun objet de type pointcoul

Dans la fonction drsquoaffichage que nous nommerons elle aussi affiche nous vous proposons

drsquoemployer successivement les fonctions affiche de point et de coul Comme dans le cas de

lrsquoheacuteritage simple dans une fonction membre de la classe deacuteriveacutee on peut utiliser toute fonc-

tion membre publique (ou proteacutegeacutee) dune classe de base Lorsque plusieurs fonctions mem-

bres portent le mecircme nom dans diffeacuterentes classes on peut lever lambiguiumlteacute en employant

lopeacuterateur de reacutesolution de porteacutee Ainsi la fonction affiche de pointcoul sera

void affiche ()

pointaffiche () coulaffiche ()

Bien entendu si les fonctions drsquoaffichage de point et de coul se nommaient par exemple affp

et affc la fonction affiche aurait pu seacutecrire simplement

void affiche ()

affp () affc ()

Lutilisation de la classe pointcoul est classique Un objet de type pointcoul peut faire appel

aux fonctions membres de pointcoul ou eacuteventuellement aux fonctions membres des classes

de base point et coul (en se servant de lopeacuterateur de reacutesolution de porteacutee pour lever des ambi-

guiumlteacutes) Par exemple avec

pointcoul p(3 9 2)

paffiche () appellera la fonction affiche de pointcoul tandis que ppointaffiche () appellera

la fonction affiche de point

Naturellement si lune des classes point et coul eacutetait elle-mecircme deacuteriveacutee dune autre classe il

serait eacutegalement possible den utiliser lun des membres (en ayant eacuteventuellement plusieurs

fois recours agrave lopeacuterateur de reacutesolution de porteacutee)

Lheacuteritage multipleCHAPITRE 14

294

Voici un exemple complet de deacutefinition et dutilisation de la classe pointcoul dans laquelle

ont eacuteteacute introduits quelques affichages informatifs

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) cout ltlt ++ Constr point n x=abs y=ord ~point () cout ltlt -- Destr point n void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

class coul short couleur public coul (int cl) cout ltlt ++ Constr coul n couleur = cl ~coul () cout ltlt -- Destr coul n void affiche () cout ltlt Couleur ltlt couleur ltlt n

class pointcoul public point public coul public pointcoul (int int int) ~pointcoul () cout ltlt ---- Destr pointcoul n void affiche () pointaffiche () coulaffiche ()

pointcoulpointcoul (int abs int ord int cl) point (abs ord) coul (cl) cout ltlt ++++ Constr pointcoul n

1 - Mise en œuvre de lheacuteritage multiple295

main() pointcoul p(392) cout ltlt ------------n paffiche () appel de affiche de pointcoul cout ltlt ------------n

ppointaffiche () on force lappel de affiche de point cout ltlt ------------n pcoulaffiche () on force lappel de affiche de coul cout ltlt ------------n

++ Constr point++ Constr coul++++ Constr pointcoul------------Coordonnees 3 9

Couleur 2------------Coordonnees 3 9------------Couleur 2------------

---- Destr pointcoul-- Destr coul-- Destr point

Un exemple dheacuteritage multiple pointcoul heacuterite de point et de coul

Remarque

Nous avons vu comment distinguer deux fonctions membres de mecircme nom appartenant agrave

deux classes diffeacuterentes (par exemple affiche) La mecircme deacutemarche sappliquerait agrave des

membres donneacutees (dans la mesure ougrave leur accegraves est autoriseacute) Par exemple avec

class A class B public public

int x int x class C public A public B

C posseacutedera deux membres nommeacutes x lun heacuteriteacute de A lautre de B Au sein des fonc-

tions membres de C on fera la distinction agrave laide de lopeacuterateur de reacutesolution de

porteacutee on parlera de Ax ou de Bx

Lheacuteritage multipleCHAPITRE 14

296

En Java

Java ne connaicirct pas lrsquoheacuteritage multiple En revanche il dispose de la notion drsquointerface

(inconnue de C++) qui permet en geacuteneacuteral de traiter plus eacuteleacutegamment les problegravemes Une

interface est simplement un ensemble de speacutecifications de meacutethodes (il nrsquoy a pas de don-

neacutees) Lorsqursquoune classe impleacutemente une interface elle doit fournir effectivement les

meacutethodes correspondantes Une classe peut impleacutementer autant drsquointerfaces qursquoelle le

souhaite indeacutependamment de la notion drsquoheacuteritage

2 Pour reacutegler les eacuteventuels conflits les classes virtuelles

Consideacuterons la situation suivante

correspondant agrave des deacuteclarations telles que

class A

int x y

class B public A

class C public A

class D public B public C

A

B C

D

2 - Pour reacutegler les eacuteventuels conflits les classes virtuelles297

En quelque sorte D heacuterite deux fois de A Dans ces conditions les membres de A (fonctions

ou donneacutees) apparaissent deux fois dans D En ce qui concerne les fonctions membres cela

est manifestement inutile (ce sont les mecircmes fonctions) mais sans importance puisqursquoelles

ne sont pas reacuteellement dupliqueacutees (il nen existe quune pour la classe de base) En revanche

les membres donneacutees (x et y) seront effectivement dupliqueacutes dans tous les objets de type D

Y a-t-il redondance En fait la reacuteponse deacutepend du problegraveme Si lon souhaite que D dispose

de deux jeux de donneacutees (de A) on ne fera rien de particulier et on se contentera de les distin-

guer agrave laide de lopeacuterateur de reacutesolution de porteacutee Par exemple on distinguera

ABx de ACx

ou eacuteventuellement si B et C ne possegravedent pas de membre x

Bx de Cx

En geacuteneacuteral cependant on ne souhaitera pas cette duplication des donneacutees Dans ces condi-

tions on peut toujours se deacutebrouiller pour travailler avec lun des deux jeux (toujours le

mecircme ) mais cela risque decirctre fastidieux et dangereux En fait vous pouvez demander agrave

C++ de nincorporer quune seule fois les membres de A dans la classe D Pour cela il vous

faut preacuteciser dans les deacuteclarations des classes B et C (attention pas dans celle de D ) que la

classe A est virtuelle (mot cleacute virtual)

class B public virtual A class C public virtual A class D public B public C

Notez bien que virtual apparaicirct ici dans B et C En effet deacutefinir A comme virtuelle dans la

deacuteclaration de B signifie que A ne devra ecirctre introduite quune seule fois dans les descendants

eacuteventuels de C Autrement dit cette deacuteclaration na guegravere deffet sur les classes B et C elles-

mecircmes (si ce nest une information cacheacutee mise en place par le compilateur pour marquer

A comme virtuelle au sein de B et C ) Avec ou sans le mot virtual les classes B et C se

comportent de la mecircme maniegravere tant quelles nont pas de descendants

Remarque

Le mot virtual peut ecirctre placeacute indiffeacuteremment avant ou apregraves le mot public (ou le mot pri-

vate)

Lheacuteritage multipleCHAPITRE 14

298

3 Appels des constructeurs et des destructeurs cas des classes virtuelles

Nous avons vu comment sont appeleacutes les constructeurs et les destructeurs dans des situations

telles que

De plus nous savons comment demander des transferts dinformations entre un constructeur

dune classe et les constructeurs de ses ascendants directs (C pour B B pour A F pour D et

E) En revanche nous ne pouvons pas demander agrave un constructeur de transfeacuterer des informa-

tions agrave un constructeur dun ascendant indirect (C pour A par exemple) et nous navons

dailleurs aucune raison de le vouloir (puisque chaque transfert dinformation dun niveau

vers le niveau supeacuterieur eacutetait speacutecifieacute dans len-tecircte du constructeur du niveau correspon-

dant) Mais consideacuterons maintenant la situation suivante

Si A nest pas deacuteclareacutee virtuelle dans B et C on peut consideacuterer que la classe A eacutetant dupli-

queacutee tout se passe comme si lon eacutetait en preacutesence de la situation suivante dans laquelle les

notations A1 et A2 symbolisent toutes les deux la classe A

D E

F

A

B

C

A

B C

D

3 - Appels des constructeurs et des destructeurs cas des classes virtuelles299

Si D a deacuteclareacute les classes B et C dans cet ordre les constructeurs seront appeleacutes dans lordre

suivant

A1 B A2 C D

En ce qui concerne les transferts dinformations on peut tregraves bien imaginer que B et C naient

pas preacutevu les mecircmes arguments en ce qui concerne A

Par exemple on peut avoir

B (int n int p double z) A (n p)C (int q float x) A (q)

Cela na aucune importance puisqursquoil y aura en deacutefinitive construction de deux objets dis-

tincts de type A

Mais si A a eacuteteacute deacuteclareacutee virtuelle dans B et C il en va tout autrement (le dernier scheacutema nest

plus valable) En effet dans ce cas on ne construira quun seul objet de type A Quels argu-

ments faut-il transmettre alors au constructeur Ceux preacutevus par B ou ceux preacutevus par C

En fait C++ reacutesout cette ambiguiumlteacute de la faccedilon suivante

Le choix des informations agrave fournir au constructeur de A a lieu non plus dans B ou C mais

dans D Pour ce faire C++ vous autorise (uniquement dans ce cas de deacuterivation virtuelle) agrave

speacutecifier dans le constructeur de D des informations destineacutees agrave A Ainsi nous pourrons

avoir

D (int n int p double z) B (n p z) A (n p)

Bien entendu il sera inutile (et interdit) de preacuteciser des informations pour A au niveau des

constructeurs B et C (comme nous lavions preacutevu preacuteceacutedemment alors que A navait pas eacuteteacute

deacuteclareacutee virtuelle dans B et C)

En outre il faudra absolument que A dispose drsquoun constructeur sans argument (ou

drsquoaucun constructeur) afin de permettre la creacuteation convenable drsquoobjets de type B ou C

(puisque cette fois il nrsquoexiste plus de meacutecanisme de transmission drsquoinformation drsquoun cons-

tructeur de B ou C vers un constructeur de A)

A1

B

A2

C

D

Lheacuteritage multipleCHAPITRE 14

300

En ce qui concerne lordre des appels le constructeur dune classe virtuelle est toujours

appeleacute avant les autres Ici cela nous conduit agrave lordre A B C et D auquel on peut tout

naturellement srsquoattendre Mais dans une situation telle que

cela conduit agrave lordre (moins eacutevident) F E G H I (ou F E H G I selon lordre dans lequel

figurent G et H dans la deacuteclaration de I)

4 Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle

Nous vous proposons un petit exemple illustrant agrave la fois lrsquoheacuteritage multiple les deacuterivations

virtuelles et les transmissions drsquoinformations entre constructeur Il srsquoagit drsquoune geacuteneacuteralisation

de lrsquoexemple du pargraphe 1 Nous y avions deacutefini une clase coul pour reacutepreacutesenter une cou-

leur et une classe pointcol deacuteriveacutee de point pour repreacutesenter des points coloreacutes Ici nous deacutefi-

nissons en outre une classe masse pour repreacutesenter une masse et une classe pointmasse pour

repreacutesenter des points doteacutes drsquoune masse Enfin nous creacuteons une classe pointcolmasse pour

repreacutesenter des points doteacutes agrave la fois drsquoune couleur et drsquoune masse Nous la faisons deacuteriver de

pointcol et de pointmasse ce qui nous conduit agrave ce scheacutema

F

I

G

(virtual F)

H

(virtual F)

E

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle301

Pour eacuteviter la duplication des membres de point dans cette classe on voit qursquoil est neacutecesaire

drsquoavoir preacutevu que les classes pointcol et pointmasse deacuterivent virtuellement de la classe point

qui doit alors disposser drsquoun constructeur sans argument

include ltiostreamgtclass point int x y public point (int abs int ord) cout ltlt ++ Constr point ltlt abs ltlt ltlt ord ltlt n x=abs y=ord point () constr par deacutefaut neacutecessaire pour deacuterivations virtuelles cout ltlt ++ Constr defaut point n x=0 y=0 void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n class coul short couleur public coul (short cl) cout ltlt ++ Constr coul ltlt cl ltlt n couleur = cl void affiche () cout ltlt Couleur ltlt couleur ltlt n

point

pointcoul pointmasse

pointcolmasse

coul masse

Lheacuteritage multipleCHAPITRE 14

302

class masse int mas public masse (int m) cout ltlt ++ Constr masse ltlt m ltlt n mas = m void affiche () cout ltlt Masse ltlt mas ltlt n class pointcoul public virtual point public coul public pointcoul (int abs int ord int cl) coul (cl) pas dinfo pour point car deacuterivation virtuelle cout ltlt ++++ Constr pointcoul ltlt abs ltlt ltlt ord ltlt ltlt cl ltlt n void affiche () pointaffiche () coulaffiche ()

class pointmasse public virtual point public masse public pointmasse (int abs int ord int m) masse (m) pas dinfo pour point car deacuterivation virtuelle cout ltlt ++++ Constr pointmasse ltlt abs ltlt ltlt ord ltlt ltlt m ltlt n void affiche () pointaffiche () masseaffiche () class pointcolmasse public pointcoul public pointmasse public pointcolmasse (int abs int ord short c int m) point (abs ord) pointcoul (abs ord c) pointmasse (abs ord m) infos abs ord en fait inutiles pour pointcol et pointmasse cout ltlt ++++ Constr pointcolmasse ltlt abs + ltlt ord ltlt ltlt c ltlt ltlt m ltlt n void affiche () pointaffiche () coulaffiche() masseaffiche ()

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle303

main() pointcoul p(392) paffiche () appel de affiche de pointcoul pointmasse pm(12 25 100) pmaffiche () pointcolmasse pcm (2 5 10 20) pcmaffiche () int n cin gtgt n

++ Constr defaut point++ Constr coul 2++++ Constr pointcoul 3 9 2Coordonnees 0 0Couleur 2++ Constr defaut point++ Constr masse 100++++ Constr pointmasse 12 25 100Coordonnees 0 0Masse 100++ Constr point 2 5++ Constr coul 10++++ Constr pointcoul 2 5 10++ Constr masse 20++++ Constr pointmasse 2 5 20++++ Constr pointcolmasse 5 10 20Coordonnees 2 5Couleur 10Masse 20

Exemple drsquoutilisation de lrsquoheacuteritage multiple et des deacuterivations virtuelles

15

Les fonctions virtuelleset le polymorphisme

Nous avons vu quen C++ un pointeur sur un type dobjet pouvait recevoir lrsquoadresse de

nimporte quel objet descendant Toutefois comme nous lrsquoavons constateacute au paragraphe 63

du chapitre 13 agrave cet avantage srsquooppose une lacune importante lappel dune meacutethode pour

un objet pointeacute conduit systeacutematiquement agrave appeler la meacutethode correspondant au type du

pointeur et non pas au type effectif de lobjet pointeacute lui-mecircme

Cette lacune provient essentiellement de ce que dans les situations rencontreacutees jusquici

C++ reacutealise ce que lon nomme une ligature statique1 ou encore un typage statique Le type

dun objet (pointeacute) y est deacutetermineacute au moment de la compilation Dans ces conditions le

mieux que puisse faire le compilateur est effectivement de consideacuterer que lobjet pointeacute a le

type du pointeur

Pour pouvoir obtenir lappel de la meacutethode correspondant au type de lobjet pointeacute il est

neacutecessaire que le type de lobjet ne soit pris en compte quau moment de lexeacutecution (le type

de lobjet deacutesigneacute par un mecircme pointeur pourra varier au fil du deacuteroulement du programme)

On parle alors de ligature dynamique2 ou de typage dynamique ou mieux de polymor-

phisme

Comme nous allons le voir maintenant en C++ le polymorphisme peut ecirctre mis en œuvre en

faisant appel au meacutecanisme des fonctions virtuelles

1 En anglais early binding

2 En anglais late binding ou encore dynamic binding

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

306

1 Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire

Consideacuterons la situation suivante deacutejagrave rencontreacutee au 13

class point class pointcol public point

void affiche () void affiche ()

point p

pointcol pc

point adp = ampp

Linstruction

adp -gt affiche ()

appelle la meacutethode affiche du type point

Mais si nous exeacutecutons cette affectation (autoriseacutee)

adp = amp pc

le pointeur adp pointe maintenant sur un objet de type pointcol Neacuteanmoins linstruction

adp -gt affiche ()

fait toujours appel agrave la meacutethode affiche du type point alors que le type pointcol dispose

lui aussi dune meacutethode affiche

En effet le choix de la meacutethode agrave appeler a eacuteteacute reacutealiseacute lors de la compilation il a donc eacuteteacute

fait en fonction du type de la variable adp Cest la raison pour laquelle on parle de ligature

statique

2 Le meacutecanisme des fonctions virtuellesLe meacutecanisme des fonctions virtuelles proposeacute par C++ va nous permettre de faire en sorte

que linstruction

adp -gt affiche ()

appelle non plus systeacutematiquement la meacutethode affiche de point mais celle correspondant au

type de lobjet reacuteellement deacutesigneacute par adp (ici point ou pointcol)

Pour ce faire il suffit de deacuteclarer virtuelle (mot cleacute virtual) la meacutethode affiche de la classe

point

class point

virtual void affiche ()

2 - Le meacutecanisme des fonctions virtuelles307

Cete instruction indique au compilateur que les eacuteventuels appels de la fonction affiche doi-

vent utiliser une ligature dynamique et non plus une ligature statique Autrement dit lorsque

le compilateur rencontrera un appel tel que

adp -gt affiche ()

il ne deacutecidera pas de la proceacutedure agrave appeler Il se contentera de mettre en place un dispositif

permettant de neffectuer le choix de la fonction quau moment de lexeacutecution de cette instruc-

tion ce choix eacutetant baseacute sur le type exact de lobjet ayant effectueacute lappel (plusieurs exeacutecu-

tions de cette mecircme instruction pouvant appeler des fonctions diffeacuterentes)

Dans la classe pointcol on ne proceacutedera agrave aucune modification il nest pas neacutecessaire de

deacuteclarer virtuelle dans les classes deacuteriveacutees une fonction deacuteclareacutee virtuelle dans une classe de

base (cette information serait redondante)

A titre dexemple voici le programme correspondant agrave celui du paragraphe 63 du chapitre

13 dans lequel nous nous sommes contenteacute de rendre virtuelle la fonction affiche

include ltiostreamgtusing namespace std

class point protected pour que x et y soient accessibles agrave pointcol int x y public

point (int abs=0 int ord=0) x=abs y=ord virtual void affiche () cout ltlt Je suis un point n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y

cout ltlt et ma couleur est ltlt couleur ltlt n

main() point p(35) point adp = ampp pointcol pc (862) pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche ()

cout ltlt -----------------n adp = adpc adpc = adp serait rejeteacute adp-gtaffiche () adpc-gtaffiche ()

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

308

Je suis un point

mes coordonneacutees sont 3 5

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

-----------------

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

Mise en œuvre drsquoune ligature dynamique (ici pour affiche) par la technique des fonctions virtuelles

Remarques

1 Par deacutefaut C++ met en place des ligatures statiques A laide du mot virtual on peut choi-

sir la ou les fonctions pour lesquelles on souhaite mettre en place une ligature dynamique

2 En C++ la ligature dynamique est limiteacutee agrave un ensemble de classes deacuteriveacutees les unes

des autres

En Java

En Java les objets sont manipuleacutes par reacutefeacuterence et la ligature des fonctions est toujours

dynamique La notion de fonction virtuelle nrsquoexiste pas tout se passe en fait comme si

toutes les fonctions membres eacutetaient virtuelles En outre comme toute classe est toujours

deacuteriveacutee de la classe Object deux classes diffeacuterentes appartiennent toujours agrave une mecircme

hieacuterarchie Le polymorphisme est donc toujours effectif en Java

3 Autre situation ougrave la ligature dynamique est indispensable

Dans lrsquoexemple preacuteceacutedent lors de la conception de la classe point nous avons preacutevu que cha-

cune de ses descendantes redeacutefinirait agrave sa guise la fonction affiche Cela conduit agrave preacutevoir

dans chaque fonction des instructions drsquoaffichage des coordonneacutees Pour eacuteviter cette redon-

dance1 nous pouvons deacutefinir la fonction affiche (de la classe point) de maniegravere quelle

bull affiche les coordonneacutees (action commune agrave toutes les classes)

1 Bien entendu lenjeu est tregraves limiteacute ici Mais il pourrait ecirctre important dans un cas reacuteel

3 - Autre situation ougrave la ligature dynamique est indispensable309

bull fasse appel agrave une autre fonction (nommeacutee par exemple identifie) ayant pour vocation daf-

ficher les informations speacutecifiques agrave chaque objet Bien entendu ce faisant nous supposons

que chaque descendante de point redeacutefinira identifie de faccedilon approprieacutee (mais elle naura

plus agrave prendre en charge laffichage des coordonneacutees)

Cette deacutemarche nous conduit agrave deacutefinir la classe point de la faccedilon suivante

class point

int x y public

point (int abs=0 int ord=0) x=abs y=ord void identifie ()

cout ltlt Je suis un point n

void affiche () identifie ()

cout ltlt Mes coordonnees sont ltlt x ltlt ltlt y ltlt n

Deacuterivons une classe pointcol en redeacutefinissant comme voulu la fonction identifie

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 ltlt Je suis un point colore de couleur ltlt couleur ltlt n

Si nous cherchons alors agrave utiliser pointcol de la faccedilon suivante

pointcol pc (8 6 2)

pcaffiche ()

nous obtenons le reacutesultat

Je suis un point

Mes coordonneacutees sont 8 6

ce qui nest pas ce que nous espeacuterions

Certes la compilation de lappel

pcaffiche ()

a conduit le compilateur agrave appeler la fonction affiche de la classe point (puisque cette fonc-

tion nest pas redeacutefinie dans pointcol) En revanche agrave ce moment-lagrave lappel

identifie ()

figurant dans cette fonction a deacutejagrave eacuteteacute compileacute en un appel didentifie de la classe point

Comme vous le constatez bien quici la fonction affiche ait eacuteteacute appeleacutee explicitement pour un

objet (et non comme preacuteceacutedemment agrave laide dun pointeur) nous nous trouvons agrave nouveau

en preacutesence dun problegraveme de ligature statique

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

310

Pour le reacutesoudre il suffit de deacuteclarer virtuelle la fonction identifie dans la classe point Cela

permet au compilateur de mettre en place les instructions assurant lappel de la fonction iden-

tifie correspondant au type de lobjet layant effectivement appeleacutee Ici vous noterez cepen-

dant que la situation est leacutegegraverement diffeacuterente de celle qui nous a servi agrave preacutesenter les

fonctions virtuelles (paragraphe 1) En effet lappel didentifie est reacutealiseacute non plus directe-

ment par lobjet lui-mecircme mais indirectement par la fonction affiche Nous verrons comment

le meacutecanisme des fonctions virtuelles est eacutegalement capable de prendre en charge cet aspect

Voici un programme complet reprenant les deacutefinitions des classes point et pointcol Il mon-

tre comment un appel tel que pcaffiche () entraicircne bien lappel de identifie du type pointcol

(ce qui constitue le but de ce paragraphe) A titre indicatif nous avons introduit quelques

appels par pointeur afin de montrer que lagrave aussi les choses se deacuteroulent convenablement

include ltiostreamgtusing namespace std

class point int x y public point (int abs=0 int ord=0) x=abs y=ord virtual void identifie () cout ltlt Je suis un point n void affiche () identifie () cout ltlt Mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore de couleur ltlt couleur ltlt n main() point p(34) pointcol pc(595) paffiche () pcaffiche () cout ltlt ---------------n point adp = ampp pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche () cout ltlt ---------------n adp = adpc adp-gtaffiche () adpc-gtaffiche ()

Je suis un pointMes coordonnees sont 3 4Je suis un point colore de couleur 5Mes coordonnees sont 5 9---------------

4 - Les proprieacuteteacutes des fonctions virtuelles311

Je suis un point

Mes coordonnees sont 3 4

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

---------------

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

Mise en œuvre de ligature dynamique (ici pour identifie) par la technique des fonctions virtuelles

4 Les proprieacuteteacutes des fonctions virtuellesLes deux exemples preacuteceacutedents constituaient des cas particuliers dutilisation de meacutethodes vir-

tuelles Nous vous proposons ici de voir quelles en sont les possibiliteacutes et les limitations

41 Leurs limitations sont celles de lrsquoheacuteritageA partir du moment ougrave une fonction f a eacuteteacute deacuteclareacutee virtuelle dans une classe A elle sera sou-

mise agrave la ligature dynamique dans A et dans toutes les classes descendantes de A on nest

donc pas limiteacute aux descendantes directes Ainsi on peut imaginer une hieacuterarchie de formes

geacuteomeacutetriques

Si la fonction affiche est deacuteclareacutee virtuelle dans la classe point et redeacutefinie dans les autres

classes descendant de point elle sera bien soumise agrave la ligature dynamique Il est mecircme envi-

sageable que les six classes ci-dessus soient parfaitement deacutefinies et compileacutees et quon

vienne en ajouter de nouvelles sans remettre en cause les preacuteceacutedentes de quelque faccedilon que

ce soit Ce dernier point serait dailleurs encore plus flagrant si comme dans le second exem-

ple (paragraphe 3) la fonction affiche non virtuelle faisait elle-mecircme appel agrave une fonction

virtuelle identifie redeacutefinie dans chaque classe En effet dans ce cas on voit que la fonction

affiche aurait pu ecirctre reacutealiseacutee et compileacutee (au sein de point) sans que toutes les fonctions

identifie quelle eacutetait susceptible dappeler soient connues On trouve lagrave un aspect seacuteduisant

point

carreacute

rectangle

cercle

ellipse

vecteur

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

312

de reacuteutilisabiliteacute on a deacutefini dans affiche un sceacutenario dont certaines parties pourront ecirctre

preacuteciseacutees plus tard lors de la creacuteation de classes deacuteriveacutees

De mecircme supposons que lon ait deacutefini la structure suivante deacutejagrave preacutesenteacutee au paragraphe 4

du chapitre 14

Si dans point la fonction affiche a eacuteteacute deacuteclareacutee virtuelle il devient possible dutiliser la

classe liste-points pour geacuterer une liste dobjets heacuteteacuterogegravenes en deacuterivant les classes voulues

de point et en y redeacutefinissant affiche Vous trouverez un exemple au paragraphe suivant

42 La redeacutefinition dune fonction virtuelle nest pas obligatoireJusquici nous avons toujours redeacutefini dans les classes descendantes une meacutethode deacuteclareacutee

virtuelle dans une classe de base Cela nest pas plus indispensable que dans le cas des fonc-

tions membres ordinaires Ainsi consideacuterons de nouveau la preacuteceacutedente hieacuterarchie de figures

en supposant que affiche na eacuteteacute redeacutefinie que dans les classes que nous avons marqueacutees dune

eacutetoile (et deacutefinie bien sucircr comme virtuelle dans point)

Dans ces conditions lappel daffiche conduira pour chaque classe agrave lappel de la fonction

mentionneacutee agrave cocircteacute

vecteur vecteuraffiche

carre pointaffiche

rectangle pointaffiche

cercle pointaffiche

ellipse ellipseaffiche

liste point

liste_points

point

carreacute

rectangle

cercle

ellipse

vecteur

4 - Les proprieacuteteacutes des fonctions virtuelles313

Le mecircme meacutecanisme sappliquerait en cas dheacuteritage multiple agrave condition de le compleacuteter par

les regravegles concernant les ambiguiumlteacutes

43 Fonctions virtuelles et surdeacutefinitionOn peut surdeacutefinir1 une fonction virtuelle chaque fonction surdeacutefinie pouvant ecirctre deacuteclareacutee

virtuelle ou non

Par ailleurs si lon a deacutefini une fonction virtuelle dans une classe et quon la surdeacutefinit dans

une classe deacuteriveacutee avec des arguments diffeacuterents il sagira alors bel et bien dune autre fonc-

tion Si cette derniegravere nest pas deacuteclareacutee virtuelle elle sera soumise agrave une ligature statique

En fait on peut consideacuterer que le statut virtuelnon virtuel joue lui aussi un rocircle discrimina-

teur dans le choix dune fonction surdeacutefinie Par souci de simpliciteacute et de lisibiliteacute nous vous

conseillons deacuteviter dexploiter cette possibiliteacute si vous devez surdeacutefinir une fonction vir-

tuelle il est preacutefeacuterable que toutes les fonctions de mecircme nom restent virtuelles

44 Le type de retour drsquoune fonction virtuelle redeacutefinieDans la redeacutefinition drsquoune fonction membre usuelle (non virtuelle) on ne tient pas compte du

type de la valeur de retour ce qui est logique Mais dans le cas drsquoune fonction virtuelle des-

tineacutee agrave ecirctre deacutefinie ulteacuterieurement il nrsquoen va plus de mecircme Par exemple supposons que

dans la hieacuterarchie de classes du paragraphe preacuteceacutedent la fonction affiche soit deacutefinie ainsi

dans point

virtual void affiche ()

et ainsi dans ellipse

virtual int affiche ()

Il va alors de soi que le polymorphisme fonctionnerait mal Crsquoest pourquoi C++ refuse cette

possibiliteacute qui conduit agrave une erreur de compilation

La redeacutefinition drsquoune fonction virtuelle doit donc respecter exactement le type de la

valeur de retour Il existe toutefois une exception agrave cette regravegle qui concerne ce que lrsquoon

nomme parfois les valeurs de retour covariantes Il srsquoagit du cas ougrave la valeur de retour

drsquoune fonction virtuelle est un pointeur ou une reacutefeacuterence sur une classe C La redeacutefinition

de cette fonction virtuelle dans une classe deacuteriveacutee peut alors se faire avec un pointeur ou une

reacutefeacuterence sur une classe deacuteriveacutee de C En voici un exemple

class Y public X Y deacuterive de Xclass A public virtual X amp f (int) Af(int) renvoie un X

1 Ne confondez pas surdeacutefinition et redeacutefinition

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

314

class B public A public virtual Y amp f (int) Bf(int) renvoie un Y Bf(int) redeacutefinit bien Af(int)

Bien entendu qui peut le plus peut le moins Si X et Y correspondent agrave A et B on a

class A public virtual A amp f (int) Af(int) renvoie un A class B public A public virtual B amp f (int) Bf(int) renvoie un B Bf(int) redeacutefinit bien Af(int) et renvoie un B

On obtient ainsi une geacuteneacuteralisation du polymorphisme agrave la valeur de retour

45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe

Dans tous nos exemples nous avions deacuteclareacute virtuelle une fonction dune classe qui neacutetait

pas elle-mecircme deacuteriveacutee dune autre Cela nest pas obligatoire Ainsi dans les exemples de

hieacuterarchie de formes point pourrait elle-mecircme deacuteriver dune autre classe Cependant il faut

alors distinguer deux situations

bull La fonction affiche de la classe point na jamais eacuteteacute deacutefinie dans les classes ascendantes

aucun problegraveme particulier ne se pose

bull La fonction affiche a deacutejagrave eacuteteacute deacutefinie avec les mecircmes arguments dans une classe ascendan-

te Dans ce cas il faut consideacuterer la fonction virtuelle affiche comme une nouvelle fonction

(comme sil y avait eu surdeacutefinition le caractegravere virtuelnon virtuel servant agrave faire la dis-

tinction) Bien entendu toutes les nouvelles deacutefinitions daffiche dans les classes descendan-

tes seront soumises agrave la ligature dynamique sauf si lon effectue un appel explicite dune

fonction dune classe ascendante au moyen de lopeacuterateur de reacutesolution de porteacutee Rappelons

toutefois que nous vous deacuteconseillons fortement ce type de situation

46 Quelques restrictions et conseils

461 Seule une fonction membre peut ecirctre virtuelleCela se justifie par le meacutecanisme employeacute pour effectuer la ligature dynamique agrave savoir un

choix baseacute sur le type de lrsquoobjet ayant appeleacute la fonction Cela ne pourrait pas srsquoappliquer agrave

une fonction ordinaire (mecircme si elle eacutetait amie drsquoune classe)

4 - Les proprieacuteteacutes des fonctions virtuelles315

462 Un constructeur ne peut pas ecirctre virtuel

De par sa nature un construteur ne peut ecirctre appeleacute que pour un type classe parfaitement

deacutefini qui sert preacuteciseacutement agrave deacutefinir le type de lrsquoobjet agrave construire A priori donc un cons-

tructeur nrsquoa aucune raison drsquoecirctre soumis au polymorphisme Drsquoailleurs on peut penser qursquoon

nrsquoappelle jamais un constructeur par pointeur ou reacutefeacuterence Cependant il existe des situations

particuliegraveres lieacutees agrave lrsquoappel implicite drsquoun constructeur par recopie (qui constitue un cons-

tructeur comme un autre ) Voyez cet exemple

include ltiostreamgtusing namespace std class A public A (const A amp) cout ltlt Constructeur de recopie de An A () class B public A public B (const B amp b) A (b) cout ltlt CR copy Bn B() void g (A a) reccediloit une copievoid f (A ada) g(ada) main () B adb = new B A ada = adb f(ada) ada pointe sur un objet de type B

Constructeur de recopie de A

Appel implicite drsquoun constructeur par recopie

La fonction ordinaire f reccediloit lrsquoadresse drsquoun objet de type B par lrsquointermeacutediaire drsquoun poin-

teur de type A Elle appelle alors la fonction g en lui transmettant lrsquoobjet correspondant par

valeur ce qui entraicircne lrsquoappel du construteur par recopie de la classe A Pour qursquoil y ait appel

de celui de la classe B il aurait fallu qursquoil y ait polymorphisme donc que ce constructeur soit

virtuel ce qui nrsquoest pas possible

463 Un destructeur peut ecirctre virtuel

En revanche un destructeur peut ecirctre virtuel Il est toutefois conseilleacute de prendre quelques

preacutecautions agrave ce sujet En effet consideacuterons cette situation

class A public ~A() class B public A public ~B() la presence de virtual ici ne changerait rien

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

316

main()

A a B b

b = new B()

a = b

delete a a pointe sur un objet de type B mais on nrsquoappelle que ~A

Comme on peut srsquoy attendre lrsquoappel de delete sur lrsquoobjet de type B pointeacute par a ne conduira

qursquoagrave lrsquoappel du destructeur de A lequel opegravere quand mecircme sur un objet de type B Il est clair

que les conseacutequences peuvent ecirctre deacutesastreuses Deux deacutemarches permettent de pallier cette

difficulteacute

bull soit interdire la suppression drsquoobjets de type A il suffit alors de ne pas placer de destructeur

dans A ou encore de le rendre priveacute ou proteacutegeacute

bull soit placer dans A un constructeur virtuel (quitte agrave ce qursquoil soit vide)

class A public ~A()

class B public A

public ~B() la presence de virtual ici est facultative

main()

A a B b

b = new B()

a = b

delete a a pointe sur un objet de type B et on appelle bien ~B

Dans ces conditions les destructeurs des classes deacuteriveacutees seront bien virtuels (mecircme si le

mot-cleacute virtual nrsquoest pas rappeleacute et bien que leurs noms soient diffeacuterents drsquoune classe agrave sa

deacuteriveacutee) Ici on appellera donc bien le destructeur du type B

Drsquoune maniegravere geacuteneacuterale nous vous encourageons agrave respecter la regravegle suivante

464 Cas particulier de lrsquoopeacuterateur drsquoaffectation

En theacuteorie lrsquoopeacuterateur drsquoaffectation peut comme toute fonction membre ecirctre deacuteclareacute virtuel

Cependant il faut bien voir que cette fonction est particuliegravere dans la mesure ougrave la deacutefinition

de lrsquoaffectation drsquoune classe B deacuteriveacutee de A ne constitue pas une redeacutefinition de lrsquoopeacuterateur

drsquoaffectation de A On nrsquoest donc pas dans une situation de polymorphisme comme le mon-

tre cet exemple artificiel

Dans une classe de base (destineacutee agrave ecirctre deacuteriveacutee) preacutevoir

- soit aucun destructeur

- soit un destructeur priveacute ou proteacutegeacute

- soit un destructeur public et virtuel

5 - Les fonctions virtuelles pures pour la creacuteation de classes abstraites317

include ltiostreamgtusing namespace std

class A public virtual A amp operator = (const A amp) cout ltlt affectation fictive An

class B public A public virtual B amp operator = (const B amp) cout ltlt affectation fictive Bn

main () B adb1 = new B B adb2 = new B

adb1 = adb2 A ada1 = new A A ada2 = new A ada1 = adb1 ada2 = adb2

ada1 = ada2 appelle affectation de A - virtual ne sert a rien car on ne redeacutefinit pas la meme fonction

affectation fictive Baffectation fictive A

Le polymorphisme ne peut pas srsquoappliquer agrave lrsquoaffectation

5 Les fonctions virtuelles pures pour la creacuteation de classes abstraites

Nous avons deacutejagrave eu loccasion de dire quon pouvait deacutefinir des classes destineacutees non pas agrave

instancier des objets mais simplement agrave donner naissance agrave dautres classes par heacuteritage En

POO on dit quon a affaire agrave des classes abstraites

En C++ vous pouvez toujours deacutefinir de telles classes Mais vous devrez peut-ecirctre y intro-

duire certaines fonctions virtuelles dont vous ne pouvez encore donner aucune deacutefinition

Imaginez par exemple une classe abstraite forme_geo destineacutee agrave geacuterer le dessin sur un eacutecran

de diffeacuterentes formes geacuteomeacutetriques (carreacute cercle) Supposez que vous souhaitiez deacutejagrave y

faire figurer une fonction deplace destineacutee agrave deacuteplacer une figure Il est probable que celle-ci

fera alors appel agrave une fonction daffichage de la figure (nommeacutee par exemple dessine) La

fonction dessine sera deacuteclareacutee virtuelle dans la classe forme_geo et devra ecirctre redeacutefinie dans

ses descendants Mais quelle deacutefinition lui fournir dans forme_geo Avec ce que vous con-

naissez de C++ vous avez toujours la ressource de preacutevoir une deacutefinition vide1

1 Notez bien quil vous faut absolument deacutefinir dessine dans forme_geo puisquelle est appeleacutee par deplace

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

318

Toutefois deux lacunes apparaissent alors

bull Rien ninterdit agrave un utilisateur de deacuteclarer un objet de classe forme_geo alors que dans les-

prit du concepteur il sagissait dune classe abstraite Lappel de deplace pour un tel objet

conduira agrave un appel de dessine ne faisant rien mecircme si aucune erreur nen deacutecoule cela na

guegravere de sens

bull Rien noblige une classe descendant de forme_geo agrave redeacutefinir dessine Si elle ne le fait pas

on retrouve les problegravemes eacutevoqueacutes ci-dessus

C++ propose un outil facilitant la deacutefinition de classes abstraites les fonctions virtuelles

pures Ce sont des fonctions virtuelles dont la deacutefinition est nulle (0) et non plus seulement

vide Par exemple nous aurions pu faire de notre fonction dessine de la classe forme_geo une

fonction virtuelle pure en la deacuteclarant1 ainsi

virtual void dessine () = 0

Certes agrave ce niveau linteacuterecirct de cette convention napparaicirct pas encore Mais C++ adopte les

regravegles suivantes

bull Une classe comportant au moins une fonction virtuelle pure est consideacutereacutee comme abstraite

et il nest plus possible de deacuteclarer des objets de son type

bull Une fonction deacuteclareacutee virtuelle pure dans une classe de base doit obligatoirement ecirctre redeacute-

finie2 dans une classe deacuteriveacutee ou deacuteclareacutee agrave nouveau virtuelle pure3 dans ce dernier cas la

classe deacuteriveacutee est elle aussi abstraite

Comme vous le voyez lemploi de fonctions virtuelles pures regravegle les deux problegravemes soule-

veacutes par lemploi de deacutefinitions vides Dans le cas de notre classe forme_geo le fait davoir

rendu dessine virtuelle pure interdit

bull la deacuteclaration dobjets de type forme_geo

bull la deacutefinition de classes deacuteriveacutees de forme_geo dans lesquelles on omettrait la deacutefinition de

dessine

Remarque

La notion de fonction virtuelle pure deacutepasse celle de classe abstraite Si C++ seacutetait con-

tenteacute de deacuteclarer une classe comme abstraite cela naurait servi quagrave en interdire

lutilisation il aurait fallu une seconde convention pour preacuteciser les fonctions devant

obligatoirement ecirctre redeacutefinies

1 Ici on ne peut plus distinguer deacuteclaration et deacutefinition

2 Toujours avec les mecircmes arguments sinon il sagit dune autre fonction

3 Depuis la version 30 si une fonction virtuelle pure dune classe de base nest pas redeacutefinie dans une classe deacuteri-

veacutee elle reste une fonction virtuelle pure de cette classe deacuteriveacutee dans les versions anteacuterieures on obtenait une

erreur

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene319

En Java

On peut deacutefinir explicitement une classe abstraite en utilisant tout naturellement le mot

cleacute abstract1 On y preacutecise alors (toujours avec ce mecircme mot cleacute abstract) les meacutethodes

qui doivent obligatoirement ecirctre redeacutefinies dans les classes deacuteriveacutees

6 Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene

Nous allons creacuteer une classe permettant de geacuterer une liste chaicircneacutee drsquoobjets de types diffeacuterents

et disposant des fonctionnaliteacutes suivantes

bull ajout drsquoun nouvel eacuteleacutement

bull affichage des valeurs de tous les eacuteleacutements de la liste

bull meacutecanisme de parcours de la liste

Rappelons que dans une liste chaicircneacutee chaque eacuteleacutement comporte un pointeur sur lrsquoeacuteleacutement

suivant En outre un pointeur deacutesigne le premier eacuteleacutement de la liste Cela correspond agrave ce

scheacutema

Mais ici lrsquoon souhaite que les diffeacuterentes informations puissent ecirctre de types diffeacuterents Aussi

chercherons nous agrave isoler dans une classe (nommeacutee liste) toutes les fonctionnaliteacutes de gestion

de la liste elle-mecircme sans entrer dans les deacutetails speacutecifiques aux objets concerneacutes Nous

appliquerons alors ce scheacutema

1 Ce qui est manifestement plus logique et plus direct qursquoen C++

Informations

1

Informations

3

Informations

2

debut

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

320

La classe liste elle-mecircme se contentera donc de geacuterer des eacuteleacutements simples reacuteduits chacun agrave

bull un pointeur sur leacuteleacutement suivant

bull un pointeur sur linformation associeacutee (en fait ici un objet)

On voit donc que la classe va posseacuteder au moins

bull un membre donneacutee pointeur sur le premier eacuteleacutement (debut dans notre scheacutema)

bull une fonction membre destineacutee agrave inseacuterer dans la liste un objet dont on lui fournira lrsquoadresse

(nous choisirons lrsquoinsertion en deacutebut de liste par souci de simplification)

Lrsquoaffichage des eacuteleacutements de la liste se fera en appelant une meacutethode affiche speacutecifique agrave

lrsquoobjet concerneacute Cela implique la mise en oeuvre de la ligature dynamique par le biais des

fonctions virtuelles La fonction affiche sera deacutefinie dans un premier type drsquoobjet (nommeacute ici

mere) et redeacutefinie dans chacune de ses descendantes

En deacutefinitive on pourra geacuterer une liste dobjets de types diffeacuterents sous reacuteserve que les clas-

ses correspondantes soient toutes deacuteriveacutees dune mecircme classe de base Cela peut sembler

quelque peu restrictif En fait cette famille de classes peut toujours ecirctre obtenue par la

creacuteation dune classe abstraite (reacuteduite au minimum eacuteventuellement agrave une fonction affiche

vide ou virtuelle pure) destineacutee simplement agrave donner naissance aux classes concerneacutees Bien

entendu cela nest concevable que si les classes en question ne sont pas deacutejagrave figeacutees (car il faut

quelles heacuteritent de cette classe abstraite)

Dougrave une premiegravere eacutebauche de la classe liste

struct element structure dun eacuteleacutement de liste element suivant pointeur sur leacuteleacutement suivant

mere contenu pointeur sur un objet quelconque

Objet

1

Objet

3

Objet

2

debut

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene321

class liste element debut pointeur sur premier eacuteleacutement public liste () constructeur ~liste () destructeur void ajoute (mere ) ajoute un eacuteleacutement en deacutebut de liste void affiche ()

Pour mettre en oeuvre le parcours de la liste nous preacutevoyons des fonctions eacuteleacutementaires

pour

bull initialiser le parcours

bull avancer dun eacuteleacutement

Celles-ci neacutecessitent un pointeur sur un eacuteleacutement courant Il sera membre donneacutee de notre

classe liste nous le nommerons courant Par ailleurs les deux fonctions membres eacutevoqueacutees

doivent fournir en retour une information concernant lobjet courant A ce niveau on peut

choisir entre

bull lrsquoadresse de leacuteleacutement courant

bull lrsquoadresse de lobjet courant (crsquoest-agrave-dire lrsquoobjet pointeacute par lrsquoeacuteleacutement courant)

bull la valeur de leacuteleacutement courant

La deuxiegraveme solution semble la plus naturelle Il faut simplement fournir agrave lrsquoutilisateur un

moyen de deacutetecter la fin de liste Nous preacutevoirons donc une fonction suppleacutementaire permet-

tant de savoir si la fin de liste est atteinte (en toute rigueur nous aurions aussi pu fournir un

pointeur nul comme adresse de lobjet courant mais ce serait moins pratique car il faudrait

obligatoirement agir sur le pointeur de liste avant de savoir si lon est agrave la fin)

En deacutefinitive nous introduisons trois nouvelles fonctions membres

void premier () void prochain () int fini ()

Voici la liste complegravete des diffeacuterentes classes voulues Nous lui avons adjoint un petit pro-

gramme drsquoessai qui deacutefinit deux classes point et complexe (lesquelles nrsquoont pas besoin de

deacuteriver lrsquoune de lrsquoautre) deacuteriveacutees de la classe abstraite mere et doteacutees chacune drsquoune fonction

affiche approprieacutee

include ltiostreamgtinclude ltcstddefgt pour la deacutefinition de NULLusing namespace std classe mere class mere public virtual void affiche () = 0 fonction virtuelle pure

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

322

classe liste struct element structure dun eacuteleacutement de liste element suivant pointeur sur leacuteleacutement suivant mere contenu pointeur sur un objet quelconque class liste element debut pointeur sur premier eacuteleacutement element courant pointeur sur eacuteleacutement courant public liste () constructeur debut = NULL courant = debut ~liste () destructeur void ajoute (mere ) ajoute un eacuteleacutement void premier () positionne sur premier eacuteleacutement courant = debut

mere prochain () fournit lrsquoadresse de leacuteleacutement courant (0 si fin) et positionne sur prochain eacuteleacutement (rien si fin) mere adsuiv = NULL if (courant = NULL) adsuiv = courant -gt contenu courant = courant -gt suivant return adsuiv void affiche_liste () affiche tous les eacuteleacutements de la liste int fini () return (courant == NULL)

liste~liste () element suiv courant = debut while (courant = NULL ) suiv = courant-gtsuivant delete courant courant = suiv

void listeajoute (mere chose) element adel = new element adel-gtsuivant = debut adel-gtcontenu = chose debut = adel

void listeaffiche_liste () mere ptr premier() while ( fini() ) ptr = (mere ) prochain() ptr-gtaffiche ()

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene323

classe point

class point public mere

int x y

public

point (int abs=0 int ord=0) x=abs y=ord

void affiche ()

cout ltlt Point de coordonnees ltlt x ltlt ltlt y ltlt n

classe complexe

class complexe public mere

double reel imag

public

complexe (double r=0 double i=0) reel=r imag=i

void affiche ()

cout ltlt Complexe ltlt reel ltlt + ltlt imag ltlt in

programme drsquoessai

main()

liste l1

point a(23) b(59)

complexe x(4527) y(235486)

l1ajoute (ampa) l1ajoute (ampx) l1affiche_liste ()

cout ltlt --------n

l1ajoute (ampy) l1ajoute (ampb) l1affiche_liste ()

Complexe 45 + 27i

Point de coordonnees 2 3

--------

Point de coordonnees 5 9

Complexe 235 + 486i

Complexe 45 + 27i

Point de coordonnees 2 3

Deacuteclaration deacutefinition et utilisation drsquoune liste heacuteteacuterogegravene

Remarque

Par souci de simpliciteacute nous nrsquoavons pas redeacutefini dans la classe liste lrsquoopeacuterateur drsquoaffec-

tation et le constructeur de recopie Dans un programme reacuteel il faudrait le faire quite

drsquoailleurs agrave ce que ces fonctions se contentent drsquointerrompre lrsquoexeacutecution ou encore de

lever une exception (comme nous apprendrons agrave le faire plus tard)

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

324

7 Le meacutecanisme drsquoidentification dynamique des objetsNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Nous avons vu que la technique des fonctions virtuelles permettait de mettre en œuvre la

ligature dynamique pour les fonctions concerneacutees Cependant pour linstant cette technique

peut vous apparaicirctre comme une simple recette La compreacutehension plus fine du meacutecanisme

et donc sa porteacutee veacuteritable passent par la connaissance de la maniegravere dont il est effective-

ment implanteacute Bien que cette impleacutementation ne soit pas explicitement imposeacutee par le lan-

gage nous vous proposons de deacutecrire ici la deacutemarche couramment adopteacutee par les diffeacuterents

compilateurs existants

Pour ce faire nous allons consideacuterer un exemple un peu plus geacuteneacuteral que le preacuteceacutedent agrave

savoir

bull une classe point comportant deux fonctions virtuelles

class point virtual void identifie () virtual void deplace ()

bull une classe pointcol deacuteriveacutee de point ne redeacutefinissant que identifie

class pointcol public point void identifie ()

Dune maniegravere geacuteneacuterale lorsquune classe comporte au moins une fonction virtuelle le com-

pilateur lui associe une table contenant les adresses de chacune des fonctions virtuelles cor-

respondantes Avec lexemple citeacute nous obtiendrons les deux tables suivantes

bull lors de la compilation de point

Table de point

amppointdeplace

amppointidentifie

7 - Le meacutecanisme drsquoidentification dynamique des objets325

bull lors de la compilation de pointcol

Table de pointcol

Notez quici la seconde adresse de la table de pointcol est la mecircme que pour la table de point

dans la mesure ougrave la fonction deplace na pas eacuteteacute redeacutefinie

Dautre part tout objet dune classe comportant au moins une fonction virtuelle se voit attri-

buer par le compilateur outre lemplacement meacutemoire neacutecessaire agrave ses membres donneacutee un

emplacement suppleacutementaire de type pointeur contenant ladresse de la table associeacutee agrave sa

classe Par exemple si nous deacuteclarons (en supposant que nous disposons des constructeurs

habituels)

point p (3 5) pointcol pc (8 6 2)

nous obtiendrons

On peut ainsi dire que ce pointeur introduit dans chaque objet repreacutesente linformation per-

mettant didentifier la classe de lobjet Cest effectivement cette information qui est exploiteacutee

pour mettre en œuvre la ligature dynamique Chaque appel dune fonction virtuelle est traduit

par le compilateur de la faccedilon suivante

bull preacutelegravevement dans lobjet de ladresse de la table correspondante (quelle que soit la maniegravere

dont une fonction est appeleacutee ndash directement ou par pointeur ndash elle reccediloit toujours ladresse

de lobjet en argument implicite)

bull branchement agrave ladresse figurant dans cette table agrave un rang donneacute Notez bien que ce rang

est parfaitement deacutefini agrave la compilation toutes les tables comporteront ladresse de depla-

ce1 par exemple en position 2 En revanche cest lors de lexeacutecution que sera effectueacute le

choix de la bonne table

amppointcolidentifie

amppointcoldeplace

3

vers table de point

vers table de pointcol

5

6

8

2

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

326

8 Identification de type agrave lexeacutecutionLa norme ANSI a introduit dans C++ un meacutecanisme permettant de connaicirctre (identifier et

comparer) lors de lexeacutecution du programme le type dune variable dune expression ou dun

objet1

Bien entendu cela ne preacutesente guegravere dinteacuterecirct si un tel type est deacutefini lors de la compilation

Ainsi avec

int n float x

il ne sera guegravere inteacuteressant de savoir que le type de n ou celui de x peuvent ecirctre connus ou

encore que n et x sont dun type diffeacuterent La mecircme remarque sappliquerait agrave des objets dun

type classe

En fait cette possibiliteacute a surtout eacuteteacute introduite pour ecirctre utiliseacutee dans les situations de poly-

morphisme que nous avons eacutevoqueacutees tout au long de ce chapitre

Plus preacuteciseacutement il est possible lors de lexeacutecution de connaicirctre le veacuteritable type dun

objet deacutesigneacute par un pointeur ou par une reacutefeacuterence

Pour ce faire il existe un opeacuterateur agrave un opeacuterande nommeacute typeid fournissant en reacutesultat un

objet de type preacutedeacutefini type_info Cette classe contient la fonction membre name() laquelle

fournit une chaicircne de caractegraveres2 repreacutesentant le nom du type Ce nom nest pas imposeacute par la

norme il peut donc deacutependre de limpleacutementation mais on est sucircr que deux types diffeacuterents

nauront jamais le mecircme nom

De plus la classe dispose de deux opeacuterateurs binaires == et = qui permettent de comparer

deux types

81 Utilisation du champ name de type_infoVoici un premier exemple inspireacute du programme utiliseacute au paragraphe 2 pour illustrer le

meacutecanisme des fonctions virtuelles il montre linteacuterecirct que preacutesente typeid lorsquon lappli-

que dans un contexte de polymorphisme

include ltiostreamgtinclude lttypeinfogt pour typeidusing namespace std

1 Eventuellement les tables de certaines classes pourront contenir plus dadresses si elles introduisent de nouvelles

fonctions virtuelles mais celles quelles partagent avec leurs ascendantes occuperont toujours la mecircme place et cest

lagrave lessentiel pour le bon deacuteroulement des opeacuterations

1 En anglais ce meacutecanisme est souvent nommeacute RTTI (Run Time Type Identification)

2 Il srsquoagit drsquoune chaicircne au sens du C (pointeur de type char ) et non drsquoun objet de type preacutedeacutefini string

8 - Identification de type agrave lexeacutecution327

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 = ampp cout ltlt type de adp ltlt typeid (adp)name() ltlt n cout ltlt type de adp ltlt typeid (adp)name() ltlt n

adp = amppc cout ltlt type de adp ltlt typeid (adp)name() ltlt n cout ltlt type de adp ltlt typeid (adp)name() ltlt n

type de adp point type de adp point

type de adp point type de adp pointcol

Exemple dutilisation de lopeacuterateur typeid

On notera bien que pour typeid le type du pointeur adp reste bien point En revanche le

type de lobjet pointeacute (adp) est bien deacutetermineacute par la nature exacte de lobjet pointeacute

Remarques

1 Rappelons que la norme nimpose pas le nom exact que doit fournir cet opeacuterateur on

nest donc pas assureacute que le nom de type sera toujours point point pointcol comme

ici

2 Ici les meacutethodes affiche ont eacuteteacute preacutevues vides elles ne servent en fait quagrave assurer le

polymorphisme En lrsquoabsence de meacutethode virtuelle lopeacuterateur typeid se contenterait de

fournir comme type dun objet pointeacute celui deacutefini par le type (statique) du pointeur

Notez que nous nrsquoavons pas utiliseacute une fonction virtuelle pure dans point car il nrsquoaurait

plus eacuteteacute possible drsquoinstancier un objet de type point

3 Le typage dynamique obtenu par les fonctions virtuelles permet drsquoobtenir drsquoun objet un

comportement adapteacute agrave son type sans qursquoil soit pour autant possible de connaicirctre expli-

citement ce type Ces possibiliteacutes srsquoavegraverent geacuteneacuteralement suffisantes Seules quelques

applications tregraves speacutecifiques (telles que des deacutebogueurs) auront besoin de recourir agrave

lrsquoidentification dynamique de type

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

328

82 Utilisation des opeacuterateurs de comparaison de type_infoVoici toujours inspireacute du programme utiliseacute au paragraphe 2 un exemple montrant lrsquoutilisa-

tion de lrsquoopeacuterateur ==

include ltiostreamgtinclude lttypeinfogt pour typeid

using namespace std 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 = ampp1 adp2 = ampp2 cout ltlt En A les objets pointes par adp1 et adp2 sont de if (typeid(adp1) == typeid (adp2)) cout ltlt meme typen else cout ltlt type differentn adp1 = ampp1 adp2 = amppc cout ltlt En B les objets pointes par adp1 et adp2 sont de if (typeid(adp1) == typeid (adp2)) cout ltlt meme typen else cout ltlt type differentn

En A les objets pointes par adp1 et adp2 sont de meme typeEn B les objets pointes par adp1 et adp2 sont de type different

Exemple de comparaison de types dynamiques avec lrsquoopeacuterateur == (1)

83 Exemple avec des reacutefeacuterencesVoici un dernier exemple ougrave lrsquoon applique lrsquoopeacuterateur == agrave des reacutefeacuterences On voit qursquoon dis-

pose ainsi drsquoun moyen de srsquoassurer dynamiquement (au moment de lrsquoexeacutecution) de lrsquoidentiteacute

de type de deux objets reccedilus en argument drsquoune fonction

include ltiostreamgtinclude lttypeinfogt pour typeidusing namespace std

9 - Les cast dynamiques329

class point public virtual void affiche () ici vide class pointcol public point public void affiche () ici vide void fct (point amp a point amp b) if (typeid(a) == typeid(b)) cout ltlt reference a des objets de meme type n else cout ltlt reference a des objets de type different n main() point p pointcol pc1 pc2 cout ltlt Appel A fct (p pc1) cout ltlt Appel B fct (pc1 pc2)

Appel A reference a des objets de meme typeAppel B reference a des objets de type different

Exemple de comparaison de types dynamiques avec lrsquoopeacuterateur == (2)

9 Les cast dynamiquesNous venons de voir comment les possibiliteacutes didentification des types agrave lexeacutecution complegrave-

tent le polymorphisme offert par les fonctions virtuelles en permettant didentifier le type des

objets pointeacutes ou reacutefeacuterenceacutes

Cependant une lacune subsiste on sait agir sur lobjet pointeacute en fonction de son type on

peut connaicirctre le type exact de cet objet mais le type proprement dit des pointeurs utiliseacutes

dans ce polymorphisme reste celui deacutefini agrave la compilation Par exemple si lon sait que adp

pointe sur un objet de type pointcol (deacuteriveacute de point) on pourrait souhaiter convertir sa

valeur en un pointeur de type pointcol

La norme de C++ a introduit cette possibiliteacute par le biais dopeacuterateurs dits cast dynamiques

Ainsi avec lhypothegravese preacuteceacutedente (on est sucircr que adp pointe reacuteellement sur un objet de type

pointcol) on pourra eacutecrire

pointcol adpc = dynamic_cast ltpointcol gt (adp)

Bien entendu en compilation la seule veacuterification qui sera faite est que cette conversion est

(peut-ecirctre) acceptable car lobjet pointeacute par adp est dun type point ou deacuteriveacute et pointcol est

lui-mecircme deacuteriveacute de point Mais ce nest quau moment de lexeacutecution quon saura si la conver-

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

330

sion est reacutealisable ou non Par exemple si adp pointait sur un objet de type point la conver-

sion eacutechouerait

Drsquoune maniegravere geacuteneacuterale lopeacuterateur dynamic_cast aboutit si lobjet reacuteellement pointeacute est par

rapport au type darriveacutee demandeacute dun type identique ou dun type descendant (mais dans un

contexte de polymorphisme cest-agrave-dire quil doit exister au moins une fonction virtuelle)

Lorsque lopeacuterateur naboutit pas

bull il fournit le pointeur NULL sil sagit dune conversion de pointeur

bull il deacuteclenche une exception bad_cast sil sagit dune conversion de reacutefeacuterence

Voici un exemple faisant intervenir une hieacuterarchie de trois classes deacuteriveacutees les unes des

autres

include ltiostreamgtusing namespace std

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 = ampa ada de type A pointe sur un A sa conversion dynamique en B ne marche pas adb = dynamic_cast ltB gt (ada) cout ltlt dc ltBgt(ada) ltlt adb ltlt n ada = ampb ada de type A pointe sur un B sa conversion dynamique en B marche adb = dynamic_cast ltB gt (ada) cout ltlt dc ltBgt ada ltlt adb ltlt n sa conversion dynamique en A marche ada1 = dynamic_cast ltAgt (ada) cout ltlt dc ltAgt ada ltlt ada1 ltlt n mais sa conversion dynamique en C ne marche pas adc = dynamic_cast ltC gt (ada) cout ltlt dc ltCgt ada ltlt adc ltlt n adb = ampb adb de type B pointe sur un B sa conversion dynamique en A marche

9 - Les cast dynamiques331

ada1 = dynamic_cast ltA gt (adb) cout ltlt dc ltAgt adb ltlt ada1 ltlt n sa conversion dynamique en B marche adb1 = dynamic_cast ltB gt (adb) cout ltlt dc ltAgt adb1 ltlt adb1 ltlt n mais sa conversion dynamique en C ne marche pas adc = dynamic_cast ltC gt (adb) cout ltlt dc ltCgt adb1 ltlt adc ltlt n

dc ltBgt(ada) 0x00000000dc ltBgt ada 0x54820ffcdc ltAgt ada 0x54820ffcdc ltCgt ada 0x00000000dc ltAgt adb 0x54820ffcdc ltAgt adb1 0x54820ffcdc ltCgt adb1 0x00000000

Exemple dutilisation de lopeacuterateur dynamic_cast

16

Les flots

Au cours des preacuteceacutedents chapitres nous avons souvent eacuteteacute ameneacute agrave eacutecrire sur la sortie stan-

dard Pour ce faire nous utilisions des instructions telles que

cout ltlt n

Cette derniegravere fait appel agrave lopeacuterateur ltlt auquel elle fournit deux opeacuterandes correspondant

respectivement au flot de sortie concerneacute (ici cout) et agrave lexpression dont on souhaite eacutecrire

la valeur (ici n)

De mecircme nous avons eacuteteacute ameneacute agrave lire sur lrsquoentreacutee standard en utilisant des instructions telles

que

cin gtgt x

Celle-ci fait appel agrave lopeacuterateur gtgt auquel elle fournit deux opeacuterandes correspondant respec-

tivement au flot dentreacutee concerneacute (ici cin) et agrave la lvalue dans laquelle on souhaite lire une

information

Dune maniegravere geacuteneacuterale un flot peut ecirctre consideacutereacute comme un canal

bull recevant de linformation ndash flot de sortie

bull fournissant de linformation ndash flot dentreacutee

Les opeacuterateurs ltlt ou gtgt servent agrave assurer le transfert de linformation ainsi que son eacuteventuel

formatage

Un flot peut ecirctre connecteacute agrave un peacuteripheacuterique ou agrave un fichier Par convention le flot preacutedeacutefini

cout est connecteacute agrave ce que lon nomme la sortie standard correspondant au fichier preacutedeacutefini

stdout du langage C De mecircme le flot preacutedeacutefini cin est connecteacute agrave ce que lon nomme

lentreacutee standard correspondant au fichier preacutedeacutefini stdin du langage C Geacuteneacuteralement

Les flotsCHAPITRE 16

334

lentreacutee standard correspond par deacutefaut au clavier et la sortie standard agrave lrsquoeacutecran mais la plu-

part des impleacutementations vous permettent de rediriger lentreacutee standard ou la sortie standard

vers un fichier

En dehors de ces flots preacutedeacutefinis1 lutilisateur peut deacutefinir lui-mecircme dautres flots quil

pourra connecter agrave un fichier de son choix

On peut dire quun flot est un objet dune classe preacutedeacutefinie agrave savoir

bull ostream pour un flot de sortie

bull istream pour un flot dentreacutee

Chacune de ces deux classes surdeacutefinit les opeacuterateurs ltlt et gtgt pour les diffeacuterents types de

base Leur emploi neacutecessite lincorporation du fichier en-tecircte iostream

Jusquici nous nous sommes contenteacute dexploiter quelques-unes des possibiliteacutes des classes

istream et ostream en nous limitant aux flots preacutedeacutefinis cin et cout Ce chapitre va faire le

point sur lensemble des possibiliteacutes dentreacutees-sorties offertes par C++ telles quelles sont preacute-

vues par la norme ANSI

Nous adopterons la progression suivante

bull preacutesentation geacuteneacuterale des possibiliteacutes de la classe ostream types de base accepteacutes princi-

pales fonctions membres (put write) exemples de formatage de linformation

bull preacutesentation geacuteneacuterale des possibiliteacutes de la classe istream types de base accepteacutes principa-

les fonctions membres (get getline gcount read)

bull gestion du statut derreur dun flot

bull possibiliteacutes de surdeacutefinition des opeacuterateurs ltlt et gtgt pour des types (classes) deacutefinis par

lutilisateur

bull eacutetude deacutetailleacutee des possibiliteacutes de formatage des informations aussi bien en entreacutee quen

sortie

bull connexion dun flot agrave un fichier et possibiliteacutes daccegraves direct offertes dans ce cas

Drsquoune maniegravere geacuteneacuterale sachez que tout ce qui sera dit degraves le deacutebut de ce chapitre agrave propos

des flots sappliquera sans restriction agrave nrsquoimporte quel flot donc agrave un flot connecteacute agrave un

fichier

Informations compleacutementaires

La nouvelle bibliothegraveque drsquoentreacutees-sorties deacutefinie par la norme est une geacuteneacuteralisation de

celle qui existait auparavant (jusqursquoagrave la version 3 de C++) Elle est fondeacutee sur des patrons

de classes permettant de manipuler des flots geacuteneacuteraliseacutes crsquoest-agrave-dire recevant ou fournis-

1 Nous verrons quil en existe dailleurs deux autres cerr et clog

1 - Preacutesentation geacuteneacuterale de la classe ostream335

sant des suites de valeurs drsquoun type donneacute type qui apparaicirct comme paramegravetre despatrons Mais il existe des versions speacutecialiseacutees de ces patrons pour le type char1 qui por-tent le mecircme nom que les classes drsquoavant la norme et qui se comportent de la mecircmemaniegravere2 Ce sont de tregraves loin les plus utiliseacutees et ce sont celles que nous eacutetudierons iciLa geacuteneacuteralisation agrave drsquoautres types ne preacutesenterait de toute faccedilon pas de difficulteacutes

Dans certaines impleacutementations anciennes on risque de trouver encore les deux ver-sions de classes Dans ce cas il faut savoir que lrsquoen-tecircte ltiostreamhgt correspond agravelrsquoancienne version et que les identificateurs correspondants restent comme avant lanorme deacutefinis en dehors de tout espace de noms3 Autrement dit lrsquoinstruction using

namespace std nrsquoest pas requise dans ce cas (neacuteanmoins elle peut le devenir si lrsquoon faitappel agrave drsquoautres fichiers en-tecirctes)

1 Preacutesentation geacuteneacuterale de la classe ostreamApregraves avoir preacuteciseacute le rocircle de lopeacuterateur ltlt et rappeleacute les types de base pour lesquels lopeacutera-teur ltlt est surdeacutefini nous verrons le rocircle des deux fonctions membres put et write Nousexaminerons ensuite quelques exemples de formatage de linformation ce qui nous permettradintroduire la notion importante de manipulateur

11 Lopeacuterateur ltltDans la classe ostream lopeacuterateur ltlt est surdeacutefini pour les diffeacuterents types de base sous laforme

ostream amp operator ltlt (expression)

Il reccediloit deux opeacuterandes

bull la classe layant appeleacute (argument implicite this)

bull une expression dun type de base quelconque

Son rocircle consiste agrave transmettre la valeur de lexpression au flot concerneacute en la formatant4 defaccedilon approprieacutee Consideacuterons par exemple linstruction

cout ltlt n

Si n contient la valeur 1234 le travail de lopeacuterateur ltlt consiste agrave convertir la valeur (binaire)de n dans le systegraveme deacutecimal et agrave envoyer au flot cout les caractegraveres correspondant agrave chacun

1 Il existe eacutegalement des versions speacutecialiseacutees pour le type wchar Les classes correspondantes portent le mecircme nom

que pour le type char preacuteceacutedeacute de w par exemple wistream ou lieu de istream

2 Les diffeacuterences sont extrecircmement mineures Elles seront mentionneacutees le moment venu

3 Rappelons que les espaces de noms seront eacutetudieacutes en deacutetail au chapitre 24

4 Nous verrons quil est possible dintervenir sur la maniegravere dont est effectueacute ce formatage Dautre part dans cer-

tains cas il pourra ne pas y avoir de formatage cest ce qui se produira par exemple lorsque lon utilisera la fonc-

tion write

Les flotsCHAPITRE 16

336

des chiffres ainsi obtenus (ici les caractegraveres 1 2 3 et 4) Nous emploierons le mot eacutecri-ture pour qualifier le rocircle de cet opeacuterateur sachez toutefois que ce terme nest pas universel-lement reacutepandu notamment on rencontre parfois injection

Par ailleurs cet opeacuterateur ltlt fournit comme reacutesultat la reacutefeacuterence au flot concerneacute apregraves quila eacutecrit linformation voulue Cela permet de lappliquer facilement plusieurs fois de suitecomme dans

cout ltlt valeur ltlt na ltlt n

Voici un reacutecapitulatif concernant les types accepteacutes par cet opeacuterateur

Les types accepteacutes par lrsquoopeacuterateur ltlt

12 Les flots preacutedeacutefinisEn plus de cout il existe deux autres flots preacutedeacutefinis de classe ostream

bull cerr flot de sortie connecteacute agrave la sortie standard derreur (stderr en C) sans tampon1 in-termeacutediaire

bull clog flot de sortie connecteacute aussi agrave la sortie standard derreur mais en utilisant un tam-pon2 intermeacutediaire

Tous les types de base sont accepteacutes par lrsquoopeacuterateur ltlt

- soit par surdeacutefinition effective de lrsquoopeacuterateur types char (avec les variantes signed ou unsigned) int (avec sa variante unsigned) long (avec sa variante unsigned) float double et long double

- soit par le jeu des conversions implicites types bool short

Les types pointeurs sont accepteacutes

- char on obtient la chaicircne situeacutee agrave lrsquoadresse correspondante le type string sera accepteacute avec le mecircme comportement

- pointeur sur un type quelconque autre que char on obtient la valeur du pointeur correspondant Si lrsquoon souhaite afficher la valeur drsquoun pointeur de type char (et non plus la chaicircne qursquoil reacutefeacuterence) il suffit de le convertir explicitement en void

Les tableaux sont accepteacutes mais ils sont alors convertis dans le pointeur correspon-dant on nrsquoobtient donc geacuteneacuteralement une adresse et non les valeurs des eacuteleacutements du tableau sauf pour les tableaux de caractegraveres traiteacutes comme une chaicircne de style C (attention au problegraveme du zeacutero de fin )

Les types classes seront accepteacutes si lrsquoon y a deacutefini convenablement lrsquoopeacuterateur ltlt

1 En anglais buffer On parle parfois en franglais de sortie non bufferiseacutee

2 On parle parfois de sortie bufferiseacutee

1 - Preacutesentation geacuteneacuterale de la classe ostream337

13 La fonction putIl existe dans la classe ostream une fonction membre nommeacutee put qui transmet au flot cor-respondant le caractegravere reccedilu en argument Ainsi

coutput(c)

transmet au flot cout le caractegravere contenu dans c comme le ferait cout ltlt c

En fait la fonction put eacutetait surtout indispensable dans les versions anteacuterieures agrave la 20 pourpallier labsence de surdeacutefinition de lopeacuterateur pour le type char

La valeur de retour de put est le flot concerneacute apregraves quon y a eacutecrit le caractegravere correspon-dant Cela permet deacutecrire par exemple (c1 c2 et c3 eacutetant de type char)

coutput(c1)put(c2)put(c3)

ce qui est eacutequivalent agrave coutput(c1) coutput(c2) coutput(c3)

14 La fonction writeDans la classe ostream la fonction membre write permet de transmettre une suite drsquooctets auflot de sortie consideacutereacute

141 Cas des caractegraveres

Comme un caractegravere est toujours rangeacute dans un octet on peut utiliser write pour une chaicircnede longueur donneacutee Par exemple avec

char t[] = bonjour

lrsquoinstruction coutwrite (t 4)

envoie sur le flot cout 4 caractegraveres conseacutecutifs agrave partir de lrsquoadresse t crsquoest-agrave-dire les caractegrave-res b o n et j

Cette fonction peut ici sembler faire double emploi avec la transmission drsquoune chaicircne agravelrsquoaide de lrsquoopeacuterateur ltlt En fait son comportement nrsquoest pas le mecircme puisque write ne faitpas intervenir de caractegravere de fin de chaicircne (caractegravere nul) si un tel caractegravere apparaicirct dans lalongueur preacutevue il sera transmis comme les autres au flot de sortie De plus cette fonctionne reacutealise aucun formatage (alors que comme nous le verrons avec lrsquoopeacuterateur ltlt on peutagir sur le gabarit de lrsquoinformation effectivement eacutecrite sur le flot)

142 Autres cas

En fait cette fonction write srsquoaveacuterera indispensable lorsque lrsquoon souhaitera transmettre uneinformation sous une forme brute (on dit souvent binaire) sans qursquoelle subisse la moin-dre modification En geacuteneacuteral cela nrsquoa guegravere drsquointeacuterecirct dans le cas drsquoun eacutecran En revanche ce

Les flotsCHAPITRE 16

338

sera la seule faccedilon de creacuteer un fichier sous forme binaire (crsquoest-agrave-dire dans lequel les infor-mations ndash quel que soit leur type ndash sont enregistreacutees telles qursquoelles figurent en meacutemoire)

Comme put la fonction write fournit en retour le flot concerneacute apregraves qursquoon y a eacutecrit lrsquoinfor-mation correspondante

15 Quelques possibiliteacutes de formatage avec ltltNous eacutetudierons au paragraphe 5 lensemble des possibiliteacutes de formatage de la classeostream ainsi que celles de la classe istream Cependant nous vous preacutesentons degraves mainte-nant les exemples de formatage en sortie les plus courants ce qui nous permettra dintroduirela notion de manipulateur (parameacutetrique ou non)

151 Action sur la base de numeacuteration

Lorsque lon eacutecrit une valeur entiegravere sur un flot de sortie on peut choisir de lexprimer danslune des bases suivantes

bull 10 deacutecimal (il sagit de la valeur par deacutefaut)

bull 16 hexadeacutecimal

bull 8 octal

En outre depuis la norme on peut choisir drsquoexprimer une expression booleacuteenne (de typebool) soit sous la forme drsquoun entier (0 ou 1) soit sous la forme false true

Voici un exemple de programme dans lequel nous eacutecrivons

bull dans diffeacuterentes bases la valeur de la mecircme variable entiegravere n

bull de diffeacuterentes maniegraveres la valeur drsquoune variable ok de type bool

include ltiostreamgtusing namespace std main() int n = 12000 cout ltlt par defaut ltlt n ltlt n cout ltlt en hexadecimal ltlt hex ltlt n ltlt n cout ltlt en decimal ltlt dec ltlt n ltlt n cout ltlt en octal ltlt oct ltlt n ltlt n cout ltlt et ensuite ltlt n ltlt n bool ok = 1 ou ok = true cout ltlt par defaut ltlt ok ltlt n cout ltlt avec noboolalpha ltlt noboolalpha ltlt ok ltlt n cout ltlt avec boolalpha ltlt boolalpha ltlt ok ltlt n cout ltlt et ensuite ltlt ok ltlt n

par defaut 12000en hexadecimal 2ee0en decimal 12000

1 - Preacutesentation geacuteneacuterale de la classe ostream339

en octal 27340et ensuite 27340par defaut 1avec noboolalpha 1avec boolalpha trueet ensuite true

Action sur la base de numeacuteration des valeurs eacutecrites sur cout

Les symboles hex dec oct se nomment des manipulateurs Il sagit dopeacuterateurs preacutedeacutefinisagrave un seul opeacuterande de type flot fournissant en retour le mecircme flot apregraves quils ont opeacutereacute unecertaine action (manipulation) Ici cette action consiste agrave modifier la valeur de la base denumeacuteration (cette information eacutetant en fait meacutemoriseacutee dans la classe ostream1) Notez bienque la valeur de la base reste la mecircme tant quon ne la modifie pas (par un manipulateur) etcela quelles que soient les informations transmises au flot (entiers caractegraveres flottants)2

Le manipulateur boolalpha demande drsquoafficher les valeurs booleacuteennes sous la forme alpha-beacutetique crsquoest-agrave-dire true ou false Le manipulateur noboolalpha demande en revanche drsquouti-liser la forme numeacuterique 0 ou 1

Nous verrons au paragraphe 5 quil existe beaucoup dautres manipulateurs dont nous feronsune analyse complegravete

152 Action sur le gabarit de linformation eacutecrite

Consideacuterons cet exemple de programme qui montre comment agir sur la largeur (gabarit)selon laquelle linformation est eacutecrite

include ltiostreamgtinclude ltiomanipgtusing namespace std main() int n = 12345 int i for (i=0 ilt15 i++) cout ltlt setw(2) ltlt i ltlt ltlt setw(i) ltlt n ltlt n

0 12345 1 12345 2 12345 3 12345 4 12345 5 12345

1 En toute rigueur de la classe ios dont deacuterivent les classes ostream et istream

2 Attention tous les manipulateurs ne se comportent pas ainsi

Les flotsCHAPITRE 16

340

6 12345

7 12345 8 12345

9 12345

10 1234511 12345

12 12345

13 12345

14 12345

Action sur le gabarit de linformation eacutecrite sur cout

Ici encore nous faisons appel agrave un manipulateur (setw) Un peu plus complexe que les preacuteceacute-dents (hex oct ou dec) il comporte un paramegravetre repreacutesentant le gabarit souhaiteacute On parlealors de manipulateur parameacutetrique Nous verrons quil existe beaucoup dautres manipula-teurs parameacutetriques leur emploi neacutecessite absolument lincorporation du fichier en-tecircteltiomanipgt1

En ce qui concerne setw sachez que ce manipulateur deacutefinit uniquement le gabarit de la pro-

chaine information agrave eacutecrire Si lon ne fait pas agrave nouveau appel agrave setw pour les informationssuivantes celles-ci seront eacutecrites suivant les conventions habituelles agrave savoir en utilisantlemplacement minimal neacutecessaire pour les eacutecrire (2 caractegraveres pour la valeur 245 caractegraverespour la valeur -2345 7 caractegraveres pour la chaicircne bonjour) Dautre part si la valeur four-nie agrave setw est insuffisante pour leacutecriture de la valeur suivante cette derniegravere sera eacutecrite selonles conventions habituelles (elle ne sera donc pas tronqueacutee)

Agrave titre indicatif en remplaccedilant lrsquoinstruction drsquoaffichage du programme preacuteceacutedent par cout ltlt setw(2) ltlt i ltlt setw(i) ltlt ltlt n ltlt n

on obtiendrait ces reacutesultats 1 12345

2 12345

3 12345 4 12345

5 12345

6 12345

7 12345 8 12345

9 12345

10 12345

11 12345

Notez bien la position du premier caractegravere dans les reacutesultats afficheacutes En effet cette foissetw(i) ne srsquoapplique qursquoagrave la chaicircne constante ( ) afficheacutee ensuite la valeur de n restantafficheacutee suivant les conventions par deacutefaut

1 ltiomaniphgt si lrsquoon utilise encore ltiostreamhgt

1 - Preacutesentation geacuteneacuterale de la classe ostream341

153 Action sur la preacutecision de lrsquoinformation eacutecriteVoyez ce programme

include ltiomanipgtinclude ltiostreamgtusing namespace std main() float x = 20003 double pi = 3141926536 cout ltlt affichage de 20003 et de pi dans differentes precisions n cout ltlt par defaut ltlt x ltlt ltlt pi ltlt n for (int i=1 ilt8 i++) cout ltlt precision ltlt i ltlt ltlt setprecision (i) ltlt x ltlt ltlt pi ltlt n

affichage de 20003 et de pi dans differentes precisions par defaut 666667 314193precision 1 7e+02 3precision 2 67e+02 31precision 3 667 314precision 4 6667 3142precision 5 66667 31419precision 6 666667 314193precision 7 6666667 3141927

Action sur la preacutecision de lrsquoinformation eacutecrite sur cout

Par deacutefaut comme on le voit dans la premiegravere ligne afficheacutee pour les informations de typeflottant lrsquoopeacuterateur ltlt

bull choisit la notation la plus approprieacutee (flottante ou exponentielle avec un chiffre avant lepoint de la mantisse)

bull utilise 6 chiffres significatifs

Le manipulateur parameacutetrique setw (precision) permet de deacutefinir le nombre de chiffres signi-catifs voulus Cette fois lrsquoeffet de ce manipulateur est permanent (jusqursquoagrave modificationexplicite) comme le montre lrsquoaffichage de la seconde information On notera que si la preacuteci-sion demandeacutee nrsquoest pas suffisante pour afficher au moins la valeur entiegravere du nombre con-cerneacute elle est modifieacutee en conseacutequence ainsi drsquoailleurs que le choix de la notation En C++on ne voit jamais de reacutesultat totalement faux (il faut quand mecircme eacuteviter la preacutecision zeacutero )

154 Choix entre notation flottante ou exponentielleVoyez cet exemple qui montre lrsquoutilisation des manipulateurs fixed (notation flottante) etscientific (notation exponentielle avec un chiffre avant le point de la mantisse) coupleacute avecle choix de la preacutecision

include ltiostreamgtinclude ltiomanipgtusing namespace std

Les flotsCHAPITRE 16

342

main() float x = 2e53

double pi = 3141926536

cout ltlt fixed ltlt choix notation flottante n for (int i=1 ilt8 i++)

cout ltlt precision ltlt i ltlt setprecision (i) ltlt ltlt x ltlt

ltlt pi ltlt n cout ltlt scientific ltlt choix notation exponentielle n

for (int i=1 ilt8 i++) cout ltlt precision ltlt i ltlt setprecision (i) ltlt ltlt x ltlt

ltlt pi ltlt n

choix notation flottante precision 1 666667 31

precision 2 6666666 314precision 3 66666664 3142

precision 4 666666641 31419

precision 5 6666666406 314193precision 6 66666664062 3141927

precision 7 666666640625 31419265choix notation exponentielle

precision 1 67e+04 31e+00

precision 2 667e+04 314e+00precision 3 6667e+04 3142e+00

precision 4 66667e+04 31419e+00

precision 5 666667e+04 314193e+00precision 6 6666666e+04 3141927e+00

precision 7 66666664e+04 31419265e+00

Choix de la notation (flottante ou exponentielle)

On notera que cette fois la preacutecision correspond au nombre de chiffres apregraves le point deacuteci-mal quelle que soit la notation utiliseacutee On aura donc inteacuterecirct agrave eacuteviter drsquoutiliser le mode pardeacutefaut degraves lors qursquoon souhaite maicirctriser la preacutecision des affichages

Lagrave encore lrsquoeffet des modificateurs fixed ou scientific est permanent (jusqursquoagrave modificationexplicite) On notera qursquoune fois choisie lrsquoune de ces notations il nrsquoest plus possible de reve-nir au comportement par deacutefaut (choix automatique de la notation) avec un manipulateur Onpourra y parvenir en utilisant drsquoautres possibliteacutes deacutecrites au paragraphe 5 (il faudrait remet-tre agrave zeacutero les bits du champ floatfield du mot drsquoeacutetat de formatage par exemple avec la fonc-tion setf)

2 Preacutesentation geacuteneacuterale de la classe istreamComme nous avons fait pour la classe ostream nous commencerons par preacuteciser le rocircle delopeacuterateur gtgt Puis nous deacutefinirons le rocircle des diffeacuterentes fonctions membres de la classe

2 - Preacutesentation geacuteneacuterale de la classe istream343

istream (get getline gcount read) Nous terminerons sur un exemple de formatage delinformation

21 Lrsquoopeacuterateur gtgtDans la classe istream lopeacuterateur gtgt est surdeacutefini pour tous les types de base y comprischar 1 sous la forme

istream amp operator gtgt (type_de_base amp )

Il reccediloit deux opeacuterandes

bull la classe layant appeleacute (argument implicite this)

bull une lvalue dun type de base quelconque

Son rocircle consiste agrave extraire du flot concerneacute les caractegraveres neacutecessaires pour former une valeurdu type de base voulu en reacutealisant une opeacuteration inverse du formatage opeacutereacute par lopeacuterateurltlt

Il fournit comme reacutesultat la reacutefeacuterence au flot concerneacute apregraves quil en a extrait linformationvoulue Cela permet de lappliquer plusieurs fois de suite comme dans

cin gtgt n gtgt p gtgt x

Les espaces blancs2 jouent un rocircle important puisque drsquoune part ils servent de seacuteparateurs etque drsquoautre part toute lecture commence par sauter ces caractegraveres srsquoil en existe Rappelonsque lrsquoon range dans cette cateacutegorie les caractegraveres espace tabulation horizontale (t) tabula-tion verticale (v) fin de ligne (n) et changement de page (f)

211 Cas des caractegraveresUne des conseacutequences immeacutediates de ce meacutecanisme fait que (par deacutefaut) ces deacutelimiteurs nepeuvent pas ecirctre lus en tant que caractegraveres Par exemple la reacutepeacutetition de lrsquoinstruction (c eacutetantsupposeacute de type char)

cin gtgt c

appliqueacutee agrave un flot contenant ce texte b o

n j

our

conduira agrave ne prendre en compte que les 7 caractegraveres b o n j o u et r

En theacuteorie il existe un modificateur nommeacute noskipws (ne pas sauter les espaces blancs) per-met drsquoagir sur ce point mais son utilisation est peu aiseacutee dans la mesure ougrave il concerne alorstoutes les informations lues en particulier celles de type numeacuterique Nous verrons ci-dessousqursquoil existe des solutions plus agreacuteables pour acceacuteder aux deacutelimiteurs en utilisant lrsquoune desfonctions membres get ou getline

1 Mais pas a priori pour les types pointeurs

2 De white spaces en anglais

Les flotsCHAPITRE 16

344

212 Cas des chaicircnes de caractegraveresLorsqursquoon lit sur un flot une information agrave destination drsquoune chaicircne de caractegraveres (typechar ) lrsquoinformation rangeacutee en meacutemoire est compleacuteteacutee par un caractegravere nul de fin de chaicircne(0) Ainsi pour lire une chaicircne de n caractegraveres il faut preacutevoir un emplacement de n+1 carac-tegraveres De plus si lrsquoon veut eacuteviter des problegravemes drsquoeacutecrasement en meacutemoire il faut ecirctre capablede deacutefinir le nombre maximal de caractegraveres que lrsquoutilisateur risque de fournir ce qui nrsquoest pastoujours une chose aiseacutee (dans certains environnements les lignes au clavier peuventatteindre des longueurs importantes) On peut recourir au manipulateur parameacutetrique setw

qui limite le nombre de caractegraveres pris en compte lors de la prochaine lecture (et uniquementcelle-la) Par exemple avec

const int LGNOM = 10 char nom[LGNOM+1] cin gtgt setw(LGNOM) gtgt nom

on est certain de ne pas prendre en compte plus de 10 caractegraveres pour le tableau nom

En outre comme par deacutefaut les espaces blancs servent de deacutelimiteurs il nrsquoest pas possiblede lire en une seule fois une chaicircne contenant par exemple un espace telle que

bonjour mademoiselle

Notez que dans ce cas il ne sert agrave rien de la placer entre guillemets bonjour mademoiselle

En effet la premiegravere chaicircne lue serait alors bonjour

Lagrave encore nous verrons un peu plus loin que la fonction getline fournit une solution agreacuteableagrave ce problegraveme

213 Les types accepteacutes par gtgtVoici un reacutecapitulatif concernant les types accepteacutes par cet opeacuterateur

Les types accepteacutes par lrsquoopeacuterateur gtgt

Tous les types de base sont accepteacutes par lrsquoopeacuterateur gtgt bool char (et ses variantes signed et unsigned) short (et sa variante unsigned) int (et sa variante unsigned) long (et sa variante unsigned) float double et long double

Parmi les types pointeurs seul char est accepteacute dans ce cas on lit une chaicircne de caractegraveres

Les tableaux ne sont pas accepteacutes hormis les tableaux de caractegraveres (on y lit une chaicircne de caractegraveres termineacutee par un caractegravere nul)

Le type string (chaicircnes de type classe) sera accepteacute (il jouera un rocircle comparable aux chaicircnes de caractegraveres avec moins de risques)

Les autres types classes seront accepteacutes si lrsquoon y a surdeacutefini convenablement lrsquoopeacuterateur gtgt

2 - Preacutesentation geacuteneacuterale de la classe istream345

22 La fonction getLa fonction

istream amp get (char amp)

permet dextraire un caractegravere dun flot dentreacutee et de le ranger dans la variable (de type char)quon lui fournit en argument Tout comme put cette fonction fournit en retour la reacutefeacuterenceau flot concerneacute apregraves quon en a extrait le caractegravere voulu

Contrairement au comportement par deacutefaut de lopeacuterateur gtgt la fonction get peut lirenimporte quel caractegravere deacutelimiteurs compris Ainsi en lappliquant agrave un flot contenant cetexte

b on j

our

elle conduira agrave prendre en compte 16 caractegraveres b espace o n n espace espace espaceespace j n n o u r et n

Il existe une autre fonction get (il y a donc surdeacutefinition) de la forme int get ()

Celle-ci permet elle aussi dextraire un caractegravere dun flot dentreacutee mais elle le fournit commevaleur de retour sous la forme dun entier Elle est ainsi en mesure de fournir une valeur speacute-ciale EOF (en geacuteneacuteral -1) lorsque la fin de fichier a eacuteteacute rencontreacutee sur le flot correspondant1

Remarque

Nous verrons au paragraphe 3 consacreacute au statut derreur dun flot quil est possible deconsideacuterer un flot comme une valeur logique (vrai ou faux) et par suite deacutecrire desinstructions telles que

char c while ( cinget(c) ) recopie le flot cin coutput (c) sur le flot cout arrecirct quand eof car alors (cin) = 0

Celles-ci sont eacutequivalentes agrave

int c while ( ( c = cinget() ) = EOF ) coutput (c)

23 Les fonctions getline et gcountCes deux fonctions facilitent la lecture des chaicircnes de caractegraveres ou plus geacuteneacuteralement dunesuite de caractegraveres quelconques termineacutee par un caractegravere connu (et non preacutesent dans lachaicircne en question)

1 Cest ce qui justifie que sa valeur de retour soit de type int et non char

Les flotsCHAPITRE 16

346

Len-tecircte de la fonction getline se preacutesente sous la forme

istream amp getline (char ch int taille char delim = n )

Cette fonction lit des caractegraveres sur le flot layant appeleacutee et les place dans lemplacementdadresse ch Elle srsquointerrompt lorsquune des deux conditions suivantes est satisfaite

bull le caractegravere deacutelimiteur delim a eacuteteacute trouveacute dans ce cas ce caractegravere nest pas recopieacute enmeacutemoire

bull taille - 1 caractegraveres ont eacuteteacute lus

Dans tous les cas cette fonction ajoute un caractegravere nul de fin de chaicircne agrave la suite des carac-tegraveres lus

Notez que le caractegravere deacutelimiteur possegravede une valeur par deacutefaut (n) bien adapteacutee agrave la lecturede lignes de texte

Quant agrave la fonction gcount elle fournit le nombre de caractegraveres effectivement lus lors du der-nier appel de getline Ni le caractegravere deacutelimiteur ni celui placeacute agrave la fin de la chaicircne ne sontcompteacutes autrement dit gcount fournit la longueur effective de la chaicircne rangeacutee en meacutemoirepar getline

Voici agrave titre dexemple un programme qui affiche des lignes entreacutees au clavier et en preacutecisele nombre de caractegraveres

include ltiostreamgt

using namespace std

main()

const int LG_LIG = 120 longueur maxi dune ligne de texte

char ch [LG_LIG+1] pour lire une ligne

int lg longueur courante dune ligne

do

cingetline (ch LG_LIG)

lg = cingcount ()

cout ltlt ligne de ltlt lg-1 ltlt caracteres ltlt ch ltlt n

while (lg gt1)

bonjour

ligne de 7 caracteres bonjour

9 fois 5 font 45

ligne de 16 caracteres 9 fois 5 font 45

nimporte quoi ltampeacute(-egrave_ccedilagrave))=

ligne de 29 caracteres nimporte quoi ltampeacute(-egrave_ccedilagrave))=

ligne de 0 caracteres

Exemple drsquoutilisation de la fonction getline

2 - Preacutesentation geacuteneacuterale de la classe istream347

Remarques

1 Le programme preacuteceacutedent peut tout agrave fait servir agrave lister un fichier texte pour peu qursquoon aitredirigeacute vers lui lrsquoentreacutee standard

2 Il existe une autre fonction getline (indeacutependante cette fois) destineacutee agrave lire des caractegrave-res dans un objet de type string nous en parlerons au paragraphe 3 du chapitre 22 ougravenous proposerons une adaptation du preacuteceacutedent programme

24 La fonction readLa fonction read permet de lire une suite drsquooctets sur le flot drsquoentreacutee consideacutereacute

241 Cas des caractegraveresComme un octet peut toujours contenir un caractegravere on peut utiliser read pour une chaicircne decaractegraveres de longueur donneacutee Par exemple avec

char t[10]

lrsquoinstruction cinread (t 5)

lira sur cin 5 caractegraveres et les rangera agrave partir de lrsquoadresse t

Lagrave encore ette fonction peut sembler faire double emploi soit avec la lecture drsquoune chaicircneavec lrsquoopeacuterateur gtgt soit avec la fonction getline Toutefois read ne neacutecessite ni seacuteparateurni caractegravere deacutelimiteur particulier En outre aucun caractegravere de fin de chaicircne nrsquointervient nisur le flot ni en meacutemoire

242 Autres casEn fait cette fonction srsquoaveacuterera indispensable lorsque lrsquoon souhaitera acceacuteder agrave une informa-tion drsquoun fichier sous forme brute (binaire) sans qursquoelle ne subisse aucune transformationcrsquoest-agrave-dire en recopiant en meacutemoire les informations telles qursquoelles figurent dans le fichierLa fonction read jouera le rocircle symeacutetrique de la fonction write

25 Quelques autres fonctionsDans la classe istream il existe eacutegalement deux fonctions membres agrave caractegravere utilitaire

bull putback (char c) pour renvoyer dans le flot concerneacute un caractegravere donneacute

bull peek () qui fournit le prochain caractegravere disponible sur le flot concerneacute mais sans lextrairedu flot (il sera donc agrave nouveau obtenu lors dune prochaine lecture sur le flot)

Remarque

En toute rigueur il existe aussi une classe iostream heacuteritant agrave la fois de istream et deostream Celle-ci permet de reacutealiser des entreacutees-sorties bidirectionnelles

Les flotsCHAPITRE 16

348

3 Statut drsquoerreur drsquoun flotA chaque flot dentreacutee ou de sortie est associeacute un ensemble de bits dun entier formant ce quelon nomme le statut derreur du flot Il permet de rendre compte du bon ou du mauvaisdeacuteroulement des opeacuterations sur le flot Nous allons tout dabord voir quelle est la significationde ces diffeacuterents bits (au nombre de 4) Puis nous apprendrons comment en connaicirctre lavaleur et le cas eacutecheacuteant la modifier Enfin nous montrerons que la surdeacutefinition des opeacutera-teurs () et permet de simplifier lutilisation dun flot

31 Les bits derreurLa position des diffeacuterents bits derreur au sein dun entier est deacutefinie par des constantes deacutecla-reacutees dans la classe ios dont deacuterivent les deux classes istream et ostream Chacune de cesconstantes correspond agrave la valeur prise par lentier en question lorsque le bit correspondant ndashet lui seul ndash est activeacute (agrave 1) Il sagit de

bull eofbit ce bit est activeacute si la fin de fichier a eacuteteacute atteinte autrement dit si le flot correspondantna plus aucun caractegravere disponible

bull failbit ce bit est activeacute lorsque la prochaine opeacuteration dentreacutee-sortie ne peut aboutir

bull badbit ce bit est activeacute lorsque le flot est dans un eacutetat irreacutecupeacuterable

La diffeacuterence entre badbit et failbit nexiste que pour les flots dentreacutee Lorsque failbit estactiveacute aucune information na eacuteteacute reacuteellement perdue sur le flot il nen va plus de mecircme lors-que badbit est activeacute

De plus il existe une constante goodbit (valant en fait 0) qui correspond agrave la valeur que doitavoir le statut derreur lorsquaucun de ses bits nest activeacute

On peut dire quune opeacuteration dentreacutee-sortie a reacuteussi lorsque lun des bits goodbit ou eofbit

est activeacute De mecircme on peut dire que la prochaine opeacuteration dentreacutee-sortie ne pourra aboutirque si goodbit est activeacute (mais il nest pas encore certain quelle reacuteussisse)

Lorsquun flot est dans un eacutetat derreur aucune opeacuteration ne peut aboutir tant que

bull la condition derreur na pas eacuteteacute corrigeacutee (ce qui va de soi )

bull le bit derreur correspondant na pas eacuteteacute remis agrave zeacutero nous allons voir quil existe des fonc-tions permettant dagir sur ces bits derreur

32 Actions concernant les bits derreurIl existe deux cateacutegories de fonctions

bull celles qui permettent de connaicirctre le statut derreur dun flot cest-agrave-dire en fait la valeur deses diffeacuterents bits derreur

bull celles qui permettent de modifier la valeur de certains de ces bits derreur

3 - Statut drsquoerreur drsquoun flot349

321 Accegraves aux bits derreur

Dune part il existe 5 fonctions membres (de ios1)

bull eof () fournit la valeur vrai (1) si la fin de fichier a eacuteteacute rencontreacutee cest-agrave-dire si le bit eofbit

est activeacute

bull bad () fournit la valeur vrai (1) si le flot est alteacutereacute cest-agrave-dire si le bit badbit est activeacute

bull fail () fournit la valeur vrai (1) si le bit failbit est activeacute

bull good () fournit la valeur vrai (1) si aucune des trois fonctions preacuteceacutedentes na la valeur vraicest-agrave-dire si aucun des bits du statut derreur nest activeacute2

Dautre part la fonction membre3 rdstate () fournit en retour un entier correspondant agrave lavaleur du statut derreur

322 Modification du statut derreur

La fonction membre clear den-tecircte

void clear (int i=0)

active les bits derreur correspondant agrave la valeur fournie en argument En geacuteneacuteral on deacutefinitla valeur de cet argument en utilisant les constantes preacutedeacutefinies de la classe ios

Par exemple si fl deacutesigne un flot linstruction flclear (iosbadbit)

activera le bit badbit du statut derreur du flot fl et mettra tous les autres bits agrave zeacutero

Si lon souhaite activer ce bit sans modifier les autres il suffit de faire appel agrave rdstate en pro-ceacutedant ainsi

flclear (iosbadbit | flrdstate () )

Remarque

Lorsque vous surdeacutefinirez les opeacuterateurs ltlt et gtgt pour vos propres types (classes) il serapratique de pouvoir activer les bits derreur en guise de compte rendu du deacuteroulement delopeacuteration

33 Surdeacutefinition des opeacuterateurs () et Comme nous lavons deacutejagrave eacutevoqueacute dans la remarque du paragraphe 22 il est possible de tes-ter un flot en le consideacuterant comme une valeur logique (vrai ou faux) Pour ce faire on arecours agrave la surdeacutefinition dans la classe ios des opeacuterateurs () et

1 Donc de istream et de ostream par heacuteritage

2 Dans les preacuteceacutedentes versions de la bibliothegraveque drsquoentreacutees-sorties (ou si lrsquoon utilise ltiostreamhgt au lieu de

ltiostreamgt cette fonction fournit la valeur vrai mecircme si eofbit est activeacute

3 Deacutesormais nous ne preacuteciserons plus quil sagit dun membre de ios dont heacuteritent istream et ostream

Les flotsCHAPITRE 16

350

Plus preacuteciseacutement lopeacuterateur () est surdeacutefini de maniegravere que si fl deacutesigne un flot

( fl )

bull prenne une valeur non nulle1 (vrai) si aucun des bits derreur nest activeacute cest-agrave-dire si good

() a la valeur vrai

bull prenne une valeur nulle (faux) dans le cas contraire cest-agrave-dire si good () a la valeur faux

Ainsi if (fl)

peut remplacer if (flgood () )

De mecircme lopeacuterateur est surdeacutefini de maniegravere que si fl deacutesigne un flot

fl

bull prenne une valeur nulle (faux) si un des bits derreur est activeacute cest-agrave-dire si good() a la va-leur faux

bull prenne une valeur non nulle (vrai) si aucun des bits derreur nest activeacute cest-agrave-dire sigood() a la valeur vrai

Ainsi if ( flot )

peut remplacer if ( flotgood () )

34 ExemplesEn testant et en modifiant lrsquoeacutetat du flot cin nous pouvons geacuterer les situations dans lesquellesun caractegravere invalide venait bloquer les lectures ulteacuterieures Nous vous proposons une adap-tation dans ce sens du programme du paragraphe 353 du chapitre 3 Nous verrons qursquoilsouffre encore de lacunes de sorte que cet exemple devra surtout ecirctre consideacutereacute comme unexemple drsquoutilisation des outils de gestion de lrsquoeacutetat drsquoun flot

include ltiostreamgtusing namespace std main() int n char c do cout ltlt donnez un nombre entier if (cin gtgt n) cout ltlt voici son carre ltlt nn ltlt n else (cinclear()) cin gtgt c while (n)

1 Sa valeur exacte nest pas preacuteciseacutee et elle na donc pas de signification particuliegravere

3 - Statut drsquoerreur drsquoun flot351

donnez un nombre entier 12

voici son carre 144

donnez un nombre entier x25

donnez un nombre entier voici son carre 625

donnez un nombre entier ampamp2

donnez un nombre entier donnez un nombre entier voici son carre 4

donnez un nombre entier 0

voici son carre 0

Pour eacuteviter une boucle infinie en cas de caractegravere invalide

Lorsque le flot est bloqueacute nous lisons artificiellement un caractegravere (correspondant au carac-tegravere invalide responsable du blocage) nous deacutebloquons le flot par appel de clear et nousrelanccedilons la lecture Comme le montre lrsquoexemple drsquoexeacutecution la situation est deacutebloqueacuteemais le dialogue avec lrsquoutilisateur laisse agrave deacutesirer

Agrave titre indicatif voici agrave quoi conduirait une adaptation comparable du programme du para-graphe 352 du chapitre 3

include ltiostreamgt

using namespace std

main()

int n = 12 char c = rsquoarsquo char cc

bool ok = false

do cout ltlt donnez un entier et un caractere n

if (cin gtgt n gtgt c)

cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

ok = true

else

ok = false

cinclear()

cin gtgt cc pour lire au moins le caractere invalide

while ( ok)

donnez un entier et un caractere

12 y

merci pour 12 et y

donnez un entier et un caractere

amp2 y

donnez un entier et un caractere

merci pour 2 et y

Les flotsCHAPITRE 16

352

donnez un entier et un caractere xx12donnez un entier et un caractere donnez un entier et un caractere 12 xmerci pour 12 et 1

Gestion de lrsquoeacutetat drsquoun flot pour sauter un caractegravere invalide

Les exemples drsquoexeacutecution montrent que la situation est encore moins agreacuteable que preacuteceacutedem-ment

Drsquoune maniegravere geacuteneacuterale nous nrsquoavons reacutegleacute ici que le problegraveme de blocage sur le caractegravereinvalide mais pas celui de manque de synchronisme entre lecture et affichage Au paragra-phe 72 du chapitre 22 nous preacutesenterons des solutions plus satisafaisantes en deacutesynchroni-sant la lecture drsquoune ligne au clavier de son utilisation par le biais drsquoun formatage enmeacutemoire

4 Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur

Comme nous lavons deacutejagrave dit les opeacuterateurs ltlt et gtgt peuvent ecirctre redeacutefinis par lutilisateurpour des types classes quil a lui-mecircme creacuteeacutes Nous allons dabord examiner la meacutethode agrave sui-vre pour reacutealiser cette surdeacutefinition avant den preacutesenter un exemple dapplication

41 MeacutethodeLes deux opeacuterateurs ltlt et gtgt deacutejagrave surdeacutefinis au sein des classes istream et ostream pour les diffeacute-rents types de base peuvent ecirctre surdeacutefinis pour nimporte quel type classe creacuteeacute par lutilisateur

Pour ce faire il suffit de tenir compte des remarques suivantes

1 Ces opeacuterateurs doivent recevoir un flot en premier argument ce qui empecircche de les surdeacute-finir sous la forme drsquoune fonction membre de la classe concerneacutee (notez quon ne peut pluscomme dans le cas des types de base les surdeacutefinir sous la forme drsquoune fonction membrede la classe istream ou ostream car lutilisateur ne peut plus modifier ces classes qui luisont fournies avec C++)

Il sagira donc de fonctions indeacutependantes ou amies de la classe concerneacutee et ayant unprototype de la forme

ostream amp operator ltlt (ostream amp expression_de_type_classe)

ou

istream amp operator gtgt (ostream amp amp type_classe)

4 - Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur353

2 La valeur de retour sera obligatoirement la reacutefeacuterence au flot concerneacute (reccedilu en premier ar-gument)

On peut dire que toutes les surdeacutefinitions de ltlt suivront ce scheacutema

ostream amp operator ltlt (ostream amp sortie type_classe objet1) Envoi sur le flot sortie des membres de objet en utilisant les possibiliteacutes classiques de ltlt pour les types de base cest-agrave-dire des instructions de la forme sortie ltlt return sortie

De mecircme toutes les surdeacutefinitions de gtgt suivront ce scheacutema

istream amp operator gtgt (istream amp entree type_classe amp objet) Lecture des informations correspondant aux diffeacuterents membres de objet en utilisant les possibiliteacutes classiques de gtgt pour les types de base cest-agrave-dire des instructions de la forme entree gtgt return entree

Remarque

Dans le cas de la surdeacutefinition de gtgt (flot dentreacutee) il sera souvent utile de sassurer quelinformation lue reacutepond agrave certaines exigences et dagir en conseacutequence sur leacutetat du flotCrsquoest ce que montre lrsquoexemple suivant

42 ExempleVoici un programme dans lequel nous avons surdeacutefini les opeacuterateurs ltlt et gtgt pour le typepoint que nous avons souvent rencontreacute dans les preacuteceacutedents chapitres

class point int x y

Nous supposerons quune valeur de type point se preacutesente toujours (aussi bien en lecturequen eacutecriture) sous la forme

lt entier entier gt

avec eacuteventuellement des espaces blancs suppleacutementaires de part et dautre des valeurs entiegrave-res

1 Ici la transmission peut se faire par valeur ou par reacutefeacuterence

Les flotsCHAPITRE 16

354

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0)

x = abs y = ord

int abscisse () return x

friend ostream amp operator ltlt (ostream amp point)

friend istream amp operator gtgt (istream amp point amp)

ostream amp operator ltlt (ostream amp sortie point p)

sortie ltlt lt ltlt px ltlt ltlt py ltlt gt

return sortie

istream amp operator gtgt (istream amp entree point amp p)1

char c = 0

float x y

int ok = 1

entree gtgt c

if (c = lt) ok = 0

else

entree gtgt x gtgt c

if (c = ) ok = 0

else

entree gtgt y gtgt c

if (c = gt) ok = 0

if (ok) px = x py = y on naffecte agrave p que si tout est OK

else entreeclear (iosbadbit | entreerdstate () )

return entree

main()

char ligne [121]

point a(23) b

cout ltlt point a ltlt a ltlt point b ltlt b ltlt n

1 Certaines impleacutementations requiegraverent (agrave tort) qursquoon preacutefixe les noms operatorltlt et operatorgtgt par std en

eacutecrivant les en-tecirctes de cette faccedilon

istream amp stdoperator gtgt (istream amp entree point amp p)

istream amp stdoperator gtgt (istream amp entree point amp p)

5 - Gestion du formatage355

do cout ltlt donnez un point

if (cin gtgt a) cout ltlt merci pour le point ltlt a ltlt n

else cout ltlt information incorrecte n cinclear ()

cingetline (ligne 120 n)

while ( aabscisse () )

point a lt23gt point b lt00gt

donnez un point 29 information incorrecte

donnez un point lt2 9lt

information incorrectedonnez un point lt29gt

merci pour le point lt29gtdonnez un point lt 12 999gt

merci pour le point lt12999gt

donnez un point bof information incorrecte

donnez un point lt0 0gtmerci pour le point lt00gt

Press any key to continue

Surdeacutefinition de lopeacuterateur ltlt pour la classe point

Dans la surdeacutefinition de gtgt nous avons pris soin de lire tout dabord toutes les informationsrelatives agrave un point dans des variables locales Ce nest que lorsque tout sest bien deacuterouleacute quenous transfeacuterons les valeurs ainsi lues dans le point concerneacute Cela eacutevite par exemple en casdinformation incomplegravete de modifier lune des composantes du point sans modifier lautreou encore de modifier les deux composantes alors que le caractegravere gt de fin na pas eacuteteacute trouveacute

Si nous ne prenions pas soin dactiver le bit badbit lorsque lon ne trouve pas lun des caractegrave-res lt ou gt lutilisateur ne pourrait pas savoir que la lecture sest mal deacuterouleacutee

Notez que dans la fonction main en cas derreur sur cin nous commenccedilons par remettre agravezeacutero leacutetat du flot avant dutiliser getline pour sauter les informations qui risquent de ne pasavoir pu ecirctre exploiteacutees

5 Gestion du formatageNous avons preacutesenteacute quelques possibiliteacutes daction sur le formatage des informations aussibien pour un flot dentreacutee que pour un flot de sortie Nous allons ici eacutetudier en deacutetail ladeacutemarche suivie par C++ pour geacuterer ce formatage

Les flotsCHAPITRE 16

356

Chaque flot cest-agrave-dire chaque objet de classe istream ou ostream conserve en permanenceun ensemble dinformations1 (indicateurs) speacutecifiant quel est agrave un moment donneacute son statutde formatage Cette faccedilon de proceacuteder est tregraves diffeacuterente de celle employeacutee par les fonctionsC telles que printf ou scanf Dans ces derniegraveres en effet on fournissait pour chaque opeacuterationdentreacutee-sortie les indications de formatage approprieacutees (sous la forme dun format com-poseacute entre autres dune succession de codes de format)

Un des avantages de la meacutethode employeacutee par C++ est quelle permet agrave lutilisateur dignorertotalement cet aspect formatage tant quil se contente dun comportement par deacutefaut (ce quiest loin drsquoecirctre le cas en C ougrave la moindre entreacutee-sortie neacutecessite obligatoirement lemploi dunformat)

Un autre avantage de la meacutethode est de permettre agrave celui qui le souhaite de deacutefinir une foispour toutes un format approprieacute agrave une application donneacutee et de ne plus avoir agrave sen soucierpar la suite

Comme nous lavons fait pour le statut derreur dun flot nous commencerons par eacutetudier lesdiffeacuterents eacuteleacutements composant le statut de formatage dun flot avant de montrer commenton peut le connaicirctre dune part le modifier dautre part

51 Le statut de formatage dun flotLe statut de formatage dun flot comporte essentiellement

bull un mot deacutetat dans lequel chaque bit est associeacute agrave une signification particuliegravere on peut

dire quon y trouve en quelque sorte toutes les indications de formatage de la forme vrai

faux2

bull les valeurs numeacuteriques preacutecisant les valeurs courantes suivantes

ndash Le gabarit il sagit de la valeur fournie a setw rappelons quelle retombe agrave zeacutero

(qui signifie gabarit standard) apregraves le transfert (lecture ou eacutecriture) dune informa-

tion Drsquoautre part pour un flot drsquoentreacutee elle ne concerne que les caractegraveres les chaicircnes

et les objets de type string

ndash La preacutecision numeacuterique il sagit du nombre de chiffres afficheacutes apregraves le point deacuteci-

mal avec la notation flottante du nombre de chiffres significatifs avec la notation

exponentielle

ndash Le caractegravere de remplissage cest-agrave-dire le caractegravere employeacute pour compleacuteter un ga-

barit dans le cas ougrave lon nutilise pas le gabarit par deacutefaut (par deacutefaut ce caractegravere de

remplissage est un espace)

1 En toute rigueur cette information est preacutevue dans la classe ios dont deacuterivent les classes istream et ostream

2 On retrouve lagrave le mecircme meacutecanisme que pour lentier contenant le statut derreur dun flot Mais comme nous le

verrons ci-dessous le statut de formatage dun flot comporte quant agrave lui dautres types dinformations que ces indi-

cations binaires

5 - Gestion du formatage357

52 Description du mot deacutetat du statut de formatageComme le statut derreur dun flot le mot deacutetat du statut de formatage est formeacute dun entier

dans lequel chaque bit est repeacutereacute par une constante preacutedeacutefinie dans la classe ios Chacune de

ces constantes correspond agrave la valeur prise par cet entier lorsque le bit correspondant ndash et lui

seul ndash est activeacute (agrave 1) Ici encore la valeur de chacune de ces constantes peut servir

bull soit agrave identifier le bit correspondant au sein du mot deacutetat

bull soit agrave fabriquer directement un mot deacutetat

De plus certains champs de bits (au nombre de trois) sont deacutefinis au sein de ce mecircme mot

Nous verrons quils facilitent dans le cas de certaines fonctions membres la manipulation

dun des bits dun champ (on peut citer le bit agrave modifier dans un champ sans avoir agrave se preacute-

occuper de la valeur des bits des autres champs)

Voici la liste des diffeacuterentes constantes accompagneacutees le cas eacutecheacuteant du nom du champ de

bit correspondant

Le mot deacutetat du statut de formatage

Au sein de chacun des trois champs de bits (adjustfield basefield floatfield) un seul des bits

doit ecirctre actif Sil nen va pas ainsi C++ legraveve lambiguiumlteacute en preacutevoyant un comportement par

deacutefaut (right dec scientific)

Nom de champ(srsquoil existe)

Nom du bit Signification

iosskipws saut des espaces blancs (en entreacutee)

iosadjustfield iosleft cadrage agrave gauche (en sortie)

iosright cadrage agrave droite (en sortie)

iosinternal remplissage apregraves signe ou base

iosbasefield iosdec conversion deacutecimale

iosoct conversion octale

ioshex conversion hexadeacutecimale

iosshowbase affichage indicateur de base (en sortie)

iosshowpoint affichage point deacutecimal (en sortie)

iosuppercase affichage caractegraveres hexa en majuscules (en sortie)

iosshowpos affichage nombres positifs preacuteceacutedeacutes du signe + (en sortie)

iosfloatfield iosscientific notation scientifique (en sortie)

iosfixed notation point fixe (en sortie)

iosunitbuf vide les tampons apregraves chaque eacutecriture

iosstdio vide les tampons apregraves chaque eacutecriture sur stdout ou stderr

Les flotsCHAPITRE 16

358

53 Action sur le statut de formatageLes exemples des paragraphes 1 et 2 ont introduit la notion de manipulateur (parameacutetrique ou

non) Comme vous vous en doutez ces manipulateurs permettent dagir sur le statut de for-

matage Mais on peut aussi pour cela utiliser des fonctions membres des classes istream ou

ostream Ces derniegraveres sont geacuteneacuteralement redondantes par rapport aux manipulateurs para-

meacutetriques (nous verrons toutefois quil existe des fonctions membres ne comportant aucun

eacutequivalent sous forme de manipulateur)

Suivant le cas laction portera sur le mot deacutetat ou sur les valeurs numeacuteriques (gabarit preacuteci-

sion caractegravere de remplissage) En outre on peut agir globalement sur le mot deacutetat Nous

verrons que certaines fonctions membres permettront notamment de le sauvegarder pour

pouvoir le restaurer ulteacuterieurement (ce quaucun manipulateur ne permet) Lrsquoaccegraves aux

valeurs numeacuteriques se fait globalement celles-ci doivent donc le cas eacutecheacuteant faire lobjet

de sauvegardes individuelles

531 Les manipulateurs non parameacutetriquesCe sont donc des opeacuterateurs qui sutilisent ainsi

flot ltlt manipulateur

pour un flot de sortie ou ainsi

flot gtgt manipulateur

pour un flot dentreacutee

Ils fournissent comme reacutesultat le flot obtenu apregraves leur action ce qui permet de les traiter de

la mecircme maniegravere que les informations agrave transmettre En particulier ils permettent eux aussi

dappliquer plusieurs fois de suite les opeacuterateurs ltlt ou gtgt

Voici la liste de ces manipulateurs

Manipulatleur Utilisation Action

dec entreacuteesortie Active le bit correspondant

hex entreacuteesortie Active le bit corrrespondant

oct entreacuteesortie Active le bit correspondant

boolalphanoboolalpha entreacuteesortie Activedeacutesactive le bit correspondant

leftbaseinternal sortie Active le bit correspondant

scientificfixed sortie Active le bit correspondant

showbasenoshowbase sortie Activedeacutesactive le bit correspondant

showpointnoshowpoint sortie Activedeacutesactive le bit correspondant

showposnoshowpos sortie Activedeacutesactive le bit correspondant

skipwsnoskipws entreacutee Activedeacutesactive le bit correspondant

uppercasenouppercase sortie Activedeacutesactive le bit correspondant

5 - Gestion du formatage359

Les manipulateurs non parameacutetriques

532 Les manipulateurs parameacutetriquesCe sont donc eacutegalement des manipulateurs cest-agrave-dire des opeacuterateurs agissant sur un flot et

fournissant en retour le flot apregraves modification Mais cette fois ils comportent un paramegravetre

qui leur est fourni sous la forme dun argument entre parenthegraveses En fait ces manipulateurs

parameacutetriques sont des fonctions dont len-tecircte est de la forme

istream amp manipulateur (argument)

ou

ostream amp manipulateur (argument)

Ils semploient comme les manipulateurs non parameacutetriques avec cette diffeacuterence quils

neacutecessitent linclusion du fichier iomanip1

Voici la liste de ces manipulateurs parameacutetriques

Les manipulateurs parameacutetriques

Notez bien que les manipulateurs resetiosflags et setiosflags agissent sur tous les bits speacuteci-

fieacutes par leur argument

ws entreacutee Active le bit saut des caractegraveres blancs

endl sortie Insegravere un saut de ligne et vide le tampon

ends sortie Insegravere un caractegravere de fin de chaicircne C (0)

flush sortie Vide le tampon

Manipulatleur Utilisation Action

1 ltiomaniphgt si lrsquoon utilise encore ltiostreamhgt

Manipulateur Utilisation Rocircle

setbase (int) EntreacuteeSortie Deacutefinit la base de conversion

resetiosflags (long) EntreacuteeSortie Remet agrave zeacutero tous les bits deacutesigneacutes par lrsquoargument (sans modifier les autres)

setiosflags (long) EntreacuteeSortie Active tous les bits speacutecifieacutes par lrsquoargument (sans modifier les autres)

setfill (int) EntreacuteeSortie Deacutefinit le caractegravere de remplissage

setprecision (int) Sortie Deacutefinit la preacutecision des nombres flottants

setw (int) EntreacuteeSodrtie Deacutefinit le gabarit

Les flotsCHAPITRE 16

360

533 Les fonctions membres

Dans les classes istream et ostream il existe cinq fonctions membres que nous navons pas

encore rencontreacutees setf unsetf fill precision et width

setf

Cette fonction permet de modifier le mot deacutetat de formatage Elle est en fait surdeacutefinie Il

existe deux versions

long setf (long)

Son appel active les bits speacutecifieacutes par son argument On obtient en retour lancienne valeur

du mot deacutetat de formatage

Notez bien que comme le manipulateur setiosflags cette fonction ne modifie pas les autres

bits Ainsi en supposant que flot est un flot avec

flotsetf (iosoct)

on activerait le bit iosoct alors quun des autres bits iosdec ou ioshex serait peut-ecirctre

activeacute1 Comme nous allons le voir ci-dessous la deuxiegraveme forme de setf se reacutevegravele plus pra-

tique dans ce cas

long setf (long long)

Son appel active les bits speacutecifieacutes par le premier argument seulement au sein du champ de

bits deacutefini par le second argument Par exemple si flot deacutesigne un flot

flotsetf (iosoct iosbasefield)

active le bit iosoct en deacutesactivant les autres bits du champ iosbasefield

Cette version de setf fournit en retour lancienne valeur du champ de bits concerneacute Cela

permet des sauvegardes pour des restaurations ulteacuterieures Par exemple si flot est un flot

avec

base_a = flotsetf (ioshex iosbasefield)

vous passez en notation hexadeacutecimale Pour revenir agrave lancienne notation quelle quelle soit

il vous suffira de proceacuteder ainsi

flotsetf (base_a iosbasefield)

unsetf

void unsetf (long)

Cette fonction joue le rocircle inverse de la premiegravere version de setf en deacutesactivant les bits men-

tionneacutes par son unique argument

1 Avec les versions de C++ drsquoavant la norme (ou avec ltiostreamhgt) seul le bit voulu eacutetait activeacute

5 - Gestion du formatage361

fill

Cette fonction permet dagir sur le caractegravere de remplissage Elle est eacutegalement surdeacutefinie Il

existe deux versions

char fill ()

Cette version fournit comme valeur de retour lactuel caractegravere de remplissage

char fill (char)

Cette version donne au caractegravere de remplissage la valeur speacutecifieacutee par son argument et

fournit en retour lancienne valeur Si flot est un flot de sortie on peut par exemple imposer

temporairement le caractegravere comme caractegravere de remplissage puis retrouver lancien ca-

ractegravere quel quil soit en proceacutedant ainsi

char car_a car_a = fill () caractegravere de remplissage = fill (car_a) retour agrave lancien caractegravere de remplissage

precision

Cette fonction permet dagir sur la preacutecision numeacuterique Elle est eacutegalement surdeacutefinie Il en

existe deux versions

int precision ()

Cette version fournit comme valeur de retour la valeur actuelle de la preacutecision numeacuterique

int precision (int)

Cette version donne agrave la preacutecision numeacuterique la valeur speacutecifieacutee par son argument et fournit

en retour lancienne valeur Si flot est un flot de sortie on peut par exemple imposer tempo-

rairement une certaine preacutecision (ici prec) puis revenir agrave lancienne quelle quelle soit en

proceacutedant ainsi

int prec_a prec prec_a = flotprecision (prec) on impose la preacutecision deacutefinie par prec flotprecision (prec_a) on revient agrave lancienne preacutecision

width

Cette fonction permet dagir sur le gabarit Elle est eacutegalement surdeacutefinie Il en existe deux

versions

int width()

Cette version fournit comme valeur de retour la valeur actuelle du gabarit

int width(int)

Cette version donne au gabarit la valeur speacutecifieacutee par son argument et fournit en retour lan-

cienne valeur Si flot est un flot de sortie on peut par exemple imposer temporairement un

certain gabarit (ici gab) puis revenir agrave lancien quel quil soit en proceacutedant ainsi

Les flotsCHAPITRE 16

362

int gab_a gab gab_a = flotwidth (gab) on impose un gabarit deacutefini par gab flotwidth (gab_a) on revient agrave lancien gabarit

6 Connexion drsquoun flot agrave un fichierJusquici nous avons parleacute des flots preacutedeacutefinis (cin et cout) et nous vous avons donneacute des

informations sappliquant agrave un flot quelconque (paragraphes 3 et 5) mais sans vous dire com-

ment ce flot pourrait ecirctre associeacute agrave un fichier Ce paragraphe va vous montrer comment y par-

venir et examiner les possibiliteacutes daccegraves direct dont on peut alors beacuteneacuteficier

61 Connexion dun flot de sortie agrave un fichierPour associer un flot de sortie agrave un fichier il suffit de creacuteer un objet de type ofstream classe

deacuterivant de ostream Lemploi de cette nouvelle classe neacutecessite dinclure un fichier en-tecircte

nommeacute fstream en plus du fichier iostream

Le constructeur de la classe ofstream neacutecessite deux arguments

bull le nom du fichier concerneacute (sous forme dune chaicircne de caractegraveres)

bull un mode douverture deacutefini par une constante entiegravere la classe ios comporte lagrave encore un

certain nombre de constantes preacutedeacutefinies (nous les passerons toutes en revue au paragraphe

64)

Voici un exemple de deacuteclaration dun objet (sortie) du type ofstream1

ofstream sortie (trucdat iosout|iosbinary) ou seulement iosout

Lobjet sortie sera donc associeacute au fichier nommeacute trucdat apregraves quil aura eacuteteacute ouvert en eacutecri-

ture

Une fois construit un objet de classe ofstream leacutecriture dans le fichier qui lui est associeacute peut

se faire comme pour nimporte quel flot en faisant appel agrave toutes les faciliteacutes de la classe

ostream (dont deacuterive ofstream)

Par exemple apregraves la deacuteclaration preacuteceacutedente de sortie nous pourrons employer des instruc-

tions telles que

sortie ltlt ltlt ltlt

pour reacutealiser des sorties formateacutees ou encore

sortiewrite ()

pour reacutealiser des eacutecritures binaires De mecircme nous pourrons connaicirctre le statut derreur du

flot correspondant en examinant la valeur de sortie

if (sortie)

1 Le paramegravetre iosbinary nrsquoest utile que dans les environnements qui distinguent les fichiers texte des autres (voir

remarque ci-dessous)

6 - Connexion drsquoun flot agrave un fichier363

Voici un programme complet qui enregistre sous forme binaire dans un fichier de nom

fourni par lutilisateur une suite de nombres entiers quil lui fournit sur lentreacutee standard

include ltcstdlibgt pour exit

include ltiostreamgt

include ltfstreamgt

include ltiomanipgt

using namespace std

const int LGMAX = 20

main()

char nomfich [LGMAX+1] int n

cout ltlt nom du fichier a creer

cin gtgt setw (LGMAX) gtgt nomfich

ofstream sortie (nomfich iosout|iosbinary) ou iosout

if (sortie) cout ltlt creation impossible n exit (1)

do cout ltlt donnez un entier

cin gtgt n

if (n) sortiewrite ((char )ampn sizeof(int) )

while (n ampamp (sortie))

sortieclose ()

Creacuteation seacutequentielle dun fichier dentiers

Nous nous sommes servi du manipulateur setw pour limiter la longueur du nom de fichier

fourni par lutilisateur Par ailleurs nous examinons le statut derreur de sortie comme nous le

ferions pour un flot usuel

Remarque

En toute rigueur le terme connexion (ou association) dun flot agrave un fichier pourrait

laisser entendre

ndash soit quil existe deux types dobjets dune part un flot dautre part un fichier

ndash soit que lon deacuteclare tout dabord un flot que lon associe ulteacuterieurement agrave un fichier

Or il nen est rien puisque lon deacuteclare en une seule fois un objet de ofstream en speacuteci-

fiant le fichier correspondant On pourrait dailleurs dire quun objet de ce type est un

fichier si lon ne craignait pas de le confondre avec ce mecircme terme de fichier en lan-

gage C (ougrave il deacutesigne souvent un nom interne de fichier cest-agrave-dire un pointeur sur une

structure de type FILE)

Les flotsCHAPITRE 16

364

62 Connexion dun flot dentreacutee agrave un fichierPour associer un flot dentreacutee agrave un fichier on emploie un meacutecanisme analogue agrave celui utiliseacute

pour un flot de sortie On creacutee cette fois un objet de type ifstream classe deacuterivant de istream

Il faut toujours inclure le fichier en-tecircte fstreamh en plus du fichier iostreamh Le construc-

teur comporte les mecircmes arguments que preacuteceacutedemment cest-agrave-dire nom de fichier et mode

douverture

Par exemple avec linstruction1

ifstream entree (trucdat iosin|iosbinary) ou seulement iosin

lobjet entree sera associeacute au fichier de nom trucdat apregraves quil aura eacuteteacute ouvert en lecture

Une fois construit un objet de classe ifstream la lecture dans le fichier qui lui est associeacute

pourra se faire comme pour nimporte quel flot dentreacutee en faisant appel agrave toutes les faciliteacutes

de la classe istream (dont deacuterive ifstream)

Par exemple apregraves la deacuteclaration preacuteceacutedente de entree nous pourrions employer des instruc-

tions telles que

entree gtgt gtgt gtgt

pour reacutealiser des lectures formateacutees ou encore

entreeread ()

pour reacutealiser des lectures binaires

Voici un programme complet qui permet de lister le contenu dun fichier quelconque creacuteeacute par

le programme preacuteceacutedent

include ltiostreamgtinclude ltfstreamgtinclude ltiomanipgtusing namespace std const int LGMAX = 20 main() char nomfich [LGMAX+1] int n cout ltlt nom du fichier a lister cin gtgt setw (LGMAX) gtgt nomfich ifstream entree (nomfich iosin|iosbinary) ou iosin if (entree) cout ltlt ouverture impossible n exit (-1) while ( entreeread ( (char)ampn sizeof(int) ) ) cout ltlt n ltlt n entreeclose ()

Lecture seacutequentielle dun fichier dentiers

1 Le paramegravetre iosbinary nrsquoest utile que dans les environnements qui distinguent les fichiers texte des autres ce qui

est le cas de Visual C++ (ou plutocirct de Windows)

6 - Connexion drsquoun flot agrave un fichier365

Remarque

Il existe eacutegalement une classe fstream deacuteriveacutee des deux classes ifstream et ofstream per-

mettant deffectuer agrave la fois des lectures et des eacutecritures avec un mecircme fichier Cela peut

saveacuterer fort pratique dans le cas de laccegraves direct que nous examinons ci-dessous La

deacuteclaration dun objet de type fstream se deacuteroule comme pour les types ifstream ou ofs-

tream Par exemple

fstream fich (trucdat iosin|iosout|iosbinary)

associe lobjet fich au fichier de nom trucdat apregraves lavoir ouvert en lecture et en eacutecri-

ture

63 Les possibiliteacutes daccegraves directComme en langage C en C++ degraves quun flot a eacuteteacute connecteacute agrave un fichier il est possible de

reacutealiser un accegraves direct agrave ce fichier en agissant tout simplement sur un pointeur dans ce

fichier cest-agrave-dire un nombre preacutecisant le rang du prochain octet (caractegravere) agrave lire ou agrave

eacutecrire Apregraves chaque opeacuteration de lecture ou deacutecriture ce pointeur est increacutementeacute du nombre

doctets transfeacutereacutes Ainsi lorsque lon nagit pas explicitement sur ce pointeur on reacutealise un

classique accegraves seacutequentiel cest ce que nous avons fait preacuteceacutedemment

Les possibiliteacutes daccegraves direct se reacutesument donc en fait aux possibiliteacutes daction sur ce poin-

teur ou agrave la deacutetermination de sa valeur

Dans chacune des deux classes ifstream et ofstream une fonction membre nommeacutee seekg

(pour ifstream) et seekp (pour ofstream) permet de donner une certaine valeur au pointeur

(attention chacune de ces deux classes possegravede le sien de sorte quil existe un pointeur pour

la lecture et un pointeur pour leacutecriture) Plus preacuteciseacutement chacune des ces deux fonctions

comporte deux arguments

bull un entier repreacutesentant un deacuteplacement du pointeur par rapport agrave une origine preacuteciseacutee par le

second argument

bull une constante entiegravere choisie parmi trois valeurs preacutedeacutefinies dans ios

ndash iosbeg le deacuteplacement est exprimeacute par rapport au deacutebut du fichier

ndash ioscur le deacuteplacement est exprimeacute par rapport agrave la position actuelle

ndash iosend le deacuteplacement est exprimeacute par rapport agrave la fin du fichier (par deacutefaut cet ar-

gument a la valeur iosbeg)

Notez quon retrouve lagrave les possibiliteacutes offertes par la fonction fseek du langage C

Par ailleurs il existe dans chacune des classes ifstream et ofstream une fonction permettant

de connaicirctre la position courante du pointeur Il sagit de tellg (pour ifstream) et de tellp (pour

ofstream) Celles-ci offrent des possibiliteacutes comparables agrave la fonction ftell du langage C

Les flotsCHAPITRE 16

366

Voici un exemple de programme permettant dacceacuteder agrave nimporte quel entier dun fichier du

type de ceux que pouvait creacuteer le programme du paragraphe 61 (ici nous supposons qursquoil

comporte une dizaine de valeurs entiegraveres)

include ltiostreamgt

include ltfstreamgt

include ltiomanipgt

using namespace std

const int LGMAX_NOM_FICH = 20 main()

char nomfich [LGMAX_NOM_FICH + 1]

int n num

cout ltlt nom du fichier a consulter

cin gtgt setw (LGMAX_NOM_FICH) gtgt nomfich

ifstream entree (nomfich iosin|iosbinary) ou iosin

if (entree) cout ltlt Ouverture impossiblen

exit (-1)

do

cout ltlt Numero de lentier recherche

cin gtgt num if (num)

entreeseekg (sizeof(int) (num-1) iosbeg )

entreeread ( (char ) ampn sizeof(int) )

if (entree) cout ltlt -- Valeur ltlt n ltlt n

else cout ltlt -- Erreurn

entreeclear ()

while (num)

entreeclose ()

nom du fichier a consulter essaidat

Numero de lentier recherche 4

-- Valeur 6

Numero de lentier recherche 15

-- ErreurNumero de lentier recherche 7

-- Valeur 9

Numero de lentier recherche -3

-- Erreur

Numero de lentier recherche 0

Accegraves direct agrave un fichier dentiers

6 - Connexion drsquoun flot agrave un fichier367

64 Les diffeacuterents modes douverture dun fichierNous avons rencontreacute quelques exemples de modes douverture dun fichier Nous allons exa-

miner ici lensemble des possibiliteacutes offertes par les classes ifstream et ofstream (et donc

aussi de fstream)

Le mode douverture est deacutefini par un mot deacutetat dans lequel chaque bit correspond agrave une

signification particuliegravere La valeur correspondant agrave chaque bit est deacutefinie par des constantes

deacuteclareacutees dans la classe ios Pour activer plusieurs bits il suffit de faire appel agrave lopeacuterateur |

Les diffeacuterents modes douverture dun fichier

A titre indicatif voici les modes douverture eacutequivalents aux diffeacuterents modes douverture de

la fonction fopen du C

Les modes drsquoouverture de la fonction fopen du C

Bit Action

iosin Ouverture en lecture (obligatoire pour la classe ifstream)

iosout Ouverture en eacutecriture (obligatoire pour la classe ofstream)

iosapp Ouverture en ajout de donneacutees (eacutecriture en fin de fichier)

iostrunc Si le fichier existe son contenu est perdu (obligatoire si iosout est activeacute sans iosate ni iosapp)

iosbinary Utiliseacute seulement dans les impleacutementations qui distinguent les fichiers textes des autres Le fichier est ouvert en mode binaire ou encore non translateacute (voir remarque ci-dessous)

Combinaison de bits Mode correspondant de fopen

iosout ws

iosout iosapp a

iosout iostrunc w

iosin r

iosin iosout r+

iosin iosout iostrunc wb+

iosout iosbinary wb

iosout iosapp iosbinary ab

iosout iostrunc iosbinary wb

iosin iosbinary rb

iosin iosout iosbinary r+b

iosin iosout iostrunc iosbinary w+b

Les flotsCHAPITRE 16

368

Remarque

Rappelons que certains environnements (PC en particulier) distinguent les fichiers de

texte des autres (quils appellent parfois fichiers binaires1) plus preacuteciseacutement lors de

louverture du fichier on peut speacutecifier si lon souhaite ou non consideacuterer son contenu

comme du texte Cette distinction est en fait principalement motiveacutee par le fait que sur ces

systegravemes le caractegravere de fin de ligne (n) possegravede une repreacutesentation particuliegravere obtenue

par la succession de deux caractegraveres (retour chariot r suivi de fin de ligne n)2 Dans ces

conditions pour quun programme C++ puisse ne voir quun seul caractegravere de fin de

ligne et quil sagisse bien de n il faut opeacuterer un traitement particulier consistant agrave

ndash remplacer chaque occurrence de ce couple de caractegraveres par n dans le cas dune lectu-

re

ndash remplacer chaque demande deacutecriture de n par leacutecriture de ce couple de caractegraveres

Bien entendu de telles substitutions ne doivent pas ecirctre reacutealiseacutees sur de vrais fichiers

binaires Il faut donc bien pouvoir opeacuterer une distinction au sein du programme Cette

distinction se fait au moment de louverture du fichier en activant le bit iosbinary

dans le mode douverture dans le cas dun fichier binaire par deacutefaut ce bit nest pas

activeacute On notera que lrsquoactivation du bit iosbinary correspond aux modes douverture

rb ou wb du langage C

7 Les anciennes possibiliteacutes de formatage en meacutemoire

En langage C

bull sscanf permet dacceacuteder agrave une information situeacutee en meacutemoire de faccedilon comparable agrave ce que

fait scanf sur lentreacutee standard

bull sprintf permet de fabriquer en meacutemoire une chaicircne de caractegraveres correspondant agrave celle qui

serait transmise agrave la sortie standard par printf

En C++ des faciliteacutes comparables existent Jusqursquoagrave la norme elles eacutetaient fournies par les

classes

bull ostrstream pour linsertion de caractegraveres dans un tableau

bull istrstream pour lextraction de caractegraveres depuis un tableau

1 Alors quau bout du compte tout fichier est binaire

2 Notez que dans ces environnements PC le caractegravere CTRLZ (de code deacutecimal 26) est interpreacuteteacute comme une fin

de fichier texte

7 - Les anciennes possibiliteacutes de formatage en meacutemoire369

La norme a introduit de nouvelles classes plus faciles drsquoemploi et faisant appel au type string

(vrai type chaicircne) Elles seront preacutesenteacutees au paragraphe 7 du chapitre 22

Ici nous vous preacutesenterons quand mecircme les anciennes possibiliteacutes afin de vous permettre

drsquoexploiter des programmes existants Notez qursquoelles sont classeacutees deprecaded feature ce

qui signifie qursquoelles sont susceptibles de disparaicirctre dans une version ulteacuterieure de C++

71 La classe ostrstreamUn objet de classe ostrstream peut recevoir des caractegraveres au mecircme titre quun flot de sortie

La seule diffeacuterence est que ces caractegraveres ne sont pas transmis agrave un peacuteripheacuterique ou agrave un

fichier mais simplement conserveacutes dans lobjet lui-mecircme plus preacuteciseacutement dans un tableau

membre de la classe ostrstream ce tableau est creacuteeacute dynamiquement et ne pose donc pas de

problegraveme de limitation de taille

Une fonction membre particuliegravere nommeacutee str permet dobtenir ladresse du tableau en ques-

tion Celui-ci pourra alors ecirctre manipuleacute comme nimporte quel tableau de caractegraveres (repeacutereacute

par un pointeur de type char )

Par exemple avec la deacuteclaration

ostrstream tab

vous pouvez inseacuterer des caractegraveres dans lobjet tab par des instructions telles que

tab ltlt ltlt ltlt

ou

tabput ()

ou encore

tabwrite ()

Ladresse du tableau de caractegraveres ainsi constitueacute pourra ecirctre obtenue par

char adt = tabstr ()

A partir de lagrave vous pourrez agir comme il vous plaira sur les caractegraveres situeacutes agrave cette adresse

(les consulter mais aussi les modifier)

Remarques

1 Lorsque str a eacuteteacute appeleacutee pour un objet il nest plus possible dinseacuterer de nouveaux carac-

tegraveres dans cet objet On peut dire que lappel de cette fonction gegravele deacutefinitivement le

tableau de caractegraveres (noubliez pas quil est alloueacute dynamiquement et que son adresse

peut mecircme eacutevoluer au fil de linsertion de caractegraveres ) avant den fournir en retour une

adresse deacutefinitive On prendra donc bien soin de nappeler str que lorsque lon aura inseacutereacute

dans lobjet tous les caractegraveres voulus

Par souci drsquoexhaustiviteacute signalons qursquoil existe une fonction membre freeze (bool

action) Lrsquoappel tabfreeze (true) fige le tableau mais il vous faut quand mecircme appeler

str pour en obtenir lrsquoadresse En revanche tabfreeze(false) preacutesente bien un inteacuterecirct si

Les flotsCHAPITRE 16

370

tab a deacutejagrave eacuteteacute geleacute il redevient dynamique on peut agrave nouveau y introduire des

informations bien entendu son adresse pourra de nouveau eacutevoluer et il faudra agrave nou-

veau faire appel agrave str pour lrsquoobtenir

2 Si un objet de classe ostrstream devient hors de porteacutee alors que la fonction str na pas

eacuteteacute appeleacutee il est deacutetruit normalement par appel dun destructeur qui deacutetruit alors eacutegale-

ment le tableau de caractegraveres correspondant En revanche si str a eacuteteacute appeleacutee on consi-

degravere que le tableau en question est maintenant sous la responsabiliteacute du programmeur et

il ne sera donc pas deacutetruit lorsque lobjet deviendra hors de porteacutee (bien sucircr le reste de

lobjet le sera) Ce sera au programmeur de le faire lorsquil le souhaitera en proceacutedant

comme pour nimporte quel tableau de caractegraveres alloueacute dynamiquement (par new)

cest-agrave-dire en faisant appel agrave lopeacuterateur delete Par exemple lemplacement meacutemoire

du tableau de lobjet tab preacuteceacutedent dont ladresse a eacuteteacute obtenue dans adt pourra ecirctre

libeacutereacute par

delete adt

72 La classe istrstreamUn objet de classe istrstream est creacuteeacute par un appel de constructeur auquel on fournit en

argument

bull ladresse dun tableau de caractegraveres

bull le nombre de caractegraveres agrave prendre en compte

Il est alors possible dextraire des caractegraveres de cet objet comme on le ferait de nimporte

quel flot dentreacutee

Par exemple avec les deacuteclarations

char t[100]

istrstream tab ( t sizeof(t) )

vous pourrez extraire des caractegraveres du tableau t par des instructions telles que

tab gtgt gtgt gtgt

ou

tabget ()

ou encore

tabread ()

Qui plus est vous pourrez agir sur un pointeur courant dans ce tableau comme vous le feriez

dans un fichier par lappel de la fonction seekg Par exemple avec lobjet tab preacuteceacutedent vous

pourrez replacer le pointeur en deacutebut de tableau par

tabseekg (0 iosbeg)

Cela pourrait permettre par exemple dexploiter plusieurs fois une mecircme information (lue

preacutealablement dans un tableau) en la lisant suivant des formats diffeacuterents

7 - Les anciennes possibiliteacutes de formatage en meacutemoire371

Voici un exemple dutilisation de la classe istrstream montrant comment reacutesoudre les problegrave-

mes engendreacutes par la frappe dun mauvais caractegravere dans le cas de lectures sur lentreacutee stan-

dard (situation que nous avons eacutevoqueacutee au paragraphe 352 du chapitre 3

const int LGMAX = 122 longueur maxi dune ligne clavierinclude ltiostreamgtinclude ltstrstreamgtusing namespace std

main() int n erreur char c char ligne [LGMAX] pour lire une ligne au clavier do cout ltlt donnez un entier et un caractere n cingetline (ligne LGMAX) istrstream tampon (ligne cingcount () ) if (tampon gtgt n gtgt c) erreur = 0 else erreur = 1 while (erreur) cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

donnez un entier et un caractere bofdonnez un entier et un caractere a 125donnez un entier et un caractere 12 bonjourmerci pour 12 et b

Pour lire en toute seacutecuriteacute sur lentreacutee standard

Nous y lisons tout dabord linformation attendue pour toute une ligne sous la forme dune

chaicircne de caractegraveres (agrave laide de la fonction getline) Nous construisons ensuite avec cette

chaicircne un objet de type istrstream sur lequel nous appliquons nos opeacuterations de lecture (ici

lecture formateacutee dun entier puis dun caractegravere) Comme vous le constatez aucun problegraveme

ne se pose plus lorsque lutilisateur fournit un caractegravere invalide (par rapport agrave lusage quon

doit en faire) contrairement agrave ce qui se serait passeacute en cas de lecture directe sur cin

17

La gestion des exceptions

Pour la mise au point drsquoun programme bon nombre drsquoenvironnements proposent des outils

de deacutebogage tregraves performants Si tel nrsquoest pas le cas il reste toujours possible de faire appel

aux possibiliteacutes heacuteriteacutees du langage C que constituent la compilation conditionnelle (ifdef)

et la macro assert

Mais mecircme lorsqursquoil est au point un programme peut rencontrer des conditions exception-

nelles qui risquent de compromettre la poursuite de son exeacutecution Dans des programmes

relativement importants il est rare que la deacutetection de lrsquoincident et son traitement puissent se

faire dans la mecircme partie de code Cette dissociation devient encore plus neacutecessaire lorsque

lrsquoon deacuteveloppe des composants reacuteutilisables destineacutes agrave ecirctre exploiteacutes par de nombreux pro-

grammes

Certes on peut toujours reacutesoudre un tel problegraveme en srsquoappuyant sur les deacutemarches utiliseacutees

en C La plus reacutepandue consistait agrave srsquoinspirer de la philosophie utiliseacutee dans la bibliothegraveque

standard fournir un code drsquoerreur comme valeur de retour des diffeacuterentes fonctions Si une

telle meacutethode preacutesente lrsquoavantage de seacuteparer la deacutetection drsquoune anomalie de son traitement

elle nrsquoen reste pas moins tregraves fastidieuse elle implique en effet lrsquoexamen systeacutematique des

valeurs de retour en de nombreux points du programme ainsi qursquoune freacutequente retransmis-

sion agrave travers la hieacuterarchie des appels Une autre deacutemarche consistait agrave exploiter les fonctions

setjmp et longjmp pour provoquer un branchement srsquoaffranchissant de la hieacuterarchie des

appels cependant aucune gestion des variables automatiques nrsquoeacutetait alors assureacutee1

1 Pour plus drsquoinformations sur les fonctions setjmp et longjmp on pourra consulter Langage C norme ANSI du mecircme

auteur chez le mecircme eacutediteur

La gestion des exceptionsCHAPITRE 17

374

La version 3 de C++ a inteacutegreacute dans le langage un meacutecanisme tregraves puissant de traitement de

ces anomalies nommeacute gestion des exceptions Il a le meacuterite de deacutecoupler totalement la deacutetec-

tion drsquoune anomalie (exception) de son traitement en srsquoaffranchissant de la hieacuterarchie des

appels tout en assurant une gestion convenable des objets automatiques

Drsquoune maniegravere geacuteneacuterale une exception est une rupture de seacutequence deacuteclencheacutee (on dit aussi

leveacutee ou lanceacutee) par une instruction throw comportant une expression drsquoun type donneacute

Il y a alors branchement agrave un ensemble drsquoinstructions nommeacute gestionnaire drsquoexception (on

parle aussi de capture par un gestionnaire) dont le nom est deacutetermineacute par la nature de

lrsquoexception Plus preacuteciseacutement chaque exception est caracteacuteriseacutee par un type et le choix du

bon gestionnaire se fait en fonction de la nature de lexpression mentionneacutee agrave throw

Compte tenu de lrsquooriginaliteacute de cette nouvelle notion nous introduirons les notions de lance-

ment et de capture drsquoune exception sur quelques exemples Nous verrons ensuite quelles sont

les diffeacuterentes faccedilons de poursuivre lrsquoexeacutecution apregraves la capture drsquoune exception Nous eacutetu-

dierons en deacutetail lrsquoalgorithme utiliseacute pour effectuer le choix du gestionnaire drsquointerruption

ainsi que le rocircle de la fonction terminate dans le cas ougrave aucun gestionnaire nrsquoest trouveacute

Nous verrons ensuite comment une fonction peut speacutecifier les exceptions qursquoelle est suscep-

tible de lancer sans les traiter et quel est alors le rocircle de la fonction unexpected Puis nous

examinerons les diffeacuterentes classes drsquoexceptions fournies par la bibliothegraveque standard et

utiliseacutees par les fonctions standards ainsi que lrsquointeacuterecirct qursquoil peut y avoir agrave les exploiter dans

la creacuteation de ses propres exceptions

1 Premier exemple drsquoexceptionDans cet exemple complet nous allons reprendre la classe vect preacutesenteacutee au paragraphe 5 du

chapitre 9 cest-agrave-dire munie de la surdeacutefinition de lopeacuterateur [] Celui-ci neacutetait alors pas

proteacutegeacute contre lutilisation dindices situeacutes en dehors des bornes Ici nous allons compleacuteter

notre classe pour quelle deacuteclenche une exception dans ce cas Puis nous verrons comment

intercepter une telle exception en eacutecrivant un gestionnaire approprieacute

11 Comment lancer une exception linstruction throwAu sein de la surdeacutefinition de [] nous introduisons donc une veacuterification de lindice lorsque

celui-ci est incorrect nous deacuteclenchons une exception agrave laide de linstruction throw Celle-ci

neacutecessite une expression quelconque dont le type (classe ou non) sert agrave identifier lrsquoexception

En geacuteneacuteral pour bien distinguer les exceptions les unes des autres il est preacutefeacuterable drsquoutiliser

un type classe deacutefini uniquement pour repreacutesenter lrsquoexception concerneacutee Crsquoest ce que nous

ferons ici Nous introduisons donc artificiellement avec la deacuteclaration de notre classe vect

une classe nommeacutee vect_limite (sans aucun membre) Son existence nous permet de creacuteer un

objet l de type vect_limite objet que nous associons agrave linstruction throw par linstruction

throw l

1 - Premier exemple drsquoexception375

Voici la deacutefinition complegravete de la classe vect

deacuteclaration de la classe vect class vect

int nelem int adr public vect (int)

~vect () int amp operator [] (int) deacuteclaration et deacutefinition dune classe vect_limite (vide pour linstant)

class vect_limite deacutefinition de la classe vect vectvect (int n)

adr = new int [nelem = n] vect~vect () delete adr

int amp vectoperator [] (int i) if (ilt0 || igtnelem) vect_limite l

throw (l) deacuteclenche une exception de type vect_limite return adr [i]

Deacutefinition dune classe provoquant une exception vect_limite

12 Utilisation dun gestionnaire dexceptionDisposant de notre classe vect voyons maintenant comment proceacuteder pour pouvoir geacuterer

convenablement les eacuteventuelles exceptions de type vect_limite que son emploi peut provo-

quer Pour ce faire il est neacutecessaire de respecter deux conditions

bull inclure dans un bloc particulier dit bloc try toutes les instructions dans lesquelles on sou-

haite pouvoir deacutetecter une exception un tel bloc se preacutesente ainsi

try instructions

bull faire suivre ce bloc de la deacutefinition des diffeacuterents gestionnaires dexceptions neacutecessaires

(ici un seul suffit) Chaque deacutefinition est preacuteceacutedeacutee dun en-tecircte introduit par le mot cleacute catch

(comme si catch eacutetait le nom dune fonction gestionnaire) Dans notre cas voici ce que

La gestion des exceptionsCHAPITRE 17

376

pourrait ecirctre notre unique gestionnaire destineacute agrave intercepter les exceptions de type

vect_limite

catch (vect_limite l) nom dargument superflu ici cout ltlt exception limite n exit (-1)

Nous nous contentons ici dafficher un message et dinterrompre lexeacutecution du programme

13 ReacutecapitulatifA titre indicatif voici la liste complegravete de la deacutefinition des diffeacuterentes classes concerneacutees

Elle est accompagneacutee dun petit programme dessai dans lequel nous deacuteclenchons volontaire-

ment une exception vect_limite en apliquant lopeacuterateur [] agrave un objet de type vect avec un

indice trop grand)

include ltiostreamgtinclude ltcstdlibgt ancien ltstdlibhgt pour exit using namespace std deacuteclaration de la classe vect class vect int nelem int adr public vect (int) ~vect () int amp operator [] (int)

deacuteclaration et deacutefinition dune classe vect_limite (vide pour linstant) class vect_limite deacutefinition de la classe vect vectvect (int n) adr = new int [nelem = n] vect~vect () delete adr int amp vectoperator [] (int i) if (ilt0 || igtnelem) vect_limite l throw (l) return adr [i]

test interception exception vect_limite main () try vect v(10) v[11] = 5 indice trop grand

1 - Premier exemple drsquoexception377

catch (vect_limite l) nom dargument superflu ici

cout ltlt exception limite n

exit (-1)

exception limite

Premier exemple de gestion dexception

Remarques

1 Ce premier exemple destineacute agrave vous preacutesenter le meacutecanisme de gestion des exceptions est

fort simple notamment

ndash il ne comporte quun seul type dexception de sorte quil ne met pas vraiment en eacutevi-

dence le meacutecanisme de choix du bon gestionnaire

ndash le gestionnaire ne reccediloit pas dinformation particuliegravere (largument l eacutetant ici artificiel)

2 Dune maniegravere geacuteneacuterale le gestionnaire dune exception est deacutefini indeacutependamment des

fonctions susceptibles de la deacuteclencher Ainsi agrave partir du moment ougrave la deacutefinition dune

classe est seacutepareacutee de son utilisation (ce qui est souvent le cas en pratique) il est tout agrave

fait possible de preacutevoir un gestionnaire dexception diffeacuterent dune utilisation agrave une

autre dune mecircme classe Dans lrsquoexemple preacuteceacutedent tel utilisateur peut vouloir afficher

un message avant de sinterrompre tel autre preacutefeacuterera ne rien afficher ou encore tenter

de preacutevoir une solution par deacutefaut

3 Nous aurions pu preacutevoir un gestionnaire drsquoexception dans la classe vect elle-mecircme Il

en sera rarement ainsi en pratique dans la mesure ougrave lrsquoun des buts primordiaux du

meacutecanisme proposeacute par C++ est de seacuteparer la deacutetection drsquoune exception de son traite-

ment

4 Ici nous avons preacutevu une instruction exit agrave linteacuterieur du gestionnaire dexception Nous

verrons au paragraphe 31 que dans le cas contraire lrsquoexeacutecution se poursuivrait agrave la

suite du bloc try concerneacute Mais dores et deacutejagrave nous pouvons remarquer que le modegravele

de gestion des exceptions proposeacute par C++ ne permet pas de reprendre lrsquoexeacutecution agrave

partir de lrsquoinstruction ayant leveacute lrsquoexception1

5 Si nous nrsquoavions pas preacutevu de bloc try lrsquoexception limite deacuteclencheacutee par lrsquoopeacuterateur []

et non prise en compte aurait alors simplement provoqueacute un arrecirct de lrsquoexeacutecution

1 Il en ira de mecircme en Java En revanche ADA dispose drsquoun meacutecanisme de reprise drsquoexeacutecution

La gestion des exceptionsCHAPITRE 17

378

2 Second exempleExaminons maintenant un exemple un peu plus reacutealiste dans lequel on trouve deux excep-

tions diffeacuterentes et ougrave il y a transmission dinformations aux gestionnaires Nous allons

reprendre la classe vect preacuteceacutedente en lui permettant de lancer deux sortes dexceptions

bull une exception de type vect_limite comme preacuteceacutedemment mais cette fois on preacutevoit de

transmettre au gestionnaire la valeur de lindice qui a deacuteclencheacute lrsquoexception

bull une exception vect_creation deacuteclencheacutee lorsque lon transmet au constructeur un nombre

deacuteleacutements incorrect1 (neacutegatif ou nul) lagrave encore on preacutevoit de transmettre ce nombre au

gestionnaire

Il suffit dappliquer le meacutecanisme preacuteceacutedent en notant simplement que lobjet indiqueacute agrave

throw et reacutecupeacutereacute par catch peut nous servir agrave communiquer toute information de notre

choix Nous preacutevoirons donc dans nos nouvelles classes vect_limite et vect_creation un

champ public de type entier destineacute agrave recevoir linformation agrave transmettre au gestionnaire

Voici un exemple complet (ici encore la deacutefinition et lutilisation des classes figurent dans le

mecircme source en pratique il en ira rarement ainsi)

include ltiostreamgtinclude ltcstdlibgt ancien ltstdlibhgt pour exitusing namespace std

deacuteclaration de la classe vect class vect int nelem int adr public vect (int) ~vect () int amp operator [] (int)

deacuteclaration - deacutefinition des deux classes exception class vect_limite public int hors valeur indice hors limites (public) vect_limite (int i) constructeur hors = i

1 Dans un cas reacuteel on pourrait aussi lancer cette interruption en cas de manque de meacutemoire

2 - Second exemple379

class vect_creation

public int nb nombre elements demandes (public)

vect_creation (int i) constructeur

nb = i

deacutefinition de la classe vect

vectvect (int n)

if (n lt= 0) vect_creation c(n) anomalie

throw c

adr = new int [nelem = n] construction normale

vect~vect ()

delete adr

int amp vectoperator [] (int i)

if (ilt0 || igtnelem)

vect_limite l(i) anomalie throw l

return adr [i] fonctionnement normal

test exception

main ()

try vect v(-3) provoque lexception vect_creation

v[11] = 5 provoquerait lexception vect_limite

catch (vect_limite l) cout ltlt exception indice ltlt lhors ltlt hors limites n

exit (-1)

catch (vect_creation c) cout ltlt exception creation vect nb elem = ltlt cnb ltlt n

exit (-1)

exception creation vect nb elem = -3

Exemple de gestion de deux exceptions

La gestion des exceptionsCHAPITRE 17

380

Bien entendu la premiegravere exception (deacuteclencheacutee par vect v(-3)) ayant provoqueacute la sorite du

bloc try nous navons aucune chance de mettre en eacutevidence celle quaurait provoqueacute v[11] =

5 Si la creacuteation de v avait eacuteteacute correcte cette derniegravere instruction aurait entraicircneacute laffichage du

message

exception indice 11 hors limites

Remarques

1 Dans un exemple reacuteel on pourrait avoir inteacuterecirct agrave transmettre dans vect_limite non seule-

ment la valeur de lindice mais aussi les limites preacutevues Il suffirait dintroduire les mem-

bres correspondants dans la classe vect_limite

2 Ici chaque type dexception nest deacuteclencheacute quen un seul endroit Mais bien entendu

nimporte quelle fonction (pas neacutecessairement membre de la classe vect ) disposant de

la deacutefinition des deux classes (vect_limite et vect_creation) peut deacuteclencher ces excep-

tions

3 Le meacutecanisme de gestion des exceptionsDans tous les exemples preacuteceacutedents le gestionnaire drsquoexception interrompait lexeacutecution par

un appel de exit (nous aurions pu eacutegalement utiliser la fonction standard abort1) Mais le

meacutecanisme offert par C++ autorise drsquoautres possibiliteacutes que nous allons examiner mainte-

nant en distinguant deux aspects

bull la possibiliteacute de poursuivre lrsquoexeacutecution du programme apregraves lrsquoexeacutecution du gestionnaire

drsquoexception

bull la maniegravere dont sont prises en compte les diffeacuterentes sorties de blocs (donc de fonctions) qui

peuvent en deacutecouler

31 Poursuite de lexeacutecution du programme Le gestionnaire drsquoexception peut tregraves bien ne pas comporter drsquoinstruction drsquoarrecirct de lrsquoexeacutecu-

tion (exit abort) Dans ce cas apregraves lexeacutecution des intructions du gestionnaire concerneacute on

passe tout simplement agrave la suite du bloc try concerneacute Cela revient agrave dire qursquoon passe agrave la pre-

miegravere instruction suivant le dernier gestionnaire

Observez cet exemple qui utilise les mecircmes classes vect vect_limite et vect_creation que

preacuteceacutedemment Nous y appelons agrave deux reprises une fonction f lrsquoexeacutecution de f se deacuteroule

normalement la premiegravere fois elle deacuteclenche une exception la seconde

1 Pour plus drsquoinformation sur le rocircle de ces fonctions on pourra consulter Langage C du mecircme auteur chez le mecircme

eacutediteur

3 - Le meacutecanisme de gestion des exceptions381

deacuteclaration et deacutefinition des classes vect vect_limite vect_creation

comme dans le paragraphe 2

main()

void f(int)

cout ltlt avant appel de f(3) n

f(3)

cout ltlt avant appel de f(8) n

f(8)

cout ltlt apres appel de f(8) n

void f(int n)

try

cout ltlt debut bloc tryn

vect v(5)

v[n] = 0 OK pour n=3 deacuteclenche une exception pour n=8

cout ltlt fin bloc tryn

catch (vect_limite l)

cout ltlt exception indice ltlt lhors ltlt hors limites n

catch (vect_creation c)

cout ltlt exception creationn

apregraves le bloc try

cout ltlt dans f apres bloc try - valeur de n = ltlt n ltlt n

avant appel de f(3)

debut bloc try

fin bloc try

dans f apres bloc try - valeur de n = 3

avant appel de f(8)

debut bloc try

exception indice 8 hors limites

dans f apres bloc try - valeur de n = 8

apres appel de f(8)

Lorsquon passe agrave travers un gestionnaire dexception

On constate qursquoapregraves lrsquoexeacutecution du gestionnaire drsquoexception vect_limite on exeacutecute lrsquoins-

truction cout figurant agrave la suite des gestionnaires On notera bien qursquoon peut y afficher la

valeur de n puisqursquoon est encore dans la porteacutee de cette variable

Freacutequemment un bloc try couvre toute une fonction de sorte qursquoapregraves exeacutecution drsquoun ges-

tionnaire drsquoexception ne provoquant pas drsquoarrecirct il y a retour de ladite fonction

La gestion des exceptionsCHAPITRE 17

382

32 Prise en compte des sorties de blocsLrsquoexemple preacuteceacutedent montrait deacutejagrave que le branchement provoqueacute par la deacutetection drsquoune

exception respectait le changement de contexte qui en deacutecoulait la valeur de n eacutetait connue

dans la suite du bloc try qursquoon y soit parvenu naturellement ou suite agrave une exception Voici

un autre exemple dans lequel nous avons simplement modifieacute la fonction f de lrsquoexemple

preacuteceacutedent

void f(int n) vect v1(5) try vect v2(5) v2[n] = 0 catch (vect_limite l) cout ltlt exception indice ltlt lhors ltlt hors limites n apregraves le bloc try ici v1 est connu v2 ne lrsquoest pas et il a eacuteteacute convenablement deacutetruit

Cette fois nous y creacuteons un vecteur en dehors du bloc try un autre agrave lrsquointeacuterieur comme preacute-

ceacutedemment Bien entendu si f srsquoexeacutecute sans deacuteclencher drsquoexception on exeacutecutera tout natu-

rellement les instructions suivant le bloc try dans ces derniegraveres v1 sera connu tandis que v2

ne le sera plus Mais il en ira encore de mecircme si f provoque une exception vect_limite apregraves

son traitement par le gestionnaire correspondant

De plus dans les deux cas le destructeur de v2 aura eacuteteacute appeleacute

Drsquoune maniegravere geacuteneacuterale le meacutecanisme associeacute au traitement drsquoune exception ne se contente

pas de supprimer les variables automatiques des blocs dont on provoque la sortie Il entraicircne

lrsquoappel du destructeur de tout objet automatique deacutejagrave construit et devenant hors de

porteacutee

Remarque

Comme on peut srsquoy attendre ce meacutecanisme de destruction ne pourra pas srsquoappliquer aux

objets dynamiques Certaines preacutecautions devront ecirctre prises degraves lors qursquoon souhaite

poursuivre lrsquoexeacutecution apregraves le traitement drsquoune exception Ce point sera examineacute en

deacutetail en Annexe C

4 Choix du gestionnaireDans les exemples que nous avons rencontreacutes jusqursquoici le choix du gestionnaire eacutetait relati-

vement intuitif Nous allons maintenant preacuteciser lrsquoensemble des regravegles utiliseacutees par C++ pour

effectuer ce choix Puis nous verrons comment la recherche se poursuit dans des blocs try

4 - Choix du gestionnaire383

englobants lorsqursquoaucun gestionnaire convenable nrsquoest trouveacute pour un bloc try donneacute Aupa-

ravant nous allons apporter quelques preacutecisions concernant la maniegravere (particuliegravere) dont

lrsquoinformation est effectivement transmise au gestionnaire

41 Le gestionnaire reccediloit toujours une copieEn ce qui concerne lrsquoinformation transmise au gestionnaire agrave savoir lrsquoexpression mentionneacutee

agrave throw le gestionnaire en reccediloit toujours une copie mecircme si lrsquoon a utiliseacute une transmission

par reacutefeacuterence Il srsquoagit lagrave drsquoune neacutecessiteacute compte tenu du changement de contexte deacutejagrave eacutevo-

queacute1 En revanche lorsque cette information consistera en un pointeur on eacutevitera qursquoil pointe

sur une variable automatique qui se trouverait deacutetruite avant lrsquoentreacutee dans le gestionnaire

c = new A () throw (c) erreur probable

42 Regravegles de choix drsquoun gestionnaire drsquoexceptionLorqursquoune exception est transmise agrave un bloc try on recherche dans les diffeacuterents blocs catch

associeacutes un gestionnaire approprieacute au type de lrsquoexpression mentionneacutee dans lrsquoinstruction

throw Comme pour la recherche drsquoune fonction surdeacutefinie on procegravede en plusieurs eacutetapes

1 Recherche drsquoun gestionnaire correspondant au type exact mentionneacute dans throw Le qua-

lificatif const nrsquointervient pas ici (il y a toujours transmission par valeur) Autrement dit

si lrsquoexpression mentionneacutee dans throw est de type T les gestionnaires suivants

conviennent

catch (T t)

catch (T amp t)catch (const T t)

catch (const T amp t)

2 Recherche drsquoun gestionnaire correspondant agrave une classe de base du type mentionneacute dans

throw Cette possibiliteacute est preacutecieuse pour regrouper plusieurs exceptions quon peut traiter

plus ou moins finement Consideacuterons cet exemple dans lequel les exceptions

vect_creation et vect_limite sont deacuteriveacutees drsquoune mecircme classe vect_erreur

class vect_erreur class vect_creation public vect_erreur

class vect_limite public vect_erreur void f()

throw vect_creation () exception 1

throw vect_limite () exception 2

1 Certains auteurs preacuteconisent drsquoutiliser toujours cette transmission par reacutefeacuterence pour eacuteviter la copie suppleacutementaire

que certains compilateurs introduisent dans le cas drsquoune transmission par valeur

La gestion des exceptionsCHAPITRE 17

384

Dans un programme utilisant f on peut geacuterer les exceptions qursquoelle est susceptible de deacute-

clencher de cette premiegravere faccedilon

main() try f() catch (vect_erreur e) on intercepte ici exception_1 et exception_2

Mais on peut aussi les geacuterer ainsi

main() try f() catch (vect_cration v) on intercepte ici exception_1 catch (vect_limite v) on intercepte ici exception_2

3 Recherche drsquoun gestionnaire correspondant agrave un pointeur sur une classe deacuteriveacutee du type

mentionneacute dans throw (lorsque ce type est lui-mecircme un pointeur)

4 Recherche drsquoun gestionnaire correspondant agrave un type quelconque repreacutesenteacute dans catch

par des points de suspension ()

Degraves quun gestionnaire correspond on lexeacutecute sans se preacuteoccuper de lexistence dautres

gestionnaires Ainsi avec

catch (truc) gestionnaire 1 catch () gestionnaire 2 (type quelconque) catch (chose) gestionnaire 3

le gestionnaire 3 na aucune chance decirctre exeacutecuteacute puisque le gestionnaire 2 interceptera tou-

tes les exceptions non intercepteacutees par le gestionnaire 1

43 Le cheminement des exceptionsQuand une exception est leveacutee par une fonction on cherche tout dabord un gestionnaire dans

leacuteventuel bloc try associeacute agrave cette fonction en appliquant les regravegles exposeacutees au paragraphe

42 Si lon ne trouve pas de gestionnaire ou si aucun bloc try nest associeacute on poursuit la

recherche dans un eacuteventuel bloc try associeacute agrave une fonction appelante1 et ainsi de suite Con-

sideacuterons cet exemple (utilisant toujours les mecircmes classes que preacuteceacutedemment)

4 - Choix du gestionnaire385

test exception

main ()

try void f1 ()

f1 ()

catch (vect_limite l)

cout ltlt dans main exception indice n

exit (-1)

void f1 ()

try

vect v(10) v[12] = 0 affiche dans main exception indice

vect v1 (-1) affiche dans f1 exception creation

(agrave condition que linstruction preacuteceacutedente

nrsquoait pas deacutejagrave provoqueacute une exception)

catch (vect_creation v)

cout ltlt dans f1 exception creation n

Si aucun gestionnaire dexception nest trouveacute on appelle la fonction terminate Par deacutefaut

cette derniegravere appelle la fonction abort Cette particulariteacute donne beaucoup de souplesse au

meacutecanisme de gestion drsquoexception En effet on peut ainsi se permettre de ne traiter que cer-

taines exceptions susceptibles drsquoecirctre deacuteclencheacutees par un programme les eacuteventuelles excep-

tions non deacutetecteacutees mettant simplement fin agrave lrsquoexeacutecution

Vous pouvez toujours demander qursquoagrave la place de terminate soit appeleacutee une fonction de votre

choix dont vous fournissez lrsquoadresse agrave set_terminate (de faccedilon comparable agrave ce que vous fai-

tes avec set_new_handler) Il est cependant neacutecessaire que cette fonction mette fin agrave lrsquoexeacutecu-

tion du programme elle ne doit pas effectuer de retour et elle ne peut pas lever drsquoexception

Remarques

1 Il est theacuteoriquement possible drsquoimbriquer des blocs try Dans ce cas lrsquoalgorithme de

recherche drsquoun gestionnaire se geacuteneacuteralise tout naturellement en prenant en compte les

eacuteventuels blocs englobants avant de remonter aux fonctions appelantes

2 Retenez bien que degraves qursquoun gestionnaire convenable a eacuteteacute trouveacute dans un bloc aucune

recherche nrsquoa lieu dans un eacuteventuel bloc englobant mecircme srsquoil contient un gestionnaire

assurant une meilleure correspondance de type

1 En fait on est presque toujours dans cette situation car il est rare que le bloc try figure dans le mecircme bloc que celui

qui contient lrsquoinstruction throw

La gestion des exceptionsCHAPITRE 17

386

44 Redeacuteclenchement drsquoune exceptionDans un gestionnaire lrsquoinstruction throw (sans expression) retransmet lrsquoexception au niveau

englobant Cette possibiliteacute permet par exemple de compleacuteter un traitement standard drsquoune

exception par un traitement compleacutementaire speacutecifique En voici un exemple dans lequel une

exception (ici de type int)1 est tout drsquoabord traiteacutee dans f avant drsquoecirctre traiteacutee dans main

include ltiostreamgtinclude ltcstdlibgt pour exit (ancien stdlibhgtusing namespace std main() try void f() f() catch (int) cout ltlt exception int dans mainn exit(-1) void f() try int n=2 throw n deacuteclenche une exception de type int catch (int) cout ltlt exception int dans fn throw

exception int dans fexception int dans main

Exemple de redeacuteclenchement drsquoune exception

Remarques

1 Dans le cas drsquoun gestionnaire drsquoexception figurant dans un constructeur ou un destruc-

teur lrsquoexception correspondante est automatiquement retransmise au niveau englobant si

lrsquoon atteint la fin du gestionnaire Tout se passe comme si le gestionnaire se terminait par

lrsquoinstruction

1 Il srsquoagit drsquoun exemple drsquoeacutecole En pratique lrsquoutilisation drsquoun type de base pour caracteacuteriser une exception nrsquoest

guegravere conseilleacutee

5 - Speacutecification dinterface la fonction unexpected387

throw geacuteneacutereacutee automatiquement agrave la fin drsquoun gestionnaire drsquoexception figurant dans un constructeur ou un destructeur

2 La relance drsquoune exception par throw srsquoavegravere surtout utile lorsqursquoun mecircme gestionnaire

risque de traiter une famille drsquoexceptions Dans le cas contraire on peut toujours la

remplacer par le deacuteclenchement explicite drsquoune nouvelle exception de mecircme type

Ainsi dans le gestionnaire

catch (A a) intercepte les exceptions de type A ou deacuteriveacute

on peut utiliser

throw a relance une exception de type A quel que soit le type de celle reacuteellement intercepteacutee (A ou deacuteriveacute)throw relance une exception du type de celle reacuteellement intercepteacutee

5 Speacutecification dinterface la fonction unexpected

Une fonction peut speacutecifier les exceptions quelle est susceptible de deacuteclencher sans les traiter

(ou de traiter et de redeacuteclencher par throw) Elle le fait agrave laide du mot cleacute throw suivi entre

parenthegraveses de la liste des exceptions concerneacutees Dans ce cas toute exception non preacutevue et

deacuteclencheacutee agrave linteacuterieur de la fonction (ou dune fonction appeleacutee) entraicircne lappel dune fonc-

tion particuliegravere nommeacutee unexpected

On peut dire que

void f() throw (A B) f est censeacutee ne deacuteclencher que des exceptions de type A et B

est eacutequivalent agrave

void f() try catch (A a) throw lrsquoexception A est retransmise catch (B b) throw lrsquoexception B est retransmise catch () unexpected() les autres appelent unexpected

Malheureusement le comportement par deacutefaut de unexpected nrsquoest pas entiegraverement deacutefini

par la norme Plus preacuteciseacutement cette fonction peut

bull soit appeler la fonction terminate (qui par deacutefaut appelle abort ce qui met fin agrave lrsquoexeacutecu-

tion)

bull soit redeacuteclencher une exception preacutevue dans la speacutecification drsquointerface de la fonction con-

cerneacutee Ce cadre assez large est essentiellement preacutevu pour permettre agrave unexpected de deacute-

clencher une exception standard bad_exception (les exceptions standard seront eacutetudieacutees au

paragraphe 6)

La gestion des exceptionsCHAPITRE 17

388

Vous pouvez eacutegalement fournir votre propre fonctionen remplacement de unexpected en

lindiquant par set_unexpected Lagrave encore cette fonction ne peut pas effectuer de retour en

revanche contrairement agrave la fonction se substituant agrave terminate elle peut lancer une excep-

tion agrave son tour

Voici un exemple dans lequel une fonction f deacuteclenche suivant la valeur de son argument

une exception de lrsquoun des types double int ou float1 Les premiegraveres disposent drsquoun gestion-

naire interne agrave f mais pas les autres Par ailleurs f a eacuteteacute deacuteclareacutee throw(int) ce qui laisse

entendre que vue de lrsquoexteacuterieur elle ne deacuteclenche que des exceptions de type int Nous exeacute-

cutons agrave trois reprises le programme de faccedilon agrave amener f agrave deacuteclencher successivement cha-

cune des trois exceptions

include ltiostreamgtusing namespace std main() void f(int) throw (int) int n cout ltlt entier (0 a 2) cin gtgt n try f(n) catch (int) cout ltlt exception int dans mainn cout ltlt suite du bloc try du mainn

void f(int n) throw (int) try cout ltlt n = ltlt n ltlt n switch (n) case 0 double d throw d break case 1 int n throw n break case 2 float f throw f break catch (double) cout ltlt exception double dans fn cout ltlt suite du bloc try dans f et retour appelantn

1 Ici encore il srsquoagit drsquoun exemple drsquoeacutecole En pratique lrsquoutilisation drsquoun type de base pour caracteacuteriser une

exception nrsquoest guegravere conseilleacutee

5 - Speacutecification dinterface la fonction unexpected389

entier (0 a 2) 0n = 0exception double dans fsuite du bloc try dans f et retour appelantsuite du bloc try du main

entier (0 a 2) 1n = 1exception int dans mainsuite du bloc try du main

entier (0 a 2) 2n = 2 ici appel de abort (fin anormale)

Exemple de speacutecification drsquointerface

On notera que dans la troisiegraveme exeacutecution du programme il y a appel de la fonction unex-

pected Comme rien nrsquoest preacutevu pour traiter lrsquoexception standard bad_alloc quel que soit le

comportement preacutevu par lrsquoimpleacutementation nous aboutirons en deacutefinitive agrave un appel de abort

Remarques

1 Lrsquoabsence de speacutecification drsquointerface revient agrave speacutecifier toutes les exceptions possibles

En revanche une speacutecification vide nrsquoautorise aucune exception

void fct throw () aucune exception permise - toute exception non traiteacutee dans la fonction appelle unexpected

2 En cas de redeacutefinition de fonction membre dans une classe deacuteriveacutee la speacutecification

drsquointerface de la fonction redeacutefinie ne peut pas mentionner drsquoautres exceptions que cel-

les preacutevues dans la classe de base en revanche elle peut nrsquoen speacutecifier que certaines

voire aucune

3 Drsquoune maniegravere geacuteneacuterale la speacutecification drsquoexceptions ne doit ecirctre utiliseacutee qursquoavec preacute-

cautions En effet eacutenumeacuterer les exceptions susceptibles drsquoecirctre leveacutees par une fonction

suppose qursquoon connaicirct avec certitude toutes les exceptions susceptibles drsquoecirctre leveacutees

par toutes les fonctions appeleacutees

La gestion des exceptionsCHAPITRE 17

390

6 Les exceptions standard

61 GeacuteneacuteraliteacutesLa bibliothegraveque standard comporte quelques classes fournissant des exceptions speacutecifiques

susceptibles drsquoecirctre deacuteclencheacutees par un programme Certaines peuvent ecirctre deacuteclencheacutees par

des fonctions ou des opeacuterateurs de la bibliothegraveque standard

Toutes ces classes deacuterivent drsquoune classe de base nommeacutee exception et sont organiseacutees suivant

la hieacuterarchie suivante (leur deacuteclaration figure dans le fichier en-tecircte ltstdexceptgt)

exception

logic_error

domain_error

invalid_argument

length_error

out_of_range

runtime_error

range_error

overflow_error

underflow_error

bad_alloc

bad_cast

bad_exception

bad_typeid

62 Les exceptions deacuteclencheacutees par la bibliothegraveque standardSept des exceptions standard sont susceptibles drsquoecirctre deacuteclencheacutees par une fonction ou un

opeacuterateur de la bibliothegraveque standard Voici leur signification

bull bad_alloc eacutechec drsquoallocation meacutemoire par new

bull bad_cast eacutechec de lrsquoopeacuterateur dynamic_cast

bull bad_typeid eacutechec de la fonction typpeid

bull bad_exception erreur de speacutecification drsquoexception cette exception peut ecirctre deacuteclencheacutee

dans certaines impleacutementations par la fonction unexpected

bull out_of_range erreur drsquoindice cette exception est deacuteclencheacutee par les fonctions at membres

des diffeacuterentes classes conteneurs (deacutecrites au chapitre 19 et au chapitre 20) ainsi que par

lrsquoopeacuterateur [] du conteneur bitset

bull invalid_argument deacuteclencheacutee par le constructeur du conteneur bitset

bull overflow_error deacuteclencheacutee par la fonction to_ulong du conteneur bitset

6 - Les exceptions standard391

63 Les exceptions utilisables dans un programmeA priori toutes les classes preacuteceacutedentes sont utilisables pour les exceptions deacuteclencheacutees par

lrsquoutilisateur soit telles quelles soit sous forme de classes deacuteriveacutees Il est cependant preacutefeacutera-

ble drsquoassurer une certaine coheacuterence agrave son programme par exemple il ne serait guegravere rai-

sonnable de deacuteclencher une exception bad_alloc pour signaler une anomalie sans rapport

avec une allocation meacutemoire

Pour utiliser ces classes quelques connaissances sont neacutecessaires

bull la classe de base exception dispose drsquoune fonction membre what censeacutee fournir comme va-

leur de retour un pointeur sur une chaicircne expliquant la nature de lrsquoexception Cette fonction

virtuelle dans exception doit ecirctre redeacutefinie dans les classes deacuteriveacutees et elle lrsquoest dans toutes

les classes citeacutees ci-dessus (la chaicircne obtenue deacutepend cependant de lrsquoimpleacutementation)

bull toutes ces classes disposent drsquoun constructeur recevant un argument de type chaicircne dont la

valeur pourra ensuite ecirctre reacutecupeacutereacutee par what

Voici un exemple de programme utilisant ces proprieacuteteacutes pour deacuteclencher deux exception de

type range_error avec deux messages explicatifs diffeacuterents

include ltiostreamgt

include ltstdexceptgt

include ltcstdlibgt

using namespace std

main()

try

throw range_error (anomalie 1) afficherait exception anomalie 1

throw range_error (anomalie 2) afficherait exception anomalie 2

catch (range_error amp re)

cout ltlt exception ltlt rewhat() ltlt n

exit (-1)

64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exceptionJusqursquoici nous avions deacutefini nos propres classes exception de faccedilon indeacutependante de la

classe standard exception On voit maintenant qursquoil peut srsquoaveacuterer inteacuteressant de creacuteer ses pro-

pres classes deacuteriveacutees de exception pour au moins deux raisons

1 On facilite le traitement ulteacuterieur des exceptions A la limite on est sucircr drsquointercepter toutes

les exceptions avec le simple gestionnaire

catch (exception amp e)

Ce ne serait pas le cas pour des exceptions non rattacheacutees agrave la classe exception

La gestion des exceptionsCHAPITRE 17

392

2 On peut srsquoappuyer sur la fonction what deacutecrite ci-dessus agrave condition de la redeacutefinir de fa-

ccedilon approprieacutee dans ses propres classes Il est alors facile drsquoafficher un message explicatif

concernant lrsquoexception deacutetecteacutee agrave lrsquoaide du simple gestionnaire suivant

catch (exception amp e) attention agrave la reacutefeacuterence pour beacuteneacuteficier de la

ligature dynamique de la fonction virtuelle what

cout ltlt exception intercepteacutee ltlt ewhat ltlt n

641 Exemple 1

Voici un premier exemple dans lequel nous creacuteons deux classes exception_1 et exception_2

deacuteriveacutees de la classe exception et dans lesquelles nous redeacutefinissons la fonction membre

what

include ltiostreamgtinclude ltstdexceptgt

using namespace std class mon_exception_1 public exception

public

mon_exception_1 () const char what() const return mon exception nummero 1

class mon_exception_2 public exception

public

mon_exception_2 () const char what() const return mon exception nummero 2

main()

try

cout ltlt bloc try 1n throw mon_exception_1()

catch (exception amp e) cout ltlt exception ltlt ewhat() ltlt n

try

cout ltlt bloc try 2n

throw mon_exception_2()

catch (exception amp e) cout ltlt exception ltlt ewhat() ltlt n

bloc try 1

exception mon exception nummero 1

bloc try 2exception mon exception nummero 2

Utilisation de classes exception deacuteriveacutees de exception (1)

Notez qursquoil est important de deacutefinir what sous la forme drsquoune fonction membre constante

sous peine de ne pas la voir appeleacutee

642 Exemple 2

Dans ce deuxiegraveme exemple nous creacuteons une seule classe mon_exception deacuteriveacutee de la classe

exception Mais nous preacutevoyons que son constructeur conserve la valeur reccedilue (chaicircne) en

argument et nous redeacutefinissons what de faccedilon qursquoelle fournisse cette valeur Il reste ainsi pos-

sible de distinguer entre plusieurs sortes drsquoexceptions (ici 2)

include ltiostreamgt

include ltstdexceptgt

using namespace std

class mon_exception public exception

public

mon_exception (char texte) ad_texte = texte

const char what() const return ad_texte

private

char ad_texte

main()

try

cout ltlt bloc try 1n

throw mon_exception (premier type)

catch (exception amp e)

cout ltlt exception ltlt ewhat() ltlt n

try

cout ltlt bloc try 2n

throw mon_exception (deuxieme type)

catch (exception amp e)

cout ltlt exception ltlt ewhat() ltlt n

bloc try 1

exception premier type

bloc try 2

exception deuxieme type

Utilisation drsquoune classe exception deacuteriveacutee de exception (2)

6 - Les exceptions standard393

18

Geacuteneacuteraliteacutes surla bibliothegraveque standard

Comme celle du C la norme du C++ comprend la deacutefinition dune bibliothegraveque standard

Bien entendu on y trouve toutes les fonctions preacutevues dans les versions C++ davant la

norme quil sagisse des flots deacutecrits preacuteceacutedemment ou des fonctions de la bibliothegraveque stan-

dard du C Mais on y deacutecouvre surtout bon nombre de nouveauteacutes originales La plupart

dentre elles sont constitueacutees de patrons de classes et de fonctions provenant en majoriteacute

dune bibliothegraveque du domaine public nommeacutee Standard Template Library (en abreacutegeacute STL)

et deacuteveloppeacutee chez Hewlett Packard

Lobjectif de ce chapitre est de vous familiariser avec les notions de base concernant lutilisa-

tion des principaux composants de cette bibliothegraveque agrave savoir les conteneurs les iteacuterateurs

les algorithmes les geacuteneacuterateurs dopeacuterateurs les preacutedicats et lutilisation dune relation

dordre

1 Notions de conteneur diteacuterateur et dalgorithme

Ces trois notions sont eacutetroitement lieacutees et la plupart du temps elles interviennent simultaneacute-

ment dans un programme utilisant des conteneurs

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

396

11 Notion de conteneur La bibliothegraveque standard fournit un ensemble de classes dites conteneurs permettant de

repreacutesenter les structures de donneacutees les plus reacutepandues telles que les vecteurs les listes les

ensembles ou les tableaux associatifs Il sagit de patrons de classes parameacutetreacutes tout naturelle-

ment par le type de leurs eacuteleacutements Par exemple on pourra construire une liste dentiers un

vecteur de flottants ou une liste de points (point eacutetant une classe) par les

deacuteclarations suivantes

list ltintgt li liste vide drsquoeacuteleacutements de type int

vector ltdoublegt ld vecteur vide drsquoeacuteleacutements de type double

list ltpointgt lp liste vide drsquoeacuteleacutements de type point

Chacune de ces classes conteneur dispose de fonctionnaliteacutes approprieacutees dont on pourrait

penser a priori quelles sont tregraves diffeacuterentes dun conteneur agrave lautre En reacutealiteacute les concep-

teurs de STL ont fait un gros effort dhomogeacuteneacuteisation et beaucoup de fonctions membres

sont communes agrave diffeacuterents conteneurs On peut dire que degraves quune action donneacutee est reacuteali-

sable avec deux conteneurs diffeacuterents elle se programme de la mecircme maniegravere

Remarque

En toute rigueur les patrons de conteneurs sont parameacutetreacutes agrave la fois par le type de leurs

eacuteleacutements et par une fonction dite allocateur utiliseacutee pour les allocations et les libeacuterations

de meacutemoire Ce second paramegravetre possegravede une valeur par deacutefaut qui est geacuteneacuteralement

satisfaisante Cependant certaines impleacutementations nacceptent pas encore les paramegravetres

par deacutefaut dans les patrons de classes et dans ce cas il est neacutecessaire de preacuteciser lalloca-

teur agrave utiliser mecircme sil sagit de celui par deacutefaut Il faut alors savoir que ce dernier est

une fonction patron de nom allocator parameacutetreacutee par le type des eacuteleacutements concerneacutes

Voici ce que deviendraient les deacuteclarations preacuteceacutedentes dans un tel cas

list ltint allocatorltintgt gt li ne pas oublier lrsquoespace

vector ltdouble allocatorltdoublegt gt ld entre intgt et gt sinon gtgt

list ltpoint allocatorltpointgt gt lp repreacutesentera lopeacuterateur gtgt

12 Notion diteacuterateur Cest dans ce souci dhomogeacuteneacuteisation des actions sur un conteneur qua eacuteteacute introduite la

notion diteacuterateur Un iteacuterateur est un objet deacutefini geacuteneacuteralement par la classe conteneur con-

cerneacutee qui geacuteneacuteralise la notion de pointeur

bull agrave un instant donneacute un iteacuterateur possegravede une valeur qui deacutesigne un eacuteleacutement donneacute dun

conteneur on dira souvent quun iteacuterateur pointe sur un eacuteleacutement dun conteneur

bull un iteacuterateur peut ecirctre increacutementeacute par lopeacuterateur ++ de maniegravere agrave pointer sur leacuteleacutement sui-

vant du mecircme conteneur on notera que ceci nest possible que comme on le verra plus loin

parce que les conteneurs sont toujours ordonneacutes suivant une certaine seacutequence

1 - Notions de conteneur diteacuterateur et dalgorithme397

bull un iteacuterateur peut ecirctre deacutereacutefeacuterenceacute comme un pointeur en utilisant lopeacuterateur par exem-

ple si it est un iteacuterateur sur une liste de points it deacutesigne un point de cette liste

bull deux iteacuterateurs sur un mecircme conteneur peuvent ecirctre compareacutes par eacutegaliteacute ou ineacutegaliteacute

Tous les conteneurs fournissent un iteacuterateur portant le nom iterator et posseacutedant au minimum

les proprieacuteteacutes que nous venons deacutenumeacuterer qui correspondent agrave ce quon nomme un iteacuterateur

unidirectionnel Certains iteacuterateurs pourront posseacuteder des proprieacuteteacutes suppleacutementaires en

particulier

bull deacutecreacutementation par lopeacuterateur -- comme cette possibiliteacute sajoute alors agrave celle qui est of-

ferte par ++ liteacuterateur est alors dit bidirectionnel

bull accegraves direct dans ce cas si it est un tel iteacuterateur lexpression it+i a un sens souvent lopeacute-

rateur [] est alors deacutefini de maniegravere que it[i] soit eacutequivalent agrave (it+i) en outre un tel iteacute-

rateur peut ecirctre compareacute par ineacutegaliteacute

Remarque

Ici nous avons eacutevoqueacute trois cateacutegories diteacuterateur unidirectionnel bidirectionnel et

accegraves direct Au chapitre 21 nous verrons quil existe deux autres cateacutegories (entreacutee et

sortie) qui sont dun usage plus limiteacute De mecircme on verra quil existe ce quon appelle des

adaptateurs diteacuterateur lesquels permettent den modifier les proprieacuteteacutes les plus impor-

tants seront liteacuterateur de flux et liteacuterateur dinsertion

13 Parcours dun conteneur avec un iteacuterateur

131 Parcours directTous les conteneurs fournissent des valeurs particuliegraveres de type iterator sous forme des

fonctions membres begin() et end() de sorte que quel que soit le conteneur le canevas sui-

vant preacutesenteacute ici sur une liste de points est toujours utilisable pour parcourir seacutequentielle-

ment un conteneur de son deacutebut jusquagrave sa fin

listltpointgt lp listltpointgtiterator il iteacuterateur sur une liste de points for (il = lpbegin() il = lpend() il++) ici il deacutesigne leacuteleacutement courant de la liste de points lp

On notera la particulariteacute des valeurs des iteacuterateurs de fin qui consiste agrave pointer non pas sur

le dernier eacuteleacutement dun conteneur mais juste apregraves Dailleurs lorsquun conteneur est vide

begin() possegravede la mecircme valeur que end() de sorte que le canevas preacuteceacutedent fonctionne tou-

jours convenablement

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

398

Remarque

Attention on ne peut pas utiliser comme condition darrecirct de la boucle for une expression

telle que il lt lpend car lopeacuterateur lt ne peut sappliquer quagrave des iteacuterateurs agrave accegraves direct

132 Parcours inverseToutes les classes conteneur pour lesquelles iterator est au moins bidirectionnel (on peut

donc lui appliquer ++ et --) disposent dun second iteacuterateur noteacute reverse_iterator Construit agrave

partir du premier il permet dexplorer le conteneur suivant lordre inverse Dans ce cas la

signification de ++ et -- appliqueacutes agrave cet iteacuterateur est alors adapteacutee en conseacutequence en outre

il existe eacutegalement des valeurs particuliegraveres de type reverse_iterator fournies par les fonc-

tions membres rbegin() et rend() on peut dire que rbegin() pointe sur le dernier eacuteleacutement du

conteneur tandis que rend() pointe juste avant le premier Voici comment parcourir une liste

de points dans lordre inverse

listltpointgt lp listltpointgtreverse_iterator ril iteacuterateur inverse sur une liste de points for (ril = lprbegin() ril = lprend() ril++) ici ril deacutesigne leacuteleacutement courant de la liste de points lp

14 Intervalle diteacuterateur Comme nous lavons deacutejagrave fait remarquer tous les conteneurs sont ordonneacutes de sorte quon

peut toujours les parcourir dun deacutebut jusquagrave une fin Plus geacuteneacuteralement on peut deacutefinir ce

quon nomme un intervalle drsquoiteacuterateur en preacutecisant les bornes sous forme de deux valeurs

diteacuterateur Supposons que lon ait deacuteclareacute

vectorltpointgtiterator ip1 ip2 ip1 et ip2 sont des iteacuterateurs sur un vecteur de points

Supposons de plus que ip1 et ip2 possegravedent des valeurs telles que ip2 soit accessible

depuis ip1 autrement dit que apregraves un certain nombre dincreacutementations de ip1 par ++ on

obtienne la valeur de ip2 Dans ces conditions le couple de valeurs ip1 ip2 deacutefinit un inter-

valle dun conteneur du type vectorltpointgt seacutetendant de leacuteleacutement pointeacute par ip1 jusquagrave

(mais non compris) celui pointeacute par ip2 Cet intervalle se note souvent [ip1 ip2) On dit eacutega-

lement que les eacuteleacutements deacutesigneacutes par cet intervalle forment une seacutequence

Cette notion dintervalle diteacuterateur sera tregraves utiliseacutee par les algorithmes et par certaines fonc-

tions membres

1 - Notions de conteneur diteacuterateur et dalgorithme399

15 Notion dalgorithme La notion dalgorithme est tout aussi originale que les deux preacuteceacutedentes Elle se fonde sur le

fait que par le biais dun iteacuterateur beaucoup dopeacuterations peuvent ecirctre appliqueacutees agrave un conte-

neur quels que soient sa nature et le type de ses eacuteleacutements Par exemple on pourra trouver le

premier eacuteleacutement ayant une valeur donneacutee aussi bien dans une liste un vecteur ou ensemble

il faudra cependant que leacutegaliteacute de deux eacuteleacutements soit convenablement deacutefinie soit par

deacutefaut soit par surdeacutefinition de lopeacuterateur == De mecircme on pourra trier un conteneur

dobjets de type T pour peu que ce conteneur dispose dun iteacuterateur agrave accegraves direct et que lon

ait deacutefini une relation dordre sur le type T par exemple en surdeacutefinissant lopeacuterateur lt

Les diffeacuterents algorithmes sont fournis sous forme de patrons de fonctions parameacutetreacutes par le

type des iteacuterateurs qui leurs sont fournis en argument Lagrave encore cela conduit agrave des program-

mes tregraves homogegravenes puisque les mecircmes fonctions pourront ecirctre appliqueacutees agrave des conteneurs

diffeacuterents Par exemple pour compter le nombre deacuteleacutements eacutegaux agrave un dans un vecteur

deacuteclareacute par

vectorltintgt v vecteur dentiers

on pourra proceacuteder ainsi

n = count (vbegin() vend() 1) compte le nombre deacuteleacutements valant 1

dans la seacutequence [vbegin() vend())

autrement dit dans tout le conteneur v

Pour compter le nombre deacuteleacutements eacutegaux agrave un dans une liste deacuteclareacutee

listltintgt l liste dentiers

on proceacutedera de faccedilon similaire (en se contentant de remplacer v par l)

n = count (lbegin() lend() 1) compte le nombre deacuteleacutements valant 1

dans la seacutequence [lbegin() lend())

autrement dit dans tout le conteneur l

Dune maniegravere geacuteneacuterale comme le laissent entendre ces deux exemples les algorithmes

sappliquent non pas agrave un conteneur mais agrave une seacutequence deacutefinie par un intervalle

diteacuterateur ici cette seacutequence correspondait agrave linteacutegraliteacute du conteneur

Certains algorithmes permettront facilement de recopier des informations dun conteneur

dun type donneacute vers un conteneur dun autre type pour peu que ses eacuteleacutements soient du mecircme

type que ceux du premier conteneur Voici par exemple comment recopier un vecteur

dentiers dans une liste dentiers

vectorltintgt v vecteur dentiers

listltintgt l liste dentiers

copy (vbegin() vend() lbegin() )

recopie lintervalle [vbegin() vend())

agrave partir de lemplacement pointeacute par lbegin()

Notez que si lon fournit lintervalle de deacutepart on ne mentionne que le deacutebut de celui darri-

veacutee

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

400

Remarque

On pourra parfois ecirctre gecircneacute par le fait que lhomogeacuteneacuteisation eacutevoqueacutee nest pas absolue

Ainsi on verra quil existe un algorithme de recherche dune valeur donneacutee nommeacute find

alors mecircme quun conteneur comme list dispose dune fonction membre comparable La

justification reacutesidera dans des consideacuterations defficaciteacute

16 Iteacuterateurs et pointeurs La maniegravere dont les algorithmes ou les fonctions membres utilisent un iteacuterateur fait que tout

objet ou toute variable posseacutedant les proprieacuteteacutes attendues (deacutereacutefeacuterenciation increacutementa-

tion) peut ecirctre utiliseacute agrave la place dun objet tel que iterator

Or les pointeurs usuels possegravedent tout naturellement les proprieacuteteacutes dun iteacuterateur agrave accegraves

direct Cela leur permet decirctre employeacutes dans bon nombre dalgorithmes Cette possibiliteacute est

freacutequemment utiliseacutee pour la recopie des eacuteleacutements dun tableau ordinaire dans un conteneur

int t[6] = 2 9 1 8 2 11 listltintgt l copy (t t+6 lbegin()) copie de lintervalle [t t+6) dans la liste l

Bien entendu ici il nest pas question dutiliser une notation telle que tbegin() qui naurait

aucun sens t neacutetant pas un objet

Remarque

Par souci de simpliciteacute nous parlerons encore de seacutequence deacuteleacutements (mais plus de

seacutequence de conteneur) pour deacutesigner les eacuteleacutements ainsi deacutefinis par un intervalle de poin-

teurs

2 Les diffeacuterentes sortes de conteneurs

21 Conteneurs et structures de donneacutees classiques On dit souvent que les conteneurs correspondent agrave des structures de donneacutees usuelles Mais agrave

partir du moment ougrave ces conteneurs sont des classes qui encapsulent convenablement leurs

donneacutees leurs caracteacuteristiques doivent ecirctre indeacutependantes de leur impleacutementation Dans ces

conditions les diffeacuterents conteneurs devraient se distinguer les uns des autres uniquement

par leurs fonctionnaliteacutes et en aucun cas par les structures de donneacutees sous-jacentes Beau-

coup de conteneurs posseacutederaient alors des fonctionnaliteacutes voisines voire identiques

En reacutealiteacute les diffeacuterents conteneurs se caracteacuterisent outre leurs fonctionnaliteacutes par leffica-

citeacute de certaines opeacuterations Par exemple on verra quun vecteur permet des insertions deacuteleacute-

3 - Les conteneurs dont les eacuteleacutements sont des objets401

ments en nimporte quel point mais celles-ci sont moins efficaces quavec une liste En

revanche on peut acceacuteder plus rapidement agrave un eacuteleacutement existant dans le cas dun vecteur que

dans celui dune liste Ainsi bien que la norme nimpose pas limpleacutementation des conte-

neurs elle introduit des contraintes defficaciteacute qui la conditionneront largement

En deacutefinitive on peut dire que le nom choisi pour un conteneur eacutevoque la structure de donneacutee

classique qui en est proche sur le plan des fonctionnaliteacutes sans pour autant coiumlncider avec

elle Dans ces conditions un bon usage des diffeacuterents conteneurs passe par un apprentissage

de leurs possibiliteacutes comme sil sagissait bel et bien de classes diffeacuterentes

22 Les diffeacuterentes cateacutegories de conteneurs La norme classe les diffeacuterents conteneurs en deux cateacutegories

bull les conteneurs en seacutequence (ou conteneurs seacutequentiels)

bull les conteneurs associatifs

La notion de conteneur en seacutequence correspond agrave des eacuteleacutements qui sont ordonneacutes comme

ceux dun vecteur ou dune liste On peut parcourir le conteneur suivant cet ordre Quand on

insegravere ou quon supprime un eacuteleacutement on le fait en un endroit quon a explicitement choisi

La notion de conteneur associatif peut ecirctre illustreacutee par un reacutepertoire teacuteleacutephonique Dans ce

cas on associe une valeur (numeacutero de teacuteleacutephone adresse) agrave ce quon nomme une cleacute (ici le

nom) A partir de la cleacute on accegravede agrave la valeur associeacutee Pour inseacuterer un nouvel eacuteleacutement dans

ce conteneur il ne sera theacuteoriquement plus utile de preacuteciser un emplacement

Il semble donc quun conteneur associatif ne soit plus ordonneacute En fait pour deacutevidentes

questions defficaciteacute un tel conteneur devra ecirctre ordonneacute mais cette fois de faccedilon intrinsegrave-

que crsquoest-agrave-dire suivant un ordre qui nest plus deacutefini par le programme La principale conseacute-

quence est quil restera toujours possible de parcourir seacutequentiellement les eacuteleacutements dun tel

conteneur qui disposera toujours au moins dun iteacuterateur nommeacute iterator et des valeurs

begin() et end() Cet aspect peut dailleurs precircter agrave confusion dans la mesure ougrave certaines

opeacuterations preacutevues pour des conteneurs seacutequentiels pourront sappliquer agrave des conteneurs

associatifs tandis que dautres poseront problegraveme Par exemple il ny aura aucun risque agrave

examiner seacutequentiellement chacun des eacuteleacutements dun conteneur associatif il y en aura mani-

festement en revanche si lon cherche agrave modifier seacutequentiellement les valeurs deacuteleacutements

existants puisqualors on risque de perturber lordre intrinsegraveque du conteneur Nous y

reviendrons le moment venu

3 Les conteneurs dont les eacuteleacutements sont des objets

Le patron de classe deacutefinissant un conteneur peut ecirctre appliqueacute agrave nimporte quel type et donc

en particulier agrave des eacuteleacutements de type classe Dans ce cas il ne faut pas perdre de vue que bon

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

402

nombre de manipulations de ces eacuteleacutements vont entraicircner des appels automatiques de certai-

nes fonctions membres

31 Construction copie et affectationToute construction drsquoun conteneur non vide dont les eacuteleacutements sont des objets entraicircne

pour chacun de ces eacuteleacutements

bull soit lrsquoappel drsquoun constructeur il peut srsquoagir drsquoun constructeur par deacutefaut lorsqursquoaucun ar-

gument nrsquoest neacutecessaire

bull soit lrsquoappel drsquoun constructeur par recopie

Par exemple on verra que la deacuteclaration suivante (point eacutetant une classe) construit un vecteur

de trois eacuteleacutements de type point

vectorltpointgt v(3) construction drsquoun vecteur de 3 points

Pour chacun des trois eacuteleacutements il y aura appel drsquoun constructeur sans argument de point Si

lrsquoon construit un autre vecteur agrave partir de v

vectorltpointgt w (v) ou vector v = w

il y aura appel du constructeur par recopie de la classe vectorltpointgt lequel appellera le

constructeur par recopie de la classe point pour chacun des trois eacuteleacutements de type point agrave

recopier

On pourrait srsquoattendre agrave des choses comparables avec lrsquoopeacuterateur drsquoaffectation dans un cas

tel que

w = v le vecteur v est affecteacute agrave w

Cependant ici les choses sont un peu moins simples En effet geacuteneacuteralement si la taille de w

est suffisante on se contentera effectivement drsquoappeler lrsquoopeacuterateur drsquoaffectation pour tous les

eacuteleacutements de v (on appellera le destructeur pour les eacuteleacutements exceacutedentaires de w) En revan-

che si la taille de w est insuffisante il y aura destruction de tous ses eacuteleacutements et creacuteation drsquoun

nouveau vecteur par appel du constructeur par recopie lequel appellera tout naturellement le

constructeur par recopie de la classe point pour tous les eacuteleacutements de v

Par ailleurs il ne faudra pas perdre de vue que par deacutefaut la transmission drsquoun conteneur en

argument drsquoune fonction se fait par valeur ce qui entraicircne la recopie de tous ses eacuteleacutements

Les trois circonstances que nous venons drsquoeacutevoquer concernent des opeacuterations portant sur

lrsquoensemble drsquoun conteneur Mais il va de soi qursquoil existe eacutegalement drsquoautres opeacuterations por-

tant sur un eacuteleacutement drsquoun conteneur et qui elles aussi feront appel au constructeur de

recopie (insertion) ou agrave lrsquoaffectation

Drsquoune maniegravere geacuteneacuterale si les objets concerneacutes ne possegravedent pas de partie dynamique les

fonctions membres preacutevues par deacutefaut seront satisfaisantes Dans le cas contraire il faudra

preacutevoir les fonctions approprieacutees ce qui sera bien sucircr le cas si la classe concerneacutee respecte le

4 - Efficaciteacute des opeacuterations sur des conteneurs403

scheacutema de classe canonique proposeacute au paragraphe 4 du chapitre 9 (et compleacuteteacute au paragra-

phe 8 du chapitre 13) Notez bien que

Remarque

Dans les descriptions des diffeacuterents conteneurs ou algorithmes nous ne rappellerons pas

ces diffeacuterents points dans la mesure ougrave ils concernent systeacutematiquement tous les objets

32 Autres opeacuterations Il existe dautres opeacuterations que les constructions ou recopies de conteneur qui peuvent

entraicircner des appels automatiques de certaines fonctions membres

Lun des exemples les plus eacutevidents est celui de la recherche dun eacuteleacutement de valeur donneacutee

comme le fait la fonction membre find du conteneur list Dans ce cas la classe concerneacutee

devra manifestement disposer de lopeacuterateur == lequel cette fois ne possegravede plus de version

par deacutefaut

Un autre exemple reacuteside dans les possibiliteacutes dites de comparaisons lexicographiques que

nous examinerons au chapitre 19 nous verrons que celles-ci se fondent sur la comparaison

par lun des opeacuterateurs lt gt lt= ou gt= des diffeacuterents eacuteleacutements du conteneur Manifestement

lagrave encore il faudra deacutefinir au moins lopeacuterateur lt pour la classe concerneacutee les possibiliteacutes de

geacuteneacuteration automatique preacutesenteacutees ci-dessus pourront eacuteviter les deacutefinitions des trois autres

Dune maniegravere geacuteneacuterale cette fois compte tenu de laspect eacutepisodique de ce type de besoin

nous le preacuteciserons chaque fois que ce sera neacutecessaire

4 Efficaciteacute des opeacuterations sur des conteneurs Pour juger de lefficaciteacute dune fonction membre dun conteneur ou dun algorithme appliqueacute

agrave un conteneur on choisit geacuteneacuteralement la notation dite de Landau (O()) qui se deacutefinit

ainsi

Le temps t dune opeacuteration est dit O(x) sil existe une constante k telle que dans tous les cas

on ait t lt= kx

Comme on peut sy attendre le nombre N deacuteleacutements dun conteneur (ou dune seacutequence de

conteneur) pourra intervenir Cest ainsi quon rencontrera typiquement

Degraves qursquoune classe est destineacutee agrave donner naissance agrave des objets susceptibles drsquoecirctre introduits dans des conteneurs il nrsquoest plus possible drsquoen deacutesactiver la recopie etou lrsquoaffectation

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

404

bull des opeacuterations en O(1) crsquoest-agrave-dire pour lesquelles le temps est constant (plutocirct borneacute par

une constante indeacutependante du nombre deacuteleacutements de la seacutequence) on verra que ce sera le

cas des insertions dans une liste ou des insertions en fin de vecteur

bull des opeacuterations en O(N) crsquoest-agrave-dire pour lesquelles le temps est proportionnel au nombre

deacuteleacutements de la seacutequence on verra que ce sera le cas des insertions en un point quelconque

dun vecteur

bull des opeacuterations en O(LogN)

Dune maniegravere geacuteneacuterale on ne perdra pas de vue quune telle information na quun caractegravere

relativement indicatif pour ecirctre preacutecis il faudrait indiquer sil sagit dun maximum ou dune

moyenne et mentionner la nature des opeacuterations concerneacutees Cest dailleurs ce que nous

ferons dans lannexe C deacutecrivant lensemble des algorithmes standard

5 Fonctions preacutedicats et classes fonctions

51 Fonction unaireBeaucoup dalgorithmes et quelques fonctions membres permettent dappliquer une fonction

donneacutee aux diffeacuterents eacuteleacutements dune seacutequence (deacutefinie par un intervalle diteacuterateur) Cette

fonction est alors passeacutee simplement en argument de lalgorithme comme dans

for_each(it1 it2 f) applique la fonction f agrave chacun des eacuteleacutements de la seacutequence [it1 it2)

Bien entendu la fonction f doit posseacuteder un argument du type des eacuteleacutements correspondants

(dans le cas contraire on obtiendrait une erreur de compilation) Il nest pas interdit quune

telle fonction possegravede une valeur de retour mais quoi quil en soit elle ne sera pas utiliseacutee

Voici un exemple montrant comment utiliser cette technique pour afficher tous les eacuteleacutements

dune liste

main() listltfloatgt lf void affiche (float) for_each (lfbegin() lfend() affiche) cout ltlt n void affiche (float x) cout ltlt x ltlt

Bien entendu on obtiendrait le mecircme reacutesultat en proceacutedant simplement ainsi

main() listltfloatgt lf void affiche (listltfloatgt) lfaffiche()

5 - Fonctions preacutedicats et classes fonctions405

void affiche (listltfloatgt l) listltfloatgtiterator il

for (il=lbegin() il=lend() il++) cout ltlt (il) ltlt cout ltlt n

52 Preacutedicats On parle de preacutedicat pour caracteacuteriser une fonction qui renvoie une valeur de type bool

Compte tenu des conversions implicites qui sont mises en place automatiquement cette

valeur peut eacuteventuellement ecirctre entiegravere sachant qualors 0 correspondra agrave false et que tout

autre valeur correspondra agrave true

On rencontrera des preacutedicats unaires crsquoest-agrave-dire disposant dun seul argument et des preacutedi-

cats binaires crsquoest-agrave-dire disposant de deux arguments de mecircme type

Lagrave encore certains algorithmes et certaines fonctions membres neacutecessiteront quon leur four-

nisse un preacutedicat en argument Par exemple lalgorithme find_if permet de trouver le premier

eacuteleacutement dune seacutequence veacuterifiant un preacutedicat passeacute en argument

main()

listltintgt l listltintgtiterator il

bool impair (int) il = find_if (lbegin() lend() impair) il deacutesigne le premier

eacuteleacutement de l veacuterifiant le preacutedicat impair

bool impair (int n) deacutefinition du preacutedicat unaire impair return n2

53 Classes et objets fonctions

531 Utilisation dobjet fonction comme fonction de rappel

Nous venons de voir que certains algorithmes ou fonctions membres neacutecessitaient un preacutedi-

cat en argument Dune maniegravere geacuteneacuterale ils peuvent neacutecessiter une fonction quelconque et

lon parle souvent de fonction de rappel pour eacutevoquer un tel meacutecanisme dans lequel une

fonction est ameneacutee agrave appeler une autre fonction quon lui a transmise en argument

La plupart du temps cette fonction de rappel est preacutevue dans la deacutefinition du patron corres-

pondant non pas sous forme dune fonction mais bel et bien sous forme dun objet de type

quelconque Les classes et les objets fonction ont eacuteteacute preacutesenteacutes au paragraphe 6 du chapitre 9

et nous en avions alors donneacute un exemple simple dutilisation En voici un autre qui montre

linteacuterecirct quils preacutesentent dans le cas de patrons de fonctions Ici le patron de fonction essai

deacutefinit une famille de fonctions recevant en argument une fonction de rappel sous forme dun

objet fonction f de type quelconque Les exemples dappels de la fonction essai montrent

quon peut lui fournir indiffeacuteremment comme fonction de rappel soit une fonction usuelle

soit un objet fonction

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

406

include ltiostreamgt

using namespace std

class cl_fonc definition dune classe fonction

int coef

public

cl_fonc(int n) coef = n

int operator () (int p) return coefp

int fct (int n) definition dune fonction usuelle

return 5n

template ltclass Tgtvoid essai (T f) deacutefinition de essai qui reccediloit en

cout ltlt f(1) ltlt f(1) ltlt n argument un objet de type quelconque

cout ltlt f(4) ltlt f(4) ltlt n et qui lutilise comme une fonction

main()

essai (fct) appel essai avec une fonction de rappel usuelle

essai (cl_fonc(3)) appel essai avec 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

Exemple dutilisation dobjets fonctions

On voit quun algorithme attendant un objet fonction peut recevoir une fonction usuelle En

revanche on notera que la reacuteciproque est fausse Cest pourquoi tous les algorithmes ont

preacutevu leurs fonctions de rappel sous forme dobjets fonction

532 Classes fonction preacutedeacutefinies

Dans ltfunctionalgt il existe un certain nombre de patrons de classes fonction correspondant

agrave des preacutedicats binaires de comparaison de deux eacuteleacutements de mecircme type Par exemple

lessltintgt instancie une fonction patron correspondant agrave la comparaison par lt (less) de deux

eacuteleacutements de type int Comme on peut sy attendre lessltpointgt instanciera une fonction

patron correspondant agrave la comparaison de deux objets de type point par lopeacuterateur lt qui

devra alors ecirctre convenablement deacutefini dans la classe point

Voici les diffeacuterents noms de patrons existants et les opeacuterateurs correspondants equal_to

(==) not_equal_to (=) greater (gt) less (lt) greater_equal (gt=) less_equal (lt=)

6 - Conteneurs algorithmes et relation dordre407

Toutes ces classes fonction disposent dun constructeur sans argument ce qui leur permet

decirctre citeacutees comme fonction de rappel Dautre part elles seront eacutegalement utiliseacutees comme

argument de type dans la construction de certaines classes

Remarque

Il existe eacutegalement des classes fonction correspondant aux opeacuterations binaires usuelles

par exemple plusltintgt pour la somme de deux int Voici les diffeacuterents noms des autres

patrons existants et les opeacuterateurs correspondants modulus () minus (-) times ()

divides () On trouve eacutegalement les preacutedicats correspondant aux opeacuterations logiques

logical_and (ampamp) logical_or (||) logical_not () Ces classes sont cependant dun usage

moins freacutequent que celles qui ont eacuteteacute eacutetudieacutees preacuteceacutedemment

6 Conteneurs algorithmes et relation dordre

61 Introduction Un certain nombre de situations neacutecessiteront la connaissance dune relation permettant

dordonner les diffeacuterents eacuteleacutements dun conteneur Citons-en quelques exemples

bull pour des questions defficaciteacute comme il a deacutejagrave eacuteteacute dit les eacuteleacutements dun conteneur associa-

tif seront ordonneacutes en permanence

bull un conteneur list disposera dune fonction membre sort permettant de reacutearranger ses eacuteleacute-

ments suivant un certain ordre

bull il existe beaucoup dalgorithmes de tri qui eux aussi reacuteorganisent les eacuteleacutements dun conte-

neur suivant un certain ordre

Bien entendu tant que les eacuteleacutements du conteneur concerneacute sont dun type scalaire ou string

pour lequel il existe une relation naturelle (lt) permettant dordonner les eacuteleacutements on peut se

permettre dappliquer ces diffeacuterentes opeacuterations dordonnancement sans trop se poser de

questions

En revanche si les eacuteleacutements concerneacutes sont dun type classe qui ne dispose pas par deacutefaut de

lopeacuterateur lt il faudra surdeacutefinir convenablement cet opeacuterateur Dans ce cas et comme on

peut sy attendre cet opeacuterateur devra respecter un certain nombre de proprieacuteteacutes neacutecessaires

au bon fonctionnement de la fonction ou de lalgorithme utiliseacute

Par ailleurs et quel que soit le type des eacuteleacutements (classe type de base) on peut choisir

dutiliser une relation autre que celle qui correspond agrave lopeacuterateur lt (par deacutefaut ou surdeacutefini)

bull soit en choisissant un autre opeacuterateur (par deacutefaut ou surdeacutefini)

bull soit en fournissant explicitement une fonction de comparaison de deux eacuteleacutements

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

408

Lagrave encore cet opeacuterateur ou cette fonction devra respecter les proprieacuteteacutes eacutevoqueacutees que nous

allons examiner maintenant

62 Proprieacuteteacutes agrave respecter Pour simplifier les notations nous noterons toujours R la relation binaire en question quelle

soit deacutefinie par un opeacuterateur ou par une fonction La norme preacutecise que R doit ecirctre une rela-

tion drsquoordre faible strict laquelle se deacutefinit ainsi

bull forall a (a R a)

bull R est transitive crsquoest-agrave-dire que forall a b c tels que a R b et b R c alors a R c

bull forall a b c tels que (a R b) et (b R c) alors (a R c)

On notera que leacutegaliteacute na pas besoin decirctre deacutefinie pour que R respecte les proprieacuteteacutes requi-

ses

Bien entendu on peut sans problegraveme utiliser les opeacuterateurs lt et gt pour les types numeacuteriques

on prendra garde cependant agrave ne pas utiliser lt= ou gt= qui ne reacutepondent pas agrave la deacutefinition

On peut montrer que ces contraintes deacutefinissent une relation dordre total non pas sur

lensemble des eacuteleacutements concerneacutes mais simplement sur les classes deacutequivalence induites

par la relation R une classe deacutequivalence eacutetant telle que a et b appartiennent agrave la mecircme

classe si lon a agrave la fois (a R b) et (b R a) A titre dexemple consideacuterons des eacuteleacutements dun

type classe (point) posseacutedant deux coordonneacutees x et y supposons quon y deacutefinisse la rela-

tion R par

p1(x1 y1) R p2(x2 y2) si x1 lt x2

On peut montrer que R satisfait les contraintes requises et que les classes deacutequivalence sont

formeacutees des points ayant la mecircme abscisse

Dans ces conditions si lon utilise R pour trier un conteneur de points ceux-ci apparaicirctront

ordonneacutes suivant la premiegravere coordonneacutee Cela nest pas tregraves grave car dans une telle opeacutera-

tion de tri tous les points seront conserveacutes En revanche si lon utilise cette mecircme relation R

pour ordonner intrinsegravequement un conteneur associatif de type map (dont on verra que deux

eacuteleacutements ne peuvent avoir de cleacutes eacutequivalentes) deux points de mecircme abscisse apparaicirctront

comme identiques et un seul sera conserveacute dans le conteneur

Ainsi lorsquon sera ameneacute agrave deacutefinir sa propre relation dordre il faudra bien ecirctre en mesure

den preacutevoir correctement les conseacutequences au niveau des opeacuterations qui en deacutependront

Notamment dans certains cas il faudra savoir si leacutegaliteacute de deux eacuteleacutements se fonde sur

lopeacuterateur == (surdeacutefini ou non) ou sur les classes deacutequivalence induites par une relation

dordre (par deacutefaut il sagira alors de lt surdeacutefini ou non) Par exemple lalgorithme find se

fonde sur == tandis que la fonction membre find dun conteneur associatif se fonde sur

lordre intrinsegraveque du conteneur Bien entendu aucune diffeacuterence napparaicirctra avec des eacuteleacute-

ments de type numeacuterique ou string tant quon se limitera agrave lordre induit par lt puisqualors

les classes deacutequivalence en question seront reacuteduites agrave un seul eacuteleacutement

Bien entendu nous attirerons agrave nouveau votre attention sur ce point au moment voulu

7 - Les geacuteneacuterateurs dopeacuterateurs409

7 Les geacuteneacuterateurs dopeacuterateurs NB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Le meacutecanisme de surdeacutefinition dopeacuterateurs utiliseacute par C++ fait que lon peut theacuteoriquement

deacutefinir pour une classe donneacutee agrave la fois lopeacuterateur == et lopeacuterateur = de maniegravere totale-

ment indeacutependante voir incoheacuterente Il en va de mecircme pour les opeacuterateurs lt lt= gt et gt=

Mais la bibliothegraveque standard dispose de patrons de fonctions permettant de deacutefinir

bull lopeacuterateur = agrave partir de lopeacuterateur ==

bull les opeacuterateurs gt lt= et gt= agrave partir de lopeacuterateur lt

Comme on peut sy attendre si a et b sont dun type classe pour laquelle on a deacutefini == =

sera deacutefini par

a = b si (a == b)

De la mecircme maniegravere les opeacuterateurs lt= gt et gt= peuvent ecirctre deacuteduits de lt par les deacutefinitions

suivantes

a gt b si b lt a

a lt= b si (a gt b)

a gt= b si (a lt b)

Dans ces conditions on voit quil suffit de munir une classe des opeacuterateurs == et lt pour

quelle dispose automatiquement des autres

Bien entendu il reste toujours possible de donner sa propre deacutefinition de lun quelconque de

ces quatre opeacuterateurs Elle sera alors utiliseacutee en tant que speacutecialisation dune fonction patron

Il est tregraves important de noter quil nexiste aucun lien entre la deacutefinition automatique de lt= et

celle de == Ainsi rien nimpose hormis le bon sens que a==b implique alt=b comme le

montre ce petit exemple deacutecole dans lequel nous deacutefinissons lopeacuterateur lt dune maniegravere

artificielle et incoheacuterente avec la deacutefinition de ==

include ltiostreamgtinclude ltutilitygt pour les geacuteneacuterateurs dopeacuterateurs using namespace std class point int x y public point(int abs=0 int ord=0) x=abs y=ord friend int operator== (point point) friend int operatorlt (point point)

int operator== (point a point b) return ( (ax == bx) ampamp (ay == by) )

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

410

int operatorlt(point a point b) return ( (ax lt bx) ampamp (ay lt by) ) main() point a(1 2) b(3 1) cout ltlt a == b ltlt (a==b) ltlt a = b ltlt (a=b) ltlt n cout ltlt a lt b ltlt (altb) ltlt a lt= b ltlt (alt=b) ltlt n char c cin gtgt c

a == b 0 a = b 1a lt b 0 a lt= b 1

Exemple de geacuteneacuteration non satisfaisante des opeacuterateurs = gt lt= et gt=

Remarque

Le manque de coheacuterence entre les deacutefinitions des opeacuterateurs == et lt est ici sans conseacute-

quence En revanche nous avons vu que lopeacuterateur lt pouvait intervenir par exemple

pour ordonner un conteneur associatif ou pour trier un conteneur de type list lorsquon uti-

lise la fonction membre sort Dans ce cas sa deacutefinition devra respecter les contraintes

eacutevoqueacutees au paragraphe 6

19

Les conteneurs seacutequentiels

Nous avons vu dans le preacuteceacutedent chapitre que les conteneurs pouvaient se classer en deux

cateacutegories tregraves diffeacuterentes les conteneurs seacutequentiels et les conteneurs associatifs les pre-

miers sont ordonneacutes suivant un ordre imposeacute explicitement par le programme lui-mecircme tan-

dis que les seconds le sont de maniegravere intrinsegraveque Les trois conteneurs seacutequentiels

principaux sont les classes vector list et deque La classe vector geacuteneacuteralise la notion de

tableau tandis que la classe list correspond agrave la notion de liste doublement chaicircneacutee Comme

on peut sy attendre vector disposera dun iteacuterateur agrave accegraves direct tandis que list ne disposera

que dun iteacuterateur bidirectionnel Quant agrave la classe deque on verra quil sagit dune classe

intermeacutediaire entre les deux preacuteceacutedentes dont la preacutesence ne se justifie que pour des ques-

tions defficaciteacute

Nous commencerons par eacutetudier les fonctionnaliteacutes communes agrave ces trois conteneurs cons-

truction affectation globale initialisation par un autre conteneur insertion et suppression

deacuteleacutements comparaisons Puis nous examinerons en deacutetail les fonctionnaliteacutes speacutecifiques agrave

chacun des conteneurs vector deque et list Nous terminerons par une bregraveve description des

trois adaptateurs de conteneurs que sont stack queue et priority_queue

Les conteneurs seacutequentielsCHAPITRE 19

412

1 Fonctionnaliteacutes communes aux conteneurs vector list et deque

Comme tous les conteneurs vector list et deque sont de taille dynamique crsquoest-agrave-dire sus-

ceptibles de varier au fil de lexeacutecution Malgreacute leur diffeacuterence de nature ces trois conteneurs

possegravedent des fonctionnaliteacutes communes que nous allons eacutetudier ici Elles concernent

bull leur construction

bull laffectation globale

bull leur comparaison

bull linsertion de nouveaux eacuteleacutements ou la suppression deacuteleacutements existants

11 Construction Les trois classes vector list et deque disposent de diffeacuterents constructeurs conteneur vide

avec nombre deacuteleacutements donneacute agrave partir dun autre conteneur

111 Construction dun conteneur vide

Lappel dun constructeur sans argument construit un conteneur vide crsquoest-agrave-dire ne compor-

tant aucun eacuteleacutement

listltfloatgt lf la liste lf est construite vide lfsize() vaudra 0 et lfbegin() == lfend( )

112 Construction avec un nombre donneacute deacuteleacutements

De faccedilon comparable agrave ce qui se passe avec la deacuteclaration dun tableau classique lappel dun

constructeur avec un seul argument entier n construit un conteneur comprenant n eacuteleacutements

En ce qui concerne linitialisation de ces eacuteleacutements elle est reacutegie par les regravegles habituelles

dans le cas deacuteleacutements de type standard (0 pour la classe statique indeacutetermineacute sinon)

Lorsquil sagit deacuteleacutements de type classe ils sont tout naturellement initialiseacutes par appel dun

constructeur sans argument

listltfloatgt lf(5) lf est construite avec 5 eacuteleacutements de type float lfsize() vaut 5 vectorltpointgt vp(5) vp est construit avec 5 eacuteleacutements de type point initialiseacutes par le constructeur sans argument

113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur

Le premier argument du constructeur fournit le nombre deacuteleacutements le second argument en

fournit la valeur

listltintgt li(5 999) li est construite avec 5 eacuteleacutements de type int ayant tous la valeur 999 point a(3 8) on suppose que point est une classe

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque413

listltpointgt lp (10 a) lp est construite avec 10 points ayant tous la valeur de a il y a appel du constructeur par recopie (eacuteventuellement par deacutefaut) de point

114 Construction agrave partir dune seacutequenceOn peut construire un conteneur agrave partir dune seacutequence deacuteleacutements de mecircme type Dans ce

cas on fournit simplement au constructeur deux arguments repreacutesentant les bornes de linter-

valle correspondant Voici des exemples utilisant des seacutequences de conteneur de type

listltpointgt

listltpointgt lp(6) liste de 6 points vectorltpointgt vp (lpbegin() lpend()) construit un vecteur de points en recopiant les points de la liste lp le constructeur par recopie de point sera appeleacute pour chacun des points listltpointgt lpi (lprbegin() lprend()) construit une liste obtenue en inversant lordre des points de la liste lp

Ici les seacutequences correspondaient agrave lensemble du conteneur il sagit de la situation la plus

usuelle mais rien nempecirccherait dutiliser des intervalles diteacuterateurs quelconques pour peu

que la seconde borne soit accessible agrave partir de la premiegravere

Voici un autre exemple de construction de conteneurs agrave partir de seacutequences de valeurs issues

dun tableau classique utilisant des intervalles deacutefinis par des pointeurs

int t[6] = 2 9 1 8 2 11 vectorltintgt vi(t t+6) construit un vecteur formeacute des 6 valeurs de t vectorltintgt vi2(t+1 t+5) construit un vecteur formeacute des valeurs t[1] agrave t[5]

Dans le premier cas si lon souhaite une formulation indeacutependante de la taille effective de t

on pourra proceacuteder ainsi

int t[] = nombre quelconque de valeurs qui seront vectorltintgt vi(t t + sizeof(t)sizeof(int)) recopieacutees dans vi

115 Construction agrave partir dun autre conteneur de mecircme typeIl sagit dun classique constructeur par recopie qui comme on peut sy attendre appelle le

constructeur de recopie des eacuteleacutements concerneacutes lorsquil sagit dobjets

vectorltintgt vi1 vecteur dentiers vectorltintgt vi2(vi1) ou encore vectorltintgt vi2 = vi1

12 Modifications globales Les trois classes vector deque et list deacutefinissent convenablement lopeacuterateur daffectation de

plus elles proposent une fonction membre assign comportant plusieurs deacutefinitions ainsi

quune fonction clear

Les conteneurs seacutequentielsCHAPITRE 19

414

121 Opeacuterateur daffectationOn peut affecter un conteneur dun type donneacute agrave un autre conteneur de mecircme type crsquoest-agrave-dire

ayant le mecircme nom de patron et le mecircme type deacuteleacutements Bien entendu il nest nullement neacuteces-

saire que le nombre deacuteleacutements de chacun des conteneurs soit le mecircme Voici quelques exemples

vectorltintgt vi1 () vi2 () vectorltfloatgt vf () vi1 = vi2 correct quels que soient le nombre deacuteleacutements de vi1 et de vi2 le contenu de vi1 est remplaceacute par celui de vi2 qui reste inchangeacute vf = vi1 incorrect (refuseacute en compilation) les eacuteleacutements de vf et de vi1 ne sont pas du mecircme type

Voici un autre exemple avec un conteneur dont les eacuteleacutements sont des objets

vectorltpointgt vp1 () vp2 () vp1 = vp2

Dans ce cas comme nous lavons deacutejagrave fait remarquer au paragraphe 31 du chapitre 18 il

existe deux faccedilons de parvenir au reacutesultat escompteacute suivant les tailles relatives des vecteurs

vp1 et vp2 agrave savoir soit lutilisation du constructeur par recopie de la classe point soit lutili-

sation de lopeacuterateur daffectation de la classe point

122 La fonction membre assignAlors que laffectation nest possible quentre conteneurs de mecircme type la fonction assign

permet daffecter agrave un conteneur existant les eacuteleacutements dune seacutequence deacutefinie par un inter-

valle [debut fin) agrave condition que les eacuteleacutements deacutesigneacutes soient du type voulu (et pas seule-

ment dun type compatible par affectation)

assign (deacutebut fin) fin doit ecirctre accessible depuis deacutebut

Il existe eacutegalement une autre version permettant daffecter agrave un conteneur un nombre donneacute

deacuteleacutements ayant une valeur imposeacutee

assign (nb_fois valeur)

Dans les deux cas les eacuteleacutements existants seront remplaceacutes par les eacuteleacutements voulus comme

sil y avait eu affectation

point a () listltpointgt lp () vectorltpointgt vp () lpassign (vpbegin() vpend()) maintenant lpsize() = vpsize() vpassign (10 a) maintenant vpsize()=10

char t[] = hello listltchargt lc(7 x) lc contient x x x x x x x

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque415

lcassign(t t+4) lc contient maintenant h e l l o lcassign(3 z) lc contient maintenant z z z

123 La fonction clearLa fonction clear() vide le conteneur de son contenu

vectorltpointgt vp(10) vpsize() = 0 vpclear () appel du destructeur de chacun des points de vp maintenant vpsize() = 0

124 La fonction swapLa fonction membre swap (conteneur) permet deacutechanger le contenu de deux conteneurs de

mecircme type Par exemple

vectorltintgt v1 v2 v1swap(v2) ou v2swap(v1)

Laffectation preacuteceacutedente sera plus efficace que la deacutemarche traditionnelle

vectorltintgt v3=v1 v1=v2 v2=v3

Remarque

Comme on peut le constater les possibiliteacutes de modifications globales dun conteneur

sont similaires agrave celles qui sont offertes au moment de la construction la seule possibiliteacute

absente eacutetant laffectation dun nombre deacuteleacutements donneacutes eacuteventuellement non initialiseacutes

13 Comparaison de conteneurs Les trois conteneurs vector deque et list disposent des opeacuterateurs == et lt par le biais des

geacuteneacuterations automatiques dopeacuterateurs ils disposent donc eacutegalement de = lt= gt et gt= Le

rocircle de == correspond agrave ce quon attend dun tel opeacuterateur tandis que celui de lt sappuie sur

ce que lon nomme parfois une comparaison lexicographique analogue agrave celle qui permet de

classer des mots par ordre alphabeacutetique

131 Lopeacuterateur ==Il ne preacutesente pas de difficulteacutes particuliegraveres Si c1 et c2 sont deux conteneurs de mecircme type

leur comparaison par == sera vraie sils ont la mecircme taille et si les eacuteleacutements de mecircme rang

sont eacutegaux

On notera cependant que si les eacuteleacutements concerneacutes sont de type classe il sera neacutecessaire que

cette derniegravere dispose elle-mecircme de lopeacuterateur ==

Les conteneurs seacutequentielsCHAPITRE 19

416

132 Lopeacuterateur ltIl effectue une comparaison lexicographique des eacuteleacutements des deux conteneurs Pour ce faire

il compare les eacuteleacutements de mecircme rang par lopeacuterateur lt en commenccedilant par les premiers

sils existent Il sinterrompt degraves que lune des conditions suivantes est reacutealiseacutee

bull fin de lun des conteneurs atteinte le reacutesultat de la comparaison est vrai

bull comparaison de deux eacuteleacutements fausse le reacutesultat de la comparaison des conteneurs est alors

faux

Si un seul des deux conteneurs est vide il apparaicirct comme lt agrave lautre Si les deux conteneurs

sont vides aucun nest infeacuterieur agrave lautre (ils sont eacutegaux)

On notera lagrave encore que si les eacuteleacutements concerneacutes sont de type classe il sera neacutecessaire que

cette derniegravere dispose elle-mecircme dun opeacuterateur lt approprieacute

133 ExemplesAvec ces deacuteclarations

int t1[] = 2 5 2 4 8 int t2[] = 2 5 2 8 vectorltintgt v1 (t1 t1+5) v1 contient 2 5 2 4 8 vectorltintgt v2 (t2 t2+4) v2 contient 2 5 2 8 vectorltintgt v3 (t2 t2+3) v3 contient 2 5 2 vectorltintgt v4 (v3) v4 contient 2 5 2 vectorltintgt v5 v5 est vide

Voici quelques comparaisons possibles et la valeur correspondante

v2 lt v1 faux v3 lt v2 vrai v3 lt v4 faux v4 lt v3 faux v3 == v4 vrai v4 gt v5 vrai v5 gt v5 faux v5 lt v5 faux

14 Insertion ou suppression deacuteleacutements Chacun des trois conteneurs vector deque et list dispose naturellement de possibiliteacutes daccegraves

agrave un eacuteleacutement existant soit pour en connaicirctre la valeur soit pour la modifier Comme ces pos-

sibiliteacutes varient quelque peu dun conteneur agrave lautre elles seront deacutecrites dans les paragra-

phes ulteacuterieurs Par ailleurs ces trois conteneurs (comme tous les conteneurs) permettent des

modifications dynamiques fondeacutees sur des insertions de nouveaux eacuteleacutements ou des suppres-

sions deacuteleacutements existants On notera que de telles possibiliteacutes nexistaient pas dans le cas

dun tableau classique alors quelles existent pour le conteneur vector mecircme si manifeste-

ment elles sont davantage utiliseacutees dans le cas dune liste

Rappelons toutefois que bien quen theacuteorie les trois conteneurs offrent les mecircmes possibili-

teacutes dinsertions et de suppressions leur efficaciteacute sera diffeacuterente dun conteneur agrave un autre

Nous verrons dans les paragraphes suivants que dans une liste elles seront toujours en O(1)

tandis que dans les conteneurs vector et deque elles seront en O(N) excepteacute lorsquelles

auront lieu en fin de vector ou en deacutebut ou en fin de deque ougrave elles se feront en O(1) dans

ces derniers cas on verra dailleurs quil existe des fonctions membres speacutecialiseacutees

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque417

141 InsertionLa fonction insert permet dinseacuterer

bull une valeur avant une position donneacutee

insert (position valeur) insegravere valeur avant leacuteleacutement pointeacute par position

fournit un iteacuterateur sur leacuteleacutement inseacutereacute

bull n fois une valeur donneacutee avant une position donneacutee

insert (position nb_fois valeur) insegravere nb_fois valeur avant leacuteleacutement

pointeacute par position

fournit un iteacuterateur sur leacuteleacutement inseacutereacute

bull les eacuteleacutements dun intervalle agrave partir dune position donneacutee

insert (debut fin position) insegravere les valeurs de lintervalle [debut fin)

avant leacuteleacutement pointeacute par position

En voici quelques exemples

listltdoublegt ld listltdoublegtiterator il on suppose que il pointe correctement dans la liste ld ldinsert(il 25) insegravere 25 dans ld avant leacuteleacutement pointeacute par il ldinsert(ldbegin() 67) insegravere 67 au deacutebut de ld ldinsert (ldend() 32) insegravere 32 en fin de ld ldinsert(il 10 -1) insegravere 10 fois -1 avant leacuteleacutement pointeacute par il vectorltdoublegt vd () ldinsert(ldbegin() vdbegin() vdend()) insegravere tous les eacuteleacutements de vd en deacutebut de la liste ld

142 SuppressionLa fonction erase permet de supprimer

bull un eacuteleacutement de position donneacutee

erase (position) supprime leacuteleacutement deacutesigneacute par position - fournit un iteacuterateur

sur leacuteleacutement suivant ou sur la fin de la seacutequence

bull les eacuteleacutements dun intervalle

erase (deacutebut fin) supprime les valeurs de lintervalle [deacutebut fin) - fournit un

iteacuterateur sur leacuteleacutement suivant ou sur la fin de la seacutequence

En voici quelques exemples

listltdoublegt ld listltdoublegtiterator il1 il2

on suppose que il1 et il2 pointent correctement dans la liste ld et que il2 est accessible agrave partir de il1 lderase(il1 il2) supprime les eacuteleacutements de lintervalle [il1 il2) lderase(ldbegin()) supprime leacuteleacutement de deacutebut de ld

Les conteneurs seacutequentielsCHAPITRE 19

418

Remarques

1 Les deux fonctions erase renvoient la valeur de liteacuterateur suivant le dernier eacuteleacutement sup-

primeacute sil en existe un ou sinon la valeur end() Voyez par exemple la construction sui-

vante dans laquelle il est un iteacuterateur de valeur convenable sur une liste dentiers ld

while (il = lderase(il) = ldend())

Elle est eacutequivalente agrave

erase (il ldend())

2 Les conteneurs seacutequentiels ne sont pas adapteacutes agrave la recherche de valeurs donneacutees ou agrave

leur suppression Il nexistera dailleurs aucune fonction membre agrave cet effet contraire-

ment agrave ce qui se produira avec les conteneurs associatifs Il nen reste pas moins quune

telle recherche peut toujours se faire agrave laide dun algorithme standard tel que find ou

find_if mais au prix dune efficaciteacute meacutediocre (en O(N))

143 Cas des insertionssuppressions en fin pop_back et push_backSi lon sen tient aux possibiliteacutes geacuteneacuterales preacutesenteacutees ci-dessus on constate que sil est possi-

ble de supprimer le premier eacuteleacutement dun conteneur en appliquant erase agrave la position begin()

il nest pas possible de supprimer le dernier eacuteleacutement dun conteneur en appliquant erase agrave la

position end() Un tel reacutesultat peut toutefois sobtenir en appliquant erase agrave la position rbe-

gin() Quoi quil en soit comme lefficaciteacute de cette suppression est en O(1) pour les trois

conteneurs il existe une fonction membre speacutecialiseacutee pop_back() qui reacutealise cette opeacuteration

si c est un conteneur cpop_back() est eacutequivalente agrave cerase(crbegin())

Dune maniegravere semblable et bien que ce ne soit guegravere indispensable il existe une fonction

speacutecialiseacutee dinsertion en fin push_back Si c est un conteneur cpush_back(valeur) est eacutequi-

valent agrave cinsert (cend() valeur)

2 Le conteneur vector Il reprend la notion usuelle de tableau en autorisant un accegraves direct agrave un eacuteleacutement quelconque

avec une efficaciteacute en O(1) crsquoest-agrave-dire indeacutependante du nombre de ses eacuteleacutements Cet accegraves

peut se faire soit par le biais dun iteacuterateur agrave accegraves direct soit de faccedilon plus classique par

lopeacuterateur [ ] ou par la fonction membre at Mais il offre un cadre plus geacuteneacuteral que le tableau

puisque

bull la taille crsquoest-agrave-dire le nombre deacuteleacutements peut varier au fil de lexeacutecution (comme celle de

tous les conteneurs)

bull on peut effectuer toutes les opeacuterations de construction daffectation et de comparaisons deacute-

crites aux paragraphes 11 12 et 13

bull on dispose des possibiliteacutes geacuteneacuterales dinsertion ou de suppressions deacutecrites au paragraphe

14 (avec cependant une efficaciteacute en O(N) dans le cas geacuteneacuteral)

2 - Le conteneur vector419

Ici nous nous contenterons dexaminer les fonctionnaliteacutes speacutecifiques de la classe vector qui

viennent donc en compleacutement de celles qui sont examineacutees au paragraphe 1

21 Accegraves aux eacuteleacutements existants On accegravede aux diffeacuterents eacuteleacutements dun vecteur aussi bien pour en connaicirctre la valeur que

pour la modifier de diffeacuterentes maniegraveres par iteacuterateur (iterator ou reverse_iterator) ou par

indice (opeacuterateur [ ] ou fonction membre at) En outre laccegraves au dernier eacuteleacutement peut se

faire par une fonction membre approprieacutee back Dans tous les cas lefficaciteacute de cet accegraves est

en O(1) ce qui constitue manifestement le point fort de ce type de conteneur

211 Accegraves par iteacuterateur

Les iteacuterateurs iterator et reverse_iterator dun conteneur de type vector sont agrave accegraves direct

Si par exemple iv est une variable de type vectorltintgtiterator une expression telle que

iv+i a alors un sens elle deacutesigne leacuteleacutement du vecteur v situeacute i eacuteleacutements plus loin que celui

qui est deacutesigneacute par iv agrave condition que la valeur de i soit compatible avec le nombre deacuteleacute-

ments de v

Liteacuterateur iv peut bien sucircr comme tout iteacuterateur bidirectionnel ecirctre increacutementeacute ou deacutecreacute-

menteacute par ++ ou -- Mais comme il est agrave accegraves direct il peut eacutegalement ecirctre increacutementeacute ou

deacutecreacutementeacute dune quantiteacute quelconque comme dans

iv += n iv -= p

Voici un petit exemple deacutecole

vectorltintgt v(10) vecteur de 10 eacuteleacutements vectorltintgtiterator iv = vbegin() iv pointe sur le premier eacuteleacutem de v iv = vibegin() iv=0 place 0 dans le premier eacuteleacutement de vi iv+=3 iv=30 place 30 dans le quatriegraveme eacuteleacutement de vi iv = viend()-2 iv=70 place 70 dans le huitiegraveme eacuteleacutement de vi

212 Accegraves par indice

Lopeacuterateur [ ] est en fait utilisable de faccedilon naturelle Si v est de type vector lexpression

v[i] est une reacutefeacuterence agrave leacuteleacutement de rang i de sorte que les deux instructions suivantes sont

eacutequivalentes

v[i] = (vbegin()+i) =

Mais il existe eacutegalement une fonction membre at telle que vat(i) soit eacutequivalente agrave v[i] Sa

seule raison decirctre est de geacuteneacuterer une exception out_of_range en cas dindice incorrect ce que

lopeacuterateur [ ] ne fait theacuteoriquement pas Bien entendu en contrepartie at est leacutegegraverement

moins rapide que lopeacuterateur [ ]

Lexemple deacutecole preacuteceacutedent peut manifestement seacutecrire plus simplement

vi[0] = 0 ou viat(0) = 0 vi[3] = 30 ou viat(3) = 30 vi[7] = 70 ou vi[visize()-2] = 70 ou viat(7) = 70

Les conteneurs seacutequentielsCHAPITRE 19

420

Il est geacuteneacuteralement preacutefeacuterable dutiliser les indices plutocirct que les iteacuterateurs dont le principal

avantage reacuteside dans lhomogeacuteneacuteiumlsation de notation avec les autres conteneurs

213 Cas de laccegraves au dernier eacuteleacutement

Comme le vecteur est particuliegraverement adapteacute aux insertions ou aux suppressions en fin il

existe une fonction membre back qui permet dacceacuteder directement au dernier eacuteleacutement

vectorltintgt v(10) vback() = 25 eacutequivalent quand v est de taille 10 agrave v[9] = 25 eacutequivalent dans tous les cas agrave v[vsize()-1] = 25

On notera bien que cette fonction se contente de fournir une reacutefeacuterence agrave un eacuteleacutement existant

Elle ne permet en aucun cas des insertions ou des suppressions en fin lesquelles sont eacutetu-

dieacutees ci-dessous

22 Insertions et suppressions Le conteneur vector dispose des possibiliteacutes geacuteneacuterales dinsertion et de suppression deacutecrites

au paragraphe 14 Toutefois leur efficaciteacute est meacutediocre puisquen O(N) alors que dans le

cas des listes elle sera en O(1) Cest lagrave le prix agrave payer pour disposer daccegraves aux eacuteleacutements

existant en O(1) En revanche nous avons vu que comme les deux autres conteneurs vector

disposait de fonctions membres dinsertion ou de suppression du dernier eacuteleacutement dont leffi-

caciteacute est en O(1)

bull la fonction push_back(valeur) pour inseacuterer un nouvel eacuteleacutement en fin

bull la fonction pop_back() pour supprimer le dernier eacuteleacutement

Voici un petit exemple deacutecole

vectorltintgt v(5 99) vecteur de 5 eacuteleacutements valant 99 vsize() = 5 vpush_back(10) ajoute un eacuteleacutement de valeur 10 vsize() = 6 et v[5] = 10 ici v[6] nexiste pas vpush_back(20) ajoute un eacuteleacutement de valeur 20 vsize() = 7 et v[6] = 20 vpop_back() supprime le dernier eacuteleacutement vsize() = 6

23 Gestion de lemplacement meacutemoire

231 Introduction

La norme nimpose pas explicitement la maniegravere dont une impleacutementation doit geacuterer lempla-

cement alloueacute agrave un vecteur Cependant comme nous lavons vu elle impose des contraintes

defficaciteacute agrave certaines opeacuterations ce qui comme on sen doute limite seacutevegraverement la marge

de manœuvre de limpleacutementation

Par ailleurs la classe vector dispose doutils fournissant des informations relatives agrave la ges-

tion des emplacements meacutemoire et permettant eacuteventuellement dintervenir dans leur alloca-

2 - Le conteneur vector421

tion Bien entendu le rocircle de tels outils est plus facile agrave appreacutehender lorsque lon connaicirct la

maniegravere exacte dont une impleacutementation gegravere un vecteur

Enfin la norme preacutevoit que suite agrave certaines opeacuterations des reacutefeacuterences ou des valeurs diteacute-

rateurs peuvent devenir invalides crsquoest-agrave-dire inutilisables pour acceacuteder aux eacuteleacutements corres-

pondants Lagrave encore il est plus facile de comprendre les regravegles imposeacutees si lon connaicirct la

maniegravere dont limpleacutementation gegravere les emplacements meacutemoire

Or preacuteciseacutement les impleacutementations actuelles allouent toujours lemplacement dun vecteur

en un seul bloc Mecircme si ce nest pas la seule solution envisageable cest certainement la plus

plausible

232 Invalidation diteacuterateurs ou de reacutefeacuterences

Un certain nombre dopeacuterations sur un vecteur entraicircnent linvalidation des iteacuterateurs ou des

reacutefeacuterences sur certains des eacuteleacutements de ce vecteur Les eacuteleacutements concerneacutes sont exactement

ceux auxquels on peut sattendre dans le cas ougrave lemplacement meacutemoire est geacutereacute en un seul

bloc agrave savoir

bull tous les eacuteleacutements en cas daugmentation de la taille en effet il se peut quune recopie de

lensemble du vecteur ait eacuteteacute neacutecessaire on verra toutefois quil est possible deacuteviter certai-

nes recopies en reacuteservant plus demplacements que neacutecessaire

bull tous les eacuteleacutements en cas dinsertion dun eacuteleacutement la raison en est la mecircme

bull les eacuteleacutements situeacutes agrave la suite dun eacuteleacutement supprimeacute ainsi que leacuteleacutement supprimeacute (ce qui va

de soi ) ici on voit que seuls les eacuteleacutements situeacutes agrave la suite de leacuteleacutement supprimeacute ont ducirc

ecirctre deacuteplaceacutes

233 Outils de gestion de lemplacement meacutemoire dun vecteur

La norme propose un certain nombre doutils fournissant des informations concernant

lemplacement meacutemoire alloueacute agrave un vecteur et permettant eacuteventuellement dintervenir dans

son allocation Comme on la dit en introduction le rocircle de ces outils est plus facile agrave appreacute-

hender si lon fait lhypothegravese que lemplacement dun vecteur est toujours alloueacute sous forme

dun bloc unique

On a deacutejagrave vu que la fonction size() permettait de connaicirctre le nombre deacuteleacutements dun vecteur

Mais il existe une fonction voisine capacity() qui fournit la taille potentielle du vecteur

crsquoest-agrave-dire le nombre deacuteleacutements quil pourra accepter sans avoir agrave effectuer de nouvelle

allocation Dans le cas usuel ougrave le vecteur est alloueacute sous forme dun seul bloc cette fonction

en fournit simplement la taille (luniteacute utiliseacutee restant leacuteleacutement du vecteur) Bien entendu agrave

tout instant on a toujours capacity() gt= size() La diffeacuterence capacity()-size() permet de con-

naicirctre le nombre deacuteleacutements quon pourra inseacuterer dans un vecteur sans quune reacuteallocation de

meacutemoire soit neacutecessaire

Mais une telle information ne serait guegravere inteacuteressante si lon ne pouvait pas agir sur cette

allocation Or la fonction membre reserve(taille) permet preacuteciseacutement dimposer la taille

minimale de lemplacement alloueacute agrave un vecteur agrave un moment donneacute Bien entendu lappel de

Les conteneurs seacutequentielsCHAPITRE 19

422

cette fonction peut tregraves bien amener agrave une recopie de tous les eacuteleacutements du vecteur en un autre

emplacement Cependant une fois ce travail accompli tant que la taille du vecteur ne deacutepas-

sera pas la limite alloueacutee on est assureacute de limiter au maximum les recopies deacuteleacutements en cas

dinsertion ou de suppression En particulier en cas dinsertion dun nouvel eacuteleacutement les eacuteleacute-

ments situeacutes avant ne seront pas deacuteplaceacutes et les reacutefeacuterences ou iteacuterateurs correspondants reste-

ront valides

Par ailleurs la fonction max_size() permet de connaicirctre la taille maximale quon peut allouer

au vecteur agrave un instant donneacute

Enfin il existe une fonction resize(taille) peu usiteacutee qui permet de modifier la taille effec-

tive du vecteur aussi bien dans le sens de laccroissement que dans celui de la reacuteduction

Attention il ne sagit plus ici comme avec reserve dagir sur la taille de lemplacement

alloueacute mais bel et bien sur le nombre deacuteleacutements du vecteur Si lappel de resize conduit agrave

augmenter la taille du vecteur on lui insegravere en fin de nouveaux eacuteleacutements Si en revanche

lappel conduit agrave diminuer la taille du vecteur on supprime en fin le nombre deacuteleacutements vou-

lus avec naturellement appel de leur destructeur sil sagit dobjets

24 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

vector que nous venons dexaminer dans ce paragraphe et dans le preacuteceacutedent Nous y avons

adjoint une recherche de valeur par lalgorithme find qui ne sera preacutesenteacute quulteacuterieurement

mais dont la signification est assez eacutevidente rechercher une valeur donneacutee

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

main() void affiche (vectorltintgt) int i int t[] = 1 2 3 4 5 6 7 8 9 10 vectorltintgt v1(4 99) vecteur de 4 entiers egaux agrave 99 vectorltintgt v2(7 0) vecteur de 7 entiers vectorltintgt v3(t t+6) vecteur construit a partir de t cout ltlt V1 init = affiche(v1) for (i=0 iltv2size() i++) v2[i] = ii v3 = v2 cout ltlt V2 = affiche(v2) cout ltlt V3 = affiche(v3) v1assign (t+1 t+6) cout ltlt v1 apres assign affiche(v1) cout ltlt dernier element de v1 ltlt v1back() ltlt n v1push_back(99) cout ltlt v1 apres push_back affiche(v1) v2pop_back() cout ltlt v2 apres pop_back affiche(v2) cout ltlt v1size() ltlt v1size() ltlt v1capacity() ltlt v1capacity() ltlt V1max_size() ltlt v1max_size() ltlt n

2 - Le conteneur vector423

vectorltintgtiterator iv iv = find (v1begin() v1end() 16) recherche de 16 dans v1 if (iv = v1end()) v1insert (iv v2begin() v2end()) attention ici iv nest plus utilisable cout ltlt v1 apres insert affiche(v1)

void affiche (vectorltintgt v) voir remarque ci-dessous unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

V1 init = 99 99 99 99V2 = 0 1 4 9 16 25 36V3 = 0 1 4 9 16 25 36v1 apres assign 2 3 4 5 6dernier element de v1 6v1 apres push_back 2 3 4 5 6 99v2 apres pop_back 0 1 4 9 16 25v1size() 6 v1capacity() 10 V1max_size() 1073741823v1 apres insert 2 3 4 5 6 99

Exemple dutilisation de la classe vector

Remarque

La transmission drsquoun vecteur agrave la fonction affiche se fait par valeur ce qui dans une situa-

tion reacuteelle peut srsquoaveacuterer peacutenalisant en temps drsquoexeacutecution Si lrsquoon souhaite eacuteviter cela il

reste possible drsquoutiliser une transmission par reacutefeacuterence ou drsquoutiliser des iteacuterateurs Par

exemple la fonction affiche pourrait alors ecirctre deacutefinie ainsi

void affiche (vectorltintgtiterator deb vectorltintgtiterator fin) vectorltintgtiterator it for (it=deb it = fin it++) cout ltlt it ltlt cout ltlt n

et ses diffeacuterents appels se preacutesenteraient de cette faccedilon

affiche (v1begin() v1end())

25 Cas particulier des vecteurs de booleacuteens La norme preacutevoit lexistence dune speacutecialisation du patron vector lorsque son argument est

de type bool Lobjectif principal est de permettre agrave limpleacutementation doptimiser le stockage

sur un seul bit des informations correspondant agrave chaque eacuteleacutement Les fonctionnaliteacutes de la

Les conteneurs seacutequentielsCHAPITRE 19

424

classe vectorltboolgt sont donc celles que nous avons eacutetudieacutees preacuteceacutedemment Il faut cepen-

dant lui adjoindre une fonction membre flip destineacutee agrave inverser tous les bits dun tel vecteur

Drsquoautre part il existe eacutegalement un patron de classes nommeacute bitset parameacutetreacute par un entier

qui permet de repreacutesenter des suites de bits de taille fixe et de les manipuler efficacement

comme on le fait avec les motifs binaires contenus dans des entiers Mais ce patron ne dis-

pose plus de toute les fonctionnaliteacutes des conteneurs deacutecrites ici Il sera deacutecrit au chapitre

3 Le conteneur deque

31 Preacutesentation geacuteneacuterale Le conteneur deque offre des fonctionnaliteacutes assez voisines de celles dun vecteur En parti-

culier il permet toujours laccegraves direct en O(1) agrave un eacuteleacutement quelconque tandis que les sup-

pressions et insertions en un point quelconque restent en O(N) En revanche il offre en plus

de linsertion ou suppression en fin une insertion ou suppression en deacutebut eacutegalement en

O(1) ce que ne permettait pas le vecteur En fait il ne faut pas en conclure pour autant que

deque est plus efficace que vector car cette possibiliteacute suppleacutementaire se paye agrave diffeacuterents

niveaux

bull une opeacuteration en O(1) sur un conteneur de type deque sera moins rapide que la mecircme opeacute-

ration toujours en O(1) sur un conteneur de type vector

bull certains outils de gestion de lemplacement meacutemoire dun conteneur de type vector nexis-

tent plus pour un conteneur de type deque plus preacuteciseacutement on disposera bien de size() et

de max_size() mais plus de capacity et de reserve

Lagrave encore et comme nous lavons fait remarquer au paragraphe 23 la norme nimpose pas

explicitement la maniegravere de geacuterer lemplacement meacutemoire dun conteneur de type deque

neacuteanmoins les choses deviennent beaucoup plus compreacutehensibles si lon admet que pour

satisfaire aux contraintes imposeacutees il nest pas raisonnable dallouer un deque en un seul bloc

mais plutocirct sous forme de plusieurs blocs contenant chacun un ou geacuteneacuteralement plusieurs

eacuteleacutements Dans ces conditions on voit bien que linsertion ou la suppression en deacutebut de con-

teneur ne neacutecessitera plus le deacuteplacement de lensemble des autres eacuteleacutements comme ceacutetait le

cas avec un vecteur mais seulement de quelques-uns dentre eux En revanche plus la taille

des blocs sera petite plus la rapiditeacute de laccegraves direct (bien que toujours en O(1)) diminuera

Au contraire les insertions et les suppressions bien quayant une efficaciteacute en O(N) seront

dautant plus performantes que les blocs seront petits

Si lon fait abstraction de ces diffeacuterences de performances les fonctionnaliteacutes de deque sont

celles de vector auxquelles il faut tout naturellement ajouter les fonctions speacutecialiseacutees con-

cernant le premier eacuteleacutement

bull front() pour acceacuteder au premier eacuteleacutement elle complegravete la fonction back permettant laccegraves

au dernier eacuteleacutement

3 - Le conteneur deque425

bull push_front(valeur) pour inseacuterer un nouvel eacuteleacutement en deacutebut elle complegravete la fonction

push_back()

bull pop_front() pour supprimer le premier eacuteleacutement elle complegravete la fonction pop_back()

Les regravegles dinvalidation des iteacuterateurs et des reacutefeacuterences restent exactement les mecircmes que

celles de la classe vector mecircme si dans certains cas elles peuvent apparaicirctre tregraves contrai-

gnantes Par exemple si un conteneur de type deque est impleacutementeacute sous forme de 5 blocs

diffeacuterents il est certain que linsertion en deacutebut ninvalidera que les iteacuterateurs sur des eacuteleacute-

ments du premier bloc qui sera le seul soumis agrave une recopie mais en pratique on ne pourra

jamais profiter de cette remarque dailleurs on ne connaicirctra mecircme pas la taille des blocs

Dune maniegravere geacuteneacuterale le conteneur deque est beaucoup moins utiliseacute que les conteneurs

vector et list qui possegravedent des fonctionnaliteacutes bien distinctes Il peut saveacuterer inteacuteressant dans

des situations de pile de type FIFO (First In First Out) ougrave il est neacutecessaire dintroduire des

informations agrave une extreacutemiteacute et de les recueillir agrave lautre En fait dans ce cas si lon na plus

besoin dacceacuteder directement aux diffeacuterents eacuteleacutements il est preacutefeacuterable dutiliser ladaptateur

de conteneur queue dont nous parlerons au paragraphe 5

32 Exemple Voici un petit exemple deacutecole illustrant quelques-unes des fonctionnaliteacutes du conteneur

deque

include ltiostreamgt

include ltdequegt

include ltalgorithmgt

using namespace std

main()

void affiche (dequeltchargt)

char mot[] = xyz

dequeltchargt pile(mot mot+3) affiche(pile)

pilepush_front(a) affiche(pile)

pile[2] = +

pilepush_front(b)

pilepop_back() affiche(pile)

dequeltchargtiterator ip

ip = find (pilebegin() pileend() x)

pileerase(pilebegin() ip) affiche(pile)

void affiche (dequeltchargt p) voir remarque paragraphe 24

int i

for (i=0 iltpsize() i++) cout ltlt p[i] ltlt

cout ltlt n

Les conteneurs seacutequentielsCHAPITRE 19

426

x y za x y zb a x +x +

Exemple dutilisation de la classe deque

4 Le conteneur list Le conteneur list correspond au concept de liste doublement chaicircneacutee ce qui signifie quon y

disposera dun iteacuterateur bidirectionnel permettant de parcourir la liste agrave lendroit ou agrave lenvers

Cette fois les insertions ou suppressions vont se faire avec une efficaciteacute en O(1) quelle que

soit leur position ce qui constitue latout majeur de ce conteneur par rapport aux deux classes

preacuteceacutedentes vector et deque En contrepartie le conteneur list ne dispose plus dun iteacuterateur agrave

accegraves direct Rappelons que toutes les possibiliteacutes exposeacutees dans le paragraphe 1 sappliquent

aux listes nous ne les reprendrons donc pas ici

41 Accegraves aux eacuteleacutements existants Les conteneurs vector et deque permettaient dacceacuteder aux eacuteleacutements existants de deux

maniegraveres par iteacuterateur ou par indice en fait il existait un lien entre ces deux possibiliteacutes

parce que les iteacuterateurs de ces classes eacutetaient agrave accegraves direct Le conteneur list offre toujours

les iteacuterateurs iterator et reverse_iterator mais cette fois ils sont seulement bidirectionnels

Si it deacutesigne un tel iteacuterateur on pourra toujours consulter leacuteleacutement pointeacute par la valeur de

lexpression it ou le modifier par une affectation de la forme

it =

Liteacuterateur it pourra ecirctre increacutementeacute par ++ ou -- mais il ne sera plus possible de lincreacutemen-

ter dune quantiteacute quelconque Ainsi pour acceacuteder une premiegravere fois agrave un eacuteleacutement dune liste

il aura fallu obligatoirement la parcourir depuis son deacutebut ou depuis sa fin eacuteleacutement par eacuteleacute-

ment jusquagrave leacuteleacutement concerneacute et ceci quel que soit linteacuterecirct quon peut attacher aux eacuteleacute-

ments intermeacutediaires

La classe list dispose des fonctions front() et back() avec la mecircme signification que pour la

classe deque la premiegravere est une reacutefeacuterence au premier eacuteleacutement la seconde est une reacutefeacuterence

au dernier eacuteleacutement

listltintgt l ()

if (lfront()=99) lfront=0 si le premier eacuteleacutement vaut 99

on lui donne la valeur 0

On ne confondra pas la modification de lun de ces eacuteleacutements opeacuteration qui ne modifie pas le

nombre deacuteleacutements de la liste avec linsertion en deacutebut ou en fin de liste qui modifie le nom-

bre deacuteleacutements de la liste

4 - Le conteneur list427

42 Insertions et suppressions Le conteneur list dispose des possibiliteacutes geacuteneacuterales dinsertion et de suppression procureacutees

par les fonctions insert et erase et deacutecrites au paragraphe 14 Mais cette fois leur efficaciteacute

est toujours en O(1) ce qui neacutetait pas le cas en geacuteneacuteral des conteneurs vector et deque On

dispose eacutegalement des fonctions speacutecialiseacutees dinsertion en deacutebut push_front(valeur) ou en

fin push_back(valeur) ou de suppression en deacutebut pop_front() ou en fin pop_back() rencon-

treacutees dans les classes vector et deque

En outre la classe list dispose de fonctions de suppressions conditionnelles que ne posseacute-

daient pas les conteneurs preacuteceacutedents

bull suppression de tous les eacuteleacutements ayant une valeur donneacutee

bull suppression des eacuteleacutements satisfaisant agrave une condition donneacutee

421 Suppression des eacuteleacutements de valeur donneacutee

remove(valeur) supprime tous eacuteleacutements eacutegaux agrave valeur

Comme on peut sy attendre cette fonction se fonde sur lopeacuterateur == qui doit donc ecirctre

deacutefini dans le cas ougrave les eacuteleacutements concerneacutes sont des objets

int t[] = 1 3 1 6 4 1 5 2 1 listltintgt li(t t+9) li contient 1 3 1 6 4 1 5 2 1 liremove (1) li contient maintenant 3 6 4 5 2

422 Suppression des eacuteleacutements reacutepondant agrave une condition

remove_if (preacutedicat) supprime tous les eacuteleacutements reacutepondant au preacutedicat

Cette fonction supprime tous les eacuteleacutements pour lesquels le preacutedicat unaire fourni en argument

est vrai La notion de preacutedicat a eacuteteacute abordeacutee au paragraphe 5 du chapitre 18 Voici un exem-

ple utilisant le preacutedicat est_paire deacutefini ainsi

bool est_paire (int n) ne pas oublier include ltfunctionalgt return (n2)

int t[] = 1 6 3 9 11 18 5 listltintgt li(t t+7) li contient 1 6 3 9 11 18 5 liremove_if(est_paire) li contient maintenant 1 3 9 11 5

Remarques

1 La fonction membre remove ne fournit aucun reacutesultat de sorte quil nest pas possible de

savoir sil existait des eacuteleacutements reacutepondant aux conditions speacutecifieacutees Il est toujours possi-

ble de recourir auparavant agrave un algorithme tel que count pour obtenir cette information

2 Il existe une fonction membre unique dont la vocation est eacutegalement la suppression

deacuteleacutements cependant nous vous la preacutesenterons dans le paragraphe suivant consacreacute

agrave la fonction de tri (sort) car elle est souvent utiliseacutee conjointement avec la fonction

unique

Les conteneurs seacutequentielsCHAPITRE 19

428

43 Opeacuterations globales En plus des possibiliteacutes geacuteneacuterales offertes par laffectation et la fonction membre assign

deacutecrites au paragraphe 12 la classe list en offre dautres assez originales tri de ses eacuteleacutements

avec suppression eacuteventuelle des occurrences multiples fusion de deux listes preacutealablement

ordonneacutees transfert de tout ou partie dune liste dans une autre liste de mecircme type

431 Tri dune liste

Il existe des algorithmes de tri des eacuteleacutements dun conteneur mais la plupart neacutecessitent des

iteacuterateurs agrave accegraves direct En fait la classe list dispose de sa propre fonction sort eacutecrite speacuteci-

fiquement pour ce type de conteneur et relativement efficace puisquen O (Log N)

Comme tout ce qui touche agrave lordonnancement dun conteneur la fonction sort sappuie sur

une relation dordre faible strict telle quelle a eacuteteacute preacutesenteacutee dans le chapitre preacuteceacutedent On

pourra utiliser par deacutefaut lopeacuterateur lt y compris pour un type classe pour peu que cette der-

niegravere lait convenablement deacutefini On aura la possibiliteacute dans tous les cas dimposer une rela-

tion de son choix par le biais dun preacutedicat binaire preacutedeacutefini ou non

sort () trie la liste concerneacutee en sappuyant sur lopeacuterateur lt

listltintgt li() on suppose que li contient 1 6 3 9 11 18 5

lisort () maintenenant li contient 1 3 5 6 9 11 18

sort (preacutedicat) trie la liste concerneacutee en sappuyant sur le

preacutedicat binaire preacutedicat

listltintgt li() on suppose que li contient 1 6 3 9 11 18 5

lisort(greaterltintgt) maintenenant li contient 18 11 9 6 5 3 1

432 Suppression des eacuteleacutements en double

La fonction unique permet deacuteliminer les eacuteleacutements en double agrave condition de la faire porter

sur une liste preacutealablement trieacutee Dans le cas contraire elle peut fonctionner mais alors elle

se contente de remplacer par un seul eacuteleacutement les seacutequences de valeurs conseacutecutives identi-

ques ce qui signifie que en deacutefinitive la liste pourra encore contenir des valeurs identiques

mais non conseacutecutives

Comme on peut sy attendre cette fonction se fonde par deacutefaut sur lopeacuterateur == pour deacuteci-

der de leacutegaliteacute de deux eacuteleacutements cet opeacuterateur devant bien sucircr ecirctre deacutefini convenablement en

cas deacuteleacutements de type classe Mais on pourra aussi dans tous les cas imposer une relation de

comparaison de son choix par le biais dun preacutedicat binaire preacutedeacutefini ou non

On notera bien que si lon applique unique agrave une liste trieacutee deacuteleacutements de type classe il sera

preacutefeacuterable dassurer la compatibiliteacute entre la relation dordre utiliseacutee pour le tri (mecircme sil

sagit de lopeacuterateur lt) et le preacutedicat binaire deacutegaliteacute (mecircme sil sagit de ==) Plus preacuteciseacute-

ment pour obtenir un fonctionnement logique de lalgorithme il faudra que les classes

deacutequivalence induites par la relation == soient les mecircmes que celles qui sont induites par la

relation dordre du tri

4 - Le conteneur list429

unique() ne conserve que le premier eacuteleacutement drsquoune suite de valeurs

conseacutecutives eacutegales (==)

unique (preacutedicat) ne conserve que le premier eacuteleacutement drsquoune suite de valeurs

conseacutecutives satisfaisant au preacutedicat binaire preacutedicat

Voici un exemple qui montre clairement la diffeacuterence deffet obtenu suivant que la liste est

trieacutee ou non

int t[] = 1 6 6 4 6 5 5 4 2 listltintgt li1(t t+9) li1 contient 1 6 6 4 6 5 5 4 2 listltintgt li2=li1 li2 contient 1 6 6 4 6 5 5 4 2 li1unique() li1 contient maintenant 1 6 4 6 5 4 2 li2sort() li2 contient maintenant 1 2 4 4 5 5 6 6 6 li2unique() li2 contient maintenant 1 2 4 5 6

433 Fusion de deux listesBien quil existe un algorithme geacuteneacuteral de fusion pouvant sappliquer agrave deux conteneurs con-

venablement trieacutes la classe list dispose dune fonction membre speacutecialiseacutee geacuteneacuteralement

leacutegegraverement plus performante mecircme si dans les deux cas lefficaciteacute est en O(N1+N2) N1 et

N2 deacutesignant le nombre deacuteleacutements de chacune des listes concerneacutees

La fonction membre merge permet de venir fusionner une autre liste de mecircme type avec la

liste concerneacutee La liste fusionneacutee est videacutee de son contenu Comme on peut sy attendre la

fonction merge sappuie comme sort sur une relation dordre faible strict par deacutefaut il

sagira de lopeacuterateur lt

merge (liste) fusionne liste avec la liste concerneacutee en sappuyant sur

lrsquoopeacuterateur gt agrave la fin liste est vide

merge (liste preacutedicat) fusionne liste avec la liste concerneacutee

en srsquoappuyant sur le preacutedicat binaire preacutedicat

On notera quen theacuteorie aucune contrainte ne pegravese sur lordonnancement des deux listes con-

cerneacutees Cependant la fonction merge suppose que les deux listes sont trieacutees suivant la mecircme

relation dordre que celle qui est utiliseacutee par la fusion Voici un premier exemple dans lequel

nous avons preacutealablement trieacute les deux listes

int t1[] = 1 6 3 9 11 18 5 int t2[] = 12 4 9 8 listltintgt li1(t1 t1+7) listltintgt li2(t2 t2+4) li1sort() li1 contient 1 3 5 6 9 11 18 li2sort() li2 contient 4 8 9 12 li1merge(li2) li1 contient maintenant 1 3 4 5 6 8 9 9 11 12 18 et li2 est vide

A simple titre indicatif voici le mecircme exemple sans tri preacutealable des deux listes

int t1[] = 1 6 3 9 11 18 5 int t2[] = 12 4 9 8 listltintgt li1(t1 t1+7) li1 contient 1 6 3 9 11 18 5 listltintgt li2(t2 t2+4) li2 contient 12 4 9 8 li1merge(li2) li1 contient maintenant 1 6 3 9 11 12 4 9 8 18 5 et li2 est vide

Les conteneurs seacutequentielsCHAPITRE 19

430

434 Transfert dune partie de liste dans une autreLa fonction splice permet de deacuteplacer des eacuteleacutements dune autre liste dans la liste concerneacutee

On notera bien comme avec merge les eacuteleacutements deacuteplaceacutes sont supprimeacutes de la liste dorigine

et pas seulement copieacutes

splice (position liste_or) deacuteplace les eacuteleacutements de liste_or agrave

lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il il = li1begin() il++ il pointe sur le deuxiegraveme eacuteleacutement de li1 li1splice(il li2) li1 contient x a b c d e f y z li2 est vide

splice (position liste_or position_or)

deacuteplace leacuteleacutement de liste_or pointeacute par position_or agrave lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il1=li1begin() listltchargtiterator il2=li2end() il2-- pointe sur avant dernier li1splice(il1 li2 il2) li1 contient f x y z li2 contient a b c d e

splice (position liste_or debut_or fin_or)

deacuteplace lintervalle [debut_or fin_or) de liste_or agrave lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il1=li1begin() listltchargtiterator il2=li2begin() il2++ li1splice(il1 li2 il2 li2end()) li1 contient b c d e f x y z li2 contient a

44 Gestion de lemplacement meacutemoire La norme nimpose pas explicitement la maniegravere de geacuterer les emplacements meacutemoire alloueacutes

agrave une liste pas plus quelle ne le fait pour les autres conteneurs Cependant elle impose agrave la

fois des contraintes defficaciteacute et des regravegles dinvalidation des iteacuterateurs et des reacutefeacuterences sur

des eacuteleacutements dune liste Notamment elle preacutecise quen cas dinsertions ou de suppressions

deacuteleacutements dans une liste seuls les iteacuterateurs ou reacutefeacuterences concernant les eacuteleacutements inseacutereacutes ou

supprimeacutes deviennent invalides Cela signifie donc que les autres nont pas ducirc changer de

place Ainsi indirectement la norme impose que chaque eacuteleacutement dispose de son propre bloc

de meacutemoire

Dans ces conditions si le conteneur list dispose toujours des fonctions dinformation size() et

max_size() on ny retrouve en revanche aucune fonction permettant dagir sur les allocations

et en particulier capacity et reserve

4 - Le conteneur list431

45 Exemple Voici un exemple complet de programme illustrant bon nombre des fonctionnaliteacutes de la

classe list que nous avons examineacutees dans ce paragraphe ainsi que dans le paragraphe 1

include ltiostreamgt

include ltlistgt

using namespace std

main()

void affiche(listltchargt)

char mot[] = anticonstitutionnellement

listltchargt lc1 (mot mot+sizeof(mot)-1)

listltchargt lc2

cout ltlt lc1 init affiche(lc1)

cout ltlt lc2 init affiche(lc2)

listltchargtiterator il1 il2

il2 = lc2begin()

for (il1=lc1begin() il1=lc1end() il1++)

if (il1=t) lc2push_back(il1) equivaut a lc2=lc1

lc2remove(t)

cout ltlt lc2 apres affiche(lc2)

lc1remove(t)

cout ltlt lc1 remove affiche(lc1)

if (lc1==lc2) cout ltlt les deux listes sont egalesn

lc1sort()

cout ltlt lc1 sort affiche(lc1)

lc1unique()

cout ltlt lc1 unique affiche(lc1)

void affiche(listltchargt lc) voir remarque paragraphe 24

listltchargtiterator il

for (il=lcbegin() il=lcend() il++) cout ltlt (il) ltlt

cout ltlt 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

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

Exemple dutilisation de la classe list

Les conteneurs seacutequentielsCHAPITRE 19

432

5 Les adaptateurs de conteneur queue stack et priority_queue

La bibliothegraveque standard dispose de trois patrons particuliers stack queue et priority_queue

dits adaptateurs de conteneurs Il sagit de classes patrons construites sur un conteneur dun

type donneacute qui en modifient linterface agrave la fois en la restreignant et en ladaptant agrave des fonc-

tionnaliteacutes donneacutees Ils disposent tous dun constructeur sans argument

51 Ladaptateur stack Le patron stack est destineacute agrave la gestion de piles de type LIFO (Last In First Out) il peut ecirctre

construit agrave partir de lun des trois conteneurs seacutequentiels vector deque ou list comme dans

ces deacuteclarations

stack ltint vectorltintgt gt s1 pile de int utilisant un conteneur vector stack ltint dequeltintgt gt s2 pile de int utilisant un conteneur deque

stack ltint listltintgt gt s3 pile de int utilisant un conteneur list

Dans un tel conteneur on ne peut quintroduire (push) des informations quon empile les unes

sur les autres et quon recueille agrave raison dune seule agrave la fois en extrayant la derniegravere intro-

duite On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la pile est vide

bull size() fournit le nombre deacuteleacutements de la pile

bull top() accegraves agrave linformation situeacutee au sommet de la pile quon peut connaicirctre ou modifier

(sans la supprimer)

bull push (valeur) place valeur sur la pile

bull pop() fournit la valeur de leacuteleacutement situeacute au sommet en le supprimant de la pile

Voici un petit exemple de programme utilisant une pile

include ltiostreamgtinclude ltstackgt

include ltvectorgtusing namespace std main()

int i stackltint vectorltintgt gt q cout ltlt taille initiale ltlt qsize() ltlt n for (i=0 ilt10 i++) qpush(ii)

cout ltlt taille apres for ltlt qsize() ltlt n cout ltlt sommet de la pile ltlt qtop() ltlt n qtop() = 99 on modifie le sommet de la pile cout ltlt on depile

for (i=0 ilt10 i++) cout ltlt qtop() ltlt qpop()

5 - Les adaptateurs de conteneur queue stack et priority_queue433

taille initiale 0taille apres for 10sommet de la pile 81on depile 99 64 49 36 25 16 9 4 1 0

Exemple dutilisation de ladaptateur de conteneur stack

52 Ladaptateur queue Le patron queue est destineacute agrave la gestion de files dattentes dites aussi queues ou encore piles

de type FIFO (First In First Out) On y place des informations quon introduit en fin et quon

recueille en tecircte dans lordre inverse de leur introduction Un tel conteneur peut ecirctre construit

agrave partir de lun des deux conteneurs seacutequentiels deque ou list (le conteneur vector ne serait

pas approprieacute puisquil ne dispose pas dinsertions efficaces en deacutebut) comme dans ces

deacuteclarations

queue ltint dequeltintgt gt q1 queue de int utilisant un conteneur deque queue ltint listltintgt gt q2 queue de int utilisant un conteneur list

On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la queue est vide

bull size() fournit le nombre deacuteleacutements de la queue

bull front() accegraves agrave linformation situeacutee en tecircte de la queue quon peut ainsi connaicirctre ou modi-

fier sans la supprimer

bull back() accegraves agrave linformation situeacutee en fin de la queue quon peut ainsi connaicirctre ou modi-

fier sans la supprimer

bull push (valeur) place valeur dans la queue

bull pop() fournit leacuteleacutement situeacute en tecircte de la queue en le supprimant

Voici un petit exemple de programme utilisant une queue

include ltiostreamgtinclude ltqueuegtinclude ltdequegtusing namespace std main() int i queueltint dequeltintgt gt q for (i=0 ilt10 i++) qpush(ii) cout ltlt tete de la queue ltlt qfront() ltlt n cout ltlt fin de la queue ltlt qback() ltlt n qfront() = 99 on modifie la tete de la queue qback() = -99 on modifie la fin de la queue cout ltlt on depile la queue for (i=0 ilt10 i++) cout ltlt qfront() ltlt qpop()

Les conteneurs seacutequentielsCHAPITRE 19

434

tete de la queue 0fin de la queue 81on depile la queue 99 1 4 9 16 25 36 49 64 -99

Exemple dutilisation de ladaptateur de conteneur stack

53 Ladaptateur priority_queue Un tel conteneur ressemble agrave une file dattente dans laquelle on introduit toujours des eacuteleacute-

ments en fin en revanche lemplacement des eacuteleacutements dans la queue est modifieacute agrave chaque

introduction de maniegravere agrave respecter une certaine prioriteacute deacutefinie par une relation dordre

quon peut fournir sous forme dun preacutedicat binaire On parle parfois de file dattente avec

prioriteacutes Un tel conteneur ne peut ecirctre construit quagrave partir dun conteneur deque comme

dans ces deacuteclarations

priority_queue ltint dequeltintgt gt q1 priority_queue ltint dequeltintgt greaterltintgt gt q2

En revanche ici on peut le construire classiquement agrave partir dune seacutequence

On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la queue est vide

bull size() fournit le nombre deacuteleacutements de la queue

bull push (valeur) place valeur dans la queue

bull top() accegraves agrave linformation situeacutee en tecircte de la queue quon peut connaicirctre ou theacuteorique-

ment modifier (sans la supprimer) actuellement nous recommandons de ne pas utiliser la

possibiliteacute de modification qui dans certaines impleacutementations nassure plus le respect de

lordre des eacuteleacutements de la queue

bull pop() fournit leacuteleacutement situeacute en tecircte de la queue en le supprimant

Voici un petit exemple de programme utilisant une file dattente avec prioriteacutes

include ltiostreamgtinclude ltqueuegtinclude ltdequegtusing namespace std main() int i priority_queue ltint dequeltintgt greaterltintgt gt q qpush (10) qpush(5) qpush(12) qpush(8) cout ltlt tete de la queue ltlt qtop() ltlt n cout ltlt on depile for (i=0 ilt4 i++) cout ltlt qtop() ltlt qpop()

5 - Les adaptateurs de conteneur queue stack et priority_queue435

tete de la queue 5on depile 5 8 10 12

Exemple dutilisation de ladaptateur de conteneur priority_queue

20

Les conteneurs associatifs

Comme il a eacuteteacute dit au chapitre 18 les conteneurs se classent en deux cateacutegories les conte-

neurs seacutequentiels et les conteneurs associatifs Les conteneurs seacutequentiels que nous avons

eacutetudieacutes dans le preacuteceacutedent chapitre sont ordonneacutes suivant un ordre imposeacute explicitement par

le programme lui-mecircme on accegravede agrave un de leurs eacuteleacutements en tenant compte de cet ordre que

lon utilise un indice ou un iteacuterateur

Les conteneurs associatifs ont pour principale vocation de retrouver une information non

plus en fonction de sa place dans le conteneur mais en fonction de sa valeur ou dune partie

de sa valeur nommeacutee cleacute Nous avons deacutejagrave citeacute lexemple du reacutepertoire teacuteleacutephonique dans

lequel on retrouve le numeacutero de teacuteleacutephone agrave partir dune cleacute formeacutee du nom de la personne

concerneacutee Malgreacute tout pour de simples questions defficaciteacute un conteneur associatif se

trouve ordonneacute intrinsegravequement en permanence en se fondant sur une relation (par deacutefaut lt)

choisie agrave la construction

Les deux conteneurs associatifs les plus importants sont map et multimap Ils correspondent

pleinement au concept de conteneur associatif en associant une cleacute et une valeur Mais alors

que map impose luniciteacute des cleacutes autrement dit labsence de deux eacuteleacutements ayant la mecircme

cleacute multimap ne limpose pas et on pourra y trouver plusieurs eacuteleacutements de mecircme cleacute qui

apparaicirctront alors conseacutecutivement Si lon reprend notre exemple de reacutepertoire teacuteleacutephonique

on peut dire que multimap autorise la preacutesence de plusieurs personnes de mecircme nom (avec

des numeacuteros associeacutes diffeacuterents ou non) tandis que map ne lautorise pas Cette distinction

permet preacuteciseacutement de redeacutefinir lopeacuterateur [ ] sur un conteneur de type map Par exemple

avec un conteneur nommeacute annuaire dans lequel les cleacutes sont des chaicircnes on pourra utiliser

lexpression annuaire [Dupont] pour deacutesigner leacuteleacutement correspondant agrave la cleacute Dupont

cette possibiliteacute nexistera naturellement plus avec multimap

Les conteneurs associatifsCHAPITRE 20

438

Il existe deux autres conteneurs qui correspondent agrave des cas particuliers de map et multimap

dans le cas ougrave la valeur associeacutee agrave la cleacute nexiste plus ce qui revient agrave dire que les eacuteleacutements se

limitent agrave la seule cleacute Dans ces conditions la notion dassociation entre une cleacute et une valeur

disparaicirct et il ne reste plus que la notion dappartenance Ces conteneurs se nomment set et

multiset et lon verra queffectivement ils permettront de repreacutesenter des ensembles au sens

matheacutematique agrave condition toutefois de disposer comme pour tout conteneur associatif dune

relation dordre approprieacutee sur les eacuteleacutements ce qui nest pas neacutecessaire en matheacutematiques en

outre multiset autorisera la preacutesence de plusieurs eacuteleacutements identiques ce qui nest manifeste-

ment pas le cas dun ensemble usuel

1 Le conteneur map Le conteneur map est donc formeacute deacuteleacutements composeacutes de deux parties une cleacute et une

valeur Pour repreacutesenter de tels eacuteleacutements il existe un patron de classe approprieacute nommeacute pair

parameacutetreacute par le type de la cleacute et par celui de la valeur Un conteneur map permet dacceacuteder

rapidement agrave la valeur associeacutee agrave une cleacute en utilisant lopeacuterateur [] lefficaciteacute de lopeacuteration

est en O(Log N) Comme un tel conteneur est ordonneacute en permanence cela suppose le

recours agrave une relation dordre qui comme agrave laccoutumeacutee doit posseacuteder les proprieacuteteacutes dune

relation dordre faible strict telles quelles ont eacuteteacute preacutesenteacutees au paragraphe 62 du chapitre

18

Comme la notion de tableau associatif est moins connue que celle de tableau de vecteur ou

mecircme que celle de liste nous commencerons par un exemple introductif dutilisation dun

conteneur de type map avant den eacutetudier les proprieacuteteacutes en deacutetail

11 Exemple introductif Une deacuteclaration telle que

mapltchar intgt m

creacutee un conteneur de type map dans lequel les cleacutes sont de type char et les valeurs associeacutees

de type int Pour linstant ce conteneur est vide msize() vaut 0

Une instruction telle que

m[S] = 5

insegravere dans le conteneur m un eacuteleacutement formeacute de lassociation de la cleacute S et de la valeur 5

On voit deacutejagrave lagrave une diffeacuterence fondamentale entre un vecteur et un conteneur de type map

dans un vecteur on ne peut acceacuteder par lopeacuterateur [ ] quaux eacuteleacutements existants et en aucun

cas en inseacuterer de nouveaux

Qui plus est si lon cherche agrave utiliser une valeur associeacutee agrave une cleacute inexistante comme dans

cout ltlt valeur associeacutee a la cleacute X m[X]

le simple fait de chercher agrave consulter m[X] creacuteera leacuteleacutement correspondant en initialisant la

valeur associeacutee agrave 0

1 - Le conteneur map439

Pour afficher tous les eacuteleacutements dun map tel que m on pourra le parcourir avec un iteacuterateur

bidirectionnel classique iterator fourni par la classe map Ceci nest possible que parce que

comme nous lavons dit agrave plusieurs reprises les conteneurs associatifs sont ordonneacutes intrinsegrave-

quement On pourra classiquement parcourir tous les eacuteleacutements de m par lun des deux scheacute-

mas suivants

mapltchar intgt iterator im iteacuterateur sur un mapltcharintgt for (im=mbegin() im=mend() im++) im parcourt tout le map m ici im deacutesigne leacuteleacutement courant de m

mapltchar intgt reverse_iterator im iteacuterateur inverse sur un mapltcharintgt for (im=mrbegin() im=mrend() im++) im parcourt tout le map m ici im deacutesigne leacuteleacutement courant de m

Cependant on constate quune petite difficulteacute apparaicirct im deacutesigne bien leacuteleacutement courant

de m mais la plupart du temps on aura besoin dacceacuteder seacutepareacutement agrave la cleacute et agrave la valeur

correspondante En fait les eacuteleacutements dun conteneur map sont dun type classe particulier

nommeacute pair qui dispose de deux membres publics

bull first correspondant agrave la cleacute

bull second correspondant agrave la valeur associeacutee

En deacutefinitive voici par exemple comment afficher suivant lordre naturel toutes les valeurs

de m sous la forme (cleacute valeur)

for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt )

Voici un petit programme complet reprenant les diffeacuterents points que nous venons dexaminer

(attention la position relative de la cleacute c peut deacutependre de limpleacutementation)

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche (mapltchar intgt) mapltchar intgt m cout ltlt map initial affiche(m) m[S] = 5 la cle S nexiste pas encore lelement est cree m[C] = 12 idem cout ltlt map SC affiche(m) cout ltlt valeur associee a la cle S ltlt m[S] ltlt n cout ltlt valeur associee a la cle X ltlt m[X] ltlt n cout ltlt map X affiche(m) m[S] = m[c] on a utilise m[c] au lieu de m[C] la cle c est creee cout ltlt map final affiche(m)

Les conteneurs associatifsCHAPITRE 20

440

void affiche (mapltchar intgt m) voir remarque paragraphe 24 du chapitre 19 mapltchar intgt iterator im for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt ) cout ltlt n

map initial map SC (C12) (S5)valeur associee a la cle S 5valeur associee a la cle X 0map X (C12) (S5) (X0)map final (C12) (S0) (X0) (c0)

Exemple introductif dutilisation dun conteneur map

12 Le patron de classes pair Comme nous venons de le voir il existe un patron de classe pair comportant deux paramegrave-

tres de type et permettant de regrouper dans un objet deux valeurs On y trouve un construc-

teur agrave deux arguments

pair ltint floatgt p(3 125) creacutee une paire formeacutee dun int de valeur 3 et dun float de valeur 125

Pour affecter des valeurs donneacutees agrave une telle paire on peut theacuteoriquement proceacuteder comme

dans

p = pairltintfloatgt (4 335) ici les arguments peuvent ecirctre dun type compatible par affectation avec celui attendu

Mais les choses sont un peu plus simples si lon fait appel agrave une fonction standard

make_pair

p = make_pair (4 335f) attention 335f car le type des arguments sert agrave instancier la fonction patron make_pair

Comme on la vu dans notre exemple introductif la classe pair dispose de deux membres

publics nommeacutes first et second Ainsi linstruction preacuteceacutedente pourrait eacutegalement seacutecrire

pfirst = 4 psecond = 335 ici 335 (double) sera converti en float

La classe pair dispose des deux opeacuterateurs == et lt Le second correspond agrave une comparaison

lexicographique crsquoest-agrave-dire quil applique dabord lt agrave la cleacute puis agrave la valeur Bien entendu

dans le cas ougrave lun des eacuteleacutements au moins de la paire est de type classe ces opeacuterateurs doivent

ecirctre convenablement surdeacutefinis

13 Construction dun conteneur de type map Les possibiliteacutes de construction dun tel conteneur sont beaucoup plus restreintes que pour les

conteneurs seacutequentiels elles se limitent agrave trois possibiliteacutes

bull construction dun conteneur vide (comme dans notre exemple du paragraphe 11)

1 - Le conteneur map441

bull construction agrave partir dun autre conteneur de mecircme type

bull construction agrave partir dune seacutequence

En outre il est possible de choisir la relation dordre qui sera utiliseacutee pour ordonner intrinsegrave-

quement le conteneur Pour plus de clarteacute nous examinerons ce point agrave part

131 Constructions utilisant la relation dordre par deacutefaut

Construction dun conteneur vide

On se contente de preacuteciser les types voulus pour la cleacute et pour la valeur comme dans ces

exemples (on suppose que point est un type classe)

map ltint longgt m1 cleacutes de type int valeurs de type long map ltchar pointgt m2 cleacutes de type char valeurs de type point map ltstring longgt repert cleacutes de type string valeurs de type long

Construction agrave partir dun autre conteneur de mecircme type

Il sagit dun classique constructeur par recopie qui comme on peut sy attendre appelle le

constructeur par recopie des eacuteleacutements concerneacutes lorsquil sagit dobjets

map ltint longgt m1 map ltint longgt m2(m1) ou encore map ltint longgt m2 = m1

Construction agrave partir dune seacutequence

Il sagit dune possibiliteacute deacutejagrave rencontreacutee pour les conteneurs seacutequentiels avec cependant une

diffeacuterence importante les eacuteleacutements concerneacutes doivent ecirctre de type pairlttype_des_cleacutes

type_des_valeursgt Par exemple sil existe une liste lr construite ainsi

listltpairltchar longgt gt lr ()

et convenablement remplie on pourra lutiliser en partie ou en totaliteacute pour construire

map ltchar longgt repert (lrbegin() lrend() )

En pratique ce type de construction est peu utiliseacute

132 Choix de lordre intrinsegraveque du conteneur

Comme on la deacutejagrave dit les conteneurs sont intrinsegravequement ordonneacutes en faisant appel agrave une

relation dordre faible strict pour ordonner convenablement les cleacutes Par deacutefaut on utilise la

relation lt quil sagisse de la relation preacutedeacutefinie pour les types scalaires ou string ou dune

surdeacutefinition de lopeacuterateur gt lorsque les cleacutes sont des objets

Il est possible dimposer agrave un conteneur decirctre ordonneacute en utilisant une autre relation que lon

fournit sous forme dun preacutedicat binaire preacutedeacutefini (comme lessltintgt) ou non Dans ce dernier

cas il est alors neacutecessaire de fournir un type et non pas un nom de fonction ce qui signifie

quil est neacutecessaire de recourir agrave une classe fonction (dont nous avons parleacute au paragraphe 53

du chapitre 18) Voici quelques exemples

map ltchar long greaterltchargt gt m1 les cleacutes seront ordonneacutees par valeurs deacutecroissantes - attention gt gt et non gtgt map ltchar long greaterltchargt gt m2(m1) si m2 nest pas ordonneacute par la mecircme relation on obtient une erreur de compilation

Les conteneurs associatifsCHAPITRE 20

442

class mon_ordre public bool operator () (int n int p) ordre faible strict map ltint float mon_ordregt m_perso cleacutes ordonneacutees par le preacutedicat mon_ordre qui doit ecirctre une classe fonction

Remarque

Certaines impleacutementations peuvent ne pas accepter le choix dune valeur par deacutefaut pour

la relation dordre des cleacutes Dans ce cas il faut toujours preacuteciser lesslttypegt comme troi-

siegraveme argument type correspondant au type des cleacutes pour instancier convenablement le

conteneur La lourdeur des notations qui en deacutecoule peut parfois inciter agrave recourir agrave lins-

truction typedef

133 Pour connaicirctre la relation dordre utiliseacutee par un conteneurLes classes map disposent dune fonction membre key_comp() fournissant la fonction utiliseacutee

pour ordonner les cleacutes Par exemple avec le conteneur de notre exemple introductif

mapltchar intgt m

on peut certes comparer deux cleacutes de type char de faccedilon directe comme dans

if (a lt c)

mais on obtiendra le mecircme reacutesultat avec

if mkey_comp() (a c) notez bien key_comp() ()

Certes tant que lon se contente dordonner de tels conteneurs en utilisant la relation dordre

par deacutefaut ceci ne preacutesente guegravere dinteacuterecirct dans le cas contraire cela peut eacuteviter davoir agrave se

demander agrave chaque fois quon compare des cleacutes quelle relation dordre a eacuteteacute utiliseacutee lors de

la construction

Dune maniegravere similaire la classe map dispose dune fonction membre value_comp() fournis-

sant la fonction utilisable pour comparer deux eacuteleacutements toujours selon la valeur des cleacutes

Linteacuterecirct de cette fonction est de permettre de comparer deux eacuteleacutements (donc deux paires)

suivant lordre des cleacutes sans avoir agrave en extraire les membres first On notera bien que con-

trairement agrave key_comp cette fonction nest jamais choisie librement elle est simplement

deacuteduite de key_comp Par exemple avec

map ltchar intgt m map ltchar intgtiterator im1 im2

on pourra comparer les cleacutes relatives aux eacuteleacutements pointeacutes par im1 et im2 de cette maniegravere

if ( value_comp() (im1 im2) )

Avec key_comp il aurait fallu proceacuteder ainsi

if ( key_comp() ( (im1)first (im2)first) )

1 - Le conteneur map443

134 Conseacutequences du choix de lordre dun conteneur

Tant que lon utilise des cleacutes de type scalaire ou string et quon se limite agrave la relation par

deacutefaut (lt) aucun problegraveme particulier ne se pose Il nen va plus neacutecessairement de mecircme

dans les autres cas

Par exemple on dit geacuteneacuteralement que dans un conteneur de type map les cleacutes sont uniques

En fait pour ecirctre plus preacutecis il faudrait dire quun nouvel eacuteleacutement nest introduit dans un tel

conteneur que sil nexiste pas dautre eacuteleacutement posseacutedant une cleacute eacutequivalente leacutequivalence

eacutetant celle qui est induite par la relation dordre tel quil a eacuteteacute expliqueacute au paragraphe 62 du

chapitre 18 Par exemple consideacuterons un map utilisant comme cleacute des objets de type point et

supposons que la relation lt ait eacuteteacute deacutefinie dans la classe point en sappuyant uniquement sur

les abscisses des points dans ces conditions les cleacutes correspondant agrave des points de mecircme

abscisse apparaicirctront comme eacutequivalentes

De plus comme on aura loccasion de le voir plus loin la recherche dun eacuteleacutement de cleacute don-

neacutee se fondera non pas sur une hypotheacutetique relation deacutegaliteacute mais bel et bien sur la relation

dordre utiliseacutee pour ordonner le conteneur Autrement dit toujours avec notre exemple de

points utiliseacutes en guise de cleacutes on pourra rechercher la cleacute (1 9) et trouver la cleacute (1 5)

14 Accegraves aux eacuteleacutements Comme tout conteneur map permet theacuteoriquement dacceacuteder aux eacuteleacutements existants soit

pour en connaicirctre la valeur soit pour la modifier Cependant par rapport aux conteneurs

seacutequentiels ces opeacuterations prennent un tour un peu particulier lieacute agrave la nature mecircme des conte-

neurs associatifs En effet dune part une tentative daccegraves agrave une cleacute inexistante amegravene agrave la

creacuteation dun nouvel eacuteleacutement dautre part comme on le verra un peu plus loin une tentative

de modification globale (cleacute + valeur) dun eacuteleacutement existant sera fortement deacuteconseilleacutee

141 Accegraves par lopeacuterateur [ ]

Le paragraphe 1 a deacutejagrave montreacute en quoi cet accegraves par lopeacuterateur est ambigu puisquil peut con-

duire agrave la creacuteation dun nouvel eacuteleacutement degraves lors quon lapplique agrave une cleacute inexistante et cela

aussi bien en consultation quen modification Par exemple

mapltchar intgt m m [S] = 2 si la cleacute S nexiste pas on creacutee lrsquoeacuteleacutement make_pair (S 2) si la cleacute existe on modifie la valeur de leacuteleacutement qui ne change pas de place = m[T] si la cleacute T nexiste pas on creacutee leacuteleacutement make_pair (T 0)

142 Accegraves par iteacuterateur

Comme on peut sy attendre et comme on la deacutejagrave fait dans les exemples preacuteceacutedents si it est

un iteacuterateur valide sur un conteneur de type map lexpression it deacutesigne leacuteleacutement

correspondant rappelons quil sagit dune paire formeacutee de la cleacute (it)first et de la valeur

Les conteneurs associatifsCHAPITRE 20

444

associeacutee (it)second en geacuteneacuteral dailleurs on sera plutocirct ameneacute agrave sinteacuteresser agrave ces deux

derniegraveres valeurs (ou agrave lune dentre elles) plutocirct quagrave la paire complegravete it

En theacuteorie il nest pas interdit de modifier la valeur de leacuteleacutement deacutesigneacute par it par exemple

pour un conteneur de type mapltchar intgt on pourrait eacutecrire

it = make_pair (R 5) remplace theacuteoriquement leacuteleacutement deacutesigneacute par ip

fortement deacuteconseilleacute en pratique

Mais le rocircle exact dun telle opeacuteration nest actuellement pas totalement speacutecifieacute par la norme

Or certaines ambiguiumlteacutes apparaissent En effet dune part comme une telle opeacuteration modi-

fie la valeur de la cleacute le nouvel eacuteleacutement risque de ne plus ecirctre agrave sa place il devrait donc ecirctre

deacuteplaceacute dautre part que doit-il se passer si la cleacute R existe deacutejagrave La seule deacutemarche raison-

nable nous semble ecirctre de dire quune telle modification devrait ecirctre eacutequivalente agrave une des-

truction de leacuteleacutement deacutesigneacute par it suivie dune insertion du nouvel eacuteleacutement En pratique ce

nest pas ce que lon constate dans toutes les impleacutementations actuelles Dans ces conditions

Il est fortement deacuteconseilleacute de modifier la valeur dun eacuteleacutement dun map par le biais

dun iteacuterateur

143 Recherche par la fonction membre find

La fonction membre

find (cleacute)

a un rocircle naturel fournir un iteacuterateur sur un eacuteleacutement ayant une cleacute donneacutee (ou une cleacute eacutequi-

valente au sens de la relation dordre utiliseacutee par le conteneur) Si aucun eacuteleacutement nest trouveacute

cette fonction fournit la valeur end()

Remarque

Attention la fonction find ne se base pas sur lopeacuterateur == cette remarque est surtout

sensible lorsque lon a affaire agrave des eacuteleacutements de type classe classe dans laquelle on a sur-

deacutefini lopeacuterateur == de maniegravere incompatible avec le preacutedicat binaire utiliseacute pour ordon-

ner le conteneur Les reacutesultats peuvent alors ecirctre deacuteconcertants

15 Insertions et suppressions Comme on peut sy attendre le conteneur map offre des possibiliteacutes de modifications dyna-

miques fondeacutees sur des insertions et des suppressions analogues agrave celles qui sont offertes par

les conteneurs seacutequentiels Toutefois si la notion de suppression dun eacuteleacutement deacutesigneacute par un

iteacuterateur conserve la mecircme signification celle dinsertion agrave un emplacement donneacute na plus

guegravere de raison decirctre puisquon ne peut plus agir sur la maniegravere dont sont intrinsegravequement

ordonneacutes les eacuteleacutements dun conteneur associatif On verra quil existe quand mecircme une fonc-

tion dinsertion recevant un tel argument mais que ce dernier a en fait un rocircle un peu particu-

lier

1 - Le conteneur map445

En outre alors quune insertion dans un conteneur seacutequentiel aboutissait toujours dans le cas

dun conteneur de type map elle naboutit que sil nexiste pas deacuteleacutement de cleacute eacutequivalente

Dune maniegravere geacuteneacuterale lefficaciteacute de ces opeacuterations est en O(Log N) Nous apporterons

quelques preacutecisions par la suite pour chacune des opeacuterations

151 InsertionsLa fonction membre insert permet dinseacuterer

bull un eacuteleacutement de valeur donneacutee

insert (eacuteleacutement) insegravere la paire eacuteleacutement

bull les eacuteleacutements dun intervalle

insert (deacutebut fin) insegravere les paires de la seacutequence [deacutebut fin)

On notera bien dans les deux cas que les eacuteleacutements concerneacutes doivent ecirctre des paires dun

type approprieacute

Lefficaciteacute de la premiegravere fonction est en O(Log N) celle de la seconde est en

O(Log(N+M)) M deacutesignant le nombre deacuteleacutements de lintervalle Toutefois si cet intervalle

est trieacute suivant lordre voulu lefficaciteacute est en O(M)

Voici quelques exemples

mapltint floatgt m1 m2 mapltint floatgtiterator im1 m1insert (make_pair(5 625f)) tentative dinsertion dun eacuteleacutement m1insert (m2begin() m2end()) tentative dinsertion dune seacutequence

Remarques

1 En toute rigueur il existe une troisiegraveme version de insert de la forme

insert (position paire)

Liteacuterateur position est une suggestion qui est faite pour faciliter la recherche de

lemplacement exact dinsertion Si la valeur fournie correspond exactement au point

dinsertion on obtient alors une efficaciteacute en O(1) ce qui sexplique par le fait que la

fonction na besoin que de comparer deux valeurs conseacutecutives

2 Les deux fonctions dinsertion dun eacuteleacutement fournissent une valeur de retour qui est une

paire de la forme pair(position indic) dans laquelle le booleacuteen indic preacutecise si linser-

tion a eu lieu et position est liteacuterateur correspondant on notera que son utilisation est

assez laborieuse voici par exemple comment adapter notre preacuteceacutedent exemple dans

ce sens

if(m1insert(make_pair(5 625f))second) cout ltlt insertion effectueacuteen else cout ltlt eacuteleacutement existantn

Les conteneurs associatifsCHAPITRE 20

446

Et encore ici nous navons pas chercheacute agrave placer la valeur de retour dans une variable

Si nous avions voulu le faire il aurait fallu deacuteclarer une variable par exemple resul

dun type pair approprieacute de plus comme pair ne dispose pas de constructeur par

deacutefaut il aurait fallu preacuteciser des arguments fictifs voici une deacuteclaration possible

pairltmapltintfloatgtiterator boolgt resul(m1end()false)

Dans les impleacutementations qui nacceptent pas la valeur lesslttypegt par deacutefaut les cho-

ses seraient encore un peu plus complexes et il serait probablement plus sage de recou-

rir agrave des deacutefinitions de types synonymes (typedef ) pour alleacuteger quelque peu leacutecriture

152 Suppressions

La fonction erase permet de supprimer

bull un eacuteleacutement de position donneacutee

erase (position) supprime leacuteleacutement deacutesigneacute par position

bull les eacuteleacutements dun intervalle

erase (deacutebut fin) supprime les paires de lintervalle [deacutebut fin)

bull leacuteleacutement de cleacute donneacutee

erase (cleacute) supprime les eacuteleacutements1 de cleacute eacutequivalente agrave cleacute

En voici quelques exemples

mapltint floatgt m mapltint floatgtiterator im1 im2 merase (5) supprime leacuteleacutement de cleacute 5 sil existe merase (im1) supprime leacuteleacutement deacutesigneacute par im1 merase (im2 mend()) supprime tous les eacuteleacutements depuis celui deacutesigneacute par im2 jusquagrave la fin du conteneur m

Enfin de faccedilon fort classique la fonction clear() vide le conteneur de tout son contenu

Remarque

Il peut arriver que lon souhaite supprimer tous les eacuteleacutements dont la cleacute appartient agrave un

intervalle donneacute Dans ce cas on pourra avoir recours aux fonctions lower_bound et

upper_bound preacutesenteacutees au paragraphe 2

16 Gestion meacutemoire Contrairement agrave ce qui se passe pour certains conteneurs seacutequentiels les opeacuterations sur les

conteneurs associatifs donc en particulier sur map nentraicircnent jamais dinvalidation des

1 Pour map il y en aura un au plus pour multimap on pourra en trouver plusieurs

1 - Le conteneur map447

reacutefeacuterences et des iteacuterateurs excepteacute bien entendu pour les eacuteleacutements supprimeacutes qui ne sont

plus accessibles apregraves leur destruction

Toutefois comme on la indiqueacute au paragraphe 14 il est theacuteoriquement possible bien que

fortement deacuteconseilleacute de modifier globalement un eacuteleacutement de position donneacutee par exemple

(iv deacutesignant un iteacuterateur valide sur un conteneur de type mapltchar intgt)

iv = make_pair (S 45)

Que la cleacute S soit preacutesente ou non on court outre les risques deacutejagrave eacutevoqueacutes celui que liteacutera-

teur iv devienne invalide

17 Autres possibiliteacutes Les manipulations globales des conteneurs map se limitent agrave la seule affectation et agrave la fonc-

tion swap permettant deacutechanger les contenus de deux conteneurs de mecircme type Il nexiste

pas de fonction assign ni de possibiliteacutes de comparaisons lexicographiques auxquelles il

serait difficile de donner une signification en effet dune part les eacuteleacutements sont des paires

dautre part un tel conteneur est ordonneacute intrinsegravequement et son organisation eacutevolue en per-

manence

En theacuteorie il existe des fonctions membres lower_bound upper_bound equal_range et

count qui sont utilisables aussi bien avec des conteneurs de type map quavec des conteneurs

de type multimap Cest cependant dans ce dernier cas quelles preacutesentent le plus dinteacuterecirct

elles seront eacutetudieacutees au paragraphe 2

18 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

map que nous venons dexaminer

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche(mapltchar intgt) mapltchar intgt m mapltchar intgtiterator im m[c] = 10 m[f] = 20 m[x] = 30 m[p] = 40 cout ltlt map initial affiche(m) im = mfind (f) ici on ne verifie pas que im est = mend() cout ltlt cle f avant insert ltlt (im)first ltlt n minsert (make_pair(a 5)) on insere un element avant f minsert (make_pair(t 7)) et un element apres f cout ltlt map apres insert affiche(m) cout ltlt cle f apres insert ltlt (im)first ltlt n im -gt f merase(c) cout ltlt map apres erase c affiche(m) im = mfind(p) if (im = mend()) merase(im mend()) cout ltlt map apres erase int affiche(m)

Les conteneurs associatifsCHAPITRE 20

448

void affiche(mapltchar intgt m) voir remarque paragraphe 24 du chapitre 19

mapltchar intgtiterator im

for (im=mbegin() im=mend() im++)

cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt )

cout ltlt n

map initial (c10) (f20) (p40) (x30)

cle f avant insert f

map apres insert (a5) (c10) (f20) (p40) (t7) (x30)

cle f apres insert f

map apres erase c (a5) (f20) (p40) (t7) (x30)

map apres erase int (a5) (f20)

Exemple dutilisation de la classe map

2 Le conteneur multimap

21 Preacutesentation geacuteneacuterale Comme nous lavons deacutejagrave dit dans un conteneur de type multimap une mecircme cleacute peut appa-

raicirctre plusieurs fois ou plus geacuteneacuteralement on peut trouver plusieurs cleacutes eacutequivalentes Bien

entendu les eacuteleacutements correspondants apparaissent alors conseacutecutifs Comme on peut sy

attendre lopeacuterateur [ ] nest plus applicable agrave un tel conteneur compte tenu de lambiguiumlteacute

quinduirait la non-uniciteacute des cleacutes Hormis cette restriction les possibiliteacutes des conteneurs

map se geacuteneacuteralisent sans difficulteacutes aux conteneurs multimap qui possegravedent les mecircmes fonc-

tions membres avec quelques nuances qui vont de soi

bull sil existe plusieurs cleacutes eacutequivalentes la fonction membre find fournit un iteacuterateur sur un des

eacuteleacutements ayant la cleacute voulue attention on ne preacutecise pas quil sagit du premier celui-ci

peut cependant ecirctre connu en recourant agrave la fonction lower_bound examineacutee un peu plus

loin

bull la fonction membre erase (cleacute) peut supprimer plusieurs eacuteleacutements tandis quavec un conte-

neur map elle nen supprimait quun seul au maximum

Dautre part comme nous lavons deacutejagrave fait remarquer un certain nombre de fonctions mem-

bres de la classe map prennent tout leur inteacuterecirct lorsquon les applique agrave un conteneur multi-

map On peut en effet

bull connaicirctre le nombre deacuteleacutements ayant une cleacute eacutequivalente agrave une cleacute donneacutee agrave laide de count

(cleacute)

bull obtenir des informations concernant lintervalle deacuteleacutements ayant une cleacute eacutequivalente agrave une

cleacute donneacutee agrave savoir

2 - Le conteneur multimap449

lower_bound (cleacute) fournit un iteacuterateur sur le premier eacuteleacutement ayant

une cleacute eacutequivalente agrave cleacute

upper__bound (cleacute) fournit un iteacuterateur sur le dernier eacuteleacutement ayant

une cleacute eacutequivalente agrave cleacute

equal_range (cleacute) fournit une paire formeacutee des valeurs des deux iteacuterateurs

preacuteceacutedents lower_bound (cleacute) et upper_bound (cleacute)

On notera quon a la relation

mequalrange(cleacute) = make_pair (mlower_bound (cleacute) mupper_bound (cleacute) )

Voici un petit exemple

multimapltchar intgt m merase(mlower_bound(c) mupper_bound(c)) eacutequivalent agrave erase(c) merase(mlower_bound(e) mupper_bound(g)) supprime toutes les cleacutes allant de e agrave g aucun eacutequivalent simple

Remarque

Le deuxiegraveme appel de erase de notre preacuteceacutedent exemple peut preacutesenter un inteacuterecirct dans le

cas dun conteneur de type map en effet malgreacute luniciteacute des cleacutes dans ce cas il nest pas

certain quun appel tel que

merase (mfind(e) mfind(g))

convienne puisquon court le risque que lune au moins des cleacutes e ou g nexiste pas

22 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

multimap que nous venons dexaminer

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche(multimapltchar intgt) multimapltchar intgt m m_bis multimapltchar intgtiterator im minsert(make_pair(c 10)) minsert(make_pair(f 20)) minsert(make_pair(x 30)) minsert(make_pair(p 40)) minsert(make_pair(y 40)) minsert(make_pair(p 35)) cout ltlt map initial n affiche(m) minsert(make_pair(f 25)) minsert(make_pair(f 20)) minsert(make_pair(x 2)) cout ltlt map avec fff et xx n affiche(m)

Les conteneurs associatifsCHAPITRE 20

450

im=mfind(x) on ne verifie pas que im = mend() m_bis = m on fait une copie de m dans m_bis merase(im) cout ltlt map apres erase(find(x)) n affiche(m) merase(f) cout ltlt map apres erase(f) n affiche(m) mswap(m_bis) cout ltlt map apres swap n affiche(m) cout ltlt il y a ltlt mcount(f) ltlt fois la cle fn merase(mupper_bound(f)) supprime derniere cle f - ici pas de test cout ltlt map apres erase (u_b(f)) n affiche(m) merase(mlower_bound(f)) cout ltlt map apres erase (l_b(f)) n affiche(m) merase(mupper_bound(g)) cout ltlt map apres erase (u_b(g)) n affiche(m) merase(mlower_bound(g)) cout ltlt map apres erase (l_b(g)) n affiche(m) merase(mlower_bound(d) mupper_bound(x)) cout ltlt map apres erase (l_b(d) u_b(x)) n affiche(m) void affiche(multimapltchar intgt m) voir remarque paragraphe 24 du chapitre 19 multimapltchar intgtiterator im for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt ) cout ltlt n

map initial (c10)(f20)(p40)(p35)(x30)(y40)map avec fff et xx (c10)(f20)(f25)(f20)(p40)(p35)(x30)(x2)(y40)map apres erase(find(x)) (c10)(f20)(f25)(f20)(p40)(p35)(x2)(y40)map apres erase(f) (c10)(p40)(p35)(x2)(y40)map apres swap (c10)(f20)(f25)(f20)(p40)(p35)(x30)(x2)(y40)il y a 3 fois la cle fmap apres erase (u_b(f)) (c10)(f20)(f25)(f20)(p35)(x30)(x2)(y40)map apres erase (l_b(f)) (c10)(f25)(f20)(p35)(x30)(x2)(y40)map apres erase (u_b(g)) (c10)(f25)(f20)(x30)(x2)(y40)map apres erase (l_b(g)) (c10)(f25)(f20)(x2)(y40)map apres erase (l_b(d) u_b(x)) (c10)(y40)

Exemple dutilisation de multimap

3 - Le conteneur set451

3 Le conteneur set

31 Preacutesentation geacuteneacuterale Comme il a eacuteteacute dit en introduction le conteneur set est un cas particulier du conteneur map

dans lequel aucune valeur nest associeacutee agrave la cleacute Les eacuteleacutements dun conteneur set ne sont

donc plus des paires ce qui en facilite naturellement la manipulation Une autre diffeacuterence

entre les conteneurs set et les conteneurs map est quun eacuteleacutement dun conteneur set est une

constante on ne peut pas en modifier la valeur

setltintgt e() ensemble dentiers setltintgtiterator ie iteacuterateur sur un ensemble dentiers cout ltlt ie correct ie = interdit

En dehors de cette contrainte les possibiliteacutes dun conteneur set se deacuteduisent tout naturelle-

ment de celles dun conteneur map aussi bien pour sa construction que pour linsertion ou la

suppression deacuteleacutements qui quant agrave elle reste toujours possible aussi bien agrave partir dune posi-

tion que dune valeur

32 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

set (attention le caractegravere espace nest pas tregraves visible dans les reacutesultats )

include ltiostreamgtinclude ltsetgtinclude ltstringgtusing namespace std

main() char t[] = je me figure ce zouave qui joue du xylophone char v[] = aeiouy void affiche (setltchargt ) setltchargt let(t t+sizeof(t)-1) let_bis setltchargt voy(v v+sizeof(v)-1)

cout ltlt lettres presentes affiche (let) cout ltlt il y a ltlt letsize() ltlt lettres differentesn if (letcount(z)) cout ltlt la lettre z est presenten if (letcount(b)) cout ltlt la lettre b nest pas presenten

let_bis = let setltchargt iterator iv for (iv=voybegin() iv=voyend() iv++) leterase(iv)

Les conteneurs associatifsCHAPITRE 20

452

cout ltlt lettres sans voyelles affiche (let) letinsert(voybegin() voyend()) cout ltlt lettres + toutes voyelles affiche (let)

void affiche (setltchargt e ) voir remarque paragraphe 24 du chapitre 19 setltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie ltlt cout ltlt n

lettres presentes a c d e f g h i j l m n o p q r u v x y zil y a 22 lettres differentesla lettre z est presentela lettre b nest pas presentelettres sans voyelles c d f g h j l m n p q r v x zlettres + toutes voyelles a c d e f g h i j l m n o p q r u v x y z

Exemple dutilisation du conteneur set

33 Le conteneur set et lensemble matheacutematique Un conteneur de type set est obligatoirement ordonneacute tandis quun ensemble matheacutematique

ne lest pas neacutecessairement Il faudra tenir compte de cette remarque degraves que lon sera ameneacute

agrave creacuteer un ensemble dobjets puisquil faudra alors munir la classe correspondante dune rela-

tion dordre faible strict En outre il ne faudra pas perdre de vue que cest cette relation qui

sera utiliseacutee pour deacutefinir leacutegaliteacute de deux eacuteleacutements et non une eacuteventuelle surdeacutefinition de

lopeacuterateur ==

Par ailleurs dans la classe set il nexiste pas de fonction membre permettant de reacutealiser les

opeacuterations ensemblistes classiques (intersection reacuteunion) Cependant nous verrons au cha-

pitre 21 quil existe des algorithmes geacuteneacuteraux utilisables avec nimporte quelle seacutequence

ordonneacutee Leur application au cas particulier des ensembles permettra de reacutealiser les opeacutera-

tions en question

4 Le conteneur multisetDe mecircme que le conteneur multimap est un conteneur map dans lequel on autorise plusieurs

cleacutes eacutequivalentes le conteneur multiset est un conteneur set dans lequel on autorise plu-

sieurs eacuteleacutements eacutequivalents agrave apparaicirctre Il correspond agrave la notion matheacutematique de multi-

ensemble (peu reacutepandue) avec cette diffeacuterence que la relation drsquoordre neacutecessaire agrave la deacutefini-

tion drsquoun multiset ne lrsquoest pas dans le multi-ensemble matheacutematique Les algorithmes geacuteneacute-

raux drsquointersection ou de reacuteunion eacutevoqueacutes ci-dessus fonctionneront encore dans le cas des

conteneurs multiset

5 - Conteneurs associatifs et algorithmes453

Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

multiset (attention le caractegravere espace nest pas tregraves visible dans les reacutesultats )

include ltiostreamgtinclude ltsetgtusing namespace std

main() char t[] = je me figure ce zouave qui joue du xylophone char v[] = aeiouy void affiche (multisetltchargt ) multisetltchargt let(t t+sizeof(t)-1) let_bis multisetltchargt voy(v v+sizeof(v)-1) cout ltlt lettres presentes affiche (let) cout ltlt il y a ltlt letsize() ltlt lettres en toutn cout ltlt la lettre e est presente ltlt letcount(e) ltlt foisn cout ltlt la lettre b est presente ltlt letcount(b) ltlt foisn let_bis = let multisetltchargt iterator iv for (iv=voybegin() iv=voyend() iv++) leterase(iv) cout ltlt lettres sans voyelles affiche (let)

void affiche (multisetltchargt e ) voir remarque paragraphe 24 du chapitre 19 multisetltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie cout ltlt n

lettres presentes acdeeeeeeefghiijjlmnoooopqruuuuuvxyzil y a 44 lettres en toutla lettre e est presente 7 foisla lettre b est presente 0 foislettres sans voyelles cdfghjjlmnpqrvxz

Exemple dutilisation du conteneur multiset

5 Conteneurs associatifs et algorithmes Il est geacuteneacuteralement difficile dappliquer certains algorithmes geacuteneacuteraux aux conteneurs asso-

ciatifs Il y a plusieurs raisons agrave cela

Tout dabord un conteneur de type map ou multimap est formeacute deacuteleacutements de pair qui se precirc-

tent assez difficilement aux algorithmes usuels Par exemple une recherche par find devrait

Les conteneurs associatifsCHAPITRE 20

454

se faire sur la paire (cleacute valeur) ce qui ne preacutesente geacuteneacuteralement guegravere dinteacuterecirct on preacutefeacute-

rera utiliser la fonction membre find travaillant sur une cleacute donneacutee

De mecircme vouloir trier un conteneur associatif deacutejagrave ordonneacute de faccedilon intrinsegraveque nest guegravere

reacutealiste soit on cherche agrave trier suivant lordre interne ce qui na aucun inteacuterecirct soit on cher-

che agrave trier suivant un autre ordre et alors apparaissent des conflits entre les deux ordres

Neacuteanmoins il reste possible dappliquer tout algorithme qui ne modifie pas les valeurs du

conteneur

Dune maniegravere geacuteneacuterale dans le chapitre 21 consacreacute aux algorithmes nous indiquerons ceux

qui sont utilisables avec des conteneurs associatifs

21

Les algorithmes standard

La notion dalgorithme a deacutejagrave eacuteteacute preacutesenteacutee au chapitre 18 et nous avons eu loccasion den

utiliser quelques-uns dans certains de nos preacuteceacutedents exemples Le preacutesent chapitre expose

les diffeacuterentes possibiliteacutes offertes par les algorithmes de la bibliothegraveque standard Aupara-

vant il preacutesente ou rappelle un certain nombre de notions geacuteneacuterales qui interviennent dans

leur utilisation en particulier les cateacutegories diteacuterateur la notion de seacutequence les iteacuterateurs

de flot et les iteacuterateurs dinsertion

On notera bien que ce chapitre vise avant tout agrave faire comprendre le rocircle des diffeacuterents algo-

rithmes et agrave illustrer les plus importants par des exemples de programmes On trouvera dans

lrsquoAnnexe C une reacutefeacuterence complegravete du rocircle preacutecis de lefficaciteacute et de la syntaxe exacte de

lappel de chacun des algorithmes existants

1 Notions geacuteneacuterales

11 Algorithmes et iteacuterateurs Les algorithmes standard se preacutesentent sous forme de patrons de fonctions Leur code est

eacutecrit sans connaissance preacutecise des eacuteleacutements quils seront ameneacutes agrave manipuler Cependant

cette manipulation ne se fait jamais directement mais toujours par lintermeacutediaire dun iteacutera-

teur qui quant agrave lui possegravede un type donneacute agrave partir duquel se deacuteduit le type des eacuteleacutements

effectivement manipuleacutes Par exemple lorsquun algorithme contient une instruction de la

forme

it =

Les algorithmes standardCHAPITRE 21

456

le code source du programme ne connaicirct effectivement pas le type de leacuteleacutement qui sera ainsi

manipuleacute mais ce type sera parfaitement deacutefini agrave la compilation lors de linstanciation de la

fonction patron correspondant agrave lalgorithme en question

12 Les cateacutegories diteacuterateurs Jusquici nous avons surtout manipuleacute des eacuteleacutements de conteneurs et les iteacuterateurs associeacutes

qui se reacutepartissaient alors en trois cateacutegories unidirectionnel bidirectionnel et agrave accegraves direct

En fait il existe deux autres cateacutegories diteacuterateurs disposant de proprieacuteteacutes plus restrictives

que les iteacuterateurs unidirectionnels il sagit des iteacuterateurs en entreacutee et des iteacuterateurs en sortie

Bien quils ne soient fournis par aucun des conteneurs ils preacutesentent un inteacuterecirct au niveau des

iteacuterateurs de flot qui comme nous le verrons un peu plus loin permettent dacceacuteder agrave un flot

comme agrave une seacutequence

121 Iteacuterateur en entreacuteeUn iteacuterateur en entreacutee possegravede les mecircmes proprieacuteteacutes quun iteacuterateur unidirectionnel avec

cette diffeacuterence quil nautorise que la consultation de la valeur correspondante et plus sa

modification si it est un tel iteacuterateur

= it correct si it est un iteacuterateur en entreacutee it = impossible si it est un iteacuterateur en entreacutee

En outre un iteacuterateur en entreacutee nautorise quun seul passage (on dit aussi une seule passe) sur

les eacuteleacutements quil permet de deacutecrire Autrement dit si agrave un moment donneacute it1==it2 it1++

et it2++ ne deacutesignent pas neacutecessairement la mecircme valeur Cette restriction nexistait pas dans

le cas des iteacuterateurs unidirectionnels Ici elle se justifie degraves lors quon sait que liteacuterateur en

entreacutee est destineacute agrave la lecture dune suite de valeurs de mecircme type sur un flot dune faccedilon

analogue agrave la lecture des informations dune seacutequence Or manifestement il nest pas possi-

ble de lire deux fois une mecircme valeur sur certains flots tels que luniteacute dentreacutee standard

122 Iteacuterateur en sortieDe faccedilon concomitante un iteacuterateur en sortie possegravede les mecircmes proprieacuteteacutes quun iteacuterateur

unidirectionnel avec cette diffeacuterence quil nautorise que la modification et en aucun cas la

consultation Par exemple si it est un tel iteacuterateur

it = correct si it est un iteacuterateur en sortie = it impossible si it est un iteacuterateur en sortie

Comme liteacuterateur en entreacutee liteacuterateur en sortie ne permettra quun seul passage si agrave un

moment donneacute on a it1==it2 les affectations successives

it1++ = it2++ =

entraicircneront la creacuteation de deux valeurs distinctes Lagrave encore pour mieux comprendre ces

restrictions il faut voir que la principale justification de liteacuterateur en sortie est de permettre

deacutecrire une suite de valeur de mecircme type sur un flot de la mecircme faccedilon quon peut introduire

des informations dans une seacutequence Or manifestement il nest pas possible deacutecrire deux

fois en un mecircme endroit de certains flots tels que luniteacute standard de sortie

1 - Notions geacuteneacuterales457

123 Hieacuterarchie des cateacutegories diteacuterateurs

On peut montrer que les proprieacuteteacutes des cinq cateacutegories diteacuterateurs permettent de les ranger

selon une hieacuterarchie dans laquelle toute cateacutegorie possegravede au moins les proprieacuteteacutes de la cateacute-

gorie preacuteceacutedente

iteacuterateur en entreacutee iteacuterateur en sortie

|___________________________|

|

iteacuterateur unidirectionnel

|

iteacuterateur bidirectionnel

|

iteacuterateur agrave accegraves direct

Les iteacuterateurs en entreacutee et en sortie seront freacutequemment utiliseacutes pour associer un iteacuterateur agrave

un flot en faisant appel agrave un adaptateur particulier diteacuterateur dit iteacuterateur de flot nous y

reviendrons au paragraphe 15 En dehors de cela ils preacutesentent un inteacuterecirct indirect agrave propos

de linformation quon peut deacuteduire au vu de la cateacutegorie diteacuterateur attendu par un

algorithme par exemple si un algorithme accepte un iteacuterateur en entreacutee cest que dune

part il ne modifie pas la seacutequence correspondante et que dautre part il neffectue quune

seule passe sur cette seacutequence

13 Algorithmes et seacutequences Beaucoup dalgorithmes sappliquent agrave une seacutequence deacutefinie par un intervalle diteacuterateur de la

forme [deacutebut fin) dans ce cas on lui communiquera simplement en argument les deux

valeurs deacutebut et fin lesquelles devront naturellement ecirctre du mecircme type sous peine derreur

de compilation

Tant que lalgorithme ne modifie pas les eacuteleacutements de cette seacutequence cette derniegravere peut

appartenir agrave un conteneur de nimporte quel type y compris les conteneurs associatifs pour

lesquels rappelons-le la notion de seacutequence a bien un sens compte tenu de leur ordre

interne Cependant dans le cas des types map ou multimap on sera geacuteneacuteralement gecircneacute par le

fait que leurs eacuteleacutements sont des paires

En revanche si lalgorithme modifie les eacuteleacutements de la seacutequence il nest plus possible quelle

appartienne agrave un conteneur de type set et multiset puisque les eacuteleacutements nen sont plus modi-

fiables Bien quil nexiste pas dinterdiction formelle il nest guegravere raisonnable quelle appar-

tienne agrave un conteneur de type map ou multimap compte tenu des risques dincompatibiliteacute

qui apparaissent alors entre lorganisation interne et celle quon chercherait agrave lui imposer

Certains algorithmes sappliquent agrave deux seacutequences de mecircme taille Cest par exemple le cas

de la recopie dune seacutequence dans une autre ayant des eacuteleacutements de mecircme type Dans ce cas

tous ces algorithmes procegravedent de la mecircme faccedilon agrave savoir

bull deux arguments deacutefinissent classiquement un premier intervalle correspondant agrave la premiegrave-

re seacutequence

Les algorithmes standardCHAPITRE 21

458

bull un troisiegraveme argument fournit la valeur dun iteacuterateur deacutesignant le deacutebut de la seconde seacute-

quence

On notera bien que cette faccedilon de proceacuteder preacutesente manifestement le risque que la seacutequence

cible soit trop petite Dans ce cas le comportement du programme est indeacutetermineacute comme il

pouvait lecirctre en cas de deacutebordement dun tableau classique dailleurs rien ninterdit de four-

nir agrave un algorithme un iteacuterateur qui soit un pointeur

Enfin quelques rares algorithmes fournissent comme valeur de retour les limites dun inter-

valle sous forme de deux iteacuterateurs dans ce cas celles-ci seront regroupeacutees au sein dune

structure de type pair

14 Iteacuterateur dinsertion Beaucoup dalgorithmes sont preacutevus pour modifier les valeurs des eacuteleacutements dune seacutequence

cest par exemple le cas de copy

copy (vbegin() vend() lbegin())

recopie lintervalle [vbegin() vend() )

agrave partir de la position lbegin()

De telles opeacuterations imposent naturellement un certain nombre de contraintes

bull les emplacements neacutecessaires agrave la copie doivent deacutejagrave exister

bull leur modification doit ecirctre autoriseacutee ce qui nest pas le cas pour des conteneurs de type set

ou multiset

bull la copie ne doit pas se faire agrave linteacuterieur dun conteneur associatif de type map ou multimap

compte tenu de lincompatibiliteacute qui reacutesulterait entre lordre seacutequentiel imposeacute et lordre in-

terne du conteneur

En fait il existe un meacutecanisme particulier permettant de transformer une succession dopeacutera-

tions de copie agrave partir dune position donneacutee en une succession dinsertions agrave partir de cette

position Pour ce faire on fait appel agrave ce quon nomme un iteacuterateur dinsertion il sagit dun

patron de classes nommeacute insert_iterator et parameacutetreacute par un type de conteneur Par exemple

insert_iterator ltlistltintgt gt ins ins est un iteacuterateur dinsertion

dans un conteneur de type listltintgt

Pour affecter une valeur agrave un tel iteacuterateur on se sert du patron de fonction inserter en voici

un exemple dans lequel on suppose que c est un conteneur et it est une valeur particuliegravere

diteacuterateur sur ce conteneur

ins = inserter(c it) valeur initiale dun iteacuterateur dinsertion

permettant dinseacuterer agrave partir de la

position it dans le conteneur c

Dans ces conditions lutilisation de ins en lieu et place dune valeur initiale diteacuterateur fera

quune instruction telle que ins = inseacuterera un nouvel eacuteleacutement en position it De plus toute

increacutementation de ins suivie dune nouvelle affectation ins= provoquera une nouvelle

insertion agrave la suite de leacuteleacutement preacuteceacutedent

1 - Notions geacuteneacuterales459

Dune maniegravere geacuteneacuterale il existe trois fonctions permettant de deacutefinir une valeur initiale dun

iteacuterateur dinsertion agrave savoir

bull front_inserter (conteneur) pour une insertion en deacutebut du conteneur le conteneur doit dis-

poser de la fonction membre push_front

bull back_inserter (conteneur) pour une insertion en fin du conteneur le conteneur doit dispo-

ser de la fonction membre push_back

bull inserter (conteneur position) pour une insertion agrave partir de position dans le conteneur le

conteneur doit disposer de la fonction membre insert(valeur position)

Voici un exemple de programme utilisant un tel meacutecanisme pour transformer une copie dans

des eacuteleacutements existant en une insertion auparavant on a tenteacute une copie usuelle dans un con-

teneur trop petit pour montrer quelle se deacuteroulait mal en pratique nous deacuteconseillons ce

genre de proceacutedeacute qui peut tregraves bien amener agrave un plantage du programme

include ltiostreamgtinclude ltlistgtinclude ltalgorithmgtusing namespace std main() void affiche (listltchargt) char t[] = essai insert_iterator listltchargt l1(t t+sizeof(t)-1) listltchargt l2 (4 x) listltchargt l3 cout ltlt l1 initiale affiche(l1) cout ltlt l2 initiale affiche(l2) copie avec liste l2 de taille insuffisante deconseille en pratique copy (l1begin() l1end() l2begin()) cout ltlt l2 apres copie usuelle affiche(l2) insertion dans liste non vide on pourrait utiliser aussi front_inserter(l2) copy (l1begin() l1end() inserter(l2 l2begin())) cout ltlt l2 apres copie inser affiche(l2) insertion dans liste vide on pourrait utiliser aussi front_inserter(l3) ou back_inserter(l3) copy (l1begin() l1end() inserter(l3 l3begin())) cout ltlt l3 apres copie inser affiche(l3) void affiche (listltchargt l) void af_car (char) for_each(lbegin() lend() af_car) appelle af_car pour chaque element cout ltlt n void af_car (char c) cout ltlt c ltlt

Les algorithmes standardCHAPITRE 21

460

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

Exemple dutilisation dun iteacuterateur dinsertion

Remarque

Si lon tient agrave mettre en eacutevidence lexistence dune classe insert_iterator la simple instruc-

tion du preacuteceacutedent programme

copy (l1begin() l1end() inserter(l2 l2begin()))

peut se deacutecomposer ainsi

insert_iteratorltlistltchargt gt ins = inserter(l2 l2begin())

copy (l1begin() l1end() ins )

15 Iteacuterateur de flot

151 Iteacuterateur de flot de sortie

Lorsquon lit par exemple sur lentreacutee standard une suite dinformations de mecircme type on

peut consideacuterer quon parcourt une seacutequence Effectivement il est possible de deacutefinir un iteacute-

rateur sur une telle seacutequence ne disposant que des proprieacuteteacutes dun iteacuterateur dentreacutee telles

quelles ont eacuteteacute deacutefinies preacuteceacutedemment Pour ce faire il existe un patron de classes nommeacute

ostream_iterator parameacutetreacute par le type des eacuteleacutements concerneacutes par exemple

ostream_iteratorltchargt type iteacuterateur sur un flot dentreacutee de caractegraveres

Cette classe dispose dun constructeur recevant en argument un flot existant Cest ainsi que

ostream_iteratorltchargt flcar(cout) flcar est un iteacuterateur sur un flot de

caractegraveres connecteacute agrave cout

Dans ces conditions une instruction telle que

flcar = x

envoie le caractegravere x sur le flot cout

On notera quil est theacuteoriquement possible dincreacutementer liteacuterateur flcar en eacutecrivant

flcar++ cependant une telle opeacuteration est sans effet car sans signification agrave ce niveau Son

existence est cependant preacutecieuse puisquelle permettra dutiliser un tel iteacuterateur avec certains

algorithmes standard tels que copy

Voici un exemple reacutesumant ce que nous venons de dire

1 - Notions geacuteneacuterales461

include ltiostreamgt

include ltlistgt

using namespace std

main()

char t[] = essai iterateur de flot

listltchargt l(t t+sizeof(t)-1)

ostream_iteratorltchargt flcar(cout)

flcar = x flcar = -

flcar++ flcar++ pour montrer que lincrementation est inoperante ici

flcar =

copy (lbegin() lend() flcar)

x-essai iterateur de flot

Exemple dutilisation dun iteacuterateur de flot de sortie

Remarque

Ici notre exemple sappliquait agrave la sortie standard dans ces conditions lutilisation

dinformations de type autre que char poserait le problegraveme de leur seacuteparation agrave laffichage

ou dans le fichier texte correspondant En revanche lapplication agrave un fichier binaire quel-

conque ne poserait plus aucun problegraveme

152 Iteacuterateur de flot dentreacutee

De mecircme quon peut deacutefinir des iteacuterateurs de flot de sortie on peut deacutefinir des iteacuterateurs de

flot dentreacutee suivant un proceacutedeacute tregraves voisin Par exemple avec

istream_iteratorltintgt flint(cin)

on deacutefinit un iteacuterateur nommeacute flint sur un flot dentreacutee dentiers connecteacute agrave cin De la mecircme

maniegravere avec

ifstream fich(essai iosin)

istream_iteratorltintgt flint(fich)

on deacutefinit un iteacuterateur nommeacute flint sur un flot dentreacutee dentiers connecteacute au flot fich sup-

poseacute convenablement ouvert

Les iteacuterateurs de flot dentreacutee neacutecessitent cependant la possibiliteacute den deacutetecter la fin Pour ce

faire il existe une convention permettant de construire un iteacuterateur en repreacutesentant la fin agrave

savoir lutilisation dun constructeur sans argument par exemple avec

istream_iteratorltintgt fin fin est un iteacuterateur repreacutesentant une fin

de fichier sur un iteacuterateur de flot dentiers

Les algorithmes standardCHAPITRE 21

462

Voici par exemple comment utiliser un iteacuterateur de flot dentreacutee pour recopier les informa-

tions dun fichier dans une liste ici nous creacuteons une liste vide et nous utilisons un iteacuterateur

dinsertion pour y introduire le reacutesultat de la copie

listltintgt l ifstream fich(essai iosin) istream_iteratorltint ptrdiff_tgt flint(fich) fin copy (flint fin inserter(l lbegin()))

2 Algorithmes dinitialisation de seacutequences existantes

Tous ces algorithmes permettent de donner des valeurs agrave des eacuteleacutements existant dune

seacutequence dont la valeur est donc remplaceacutee De par leur nature mecircme ils ne sont pas adapteacutes

aux conteneurs associatifs agrave moins dutiliser un iteacuterateur dinsertion et de tenir compte de la

nature de type pair de leurs eacuteleacutements

21 Copie dune seacutequence dans une autre Comme on la deacutejagrave vu agrave plusieurs reprises on peut recopier une seacutequence dans une autre

pour peu que les types des eacuteleacutements soient les mecircmes Par exemple si l est une liste dentiers

et v un vecteur dentiers

copy (lbegin() lend() vbegin()) recopie les eacuteleacutements de la liste l dans le vecteur v agrave partir de son deacutebut

Le sens de la copie est imposeacute agrave savoir quon commence bien par recopier lbegin() en

vbegin() La seule contrainte (logique) qui soit imposeacutee aux valeurs des iteacuterateurs est que la

position de la premiegravere copie nappartienne pas agrave lintervalle agrave copier En revanche rien

ninterdirait par exemple

copy (vbegin()+1 vbegin()+10 vbegin()) recopie v[1] dans v[0] v[2] dans v[1] v[9] dans v[8]

Il existe eacutegalement un algorithme copy_backward qui procegravede agrave la copie dans lordre inverse

de copy crsquoest-agrave-dire en commenccedilant par le dernier eacuteleacutement Dans ce cas comme on peut sy

attendre les iteacuterateurs correspondants doivent ecirctre bidirectionnels

Voici un exemple de programme utilisant copy pour reacutealiser des copies usuelles ainsi que des

insertions par le biais dun iteacuterateur dinsertion

include ltiostreamgtinclude ltvectorgtinclude ltlistgtinclude ltalgorithmgtusing namespace std

2 - Algorithmes dinitialisation de seacutequences existantes463

main() int t[5] = 1 2 3 4 5 vectorltintgt v(t t+5) v contient 1 2 3 4 5 listltintgt l(8 0) liste de 8 elements egaux a 0 listltintgt l2(3 0) liste de 3 elements egaux a 0 void affiche(vectorltintgt) void affiche(listltintgt) cout ltlt liste initiale affiche(l) copy (vbegin() vend() lbegin()) cout ltlt liste apres copie 1 affiche(l) l = l2 l contient maintenant 3 elements eacutegaux agrave 0 copy (vbegin() vend() lbegin()) sequence trop courte deconseille cout ltlt liste apres copie 2 affiche(l) lerase(lbegin() lend()) l est maintenant vide on y insere les elem de v copy (vbegin() vend() inserter(l lbegin())) cout ltlt liste apres copie 3 affiche(l) void affiche(listltintgt l) listltintgtiterator il for (il=lbegin() il=lend() il++) cout ltlt il ltlt cout ltlt n

liste initiale 0 0 0 0 0 0 0 0liste apres copie 1 1 2 3 4 5 0 0 0liste apres copie 2 5 2 3liste apres copie 3 1 2 3 4 5

Exemple de copies usuelles et de copies avec insertion

22 Geacuteneacuteration de valeurs par une fonction Il est freacutequent quon ait besoin dinitialiser un conteneur par des valeurs reacutesultant dun calcul

La bibliothegraveque standard offre un outil assez geacuteneacuteral agrave cet effet agrave savoir ce quon nomme

souvent un algorithme geacuteneacuterateur On lui fournit en argument un objet fonction (il peut donc

sagir dune fonction ordinaire) quil appellera pour deacuteterminer la valeur agrave attribuer agrave chaque

eacuteleacutement dun intervalle Une telle fonction ne reccediloit aucun argument Par exemple lappel

generate (vbegin() vend() suite)

utilisera la fonction suite pour donner une valeur agrave chacun des eacuteleacutements de la seacutequence deacutefi-

nie par lintervalle [vbegin() vend())

Voici un premier exemple faisant appel agrave une fonction ordinaire

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

Les algorithmes standardCHAPITRE 21

464

main() int n = 10 vectorltintgt v(n 0) vecteur de n elements initialises a 0 int suite() fonction utilisee pour la generation dentiers void affiche(vectorltintgt) cout ltlt vecteur initial affiche(v) generate (vbegin() vend() suite) cout ltlt vecteur genere affiche(v) int suite() static int n = 0 return n++

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 0 0 0 0 0 0 0 0 0 0vecteur genere 0 1 2 3 4 5 6 7 8 9

Geacuteneacuteration de valeurs par une fonction ordinaire

On constate quil est difficile dimposer une valeur initiale agrave la suite de nombres autrement

quen la fixant dans la fonction elle-mecircme en particulier il nest pas possible de la choisir en

argument Cest lagrave preacuteciseacutement que la notion de classe fonction savegravere inteacuteressante comme le

montre lexemple suivant

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std class sequence classe fonction utilisee pour la generation dentiers public sequence (int i) n = i constructeur int operator() () return n++ ne pas oublier () private int n valeur courante generee

2 - Algorithmes dinitialisation de seacutequences existantes465

main() int n = 10 vectorltintgt v(n 0) vecteur de n elements initialises a 0 void affiche(vectorltintgt) cout ltlt vecteur initial affiche(v) generate (vbegin() vend() sequence(0)) cout ltlt vecteur genere 1 affiche(v) generate (vbegin() vend() sequence(4)) cout ltlt vecteur genere 2 affiche(v)

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 0 0 0 0 0 0 0 0 0 0vecteur genere 1 0 1 2 3 4 5 6 7 8 9vecteur genere 2 4 5 6 7 8 9 10 11 12 13

Geacuteneacuteration de valeurs par une classe fonction

Remarques

1 Si lon compare les deux appels suivants lun du premier exemple lautre du second

generate (vbegin() vend() suite) generate (vbegin() vend() sequence(0))

on constate que dans le premier cas suite est la reacutefeacuterence agrave une fonction tandis que

dans le second sequence(0) est la reacutefeacuterence agrave un objet de type sequence Mais comme

ce dernier a convenablement surdeacutefini lopeacuterateur () lalgorithme generate na pas agrave

tenir compte de cette diffeacuterence

2 Il existe un autre algorithme generate_n comparable agrave generate qui geacutenegravere un nombre

de valeurs preacutevues en argument Dautre part lalgorithme fill permet daffecter une

valeur donneacutee agrave tous les eacuteleacutements dune seacutequence ou agrave un nombre donneacute deacuteleacutements

fill (deacutebut fin valeur)

fill (position NbFois valeur)

Les algorithmes standardCHAPITRE 21

466

3 Algorithmes de recherche Ces algorithmes ne modifient pas la seacutequence sur laquelle ils travaillent On distingue

bull les algorithmes fondeacutes sur une eacutegaliteacute ou sur un preacutedicat unaire

bull les algorithmes fondeacutes sur une relation dordre permettant de trouver le plus grand ou le plus

petit eacuteleacutement

31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire Ces algorithmes permettent de rechercher la premiegravere occurrence de valeurs ou de seacuteries de

valeurs qui sont

bull soit imposeacutees explicitement cela signifie en fait quon se fonde sur la relation deacutegaliteacute in-

duite par lopeacuterateur == quil soit surdeacutefini ou non

bull soit par une condition fournie sous forme dun preacutedicat unaire

Ils fournissent tous un iteacuterateur sur leacuteleacutement rechercheacute sil existe et liteacuterateur sur la fin de la

seacutequence sinon dans ce dernier cas cette valeur nest eacutegale agrave end() que si la seacutequence con-

cerneacutee appartient agrave un conteneur et seacutetend jusquagrave sa fin Sinon on peut obtenir un iteacuterateur

valide sur un eacuteleacutement nayant rien agrave voir avec la recherche en question Dans le cas ougrave les iteacute-

rateurs utiliseacutes sont des pointeurs on peut obtenir un pointeur sur une valeur situeacutee au-delagrave

de la seacutequence examineacutee Il faudra tenir compte de ces remarques dans le test de la valeur de

retour qui constitue le seul moyen de savoir si la recherche a abouti

Lalgorithme find permet de rechercher une valeur donneacutee tandis que find_first_of permet de

rechercher une valeur parmi plusieurs Lalgorithme find_if (deacutebut fin preacutedicat) autorise la

recherche de la premiegravere valeur satisfaisant au preacutedicat unaire fourni en argument

On peut rechercher dans une seacutequence [deacutebut_1 fin_1) la premiegravere apparition complegravete

dune autre seacutequence [deacutebut_2 fin_2) par search (deacutebut_1 fin_1 deacutebut_2 fin_2) De mecircme

search_n (deacutebut fin NbFois valeur) permet de rechercher une suite de NbFois une mecircme

valeur Lagrave encore on se base sur lopeacuterateur == surdeacutefini ou non

On peut rechercher les doublons crsquoest-agrave-dire les valeurs apparaissant deux fois de suite

par adjacent_find (deacutebut fin) Attention ce nest pas un cas particulier de search_n dans la

mesure ougrave lon nimpose pas la valeur dupliqueacutee Pour chercher les autres doublons on peut

soit supprimer lune des valeurs trouveacutees soit simplement recommencer la recherche au-delagrave

de lemplacement ougrave se trouve le doublon preacuteceacutedent

Voici un exemple de programme illustrant la plupart de ces possibiliteacutes (par souci de simpli-

fication nous supposons que les valeurs rechercheacutees existent toujours)

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

3 - Algorithmes de recherche467

main() char ch1 = anticonstitutionnellement char ch2 = uoie char ch3 = tion vectorltchargt v1 (ch1 ch1+strlen(ch1)) vectorltchargt v2 (ch2 ch2+strlen(ch2)) vectorltchargtiterator iv iv = find_first_of (v1begin() v1end() v2begin() v2end()) cout ltlt npremier de uoie en for ( iv=v1end() iv++) cout ltlt iv iv = find_first_of (v1begin() v1end() v2begin() v2begin()+2) cout ltlt npremier de uo en for ( iv=v1end() iv++) cout ltlt iv v2assign (ch3 ch3+strlen(ch3)) iv = search (v1begin() v1end() v2begin() v2end()) cout ltlt ntion en for ( iv=v1end() iv++) cout ltlt iv iv = search_n(v1begin() v1end() 2 l ) cout ltlt nl 2 fois en for ( iv=v1end() iv++) cout ltlt iv iv = adjacent_find(v1begin() v1end()) cout ltlt npremier doublon en for ( iv=v1end() iv++) cout ltlt iv

premier de uoie en iconstitutionnellementpremier de uo en onstitutionnellementtion en tionnellementl 2 fois en llementpremier doublon en nnellement

Exemple dutilisation des algorithmes de recherche

32 Algorithmes de recherche de maximum ou de minimum Les deux algorithmes max_element et min_element permettent de deacuteterminer le plus grand ou

le plus petit eacuteleacutement dune seacutequence Ils sappuient par deacutefaut sur la relation induite par lopeacute-

rateur lt mais il est eacutegalement possible dimposer sa propre relation sous forme dun preacutedicat

binaire Comme les algorithmes preacuteceacutedents ils fournissent en retour soit un iteacuterateur sur

leacuteleacutement correspondant ou sur le premier dentre eux sil en existe plusieurs soit un iteacuterateur

sur la fin de la seacutequence sil nen existe aucun Mais cette derniegravere situation ne peut se pro-

duire ici quavec une seacutequence vide ou lorsquon choisit son propre preacutedicat de sorte que

lexamen de la valeur de retour est alors moins cruciale

Voici un exemple dans lequel nous appliquons ces algorithmes agrave un tableau usuel (par souci

de simplification nous supposons que les valeurs rechercheacutees existent toujours)

include ltiostreamgtinclude ltalgorithmgtinclude ltfunctionalgt pour greaterltintgt using namespace std

Les algorithmes standardCHAPITRE 21

468

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 ltlt plus grand elem de t en position ltlt ad-t

ltlt valeur ltlt ad ltlt n

ad = min_element(t t+sizeof(t)sizeof(t[0]))

cout ltlt plus petit elem de t en position ltlt ad-t

ltlt valeur ltlt ad ltlt n

ad = max_element(t t+sizeof(t)sizeof(t[0]) greaterltintgt())

cout ltlt plus grand elem avec greaterltintgt en position ltlt ad-t

ltlt valeur ltlt ad ltlt 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 greaterltintgt en position 2 valeur 1

Exemple dutilisation de max_element et de min_element

4 Algorithmes de transformation dune seacutequence

Il sagit des algorithmes qui modifient les valeurs dune seacutequence ou leur ordre sans en modi-

fier le nombre deacuteleacutements Ils ne sont pas applicables aux conteneurs associatifs pour les-

quels lordre est imposeacute de faccedilon intrinsegraveque

On peut distinguer trois cateacutegories dalgorithmes

bull remplacement de valeurs

bull permutation de valeurs

bull partition

Beaucoup de ces algorithmes disposent dune version suffixeacutee par _copy dans ce cas la ver-

sion xxxx_copy reacutealise le mecircme traitement que xxxx avec cette diffeacuterence importante quelle

ne modifie plus la seacutequence dorigine et quelle copie le reacutesultat obtenu dans une autre

seacutequence dont les eacuteleacutements doivent alors exister comme avec copy Ces algorithmes de la

forme xxxx_copy peuvent quant agrave eux sappliquer agrave des conteneurs associatifs agrave condition

toutefois dutiliser un iteacuterateur dinsertion et de tenir compte de la nature de type pair de leurs

eacuteleacutements

4 - Algorithmes de transformation dune seacutequence469

Par ailleurs il existe un algorithme nommeacute transform qui contrairement agrave ce que son nom

pourrait laisser entendre initialise une seacutequence en appliquant une fonction de transforma-

tion agrave une seacutequence ou agrave deux seacutequences de mecircme taille ces derniegraveres neacutetant alors pas modi-

fieacutees

41 Remplacement de valeurs On peut remplacer toutes les occurrences dune valeur donneacutee par une autre valeur en se fon-

dant sur lopeacuterateur == par exemple

replace (lbegin() lend() 0 -1) remplace toutes les occurrences de 0 par -1

On peut eacutegalement remplacer toutes les occurrences dune valeur satisfaisant agrave une

condition par exemple

replace_if (lbegin() lend() impair 0) remplace par 0 toutes les valeurs satisfaisant au preacutedicat

unaire impair quil faut fournir

42 Permutations de valeurs

421 Rotation

Lalgorithme rotate permet deffectuer une permutation circulaire des valeurs dune seacutequence

On notera quon ne dispose que des possibiliteacutes de permutation circulaire inverse compte

tenu de la maniegravere dont on preacutecise lampleur de la permutation agrave savoir non pas par un nom-

bre mais en indiquant quel eacuteleacutement doit venir en premiegravere position En voici un exemple

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 1 2 3 4 5 6 7 8 int decal = 3

vectorltintgt v(t t+8) cout ltlt vecteur initial affiche(v) rotate (vbegin() vbegin()+decal vend()) cout ltlt vecteur decale de 3 affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

Les algorithmes standardCHAPITRE 21

470

vecteur initial 1 2 3 4 5 6 7 8vecteur decale de 3 4 5 6 7 8 1 2 3

Exemple dutilisation de rotate

422 Geacuteneacuteration de permutations

Degraves lors quune seacutequence est ordonneacutee par une relation dordre R il est possible dordonner

les diffeacuterentes permutations possibles des valeurs de cette seacutequence Par exemple si lon con-

sidegravere les trois valeurs 1 4 8 et la relation dordre lt voici la liste ordonneacutee de toutes les per-

mutations possibles

1 4 8

1 8 4

4 1 8

4 8 1

8 1 4

8 4 1

Dans ces conditions il est possible de parler de la permutation suivante ou preacuteceacutedente dune

seacutequence de valeurs donneacutees Dans lexemple ci-dessus la permutation preacuteceacutedente de la

seacutequence 4 1 8 serait la seacutequence 1 8 4 tandis que la permutation suivante serait 4 8 1

Pour eacuteviter tout problegraveme on considegravere que la permutation suivant la derniegravere est la pre-

miegravere et que la permutation preacuteceacutedent la derniegravere est la premiegravere

Les algorithmes next_permutation et prev_permutation permettent de remplacer une

seacutequence donneacutee respectivement par la permutation suivante ou par la permutation preacuteceacute-

dente On peut utiliser soit par deacutefaut lopeacuterateur lt soit une relation imposeacutee sous forme

dun preacutedicat binaire Actuellement il nexiste pas de variantes _copy de ces algorithmes

Voici un exemple (la valeur de retour true ou false des algorithmes permet de savoir si lon a

effectueacute un bouclage dans la liste des permutations)

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 2 1 3 int i vectorltintgt v(t t+3) cout ltlt vecteur initial affiche(v) for (i=0 ilt=10 i++) bool res = next_permutation (vbegin() vend()) cout ltlt permutation ltlt res ltlt affiche(v)

4 - Algorithmes de transformation dune seacutequence471

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 2 1 3permutation 1 2 3 1permutation 1 3 1 2permutation 1 3 2 1permutation 0 1 2 3permutation 1 1 3 2permutation 1 2 1 3permutation 1 2 3 1permutation 1 3 1 2permutation 1 3 2 1permutation 0 1 2 3permutation 1 1 3 2

Exemple dutilisation de next_permutation et de prev_permutation

423 Permutations aleacuteatoires

Lalgorithme random_shuffle permet deffectuer une permutation aleacuteatoire des valeurs dune

seacutequence En voici un exemple

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 2 1 3 int i

vectorltintgt v(t t+3) cout ltlt vecteur initial affiche(v) for (i=0 ilt=10 i++) random_shuffle (vbegin() vend()) cout ltlt vecteur hasard affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

Les algorithmes standardCHAPITRE 21

472

vecteur initial 2 1 3vecteur hasard 3 2 1vecteur hasard 2 3 1vecteur hasard 1 2 3vecteur hasard 1 3 2vecteur hasard 3 1 2vecteur hasard 3 2 1vecteur hasard 3 1 2vecteur hasard 3 2 1vecteur hasard 2 3 1vecteur hasard 2 3 1vecteur hasard 2 3 1

Exemple dutilisation de random_shuffle

Remarque

Il existe une version de random_shuffle permettant dimposer son geacuteneacuterateur de nombres

aleacuteatoires

43 Partitions On nomme partition dune seacutequence suivant un preacutedicat unaire donneacute un reacutearrangement de

cette seacutequence deacutefini par un iteacuterateur deacutesignant un eacuteleacutement tel que tous les eacuteleacutements le preacuteceacute-

dant veacuterifient la dite condition Par exemple avec la seacutequence

1 3 4 11 2 7 8

et le preacutedicat impair (supposeacute vrai pour un nombre impair et faux sinon) voici des partitions

possibles (dans tous les cas liteacuterateur deacutesignera le quatriegraveme eacuteleacutement)

1 3 11 7 4 2 8 liteacuterateur deacutesignera ici le 4

1 3 11 7 2 8 4 liteacuterateur deacutesignera ici le 2

3 1 7 11 2 4 8 liteacuterateur deacutesignera ici le 2

On dit que la partition obtenue est stable si lordre relatif des eacuteleacutements satisfaisant au preacutedicat

est conserveacute Dans notre exemple seules les deux premiegraveres permutations sont stables

Les algorithmes partition et stable_partition permettent de deacuteterminer une telle partition agrave

partir dun preacutedicat unaire fourni en argument

5 Algorithmes dits de suppression Ces algorithmes permettent deacuteliminer dune seacutequence les eacuteleacutements reacutepondant agrave un certain

critegravere Mais assez curieusement ils ne suppriment pas les eacuteleacutements correspondants ils se

5 - Algorithmes dits de suppression473

contentent de regrouper en deacutebut de seacutequence les eacuteleacutements non concerneacutes par la condition

deacutelimination et de fournir en retour un iteacuterateur sur le premier eacuteleacutement non conserveacute En fait

il faut voir quaucun algorithme ne peut supprimer des eacuteleacutements dune seacutequence pour la

bonne et simple raison quil risque decirctre appliqueacute agrave une structure autre quun conteneur (ne

serait-ce quun tableau usuel) pour laquelle la notion de suppression nexiste pas1 Dautre

part contrairement agrave toute attente il nest pas du tout certain que les valeurs apparaissant en

fin de conteneur soient celles qui ont eacuteteacute eacutelimineacutees du deacutebut

Bien entendu rien nempecircche deffectuer apregraves avoir appeleacute un tel algorithme une suppres-

sion effective des eacuteleacutements concerneacutes en utilisant une fonction membre telle que remove

dans le cas ougrave lon a affaire agrave une seacutequence dun conteneur

Lalgorithme remove (deacutebut fin valeur) permet deacuteliminer tous les eacuteleacutements ayant la valeur

indiqueacutee en se basant sur lopeacuterateur == Il existe une version remove_if qui se fonde sur un

preacutedicat binaire donneacute Seul le premier algorithme est stable crsquoest-agrave-dire quil conserve

lordre relatif des valeurs non eacutelimineacutees

Lalgorithme unique permet de ne conserver que la premiegravere valeur dune seacuterie de valeurs

eacutegales (au sens de ==) ou reacutepondant agrave un preacutedicat binaire donneacute Il nimpose nullement que la

seacutequence soit ordonneacutee suivant un certain ordre

Ces algorithmes disposent dune version avec _copy qui ne modifie pas la seacutequence dorigine

et qui range dans une autre seacutequence les seules valeurs non eacutelimineacutees Utiliseacutes conjointement

avec un iteacuterateur dinsertion ils peuvent permettre de creacuteer une nouvelle seacutequence

Voici un exemple de programme montrant les principales possibiliteacutes eacutevoqueacutees y compris

des insertions dans une seacutequence avec remove_copy_if (dont on remarque clairement

dailleurs quil nest pas stable)

include ltiostreamgtinclude ltlistgtinclude ltalgorithmgtusing namespace std main() void affiche(listltintgt) bool valeur_paire (int) int t[] = 4 3 5 4 4 4 9 4 6 6 3 3 2 listltintgt l (t t+sizeof(t)sizeof(int)) listltintgt l_bis=l listltintgt l2 liste vide listltintgtiterator il cout ltlt liste initiale affiche(l)

il = remove(lbegin() lend() 4) different de lremove(4) cout ltlt liste apres remove(4) affiche(l)

1 Un algorithme ne peut pas davantage inseacuterer un eacuteleacutement dans une seacutequence on peut toutefois y parvenir dans le

cas dun conteneur en recourant agrave un iteacuterateur dinsertion

Les algorithmes standardCHAPITRE 21

474

cout ltlt element places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

l = l_bis il = unique (lbegin() lend()) cout ltlt liste apres unique affiche(l) cout ltlt elements places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

l = l_bis il = remove_if(lbegin() lend() valeur_paire) cout ltlt liste apres remove pairs affiche(l) cout ltlt elements places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

elimination de valeurs par copie dans liste vide l2 par iterateur dinsertion l = l_bis remove_copy_if(lbegin() lend() front_inserter(l2) valeur_paire) cout ltlt liste avec remove_copy_if paires affiche(l2)

void affiche(listltintgt l) listltintgtiterator il for (il=lbegin() il=lend() il++) cout ltlt (il) ltlt cout ltlt n bool valeur_paire (int n) return (n2)

liste initiale 4 3 5 4 4 4 9 4 6 6 3 3 2liste apres remove(4) 3 5 9 6 6 3 3 2 6 6 3 3 2element places en fin 6 6 3 3 2liste apres unique 4 3 5 4 9 4 6 3 2 6 3 3 2elements places en fin 6 3 3 2liste apres remove pairs 3 5 9 3 3 4 9 4 6 6 3 3 2elements places en fin 4 9 4 6 6 3 3 2liste avec remove_copy_if paires 3 3 9 5 3

Exemple dutilisation des algorithmes de suppression

6 Algorithmes de tris Ces algorithmes sappliquent agrave des seacutequences ordonnables crsquoest-agrave-dire pour lesquelles il aeacuteteacute deacutefini une relation dordre faible strict soit par lopeacuterateur lt soit par un preacutedicat binairedonneacute Ils ne peuvent pas sappliquer agrave un conteneur associatif compte tenu du conflit quiapparaicirctrait alors entre leur ordre interne et celui quon voudrait leur imposer Pour deacuteviden-tes questions defficaciteacute la plupart de ces algorithmes neacutecessitent des iteacuterateurs agrave accegraves

6 - Algorithmes de tris475

direct de sorte quils ne sont pas applicables agrave des listes (mais le conteneur list dispose de safonction membre sort)

On peut reacutealiser des tris complets dune seacutequence Dans ce cas on peut choisir entre un algo-rithme stable stable_sort ou un algorithme non stable plus rapide On peut effectuer eacutegale-ment avec partial_sort des tris partiels crsquoest-agrave-dire qui se contentent de nordonner quuncertain nombre deacuteleacutements Dans ce cas lappel se preacutesente sous la forme partial_sort (deacutebut

milieu fin) et lamplitude du tri est deacutefinie par liteacuterateur milieu deacutesignant le premier eacuteleacutementnon trieacute Enfin avec nth_element il est possible de deacuteterminer seulement le niegraveme eacuteleacutementcrsquoest-agrave-dire de placer dans cette position leacuteleacutement qui sy trouverait si lon avait trieacute toute laseacutequence lagrave encore lappel se preacutesente sous la forme nth_element (deacutebut milieu fin) etmilieu deacutesigne leacuteleacutement en question

Voici un exemple montrant lutilisation des principaux algorithmes de tri

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) bool comp (int int) int t[] = 2 1 3 9 2 7 5 8 vectorltintgt v(t t+8) v_bis=v cout ltlt vecteur initial affiche(v) sort (vbegin() vend()) cout ltlt apres sort affiche(v) v = v_bis partial_sort (vbegin() vbegin()+5 vend()) cout ltlt apres partial_sort (5) affiche(v) v = v_bis nth_element (vbegin() vbegin()+ 5 vend()) cout ltlt apres nth_element 6 affiche(v) nth_element (vbegin() vbegin()+ 2 vend()) cout ltlt apres nth_element 3 affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 2 1 3 9 2 7 5 8apres sort 1 2 2 3 5 7 8 9apres partial_sort (5) 1 2 2 3 5 9 7 8apres nth_element 6 2 1 3 5 2 7 8 9apres nth_element 3 2 1 2 3 5 7 8 9

Exemple dutilisation des algorithmes de tri

Les algorithmes standardCHAPITRE 21

476

7 Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees

Ces algorithmes sappliquent agrave des seacutequences supposeacutees ordonneacutees par une relation dordrefaible strict

71 Algorithmes de recherche binaire Les algorithmes de recherche preacutesenteacutes dans le paragraphe 3 sappliquaient agrave des seacutequencesnon neacutecessairement ordonneacutees Les algorithmes preacutesenteacutes ici supposent que la seacutequence con-cerneacutee soit convenablement ordonneacutee suivant la relation dordre faible strict qui sera utiliseacuteequil sagisse par deacutefaut de lopeacuterateur lt ou dun preacutedicat fourni explicitement Cest ce quileur permet dutiliser des meacutethodes de recherche dichotomique (ou binaire) plus performantesque de simples recherches seacutequentielles

Comme on peut sy attendre ces algorithmes ne modifient pas la seacutequence concerneacutee et ilspeuvent donc en theacuteorie sappliquer agrave des conteneurs de type set ou multiset En revancheleur application agrave des types map et multimap nest guegravere envisageable puisque en geacuteneacuteral cene sont pas leurs eacuteleacutements qui sont ordonneacutes mais seulement les cleacutes Quoi quil en soit lesconteneurs associatifs disposent deacutejagrave de fonctions membres eacutequivalant aux algorithmes exa-mineacutes ici excepteacute pour binary_search

Lalgorithme binary_search permet de savoir sil existe dans la seacutequence une valeur eacutequiva-lente (au sens de leacutequivalence induite par la relation dordre concerneacutee) Par ailleurs on peutlocaliser lemplacement possible pour une valeur donneacutee compte tenu dun certain ordre lower_bound fournit la premiegravere position possible tandis que upper_bound fournit la derniegravereposition possible equal_range fournit les deux informations preacuteceacutedentes sous forme dunepaire

72 Algorithmes de fusion La fusion de deux seacutequences ordonneacutees consiste agrave les reacuteunir en une troisiegraveme seacutequenceordonneacutee suivant le mecircme ordre Lagrave encore ils peuvent sappliquer agrave des conteneurs de typeset ou multiset en revanche leur application agrave des conteneurs de type map ou multimap nestguegravere reacutealiste compte tenu de ce que ces derniers sont ordonneacutes uniquement suivant les cleacutesIl existe deux algorithmes

bull merge qui permet la creacuteation dune troisiegraveme seacutequence par fusion de deux autres

bull inplace_merge qui permet la fusion de deux seacutequences conseacutecutives en une seule qui vientprendre la place des deux seacutequences originales

Voici un exemple dutilisation de ces algorithmes

7 - Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees477

include ltiostreamgt

include ltvectorgt

include ltalgorithmgt

using namespace std

main()

void affiche (vectorltintgt)

int t1[8] = 2 1 3 12 2 18 5 8

int t2[5] = 5 4 15 9 11

vectorltintgt v1(t1 t1+8) v2(t2 t2+6) v

cout ltlt vecteur 1 initial affiche(v1)

sort (v1begin() v1end())

cout ltlt vecteur 1 trie affiche(v1)

cout ltlt vecteur 2 initial affiche(v2)

sort (v2begin() v2end())

cout ltlt vecteur 2 trie affiche(v2)

merge (v1begin() v1end() v2begin() v2end() back_inserter(v))

cout ltlt fusion des deux affiche(v)

random_shuffle (vbegin() vend()) v nest plus ordonne

cout ltlt vecteur v desordonne affiche(v)

sort (vbegin() vbegin()+6) tri des premiers elements de v

sort (vbegin()+6 vend()) tri des derniers elements de v

cout ltlt vecteur v trie par parties affiche(v)

inplace_merge (vbegin() vbegin()+6 vend()) fusion interne

cout ltlt vecteur v apres fusion affiche(v)

void affiche (vectorltintgt v)

unsigned int i

for (i=0 iltvsize() i++)

cout ltlt v[i] ltlt

cout ltlt 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

Exemple dutilisation des algorithmes de fusion

Les algorithmes standardCHAPITRE 21

478

8 Algorithmes agrave caractegravere numeacuterique Nous avons classeacute dans cette rubrique les algorithmes qui effectuent sur les eacuteleacutements duneseacutequence des opeacuterations numeacuteriques fondeacutees sur les opeacuterateurs + - ou Plutocirct destineacutes apriori agrave des eacuteleacutements dun type effectivement numeacuterique ils peuvent neacuteanmoins sappliqueragrave des eacuteleacutements de type classe pour peu que cette derniegravere ait convenablement surdeacutefini lesopeacuterateurs voulus ou quelle fournisse une fonction binaire approprieacutee

Comme on peut sy attendre lalgorithme accumulate fait la somme des eacuteleacutements duneseacutequence tandis que inner_product effectue le produit scalaire de deux seacutequences de mecircmetaille On prendra garde au fait que ces deux algorithmes ajoutent le reacutesultat agrave une valeur ini-tiale fournie en argument (en geacuteneacuteral on choisit 0)

Lalgorithme partial_sum creacutee agrave partir dune seacutequence une nouvelle seacutequence de mecircmetaille formeacutee des cumuls partiels des valeurs de la premiegravere le premier eacuteleacutement est inchangeacutele second est la somme du premier et du second etc Enfin lalgorithme adjacent_difference

creacutee agrave partir dune seacutequence une seacutequence de mecircme taille formeacutee des diffeacuterences de deuxeacuteleacutements conseacutecutifs (le premier eacuteleacutement restant inchangeacute)

Voici un exemple dutilisation de ces diffeacuterents algorithmes

include ltiostreamgt

include ltnumericgt pour les algorithmes numeriquesusing namespace std

main()

void affiche (int )

int v1[5] = 1 3 -1 4 1 int v2[5] = 2 5 1 -3 2

int v3[5] cout ltlt vecteur v1 affiche(v1)

cout ltlt vecteur v2 affiche(v2)

cout ltlt somme des elements de v1 ltlt accumulate (v1 v1+3 0) ltlt n ne pas oublier 0

cout ltlt produit scalaire v1v2 ltlt inner_product (v1 v1+3 v2 0) ltlt n ne pas oublier 0

partial_sum (v1 v1+5 v3)

cout ltlt sommes partielles de v 1 affiche(v3) adjacent_difference (v1 v1+5 v3)

cout ltlt differences ajdacentes de v1 affiche(v3)

void affiche (int v) int i for (i=0 ilt5 i++) cout ltlt v[i] ltlt cout ltlt n

9 - Algorithmes agrave caractegravere ensembliste479

vecteur v1 1 3 -1 4 1vecteur v2 2 5 1 -3 2somme des elements de v1 3produit scalaire v1v2 16sommes partielles de v 1 1 4 3 7 8differences ajdacentes de v1 1 2 -4 5 -3

Exemple dutilisation dalgorithmes numeacuteriques

9 Algorithmes agrave caractegravere ensembliste Comme on a pu le constater dans le chapitre preacuteceacutedent les conteneurs set et multiset ne dis-posent daucune fonction membre permettant de reacutealiser les opeacuterations ensemblistes classi-ques En revanche il existe des algorithmes geacuteneacuteraux qui quant agrave eux peuvent en theacuteoriesappliquer agrave des seacutequences quelconques il faut cependant quelles soient convenablementordonneacutees ce qui constitue une premiegravere diffeacuterence par rapport aux notions matheacutematiquesusuelles dont lordre est manifestement absent De plus ces notions ensemblistes ont ducirc ecirctrequelque peu ameacutenageacutees de maniegravere agrave accepter la preacutesence de plusieurs eacuteleacutements de mecircmevaleur

Leacutegaliteacute entre deux eacuteleacutements se fonde sur lopeacuterateur == ou eacuteventuellement sur un preacutedicatbinaire fourni explicitement Pour que les algorithmes fonctionnent convenablement il estalors neacutecessaire que cette relation deacutegaliteacute soit compatible avec la relation ayant servi agraveordonner les seacutequences correspondantes plus preacuteciseacutement il est neacutecessaire que les classesdeacutequivalence induite par la relation dordre faible strict coiumlncident avec celles qui sont indui-tes par leacutegaliteacute

Par ailleurs les algorithmes creacuteant une nouvelle seacutequence le font comme toujours dans deseacuteleacutements existants ce qui pose manifestement un problegraveme avec des conteneurs de type set

ou multiset qui nautorisent pas la modification des valeurs de leurs eacuteleacutements mais seulementles suppressions ou les insertions Dans ce cas il faudra donc recourir agrave un iteacuterateur dinser-tion pour la seacutequence agrave creacuteer De plus comme ni set ni multiset ne disposent dinsertion endeacutebut ou en fin cet iteacuterateur dinsertion ne pourra ecirctre que inserter

Voici un exemple correspondant agrave lusage le plus courant des algorithmes agrave savoir leur appli-cation agrave des conteneurs de type set

include ltiostreamgtinclude ltsetgtinclude ltalgorithmgtusing namespace std

Les algorithmes standardCHAPITRE 21

480

main() char t1[] = je me figure ce zouave qui joue du xylophone char t2[] = en buvant du whisky void affiche (setltchargt ) setltchargt e1(t1 t1+sizeof(t1)-1) setltchargt e2(t2 t2+sizeof(t2)-1) setltchargt u i d ds cout ltlt ensemble 1 affiche (e1) cout ltlt ensemble 2 affiche (e2) set_union (e1begin() e1end() e2begin() e2end() inserter(u ubegin())) cout ltlt union des deux affiche (u) set_intersection (e1begin() e1end() e2begin() e2end() inserter(i ibegin())) cout ltlt intersecton des deux affiche (i) set_difference (e1begin() e1end() e2begin() e2end() inserter(d dbegin())) cout ltlt difference des deux affiche (d) set_symmetric_difference (e1begin() e1end() e2begin() e2end() inserter(ds dsbegin())) cout ltlt difference_symetrique des deux affiche (ds) void affiche (setltchargt e ) setltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie ltlt cout ltlt n

ensemble 1 a c d e f g h i j l m n o p q r u v x y zensemble 2 a b d e h i k n s t u v w yunion 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 zintersecton des deux a d e h i n u v ydifference des deux c f g j l m o p q r x zdifference_symetrique des deux b c f g j k l m o p q r s t w x z

Exemple dutilisation dalgorithmes agrave caractegravere ensembliste avec un conteneur de type set

10 Algorithmes de manipulation de tasLa bibliothegraveque standard comporte quelques algorithmes fondeacutes sur la notion de tas (heap enanglais) Il srsquoagit en fait drsquoalgorithmes drsquoassez bas niveau eacuteventuellement utilisables pourlrsquoimpleacutementation drsquoautres algorithmes de plus haut niveau mais qui restent neacuteanmoins utili-

10 - Algorithmes de manipulation de tas481

sables tels quels Ils srsquoappliquent agrave des seacutequences munies drsquoune relation drsquoordre faible strictet drsquoun iteacuterateur agrave accegraves direct

Un tas est une organisation particuliegravere1 (unique) drsquoune seacutequence qui permet drsquoobtenir debonnes performances pour le tri lrsquoajout ou la suppression drsquoune valeur Une des proprieacuteteacutesdrsquoun tas est que sa premiegravere valeur est supeacuterieure agrave toutes les autres

Un algorithme make_heap permet de reacutearranger convenablement une seacutequence sous formedrsquoun tas Lrsquoalgorithme sort_heap permet de trier un tas (le reacutesultat nrsquoest alors plus un tas)

Lrsquoalgorithme pop_heap permet de retirer la premiegravere valeur drsquoun tas celle-ci est placeacutee enfin de seacutequence la seacutequence entiegravere nrsquoest alors plus un tas seule la seacutequence priveacutee de sa(nouvelle) derniegravere valeur en est un

Enfin lrsquoalgorithme push_heap permet drsquoajouter une valeur agrave un tas Cette valeur doit appa-raicirctre juste apregraves la derniegravere valeur du tas

Voici quelques exemples de programmes complets illustrant ces diffeacuterentes possibiliteacutes

include ltiostreamgtinclude ltalgorithmgt

using namespace std

main() int t[] = 5 1 8 0 9 4 6 3 4

void affiche (int []) cout ltlt sequence t initiale affiche (t)

make_heap (t t+9) t est maintenant ordonne en tas cout ltlt tas t initial affiche(t)

sort (t t+9) t est trie mais nest plus un tas cout ltlt sequence t triee affiche(t)

sort (t t+9) resultat incoherent car t nest plus un tas

cout ltlt sequence t triee 2 fois affiche(t) make_heap (t t+9) t est a nouveau ordonne en tas

cout ltlt tas t nouveau affiche(t)

void affiche (int t[]) int i

for (i=0 ilt9 i++) cout ltlt t[i] ltlt

cout ltlt n

1 La notion de tas est fondeacutee sur celle drsquoarbre binaire plein On peut eacutetablir une correspondance biunivoque entre un

tel arbre et un tableau (donc une seacutequence munie drsquoun iteacuterateur agrave accegraves direct) convenablement arrangeacute

Les algorithmes standardCHAPITRE 21

482

sequence t initiale 5 1 8 0 9 4 6 3 4tas t initial 9 5 8 4 1 4 6 3 0sequence t triee 0 1 3 4 4 5 6 8 9sequence t triee 2 fois 0 1 3 4 4 5 6 8 9tas t nouveau 9 8 6 4 4 5 3 1 0

Tri par tas drsquoune seacutequence

include ltiostreamgtinclude ltalgorithmgtusing namespace std main() int t[] = 5 1 7 0 6 4 6 8 9 void affiche (int int) cout ltlt sequence t complete affiche (t 9) make_heap (t t+7) 7 premiers elements de t ordonnes en tas cout ltlt tas t (1-7) initial affiche (t 7) push_heap (t t+8) ajoute t[7] au tas precedent cout ltlt tas t (1-8) apres push affiche (t 8) push_heap (t t+9) ajoute t[8] au tas precedent cout ltlt tas t (1-9) apres push affiche (t 9) sort_heap (t t+9) trie le tas cout ltlt tas t (1-9) trie affiche (t 9)

void affiche (int t int nel) int i for (i=0 iltnel i++) cout ltlt t[i] ltlt cout ltlt n

sequence t complete 5 1 7 0 6 4 6 8 9tas t (1-7) initial 7 6 6 0 1 4 5tas t (1-8) apres push 8 7 6 6 1 4 5 0tas t (1-9) apres push 9 8 6 7 1 4 5 0 6tas t (1-9) trie 0 1 4 5 6 6 7 8 9

Insertion dans un tas

include ltiostreamgtinclude ltalgorithmgtusing namespace std

10 - Algorithmes de manipulation de tas483

main() int t[] = 5 1 7 0 6 4 6 8 9 void affiche (int int) cout ltlt sequence t complete affiche (t 9) make_heap (t t+9) 9 elements de t ordonnes en tas cout ltlt tas t (0-8) initial affiche (t 9) pop_heap (t t+9) enleve t[0] au tas precedent cout ltlt tas t (0-7) apres pop affiche (t 8) cout ltlt valeurs t[8] ltlt t[8] ltlt n pop_heap (t t+8) enleve t[0] du tas precedent cout ltlt tas t (0-8) apres pop affiche (t 7) cout ltlt valeurs t[7-8] ltlt t[7] ltlt ltlt t[8] ltlt n sort_heap (t t+7) trie le tas t[0-6] cout ltlt tas t1 (0-6) trie affiche (t 7) void affiche (int t int nel) int i for (i=0 iltnel i++) cout ltlt t[i] ltlt cout ltlt n

sequence t complete 5 1 7 0 6 4 6 8 9tas t (0-8) initial 9 8 7 5 6 4 6 1 0tas t (0-7) apres pop 8 6 7 5 0 4 6 1 valeurs t[8] 9tas t (0-8) apres pop 7 6 6 5 0 4 1 valeurs t[7-8] 8 9tas t1 (0-6) trie 0 1 4 5 6 6 7

Suppression de la premiegravere valeur drsquoun tas

22

La classe string

Si lon cherche agrave manipuler des chaicircnes de caractegraveres en se fondant uniquement sur les ins-tructions de base du langage C++ les choses ne sont pas plus satisfaisantes quen C enparticulier on ny dispose pas dun type chaicircne agrave part entiegravere et mecircme une opeacuteration aussibanale que laffectation nexiste pas quant aux possibiliteacutes de gestion dynamique on ne peuty acceacuteder quen geacuterant soi mecircme les choses

La bibliothegraveque standard dispose dun patron de classes permettant de manipuler des chaicircnesgeacuteneacuteraliseacutees crsquoest-agrave-dire des suites de valeurs de type quelconque donc en particulier detype char Il sagit du patron basic_string parameacutetreacute par le type des eacuteleacutements Mais il existeune une version speacutecialiseacutee de ce patron nommeacutee string qui est deacutefinie commebasic_stringltchargt1 Ici nous nous limiterons agrave lexamen des proprieacuteteacutes de cette classe quiest de loin la plus utiliseacutee la geacuteneacuteralisation agrave basic_string ne preacutesente de toutes faccedilonsaucune difficulteacute

La classe string propose un cadre tregraves souple de manipulation de chaicircnes de caractegraveres enoffrant les fonctionnaliteacutes traditionnelles quon peut attendre dun tel type gestion dynami-que transparente des emplacements correspondants affectation concateacutenation recherche desous-chaicircnes insertions ou suppression de sous-chaicircnes On verra quelle possegravede non seu-lement beaucoup des fonctionnaliteacutes de la classe vector (plus preacuteciseacutement vectorltchargt

pour string) mais eacutegalement bien dautres Dune maniegravere geacuteneacuterale ces fonctionnaliteacutes semettent en œuvre de faccedilon tregraves naturelle ce qui nous permettra de les preacutesenter assez briegraveve-ment Il faut cependant noter une petite difficulteacute lieacutee agrave la preacutesence de certaines possibiliteacutesredondantes les unes faisant appel agrave des iteacuterateurs usuels les autres agrave des valeurs dindices

1 Il existe eacutegalement une version speacutecialiseacutee pour le type whcar nommeacutee wstring

La classe stringCHAPITRE 22

486

1 Geacuteneacuteraliteacutes Un objet de type string contient agrave un instant donneacute une suite formeacutee dun nombre quelcon-que de caractegraveres quelconques Sa taille peut eacutevoluer dynamiquement au fil de lexeacutecution duprogramme Contrairement aux conventions utiliseacutees pour les (pseudo) chaicircnes du C lanotion de caractegravere de fin de chaicircne nexiste plus et ce caractegravere de code nul peut apparaicirctreau sein de la chaicircne eacuteventuellement agrave plusieurs reprises Un tel objet ressemble donc agrave unconteneur de type vectorltchargt et il possegravede dailleurs un certain nombre de fonctionnaliteacutescommunes

bull laccegraves aux eacuteleacutements existants peut se faire avec lopeacuterateur [] ou avec la fonction membreat comme avec les vecteurs ou les tableaux usuels le premier caractegravere correspond agrave lin-dice 0

bull il possegravede une taille courante fournie par la fonction membre size() agrave noter que la classestring deacutefinit une autre fonction nommeacutee length jouant le mecircme rocircle que size

bull son emplacement est reacuteserveacute sous forme dun seul bloc de meacutemoire (ou du moins tout sepasse comme si cela eacutetait le cas) la fonction capacity fournit le nombre maximal de carac-tegraveres quon pourra y introduire sans quil soit besoin de proceacuteder agrave une nouvelle allocationmeacutemoire on peut recourir aux fonctions reserve et resize

bull on dispose des iteacuterateurs agrave accegraves direct iterator et reverse_iterator ainsi que des valeurs par-ticuliegraveres begin() end() rbegin() rend()

2 Construction La classe string dispose de beaucoup de constructeurs certains correspondent aux construc-teurs dun vecteur

string ch1 construction dune chaicircne vide ch1size() == 0 string ch2 (10 ) construction dune chaicircne de 10 caractegraveres eacutegaux agrave rsquorsquo ch2size() == 10 string ch3 (5 0) construction dune chaicircne de 5 caractegraveres de code nul ch2size() == 5

Dautres permettent dinitialiser une chaicircne lors de sa construction agrave partir de chaicircnes usuel-les constantes ou non

string mess1 (bonjour) construction chaicircne de longueur 7 bonjour ou string mess1 = bonjour char adr = salut string mess2 (adr) construction chaicircne de 5 caractegraveres salut ou string mess2 = adr

Bien entendu on dispose dun constructeur par recopie usuel string s1 string s2(s1) ou string s2 = s1 construction de s2 par recopie de s1 s2size() == s1size()

3 - Opeacuterations globales487

Bien que dun inteacuterecirct limiteacute on peut eacutegalement construire une chaicircne agrave partir dune seacutequencede caractegraveres par exemple si l est de type listltchargt

string chl (lbegin() lend()) construction dune chaicircne en y recopiant

les caractegraveres de la liste l

3 Opeacuterations globales On dispose tout naturellement des opeacuterations globales deacutejagrave rencontreacutees pour les vecteurs agravesavoir laffectation les fonctions assign et swap ainsi que des comparaisons lexicographi-ques

Comme on srsquoy attend les opeacuterateurs ltlt et gtgt sont surdeacutefinis pour le type string et gtgt utilisepar deacutefaut les mecircmes conventions de seacuteparateurs que pour les chaicircnes de style C drsquoougravelrsquoimpossibiliteacute de lire une chaicircne comportant un espace blanc (en particulier un espace ou unefin de ligne)

En revanche il nrsquoexiste pas dans la classe istream de meacutethode jouant pour les objets de typestring le rocircle de getline pour les (pseudo) chaicircnes de C Toutefois il existe une fonction indeacute-pendante nommeacutee eacutegalement getline qui srsquoutilise ainsi

string ch

getline (cin ch) lit une suite de caractegraveres termineacutee par une fin de ligne

et la range dans lrsquoobjet ch (fin de ligne non comprise)

getline (cin ch rsquoxrsquo) lit une suite de caractegraveres termineacutee par le caractegravere rsquoxrsquo

et la range dans lrsquoobjet ch (caractegravere rsquoxrsquo non compris)

Aucune restriction ne pegravese sur le nombre de caractegraveres qui pouront ecirctre rangeacutes dans lrsquoobjetch La longueur de la chaicircne ainsi constitueacutee pourra ecirctre obtenue par chlength() ou chsize()

Agrave titre drsquoexemple voici comment reacuteeacutecrire le programme du paragraphe 23 du chapitre 16qui affichait des lignes de caractegraveres entreacutees au clavier Comme vous le constatez il nrsquoestplus neacutecessaire de deacutefinir une longueur maximale de ligne

include ltiostreamgt

using namespace std

main()

string ch pour lire une ligne

int lg longueur courante drsquoune ligne

do

getline (cin ch)

lg = chlength()

cout ltlt ligne de ltlt lg ltlt caracteres ltlt ch ltlt n

while (lg gt1)

La classe stringCHAPITRE 22

488

bonjour

ligne de 7 caracteres bonjour

9 fois 5 font 45

ligne de 16 caracteres 9 fois 5 font 45

nrsquoimporte quoi ltampeacutersquo(-egrave_ccedilagrave))=

ligne de 29 caracteres nrsquoimporte quoi ltampeacutersquo(-egrave_ccedilagrave))=

ligne de 0 caracteres

Exemple drsquoutilisation de la fonction indeacutependante getline

4 Concateacutenation Lopeacuterateur + a eacuteteacute surdeacutefini de maniegravere agrave permettre la concateacutenation

bull de deux objets de type string

bull dun objet de type string avec une chaicircne usuelle ou avec un caractegravere et ceci dans nimportequel ordre

Lopeacuterateur += est deacutefini de faccedilon concomitante

Voici quelques exemples

string ch1 (bon) ch1length() == 3

string ch2 (jour) ch2length() == 4

string ch3 ch3length() == 0 ch3 = ch1 + ch2 ch3length() == 7 ch3 contient la chaicircne bonjour

ch3 = ch1 + ch3length() == 4

ch3 += ch2 ch3length() == 8 ch3 contient la chaicircne bon jour

ch3 += monsieur ch3 contient la chaicircne bon jour monsieur

On notera cependant quil nest pas possible de concateacutener deux chaicircnes usuelles ou unechaicircne usuelle et un caractegravere

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 Recherche dans une chaicircne Ces fonctions permettent de retrouver la premiegravere ou la derniegravere occurrence dune chaicircne oudun caractegravere donneacutes dun caractegravere appartenant agrave une suite de caractegraveres donneacutes duncaractegravere nappartenant pas agrave une suite de caractegraveres donneacutes

Lorsquune telle chaicircne ou un tel caractegravere a eacuteteacute localiseacute on obtient en retour lindice corres-pondant au premier caractegravere concerneacute si la recherche naboutit pas on obtient une valeur

5 - Recherche dans une chaicircne489

dindice en dehors des limites permises pour la chaicircne ce qui rend quelque peu difficile lexa-men de sa valeur

51 Recherche dune chaicircne ou dun caractegravere La fonction membre find permet de rechercher dans une chaicircne donneacutee la premiegravereoccurrence

bull dune autre chaicircne (on parle souvent de sous-chaicircne) fournie soit par un objet de type stringsoit par une chaicircne usuelle

bull dun caractegravere donneacute

Par deacutefaut la recherche commence au deacutebut de la chaicircne mais on peut la faire deacutebuter agrave uncaractegravere de rang donneacute

Voici quelques exemples string ch = anticonstitutionnellement string mot (on)char ad = ti int i i = chfind (elle) i == 17 i = chfind (elles) i lt0 ou i gt chlength() i = chfind (mot) i == 5 i = chfind (ad) i == 2 i = chfind (n) i == 1 i = chfind (n 5) i == 6 car ici la recherche deacutebute agrave ch[5] i = chfind (p) i lt0 ou i gt chlength()

De maniegravere semblable la fonction rfind permet de rechercher la derniegravere occurrence duneautre chaicircne ou dun caractegravere

string ch = anticonstitutionnellement string mot (on)char ad = ti int i i = chrfind (elle) i == 17 i = chrfind (elles) i lt0 ou i gt chlength() i = chrfind (mot) i == 14 i = chrfind (ad) i == 12 i = chrfind (n) i == 23 i = chrfind (n 18) i == 16

52 Recherche dun caractegravere preacutesent ou absent dune suite La fonction find_first_of recherche la premiegravere occurrence de lun des caractegraveres dune autrechaicircne (string ou usuelle) tandis que find_last_of en recherche la derniegravere occurrence Lafonction find_first_not_of recherche la premiegravere occurrence dun caractegravere nappartenant pasagrave une autre chaicircne tandis que find_last_not_of en recherche la derniegravere Voici quelquesexemples

La classe stringCHAPITRE 22

490

string ch = anticonstitutionnellement

char ad = oie

int i

i = chfind_first_of (aeiou) i == 0

i = chfind_first_not_of (aeiou) i == 1

i = chfind_first_of (aeiou 6) i == 9

i = chfind_first_not_of (aeiou 6) i == 6

i = chfind_first_of (ad) i == 3

i = chfind_last_of (aeiou) i == 22

i = chfind_last_not_of (aeiou) i == 24

i = chfind_last_of (aeiou 6) i == 5

i = chfind_last_not_of (aeiou 6) i == 6

i = chfind_last_of (ad) i == 22

6 Insertions suppressions et remplacements Ces possibiliteacutes sont relativement classiques mais elles se recoupent partiellement dans lamesure ougrave lon peut

bull dune part utiliser non seulement des objets de type string mais aussi des chaicircnes usuelles(char ) ou des caractegraveres

bull dautre part deacutefinir une sous-chaicircne soit par indice soit par iteacuterateur cette derniegravere possibi-liteacute neacutetant cependant pas offerte systeacutematiquement

61 Insertions La fonction insert permet dinseacuterer

bull agrave une position donneacutee deacutefinie par un indice

ndash une autre chaicircne (objet de type string) ou une partie de chaicircne deacutefinie par un indice dedeacutebut et une eacuteventuelle longueur

ndash une chaicircne usuelle (type char ) ou une partie de chaicircne usuelle deacutefinie par une lon-gueur

ndash un certain nombre de fois un caractegravere donneacute

bull agrave une position donneacutee deacutefinie par un iteacuterateur

ndash une seacutequence deacuteleacutements de type char deacutefinie par un iteacuterateur de deacutebut et un iteacuterateurde fin

ndash une ou plusieurs fois un caractegravere donneacute

Voici quelques exemples

6 - Insertions suppressions et remplacements491

include ltiostreamgt

include ltstringgt

include ltlistgt

using namespace std

main()

string ch (0123456)

string voy (aeiou)

char t[] = 778899

insere le caractere a en chbegin()+1

chinsert (chbegin()+1 a) cout ltlt ch ltlt n

insere le caractere b en position dindice 4

chinsert (4 1 b) cout ltlt ch ltlt n

insere 3 fois le caractere x en fin de ch

chinsert (chend() 3 x) cout ltlt ch ltlt n

insere 3 fois le caractere x en position dindice 6

chinsert (6 3 x) cout ltlt ch ltlt n

insere la chaine voy en position 0

chinsert (0 voy) cout ltlt ch ltlt n

insere en debut la chaine voy a partir de position 1 longueur 3

chinsert (0 voy 1 3) cout ltlt ch ltlt n

insertion dune sequence

chinsert (chbegin()+2 t t+6) cout ltlt ch ltlt n

0a123456

0a12b3456

0a12b3456xxx

0a12b3xxx456xxx

aeiou0a12b3xxx456xxx

eioaeiou0a12b3xxx456xxx

ei778899oaeiou0a12b3xxx456xxx

Exemple dinsertions dans une chaicircne

62 Suppressions La fonction erase permet de supprimer

bull une partie dune chaicircne deacutefinie soit par un iteacuterateur de deacutebut et un iteacuterateur de fin soit parun indice de deacutebut et une longueur

bull un caractegravere donneacute deacutefini par un iteacuterateur de deacutebut

Voici quelques exemples

La classe stringCHAPITRE 22

492

include ltiostreamgt

include ltstringgt

include ltlistgt

using namespace std

main()

string ch (0123456789) ch_bis=ch

supprime a partir de position dindice 3 pour une longueur de 2

cherase (3 2) cout ltlt A ltlt ch ltlt n

ch = ch_bis

supprime de begin()+3 agrave begin()+6

cherase (chbegin()+3 chbegin()+6) cout ltlt B ltlt ch ltlt n

supprime a partir de position dindice 3

cherase (3) cout ltlt C ltlt ch ltlt n

ch = ch_bis

supprime le caractere de position begin()+4

cherase (chbegin()+4) cout ltlt D ltlt ch ltlt n

A 01256789

B 0126789

C 012

D 012356789

Exemples de suppressions dans une chaicircne

63 Remplacements La fonction replace permet de remplacer une partie dune chaicircne deacutefinie soit par un indice etune longueur soit par un intervalle diteacuterateur par

bull une autre chaicircne (objet de type string)

bull une partie dune autre chaicircne deacutefinie par un indice de deacutebut et eacuteventuellement une lon-gueur

bull une chaicircne usuelle (type char ) ou une partie de longueur donneacutee

bull un certain nombre de fois un caractegravere donneacute

En outre on peut remplacer une partie dune chaicircne deacutefinie par un intervalle par une autreseacutequence deacuteleacutements de type char deacutefinie par un iteacuterateur de deacutebut et un iteacuterateur de fin

Voici quelques exemples

include ltiostreamgt

include ltstringgt

using namespace std

7 - Les possibiliteacutes de formatage en meacutemoire493

main() string ch (0123456) string voy (aeiou) char t[] = +-=ltgt char message = hello remplace a partir de indice 2 sur longueur 3 par voy chreplace (2 3 voy) cout ltlt ch ltlt n remplace a partir de indice 0 sur longueur 1 par voy a partir de indice 2 longueur 3 chreplace (0 1 voy 1 2) cout ltlt ch ltlt n remplace a partir de indice 1 sur longueur 2 par 8 fois chreplace (1 2 8 ) cout ltlt ch ltlt n remplace a partir de indice 1 sur longueur 2 par 5 fois chreplace (1 2 5 ) cout ltlt ch ltlt n remplace a partir de indice 2 sur longueur 4 par xxxxxx chreplace (2 4 xxxxxx ) cout ltlt ch ltlt n remplace les 7 derniers caracteres par les 3 premiers de message chreplace (chlength()-7 chlength() message 3) cout ltlt ch ltlt n remplace tous les caracteres sauf le dernier par (t t+5) chreplace (chbegin() chbegin()+chlength()-1 t t+5) cout ltlt ch ltlt n

01aeiou56ei1aeiou56eaeiou56eaeiou56exxxxxxaeiou56exxxxxxhel+-=l

Exemples de remplacements dans une chaicircne

7 Les possibiliteacutes de formatage en meacutemoireEn langage C

bull sscanf permet dacceacuteder agrave une information situeacutee en meacutemoire de faccedilon comparable agrave ce quefait scanf sur lentreacutee standard

bull sprintf permet de fabriquer en meacutemoire une chaicircne de caractegraveres correspondant agrave celle quiserait transmise agrave la sortie standard par printf

En C++ des faciliteacutes comparables existent Jusqursquoagrave la norme elles eacutetaient fournies par lesclasses ostrstrream et istrstream preacutesenteacutees au paragraphe 7 du chapitre 16 Doreacutenavant ilest conseilleacute drsquoutiliser agrave leur place les classes ostringstream et istringstream qui utilisent toutnaturellement un objet de type string

La classe stringCHAPITRE 22

494

71 La classe ostringstreamUn objet de classe ostringstream peut recevoir des caractegraveres au mecircme titre qursquoun flot desortie La fonction membre str permet drsquoobtenir une chaicircne (objet de type string) contenantune copie instantaneacutee de ces caractegraveres

ostringstream sortie

sortie ltlt ltlt ltlt on envoie des caractegraveres dans sortie

comme on le ferait pour un flot

string ch = sortiestr() ch contient les caractegraveres ainsi engrangeacutes

dans sortie

sortie ltlt ltlt on peut continuer agrave engranger des

dans sortie sans affecter ch

Voici un petit exemple illustrant ces possibiliteacutes

include ltiostreamgt

include ltsstreamgt

using namespace std

main()

ostringstream sortie

int n=12 p=1234

float x=125

sortie ltlt n = ltlt n ltlt p = ltlt p on envoie des caractegraveres dans

sortie comme on le ferait pour un flot

string ch1 = sortiestr() ch1 contient maintenant une copie

des caractegraveres engrangeacutes dans sortie

cout ltlt ch1 premiere fois = ltlt ch1 ltlt n

sortie ltlt x = ltlt x on peut continuer agrave engranger des caractegraveres

dans sortie sans affecter ch1

cout ltlt ch1 deuxieme fois = ltlt ch1 ltlt n

string ch2 = sortiestr() ch2 contient maintenant une copie

des caractegraveres engrangeacutes dans sortie

cout ltlt ch2 = ltlt ch2 ltlt n

ch1 premiere fois = n = 12 p = 1234

ch1 deuxieme fois = n = 12 p = 1234

ch2 = n = 12 p = 1234 x = 125

Exemple drsquoutilisation de la classe ostringstream

7 - Les possibiliteacutes de formatage en meacutemoire495

72 La classe istringstream

721 Preacutesentation

Un objet de classe istringstream peut ecirctre creacuteeacute agrave partir drsquoun tableau de caractegraveres drsquounechaicircne constante ou drsquoun objet de type string Ainsi ces trois exemples creacuteent le mecircme objetch

istringstream entree (123 452 salut)

string ch = 123 452 salut istringstream entree (ch)

char ch[] = 123 452 salut istringstream entree (ch)

On peut alors extraire des caractegraveres du flot ch par des instructions usuelles telles que ch gtgt gtgt gtgt

Voici un petit exemple illustrant ces possibiliteacutes

include ltiostreamgtinclude ltsstreamgtusing namespace std main() string ch = 123 452 salut istringstream entree (ch) int n float x string s entree gtgt n gtgt x gtgt s cout ltlt n = ltlt n ltlt x = ltlt x ltlt s = ltlt s ltlt n if (entree gtgt s) cout ltlt s = ltlt s ltlt n else cout ltlt fin flot entreen

n = 123 x = 452 s = salutfin flot entree

Exemple drsquoutilisation de la classe istringstream

722 Utilisation pour fiabiliser les lectures au clavier

On voit que drsquoune maniegravere geacuteneacuterale la deacutemarche qui consiste agrave lire une ligne en meacutemoireavant de lrsquoexploiter peut ecirctre utiliseacutee pour (revoyez eacuteventuellement le paragraphe 35 du cha-pitre 3)

bull reacutegler le problegraveme de deacutesynchronisation entre lrsquoentreacutee et la sortie

bull supprimer les risques de blocage et de bouclage en cas de preacutesence drsquoun caractegravere invalidedans le flot drsquoentreacutee

La classe stringCHAPITRE 22

496

Voici un exemple montrant comment reacutesoudre les problegravemes engendreacutes par la frappe drsquounmauvais caractegravere dans le cas de la lecture sur lrsquoentreacutee standard Il srsquoagit en fait de lrsquoadapta-tion du programme preacutesenteacute auparagraphe 352 du chapitre 3 et dont nous avions proposeacuteune ameacutelioration au paragraphe 72 du chapitre 16 (en utilisant la classe istrstream appeleacutee agravedisparaicirctre dans le futur)

include ltiostreamgt

include ltsstreamgt

using namespace std

main()

int n

bool ok = false

char c

string ligne pour lire une ligne au clavier

do cout ltlt donnez un entier et un caractere n

getline (cin ligne)

istringstream tampon (ligne)

if (tampon gtgt n gtgt c) ok = true

else ok = false

while ( ok)

cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

donnez un entier et un caractere

bof

donnez un entier et un caractere

x 123

donnez un entier et un caractere

12 bonjour

merci pour 12 et b

Pour lire en toute seacutecuriteacute sur lrsquoentreacutee standard (1)

Nous y lisons tout drsquoabord lrsquoinformation attendue pour toute une ligne sous forme drsquounechaicircne de caractegraveres agrave lrsquoaide de la fonction getline (pour pouvoir lire tous les caractegraveres seacutepa-rateurs agrave lrsquoexception de la fin de ligne) Nous construisons ensuite avec cette chaicircne unobjet de type istrsingtream sur lequel nous appliquons nos opeacuterations de lecture (ici lectureformateacutee drsquoun entier puis drsquoun caractegravere) Comme vous le constatez aucun problegraveme ne sepose plus lorsque lrsquoutilisateur fournit un caractegravere invalide

Voici eacutegalement une ameacutelioration du programme proposeacute au paragraphe 353 du chapitre 3

include ltiostreamgt

include ltsstreamgt

using namespace std

7 - Les possibiliteacutes de formatage en meacutemoire497

main() int n bool ok = false string ligne pour lire une ligne au clavier do ok = false cout ltlt donnez un nombre entier while ( ok) do getline (cin ligne) istringstream tampon (ligne) if (tampon gtgt n) ok = true else ok = false cout ltlt information incorrecte - donnez un nombre entier while ( ok) cout ltlt voici son carre ltlt nn ltlt n while (n)

donnez un nombre entier 4voici son carre 16donnez un nombre entier ampinformation incorrecte - donnez un nombre entier 7voici son carre 49donnez un nombre entier ze 25 8information incorrecte - donnez un nombre entier 5voici son carre 25donnez un nombre entier 0voici son carre 0

Pour lire en toute seacutecuriteacute sur lrsquoentreacutee standard (2)

23

Les outils numeacuteriques

La bibliothegraveque standard offre quelques patrons de classes destineacutes agrave faciliter les opeacuterationsmatheacutematiques usuelles sur les nombres complexes et sur les vecteurs de maniegravere agrave doterC++ de possibiliteacutes voisines de celles de Fortran 90 et agrave favoriser son utilisation sur des cal-culateurs vectoriels ou parallegraveles Il sagit essentiellement

bull des classes complex

bull des classes valarray et des classes associeacutees

Drsquoautre part on dispose de classes bitset permettant de manipuler efficacement des suites debits

On notera bien que les classes deacutecrites dans ce chapitre ne sont pas des conteneurs agrave partentiegravere mecircme si elles disposent de certaines de leurs proprieacuteteacutes

1 La classe complex Le patron de classe complex offre de tregraves riches outils de manipulation des nombres comple-xes Il peut ecirctre parameacutetreacute par nimporte quel type flottant float double ou long double Ilcomporte

bull les opeacuterations arithmeacutetiques usuelles + -

bull laffectation (ordinaire ou composeacutee comme += -=)

bull les fonctions de base

ndash abs module

Les outils numeacuteriquesCHAPITRE 23

500

ndash arg argument

ndash real partie reacuteelle

ndash imag partie imaginaire

ndash conj complexe conjugueacute

bull les fonctions transcendantes

ndash cos sin tan

ndash acos asin atan

ndash cosh sinh tanh

ndash exp log

bull le patron de fonctions polar (parameacutetreacute par un type) qui permet de construire un nombrecomplexe agrave partir de son module et de son argument

Voici un exemple dutilisation de la plupart de ces possibiliteacutes

include ltiostreamgtinclude ltcomplexgtusing namespace std main() complexltdoublegt z1(1 2) z2(2 5) z zr cout ltlt z1 ltlt z1 ltlt z2 ltlt z2 ltlt n cout ltlt Re(z1) ltlt real(z1) ltlt Im(z1) ltlt imag(z1) ltlt n cout ltlt abs(z1) ltlt abs(z1) ltlt arg(z1) ltlt arg(z1) ltlt n cout ltlt conj(z1) ltlt conj(z1) ltlt n cout ltlt z1 + z2 ltlt (z1+z2) ltlt z1z2 ltlt (z1z2) ltlt z1z2 ltlt (z1z2) ltlt n

complexltdoublegt i(0 1) on definit la constante i z = 10+i zr = exp(z) cout ltlt exp(1+i) ltlt zr ltlt exp(i) ltlt exp(i) ltlt n zr = log(i) cout ltlt log(i) ltlt zr ltlt n zr = log(10+i) cout ltlt log(1+i) ltlt zr ltlt n double rho theta norme rho = abs(z) theta = arg(z) norme = norm(z) cout ltlt abs(1+i) ltlt rho ltlt arg(1+i) ltlt theta ltlt norm(1+i) ltlt norme ltlt n double pi = 31415926535 cout ltlt cos(i) ltlt cos(i) ltlt sinh(pii) ltlt sinh(pii) ltlt cosh(pii) ltlt cosh(pii) ltlt n

z = polarltdoublegt (1 pi4) cout ltlt polar (1 pi4) ltlt z ltlt n

2 - La classe valarray et les classes associeacutees501

z1 (12) z2 (25)Re(z1) 1 Im(z1) 2abs(z1) 223607 arg(z1) 110715conj(z1) (1-2)z1 + z2 (37) z1z2 (-89) z1z2 (0413793-00344828)exp(1+i) (146869228736) exp(i) (05403020841471)log(i) (015708)log(1+i) (03465740785398)abs(1+i) 141421 arg(1+i) 0785398 norm(1+i) 2cos(i) (1543080) sinh(pii) (0897932e-011) cosh(pii) (-10)polar (1 pi4) (07071070707107)

Exemples dutilisation de nombres complexes

2 La classe valarray et les classes associeacuteesLa bibliothegraveque standard dispose drsquoun patron de classes valarray particuliegraverement bienadapteacute agrave la manipulation de vecteurs (au sens matheacutematique du terme) crsquoest-agrave-dire detableaux numeacuteriques Il offre en particulier des possibliteacutes de calcul vectoriel comparables agravecelles qursquoon trouve dans un langage scientifique tel que Fortran 90 En outre quelques clas-ses utilitaires permettent de manipuler des sections de vecteurs certaines drsquoentre elles facili-tent la manipulation de tableaux agrave plusieurs dimensions (deux ou plus)

21 Constructeurs des classes valarrayOn peut construire des vecteurs dont les eacuteleacutements sont dun type de base bool char int floatdouble ou drsquoun type complex1

Voici quelques exemples de construction include ltvalarraygtusing namespace std valarrayltintgt vi1 (10) vecteur de 10 int non initialiseacutes2 valarrayltfloatgt vf (01 20) vecteur de 20 float initialiseacutes agrave 01 int t[] = 1 3 5 7 9 valarray ltintgt vi2 (t 5) vecteur de 5 int intialiseacute avec les 5 (premiegraveres) valeurs de t valarray ltcomplexltfloatgt gt vcf (20) vecteur de 20 complexes valarray ltintgt v vecteur vide pour lrsquoinstant

1 En fait on peut utiliser comme paramegravetre de type du patron valarray tout type classe muni drsquoun constructeur par

recopie drsquoun destructeur drsquoun opeacuterateur drsquoaffectation et doteacute de tous les opeacuterateurs et de toutes les fonctions

applicables agrave un type numeacuterique

2 En toute rigueur si le vecteur vi1 est de classe statique ses eacuteleacutements seront initialiseacutes agrave 0 Dans le cas de vecteurs

dont les eacuteleacutements sont des objets ces derniers seront initialiseacutes par appel du constructeur par deacutefaut

Les outils numeacuteriquesCHAPITRE 23

502

On notera que la classe valarray nrsquoest pas un vrai conteneur en particulier il nrsquoest pas pos-sible de construire directement un objet de ce type agrave partir drsquoune seacutequence sauf si cetteseacutequence est celle deacutecrite par un pointeur usuel (comme dans le cas de vi2)

22 Lrsquoopeacuterateur []Une fois un vecteur construit on peut acceacuteder agrave ses eacuteleacutements de faccedilon classique en utilisantlrsquoopeacuterateur [] comme dans

valarray ltintgt vi (5) int n i v[3] = 1 n = v[i] + 2

Aucune protection nrsquoest preacutevue sur la valeur utiliseacutee comme indice

23 Affectation et changement de tailleLrsquoaffectation entre vecteurs dont les eacuteleacutements sont de mecircme type est possible mecircme srsquoilsnrsquoont pas le mecircme nombre drsquoeacuteleacutements En revanche lrsquoaffectation nrsquoest pas possible si les eacuteleacute-ments ne sont pas de mecircme type

valarray ltfloatgt vf1 (01 20) vecteur de 20 float eacutegaux agrave 01 valarray ltfloatgt vf2 (05 10) vecteur de 10 float eacutegaux agrave 05 valarray ltfloatgt vf3 vecteur vide pour lrsquoinstant valarray ltintgt vi (1 10) vecteur de 10 int eacutegaux agrave 1 vf1 = vf2 OK vf1 et vf2 sont deux vecteurs de 10 float eacutegaux agrave 05 les anciennes valeurs de vf1 sont perdues vf3 = vf2 OK vf3 comporte maintenant 10 eacuteleacutements vf1 = vi incorrect on peut faire for (i=0 iltvf1size() i++) vf1[i] = vi [i]

La fonction membre resize permet de modifier la taille drsquoun vecteur vf1resize(15) vf1 comporte maintenant 15 eacuteleacutements les 10 premiers ont conserveacute leur valeur vf3resize (6) vf3 ne comporte plus que 6 eacuteleacutements (leur valeur nrsquoa pas changeacute)

24 Calcul vectorielLes classes valarray permettent deffectuer des opeacuterations usuelles de calcul vectoriel engeacuteneacuteralisant le rocircle des opeacuterateurs et des fonctions numeacuteriques un opeacuterateur unaire appliqueacuteagrave un vecteur fournit en reacutesultat le vecteur obtenu en appliquant cet opeacuterateur agrave chacun de seseacuteleacutements un opeacuterateur binaire appliqueacute agrave deux vecteurs de mecircme taille fournit en reacutesultat levecteur obtenu en appliquant cet opeacuterateur agrave chacun des eacuteleacutements de mecircme rang Parexemple

2 - La classe valarray et les classes associeacutees503

valarrayltfloatgt v1(5) v2(5) v3(5)

v3 = -v1 v3[i] = -v1[i] pour i de 0 agrave 4

v3 = cos(v1) v3[i] = cos(v1[i]) pour i de 0 agrave 4

v3 = v1 + v2 v3[i] = v2[i] + v1[i] pour i de 0 agrave 4

v3 = v1v2 + exp(v1) v3[i] = v1[i]v2[i] + exp(v1[i]) pour i de 0 agrave 4

On peut mecircme appliquer une fonction de son choix agrave tous les eacuteleacutements drsquoun vecteur en utili-sant la fonction membre apply Par exemple si fct est une fonction recevant un float et ren-voyant un float

v3 = v1apply(fct) v3[i] = fct (v1[i]) pour i de 0 agrave 4

On trouve eacutegalement des opeacuterateurs de comparaison (== = lt lt=) qui sappliquent agrave deuxopeacuterandes (de type valarray) de mecircme nombre deacuteleacutements et qui fournissent en reacutesultat unvecteur de booleacuteens

int dim =

valarrayltfloatgt v1(dim) v2(dim)

valarrayltboolgt egal(dim) inf(dim)

egal = (v1 == v2) egal[i] = (v1[i] == v2[i]) pour i de 0 agrave dim-1

inf = (v1 lt v2) inf[i] = (v1[i] lt v2[i]) pour i de 0 agrave dim-1

Les fonctions max et min permettent drsquoobtenir le plus grand1 ou le plus petit eacuteleacutement drsquounvecteur

int vmax vmin t[] = 3 9 12 4 7 6

valarray ltintgt vi (t 6)

vmax = max (vi) vmax vaut 12

vmin = min (vi) vmin vaut 3

La fonction membre shift permet drsquoeffectuer des deacutecalages des eacuteleacutements drsquoun vecteur Ellefournit un vecteur de mecircme taille que lrsquoobjet lrsquoayant appeleacute dans lequel les eacuteleacutements ont eacuteteacutedeacutecaleacutes drsquoun nombre de positions indiqueacute par son unique argument (vers la gauche pour lesvaleurs positives vers la droite pour les valeurs neacutegatives) Les valeurs sortantes sont per-dues les valeurs entrantes sont agrave zeacutero Enfin la fonction membre cshift permet drsquoeffecteurdes deacutecalages circulaires

int t[] = 3 9 12 4 7 6

valarray ltintgt vi (t 6) vig vid vic

vig = vishift (2) vi est inchangeacute - vig contient 12 4 7 6 0 0

vid = vishift (-3) vi est inchangeacute - vid contient 0 0 0 3 9 12

vic = vicshift (3) vi est inchangeacute - vic contient 4 7 6 3 9 12

1 Lorsque les eacuteleacutements sont des objets on utilise operator lt qui doit alors avoir eacuteteacute surdeacutefini

Les outils numeacuteriquesCHAPITRE 23

504

25 Seacutelection de valeurs par masqueOn peut seacutelectionner certaines des valeurs drsquoun vecteur afin de constituer un vecteur de tailleinfeacuterieure ou eacutegale Pour ce faire on utilise un masque crsquoest-agrave-dire un vecteur de type valar-

rayltboolgt dans lequel chacun des eacuteleacutements preacutecise si lrsquoon seacutelectionne (true) ou non (false)lrsquoeacuteleacutement correspondant Supposons par exemple que lrsquoon dispose de ces deacuteclarations

valarray ltboolgt masque(6) on suppose que masque contient true true false true false true valarray ltintgt vi(6) on suppose que vi contient 5 8 2 7 3 9

Lrsquoexpression vi[masque] deacutesigne un vecteur formeacute des seuls eacuteleacutements de vi pour lesquelslrsquoeacuteleacutement correspondant de masque a la valeur true Ici il srsquoagit donc drsquoun vecteur de quatreentiers (5 8 7 9) Par exemple

valarray ltintgt vi1 vecteur vide pour lrsquoinstant vi1 = vi[masque] vi1 est un vecteur de 4 entiers 5 8 7 9

Qui plus est une telle notation reste utilisable comme lvalue En voici deux exemples utili-sant les mecircmes deacuteclarations que ci-dessus

vi[masque] = -1 place la valeur -1 dans les eacuteleacutements de vi pour lesquels la valeur de lrsquoeacuteleacutement correspondant de masque est true valarrayltintgt v(12 4) vecteur de 4 eacuteleacutements vi[masque] = v recopie les premiers eacuteleacutements de v dans les eacuteleacutements de vi pour lesquels la valeur de lrsquoeacuteleacutement correspondant de masque est true

Voici un exemple de programme complet illustrant ces diffeacuterentes possibiliteacutes

include ltiostreamgtinclude ltvalarraygtinclude ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtusing namespace std main() int i int t[] = 1 2 3 4 5 6 bool mt[] = true true false true false true valarray ltintgt v1 (t 6) v2 v2 vide pour linstant valarray ltboolgt masque (mt 6) v2 = v1[masque] cout ltlt v2 for (i=0 iltv2size() i++) cout ltlt setw(4) ltlt v2[i] cout ltlt n

v1[masque] = -1 cout ltlt v1 for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

2 - La classe valarray et les classes associeacutees505

valarray ltintgt v3(8) il faut au moins 4 elements dans v3 for (i=0 iltv3size() i++) v3[i] = 10(i+1) v1[masque] = v3 cout ltlt v1 for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

v2 1 2 4 6v1 -1 -1 3 -1 5 -1v1 10 20 3 30 5 40

Exemple drsquoutilisation de masques

26 Sections de vecteursIl est possible de deacutefinir des sections de vecteurs on nomme ainsi un sous-ensemble deseacuteleacutements dun vecteur sur lequel on peut travailler comme sil sagissait dun vecteur Parexemple si v est deacuteclareacute ainsi

valarray ltintgt v(12)

lrsquoexpression v[slice(0 4 2)] deacutesigne le vecteur obtenu en ne consideacuterant de v que les eacuteleacute-ments de rang 0 2 4 et 6 (on part de 0 on considegravere 4 valeurs en progressant par pas de 2)

Lagrave encore une telle notation est utilisable comme lvalue v1 [slice(0 4 2)] = 99 place la valeur 99 dans les eacuteleacutements v1[0] v1[2] v1[4] et v1[6]

Voici un exemple de programme complet illustrant ces possibiliteacutes

include ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtusing namespace std main() int i int t [] = 0 1 2 3 4 5 6 7 8 9 valarray ltintgt v1 (t 10) v2 cout ltlt v1 initial for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

v1[slice(0 4 2)] = -1 v1[0] = -1 v1[2] = -1 v1[4] = -1 v1[6] = -1 cout ltlt v1 modifie for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n v2 = v1[slice(1 3 4)] on considegravere v1[1] v1[5] et v1[9] cout ltlt v2 for (i=0 iltv2size() i++) cout ltlt setw(4) ltlt v2[i] cout ltlt n

Les outils numeacuteriquesCHAPITRE 23

506

v1 initial 0 1 2 3 4 5 6 7 8 9v1 modifie -1 1 -1 3 -1 5 -1 7 8 9v2 1 5 9

Exemple drsquoutilisation de sections de vecteurs

On notera que les sections de vecteurs peuvent srsquoaveacuterer utiles pour manipuler des tableaux agravedeux dimensions et en particulier des matrices Consideacuterons ces deacuteclarations dans lesquellesmat est un vecteur dont les NLIGNCOL eacuteleacutements peuvent servir agrave repreacutesenter une matricede NLIG lignes et de NCOL colonnes

define NLIG 5define NCOL 12 valarray ltfloatgt v(NLIG) vecteur de NLIG eacuteleacutements valarray ltfloatgt mat (NLIGNCOL) pour repreacutesenter une matrice

Si lrsquoon convient drsquoutiliser les conventions du C pour ranger les eacuteleacutements de notre matricedans le vecteur mat voici quelques exemples drsquoopeacuterations faciliteacutees par lrsquoutilisation desections

bull placer la valeur 12 dans la ligne i de la matrice mat

mat [slice (iNCOL NCOL 1)] = 12

bull placer la valeur 15 dans la colonne j de la matrice mat

mat [slice (j NLIG NCOL)] = 15

bull recopier le vecteur v dans la colonne j de la matrice mat

mat [slice (j NLIG NCOL)] = v

Remarque

La notion de section de vecteur peut permettre de manipuler non seulement des matrices

mais aussi des tableaux agrave plus de deux dimensions Dans ce dernier cas on peut eacutegale-

ment recourir agrave la notion de sections multiples obtenues en utilisant gslice agrave la place de

slice

27 Vecteurs drsquoindicesLes sections de vecteurs obtenues par slice sont dites reacuteguliegraveres dans la mesure ougrave les eacuteleacute-

ments seacutelectionneacutes sont reacuteguliegraverement espaceacutes les uns des autres On peut aussi obtenir des

sections quelconques en recourant agrave ce que lrsquoon nomme un vecteur drsquoindices Par exemple

si les vecteurs indices et vf sont deacuteclareacutes ainsi

valarray ltfloatgt vf(12) valarray ltintgt indices (5) on suppose que indices contient les valeurs 1 4 2 3 0

3 - La classe bitset507

lrsquoexpression v[indices] deacutesigne le vecteur obtenu en consideacuterant les eacuteleacutements de vf2 suivant

lrsquoordre mentionneacute par le vecteur drsquoindices indices crsquoest-agrave-dire ici 1 4 2 3 0 Lagrave encore

cette notation peut ecirctre utiliseacutee comme lvalue

Voici un exemple de programme complet illustrant ces possibiliteacutes

include ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtinclude ltcstdlibgt pour size_tusing namespace std main() size_t ind[] = 1 4 2 3 0 float tf [] = 125 25 52 83 54 int i valarray ltsize_tgt indices (ind 5) contient 1 4 2 3 0 for (i=0 ilt5 i++) cout ltlt setw(8) ltlt indices[i] cout ltlt n valarray ltfloatgt vf1 (tf 5) vf2(5) vf2[indices] = vf1 affecte vf1[i] agrave vf2 [indices[i]] for (i=0 ilt5 i++) cout ltlt setw(8) ltlt vf2[i] cout ltlt n

1 4 2 3 0 54 125 52 83 25

Exemple drsquoutilisation de vecteurs drsquoindices

On notera qursquoil nrsquoest pas neacutecessaire que tous les eacuteleacutements de vf2 soient concerneacutes par les

indices mentionneacutes (le vecteur drsquoindice peut comporter moins drsquoeacuteleacutements que vf2) En revan-

che comme on peut srsquoy attendre il faut eacuteviter qursquoun mecircme indice ne figure deux fois dans le

vecteur drsquoindice dans ce cas le comportement du programme est indeacutetermineacute (en pratique

un mecircme eacuteleacutement est modifieacute deux fois)

3 La classe bitsetLe patron de classes bitsetltNgt permet de manipuler efficacement des suites de bits dont la

taille N apparaicirct en paramegravetre (expression) du patron Lrsquoaffectation nrsquoest donc possible

qursquoentre suites de mecircme taille On dispose notamment des opeacuterations classiques de manipu-

lation globale des bits agrave lrsquoaide des opeacuterateurs amp | ~ amp= |= ltlt= gtgt= ~= == = qui fonc-

tionnent comme les mecircmes opeacuterateurs appliqueacutes agrave des entiers

On peut acceacuteder agrave un bit de la suite agrave lrsquoaide de lrsquoopeacuterateur [] il deacuteclenche une exception

out_of_range si son second opeacuterande nrsquoest pas dans les limites permises

Les outils numeacuteriquesCHAPITRE 23

508

Il existe trois constructeurs

bull sans argument on obtient une suite de bits nuls

bull agrave partir drsquoun unsigned long on obtient la suite correspondant au motif binaire contenu dans

lrsquoargument

bull agrave partir drsquoune chaicircne de caractegraveres (string) on peut aussi utiliser une chaicircne usuelle (notam-

ment une constante) gracircce aux possibiliteacutes de conversions

Voici un exemple illustrant la plupart des fonctionnaliteacutes de ces patrons de classes

include ltiostreamgtinclude ltbitsetgtusing namespace std main() bitsetlt12gt bs1 (1101101101) bitset initialise par une chaine long n=0x0FFF bitsetlt12gt bs2 (n) bitset initialise par un entier bitsetlt12gt bs3 bitset initialise a zero cout ltlt bs1 = ltlt bs1 ltlt n cout ltlt bs2 = ltlt bs2 ltlt n cout ltlt bs3 = ltlt bs3 ltlt n if (bs3 = bs1) cout ltlt bs3 differe de bs1n bs3 = bs1 affectation entre bitset de mecircme taille cout ltlt bs3 = ltlt bs3 ltlt n if (bs3 == bs1) cout ltlt bs3 est maintenant egal a bs1n cout ltlt bit de rang 3 de bs3 ltlt boolalpha ltlt bs3[3] ltlt n bs3[3] = 0 cout ltlt bit de rang 3 de bs3 ltlt boolalpha ltlt bs3[3] ltlt n try bs3[15] = 1 indice hors limite --gt exception catch (exception ampe) cout ltlt exception ltlt ewhat() ltlt n

cout ltlt bs3 ltlt amp ltlt bs2 ltlt = bs3 amp= bs2 cout ltlt bs3 ltlt n cout ltlt bs3 ltlt | ltlt bs2 ltlt = bs3 |= bs2 cout ltlt bs3 ltlt n cout ltlt ~ ltlt bs3 ltlt = ltlt ~bs3 ltlt n cout ltlt dans ltlt bs3 ltlt il y a ltlt bs3count() ltlt bits a unn cout ltlt bs3 ltlt decale de 4 a gauche = ltlt (bs3 ltlt= 4) ltlt n

bitsetlt14gt bs4 bs4 = bs1 serait incorrect car bs1 et bs4 nrsquoont pas la mecircme taille

3 - La classe bitset509

bs1 = 001101101101bs2 = 111111111111bs3 = 000000000000bs3 differe de bs1bs3 = 001101101101bs3 est maintenant egal a bs1bit de rang 3 de bs3 truebit de rang 3 de bs3 falseexception invalid bitsetltNgt position001101100101 amp 111111111111 = 001101100101001101100101 | 111111111111 = 111111111111~ 111111111111 = 000000000000dans 111111111111 il y a 12 bits a un111111110000 decalle de 4 a gauche = 111111110000

Exemples drsquoutilisation du patron de classes bitset

24

Les espaces de noms

La notion drsquoespace de noms a eacuteteacute preacutesenteacutee succinctement au paragraphe 8 du chapitre 4 afin

de vous permettre drsquoutiliser convenablement la bibliothegraveque standard du C++

Drsquoune maniegravere geacuteneacuterale elle permet de deacutefinir des ensembles disjoints drsquoidentificateurs cha-

que ensemble eacutetant repeacutereacute par un nom qursquoon utilise pour qualifier les symboles concerneacutes Il

devient ainsi possible drsquoutiliser le mecircme identificateur pour deacutesigner deux choses diffeacuterentes

(ou deux versions diffeacuterentes drsquoune mecircme chose par exemple une classe) pour peu qursquoelles

appartiennent agrave deux espaces de noms diffeacuterents Cette notion preacutesente surtout un inteacuterecirct dans

le cadre de deacuteveloppement de gros programmes ou de bibliothegraveques Crsquoest ce qui justifie sa

preacutesentation deacutetailleacutee dans un chapitre seacutepareacute aussi tardif

Nous commencerons par vous montrer comment deacutefinir un nouvel espace de noms et com-

ment deacutesigner les symboles qursquoil contient Puis nous verrons comment lrsquoinstruction using

permet de simplifier les notations soit en citant une seule fois les symboles concerneacutes soit en

citant lrsquoespace de noms lui-mecircme (comme vous le faites actuellement avec using namespace

std) Nous montrerons ensuite comment la surdeacutefinition des fonctions franchit les limites des

espaces de noms Enfin nous apporterons quelques informations compleacutementaires concer-

nant lrsquoimbrication des espaces de noms la transitiviteacute de lrsquoinstruction using et les espaces de

noms anonymes

1 Creacuteation drsquoespaces de nomsIci nous allons vous montrer comment creacuteer un ou plusieurs nouveaux espaces de noms et

comment utiliser les symboles correspondants

Les espaces de nomsCHAPITRE 24

512

11 Exemple de creacuteation drsquoun nouvel espace de nomsConsideacuterons ces instructions

namespace A les symbole deacuteclareacutes agrave partir drsquoici appartiennent agrave lrsquoespace de noms nommeacute A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) fin de la deacutefinition de lrsquoespace de noms A

A lrsquointeacuterieur du bloc

namespace A

on trouve des deacuteclarations usuelles ici de types de variables (n et x) et de deacutefinition de classe

(point) Le fait que ces deacuteclarations figurent dans un espace de noms ne modifie pas la

maniegravere de les eacutecrire En revanche les symboles correspondants ne seront utilisables agrave lrsquoexteacute-

rieur de ce bloc que moyennant lrsquoutilisation drsquoun preacutefixe approprieacute A Voici quelques

exemples

la deacutefinition de A est supposeacutee connue icimain() Ax=25 utilise la variable globale x deacuteclareacutee dans A Apoint p1 on utilise le type point de A Apoint p2 (1 3) idem An = 1 on utilise la variable globale n deacuteclareacutee dans A

Ces symboles peuvent cohabiter sans problegraveme avec des symboles deacuteclareacutes en dehors de tout

espace de noms comme nous lrsquoavons fait jusqursquoici

la deacutefinition de A est supposeacutee connue icilong n variable globale n sans rapport avec An main() double x variable x locale agrave main sans rapport avec Ax Ax = 25 utilise toujours la variable globale x deacuteclareacutee dans A point p incorrect le type point nrsquoest pas connu An = 12 utilise la variable globale n deacuteclareacutee dans A n = 5 utilise la variable globale n deacuteclareacutee en dehors de A

On notera bien que le preacutefixe A est neacutecessaire degraves lors qursquoon est en dehors de la porteacutee de la

deacutefinition de lrsquoespace de noms A mecircme si lrsquoon se trouve dans le mecircme fichier source Crsquoest

drsquoailleurs gracircce agrave cette regravegle que nous pouvons utiliser conjointement les identificateurs n et

An

1 - Creacuteation drsquoespaces de noms513

On dit des symboles comme n ou x deacuteclareacutes en dehors de tout espace de noms qursquoils appar-

tiennent agrave lrsquoespace global1 Ces symboles pourraient drsquoailleurs ecirctre aussi deacutesigneacutes sous la

forme x ou n2

Remarque

Nous verrons au paragraphe 2 que les deux formes de lrsquoinstruction using permettent de

simplifier lrsquoutilisation de symboles deacutefinis dans des espaces de noms en eacutevitant drsquoavoir agrave

utiliser le preacutefixe correspondant

12 Exemple avec deux espaces de nomsConsideacuterons maintenant ces instructions deacutefinissant et utilisant deux espaces de noms nom-

meacutes A et B

namespace A deacutebut deacutefinition espace de noms A

int n

double x

class point

int x y

public

point (int abs=0 int ord=0) x(abs) y(ord)

fin deacutefinition espace de noms A

namespace B deacutebut deacutefinition espace de noms B

float x

class point

int x y

public

point () x(0) y(0)

fin deacutefinition espace de noms B

main()

Apoint pA1(3) OK utilise le type point de A

Bpoint pB1 OK utilise le type point de B

Bpoint pb2 (3) erreur pas de constructeur agrave un argument

dans le type point de B

Ax = 25 utilise la variable globale x de lrsquoespace A

Bx = 32 utilise la variable globale x de lrsquoespace B

1 On ne confondra pas cette notion drsquoespace global avec celle drsquoespace anonyme (preacutesenteacutee au paragraphe 7)

2 Cette forme sera surtout utiliseacutee pour lever une ambiguiumlteacute

Les espaces de nomsCHAPITRE 24

514

13 Espace de noms et fichier en-tecircteDans nos preacuteceacutedents exemples drsquointroduction la deacutefinition de lrsquoespace de noms et lrsquoutilisa-

tion des symboles correspondants se trouvaient dans le mecircme fichier source Il va de soi qursquoil

nrsquoen ira pratiquement jamais ainsi la deacutefinition drsquoun espace de noms figurera dans un fichier

en-tecircte qursquoon incorporera classiquement par une directive include on notera bien qursquoalors

lrsquoabsence de cette directive conduira agrave une erreur

main() Ax = 2 si la deacutefinition de lrsquoespace de noms A nrsquoa pas eacuteteacute compileacutee agrave ce niveau on obtiendra une erreur

14 Instructions figurant dans un espace de nomsIl faut tout drsquoabord remarquer que la deacutefinition drsquoun espace de noms a toujours lieu agrave un

niveau global1 Il nrsquoest (heureusement) pas permis de lrsquoeffectuer au sein drsquoune classe ou

drsquoune fonction

main() intx namespace A incorrect

Comme on srsquoy attend un espace de noms peut renfermer des deacutefinitions de fonctions ou de

classes comme dans cet exemple

namespace A deacutebut deacutefinition espace de noms A class point int x y public point () deacuteclaration constructeur void affiche () deacuteclaration fonction membre affiche pointpoint() deacutefinition du constructeur de Apoint void pointaffiche() deacutefinition de la fonction affiche de Apoint void f (int n) deacutefinition de f fin deacutefinition espace de noms A

Dans ce cas il est cependant preacutefeacuterable de dissocier la deacuteclaration des classes et des fonc-

tions de leur deacutefinition en preacutevoyant

1 Nous verrons toutefois au paragraphe 4 que les deacutefinitions drsquoespaces de noms peuvent srsquoimbriquer

1 - Creacuteation drsquoespaces de noms515

bull un fichier en-tecircte contenant la deacutefinition de lrsquoespace de noms limiteacutee aux deacuteclarations des

fonctions et des classes

fichier en-tecircte Ah

deacuteclaration des symboles figurant dans lrsquoespace A

namespace A deacutebut deacutefinition espace de noms A

class point

int x y

public

point () deacuteclaration constructeur

void affiche () deacuteclaration fonction membre affiche

void f (int n) deacuteclaration de f

fin deacutefinition espace de noms A

bull un fichier source contenant la deacutefinition des classes et des fonctions

deacutefinition des symboles figurant dans lrsquoespace A

include Ah incorporation de la deacutefinition de lrsquoespace A

void Apointpoint()

deacutefinition du constructeur de Apoint

Apointaffiche()

deacutefinition de la fonction affiche de Apoint

void f (int n) deacutefinition de la fonction f

15 Creacuteation increacutementale drsquoespaces de nomsIl est tout agrave fait possible de deacutefinir un mecircme espace de noms en plusieurs fois Par exemple

namespace A

int n

namespace B

float x

namespace A

double x

Cette deacutefinition est ici eacutequivalente agrave

namespace A

int n

double x

namespace B

float x

Les espaces de nomsCHAPITRE 24

516

A ce propos il faut signaler que si un identificateur deacuteclareacute dans un espace de noms peut

ensuite ecirctre deacutefini agrave lrsquoexteacuterieur (voir paragraphe 14) il nrsquoest pas possible de deacuteclarer un nou-

vel identificateur de cette mecircme maniegravere

namespace A int n namespace B float x double Ax erreur

Cette possibiliteacute de creacuteation increacutementale srsquoavegravere extrecircmement inteacuteressante dans le cas drsquoune

bibliothegraveque En effet elle permet de la deacutecouper en plusieurs parties relativement indeacutepen-

dantes tout en nrsquoutilisant qursquoun seul espace de noms pour lrsquoensemble Lrsquoutilisateur peut ainsi

nrsquointroduire que les seules deacutefinitions utiles Crsquoest drsquoailleurs exactement ce qui se produit

avec la bibliothegraveque standard dont les symboles sont deacutefinis dans lrsquoespace de noms std Une

directive telle que include ltiostreamgt incorpore en fait une deacutefinition partielle de lrsquoespace

de noms std une directive include ltvectorgt en incorpore une autre

2 Les instructions usingNous venons de voir comment utiliser un symbole deacutefini dans un espace de noms en le qua-

lifiant explicitement par le nom de lrsquoespace (comme dans Ax) Cette meacutethode peut toutefois

devenir fastidieuse lorsqursquoon recourt systeacutematiquement aux espaces de noms dans un gros

programme En fait C++ offre deux faccedilons drsquoabreacuteger lrsquoeacutecriture

bull lrsquoune ougrave lrsquoon nomme une fois chacun des symboles qursquoon deacutesire utiliser

bull lrsquoautre ougrave lrsquoon se contente de citer lrsquoespace de noms lui-mecircme

Toutes les deux utilisent le mot cleacute using mais de maniegravere diffeacuterente on parle souvent de

deacuteclaration using dans le premier cas et de directive using dans le second

21 La deacuteclaration using pour les symboles

211 Preacutesentation geacuteneacuterale

La deacuteclaration using permet de citer un symbole appartenant agrave un espace de noms (dont la

deacutefinition est supposeacutee connue) En voici un exemple

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord)

2 - Les instructions using517

using Ax doreacutenavant x est synonyme de Axusing Apoint doreacutenavant point est synonyme de Apointlong n variable globale n sans rapport avec An main() x = 25 idem Ax = 25 n = 5 n deacutesigne la variable globale sans rapport avec An An = 10 correct point p1 (3) idem Apoint p1 (3)

La deacuteclaration using peut ecirctre locale comme dans cet exemple

namespace A int n double x long n variable globale n sans rapport avec Anmain () using An ici n est synonyme de Anvoid f () ici n nrsquoest plus synonyme de An mais de n

Bien entendu mecircme lorsque using est locale elle ne concerne que des symboles globaux

puisque les espaces de noms sont toujours deacutefinis agrave un niveau global

Voici un autre exemple utilisant plusieurs espaces de noms

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) namespace B float x class point int x y public point () x(0) y(0) using An n sera synonyme de Anusing Bx x sera synonyme de Bx

Les espaces de nomsCHAPITRE 24

518

main()

using Bpoint point sera (localement) synonyme de Bpoint

n = 2 idem An = 2

x = 5 idem Bx = 5

Ax = 3 correct

point pB1 idem Bpoint pB1

Apoint pA1(3) correct

void f()

using Apoint point sera (localement) synonyme de Apoint

using Ax x sera (localement agrave f) synonyme de Bx

point p (2) idem Apoint p (2)

212 Masquage et ambiguiumlteacutes

Comme on srsquoy attend un synonyme peut en cacher un autre drsquoune porteacutee englobante

les deacutefinitions des espaces de noms A et B sont supposeacutees connues ici

using Ax

ici x est synonyme de Ax

main()

using Bx

ici x est synonyme de Bx on peut toujours utiliser Ax

En revanche dans une mecircme porteacutee la deacuteclaration drsquoun synonyme ne doit pas creacuteer drsquoambi-

guiumlteacute comme dans

using Ax x est synonyme de Ax

using Bx x ne peut pas eacutegalement ecirctre synonyme de Bx

dans la mecircme porteacutee

ou dans

void g()

float x

using Ax incorrect on change la signification de x

On notera bien que ce genre drsquoambiguiumlteacute peut toujours ecirctre leveacutee en recourant agrave la notation

deacuteveloppeacutee des symboles

Remarque

Comme on le verra au paragraphe 3 cette notion drsquoambiguiumlteacute nrsquoexistera pas dans le cas

des fonctions afin de preacuteserver les possibiliteacutes de surdeacutefinition

2 - Les instructions using519

22 La directive using pour les espaces de nomsAvec la deacuteclaration using on peut choisir les symboles qursquoon souhaite utiliser dans une

espace de noms mais il est neacutecessaire drsquoutiliser une instruction par symbole Avec une seule

directive using on va pouvoir utiliser tous les symboles drsquoun espace de noms mais bien sucircr

on ne pourra plus opeacuterer de seacutelection

Voici un premier exemple

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) using namespace A tous les symboles deacutefinis dans A peuvent ecirctre utiliseacutes sans Amain() x = 25 idem Ax = 25 n = 5 idem An = 5 An = 10 toujours possible point p1 (3) idem Apoint p1 (3)

Comme la deacuteclaration using la directive using peut ecirctre locale

namespace A int n double x float x main () using namespace A ici n est synonyme de Anvoid f () ici x est synonyme de x

Les diffeacuterentes directives using se cumulent sans qursquoune quelconque prioriteacute ne permette de

les deacutepartager en cas drsquoambiguiumlteacute Il faut cependant noter que cette fois on nrsquoaboutit agrave une

erreur (de compilation) que lors de la tentative drsquoutilisation drsquoun symbole ambigu Voyez cet

exemple

namespace A int n double x class point int x y public point (int abs int ord) x(abs) y(ord) constructeur 2 arg

Les espaces de nomsCHAPITRE 24

520

namespace B float x class point int x y public point () x(0) y(0) constructeur 0 arg using namespace A using namespace B main() n = 2 idem An = 2 point p1 (3 5) ambiguuml Apoint ou Bpoint x = 5 ambiguuml Ax ou Bx

Le symbole n ne preacutesente aucune ambiguiumlteacute car il nrsquoest deacutefini que dans lrsquoespace A En revan-

che les symboles point et x eacutetant deacutefinis agrave la fois dans A et B il y ambiguiumlteacute Bien entendu il

reste toujours possible de la lever en preacutefixant explicitement les symboles concerneacutes par

exemple

Apoint p1 (3 5) Bx = 5

On notera qursquoavec la directive using la notion de masquage nrsquoexiste plus Une directive

situeacutee dans une porteacutee donneacutee ne se substitue pas agrave une directive drsquoune porteacutee englobante

elle la complegravete Par exemple avec les mecircmes espaces de noms A et B que preacuteceacutedemment

mecircmes deacutefinitions des espaces de noms A et B que preacuteceacutedemmentusing namespace A main() using namespace B n = 2 idem An = 2 point p1 (3 5) toujours ambigu Apoint ou Bpoint x = 5 ambigu Ax ou Bx

Remarques

1 Lagrave encore et comme on le verra au paragraphe 3 cette notion drsquoambiguiumlteacute nrsquoexistera pas

dans le cas des fonctions afin de preacuteserver les possibiliteacutes de surdeacutefinition On notera agrave ce

propos que dans lrsquoexemple preacuteceacutedent lrsquoambiguiumlteacute portait sur le nom de classe point et

non pas sur le nom drsquoune fonction (constructeur)

2 Notez que la plupart de nos exemples de programmes utilisent ces deux instructions

include ltiostreamgt using namespace std

Il faut bien prendre garde agrave ne pas en inverser lrsquoordre ainsi avec

using namespace std include ltiostreamgt

3 - Espaces de noms et surdeacutefinition521

on obtiendrait une erreur de compilation due agrave ce que lrsquoinstruction using mentionnerait

un espace de noms (std) inexistant (il est deacutefini de faccedilon increacutementale dans chacun

des fichiers en-tecircte comme iostream) En revanche avec ces instructions

include ltvectorgt

using namespace std

include ltiostreamgt

on nrsquoobtiendrait plus drsquoerreurs car le fichier en-tecircte vector contient deacutejagrave une deacutefinition

(partielle) de lrsquoespace de noms std

3 Espaces de noms et surdeacutefinitionLrsquointroduction drsquoun nom de fonction drsquoun espace de noms introduit simultaneacutement toutes les

deacuteclarations correspondantes

include ltiostreamgt

namespace A

void f(char c) stdcout ltlt f(char)n std car pas de using1

void f(int n) stdcout ltlt f(int)n

using Af on aurait la mecircme chose avec using namespace A

main()

int n=10 char c=a

f(n)

f(c)

f(int)

f(char)

Espaces de noms et surdeacutefinition de fonctions (1)

Lrsquointroduction drsquoun synonyme de fonction ne masque pas les autres fonctions de mecircme nom

deacutejagrave accessibles2 Voici un exemple ougrave la fonction f est deacutefinie dans deux espaces de noms

ainsi que dans lrsquoespace global

1 Ici par souci de clarteacute nous nrsquoavons pas utiliseacute drsquoinstruction using namespace std dans ces conditions il est alors

neacutecessaire de preacutefixer les noms de flots cin et cout par std

2 On dit parfois que la recherche drsquoune fonction surdeacutefinie franchit les espaces de noms

Les espaces de nomsCHAPITRE 24

522

include ltiostreamgtnamespace A void f(char c) stdcout ltlt Af(char)n void f(float x) stdcout ltlt Af(float)n namespace B void f(int n) stdcout ltlt Bf(int)n void f(double y) stdcout ltlt f(double)n using Af idem avec using namespace A using Bf idem avec using namespace B

main() int n=10 char c=a float x=25 double y=13 f(n) f(c) f(x) f(y)

Bf(int)Af(char)Af(float)f(double)

Espaces de noms et surdeacutefinition de fonctions (2)

Aux diffeacuterents espaces de noms susceptibles drsquoecirctre consideacutereacutes dans la reacutesolution drsquoun appel

de fonction il faut ajouter les espaces de noms de ses arguments effectifs Consideacuterez

namespace A class C void f(C) main() using AC introduit la classe C

C c f(c) recherche dans espace courant et dans celui de c (A) appelle bien Af(C) comme si on avait fait using Af

Ici nous nrsquointroduisons que le symbole C de lrsquoespace A Lrsquoappel de f est reacutesolu en examinant

non seulement les espaces concerneacutes (ici il ne srsquoagit que de lrsquoespace global qui ne possegravede

pas de fonction f) mais aussi celui dans lequel est deacutefini lrsquoargument effectif c crsquoest-agrave-dire

lrsquoespace de noms A Drsquoune maniegravere geacuteneacuterale si les argments effectifs appartiennent agrave des

espaces de noms diffeacuterents la recherche se fera dans ces diffeacuterentes porteacutees

4 - Imbrication des espaces de noms523

4 Imbrication des espaces de nomsLes deacutefinitions drsquoespaces de noms peuvent srsquoimbriquer comme dans cet exemple

namespace A deacutebut deacutefinition de lrsquoespace A int n An namespace B deacutebut deacutefinition de lrsquoespace AB float x ABx int n ABn fin deacutefinition de lrsquoespace AB float y Ay fin deacutefinition de lrsquoespace A

Disposant de ces deacuteclarations on pourra tout naturellement se reacutefeacuterer aux symboles corres-

pondants en utilisant les preacutefixes A ou AB De mecircme on pourra utiliser lrsquoune de ces

deacuteclarations1

using An n sera synonyme de Anusing ABn n sera synonyme de ABn

De la mecircme maniegravere on pourra recourir agrave des directives using comme dans

using namespace A on peut preacutefixer les symboles par A ici n deacutesigne An

ou dans

using namespace AB on peut preacutefixer les symboles par AB ici n deacutesigne ABn

ou encore dans

using namespace A ici x nrsquoa pas de signification (ni x ni Ax nrsquoexistent) Bx deacutesigne ABx

Ce dernier exemple montre que le fait de citer le nom drsquoun espace dans using nrsquointroduit pas

drsquooffice les noms des espaces imbriqueacutes

5 Transitiviteacute de la directive usingLa directive using peut srsquoutiliser dans la deacutefinition drsquoun espace de noms ce qui ne pose pas

de problegraveme particulier si lrsquoon sait que cette directive est transitive Autrement dit si une

directive using concerne un espace de noms qui contient lui-mecircme une directive using tout

se passe comme si lrsquoon avait eacutegalement mentionneacute cette seconde directive dans la porteacutee con-

cerneacutee Consideacuterons par exemple ces deacutefinitions

namespace A deacutebut deacutefinition espace A int n float y fin deacutefinition espace A

1 Bien entendu leur utilisation simultaneacutee conduirait agrave une ambiguiumlteacute

Les espaces de nomsCHAPITRE 24

524

namespace B deacutebut deacutefinition espace B using namepace A mecircme reacutesultat avec using An using Ay float x fin deacutefinition espace B

Avec une seule directive using namespace B on accegravede aux symboles deacutefinis effectivement

dans B mais eacutegalement agrave ceux deacutefinis dans A

using namepsace B ici x deacutesigne Bx n deacutesigne An et y deacutesigne Ay

On ne confondra pas cette situation avec lrsquoimbrication des espaces de noms eacutetudieacutee au para-

graphe 4

6 Les aliasIl est possible de deacutefinir un alias drsquoun espace de noms autrement dit un synonyme Par

exemple

namespace mon_espace_de_noms_favoris deacutefinition de mon_espace_de_noms_favorisnamespace MEF mon_espace_de_noms_favoris MEF est doreacutenavant un synonyme de mon_espace_de_noms_favorisusing namespace MEF eacutequivalent agrave using namespace mon_espace_de_noms_favoris

Cette possibiliteacute srsquoavegravere inteacuteressante pour deacutefinir des noms abreacutegeacutes drsquoespaces de noms jugeacutes

un peu trop longs comme nous lrsquoavons fait dans notre exemple

Elle permet eacutegalement agrave un programme de travailler avec diffeacuterentes bibliothegraveques posseacutedant

les mecircmes interfaces sans neacutecessiter de modification du code Par exemple supposons que

nous ayons deacutefini ces trois espaces de noms

namespace Win bibliothegraveque pour Windowsnamespace Unix bibliothegraveque pour Unixnamespace Linux bibliothegraveque pour Linux

Avec cette simple instruction

namespace Bibli Win

on pourra eacutecrire un programme travaillant avec un espace de nom fictif (Bibli) quelle que

soit la maniegravere drsquoacceacuteder aux symboles par une directive using namespace Bibli par une

deacuteclaration using individuelle using Biblixxx ou mecircme en les citant explicitement sous la

forme Biblixxx

7 Les espaces anonymesIl est possible de deacutefinir des espaces de noms anonymes crsquoest-agrave-dire ne posseacutedant pas de

nom explicite comme dans

namespace deacutebut deacutefinition espace anonyme fin deacutefinition espace anonyme

8 - Espaces de noms et deacuteclaration drsquoamitieacute525

Un tel espace de noms nrsquoest utilisable que dans la porteacutee ougrave il a eacuteteacute deacuteclareacute On peut dire que

tout se passe comme si le compilateur attribuait agrave cet espace un nom choisi de faccedilon agrave ecirctre

toujours diffeacuterent drsquoun fichier source agrave un autre Autrement dit les deacuteclarations preacuteceacutedentes

sont eacutequivalentes agrave

namespace nom_unique deacutebut deacutefinition espace nom_unique fin deacutefinition espace nom_uniqueusing nom_unique

En fait la vocation des espaces anonymes est de deacutefinir des symboles agrave porteacutee limiteacutee au

fichier source Le comiteacute ANSI recommande drsquoailleurs drsquoutiliser cette possibiliteacute de preacutefeacute-

rence agrave static voueacute agrave disparaicirctre1 dans une future actualisation de la norme

Par exemple on preacutefeacuterera ces deacuteclarations

namespace deacuteclaration des identificateurs cacheacutes dans le fichier source int globale_cachee void f(float) fonction de service non utilisable en dehors du source

agrave celles-ci

static int globale_cachee static void f(float)

8 Espaces de noms et deacuteclaration drsquoamitieacuteLorsqursquoune deacuteclaration drsquoamitieacute figure dans une classe la fonction ou la classe concerneacutee est

censeacutee se trouver dans le mecircme espace de noms ou dans un espace englobant

namespace A class X friend void f (int) obligatoirement Af namespace A namespace B class X friend void f (int) ABf ou Af

1 Cela concerne lrsquoutilisation de static pour cacher un symbole dans un fichier et nullement la deacuteclaration de membres

statiques dans une classe

Les espaces de nomsCHAPITRE 24

526

Drsquoautre part lors de lrsquoappel drsquoune fonction amie la recherche srsquoeffectue dans les espaces de

noms de ses diffeacuterents arguments

Annexes

Annexe A

Mise en correspondancedrsquoarguments

Voici lrsquoensemble des regravegles preacutesidant agrave la mise en correspondance drsquoarguments lors de

lrsquoappel drsquoune fonction surdeacutefinie ou drsquoun opeacuterateur Nous commencerons par voir comment

srsquoeacutetablit la liste des fonctions candidates Nous deacutecrirons ensuite lrsquoalgorithme utiliseacute pour

choisir la bonne fonction en examinant tout drsquoabord le cas particulier des fonctions agrave un

argument avant de voir comment il se geacuteneacuteralise aux fonctions agrave plusieurs arguments

NB Comme nous lrsquoavons signaleacute dans les chapitres correspondants ces regravegles ne srsquoappli-

quent pas inteacutegralement agrave lrsquoinstanciation drsquoune fonction patron

1 Deacutetermination des fonctions candidatesPour reacutesoudre un appel donneacute de fonction on eacutetablit une liste de fonctions candidates il

srsquoagit de toutes les fonctions ayant le nom voulu

bull situeacutees dans la porteacutee courante

bull situeacutees dans les espaces de noms introduits par une directive using (de la forme

using namespace xxx)

bull introduites par une instruction using (de la forme using xf) on introduit alors toutes les

fonctions de mecircme nom (ici f) de lrsquoespace de noms mentionneacute (ici x)

bull situeacutees dans les espaces de noms dans lesquels se situent les arguments effectifs de lrsquoappel

Mise en correspondance drsquoargumentsANNEXE A

530

On notera que les droits drsquoaccegraves agrave la fonction (publique priveacutee proteacutegeacutee) nrsquointerviennent pas

dans cette deacutetermination des fonctions candidates

Apregraves avoir deacutecrit la deacutemarche employeacutee pour les fonctions agrave un seul argument nous verrons

comment elle se geacuteneacuteralise aux fonctions agrave plusieurs arguments

2 Algorithme de recherche drsquoune fonction agrave un seul argument

21 Recherche dune correspondance exacteDans la recherche dune correspondance exacte

bull On distingue bien les diffeacuterents types entiers (char short int et long) avec leur attribut de

signe ainsi que les diffeacuterents types flottants (float double et long double) Notez que assez

curieusement char est agrave la fois diffeacuterent de signed char et de unsigned char (alors que dans

une impleacutementation donneacutee1 char est eacutequivalent agrave lun de ces deux types )

bull On ne tient pas compte des eacuteventuels qualificatifs volatile et const avec deux exceptions

pour const

ndash On distingue un pointeur de type t ( t eacutetant un type quelconque) dun pointeur de type

const t cest-agrave-dire un pointeur sur une valeur constante de type t

Plus preacuteciseacutement il peut exister deux fonctions lune pour le type t lautre pour le

type const t La preacutesence ou labsence du qualificatif const permettra de choisir la

bonne fonction

Sil nexiste quune seule de ces deux fonctions correspondant au type const t t cons-

titue quand mecircme une correspondance exacte pour const t (lagrave encore cela se justifie

par le fait que le traitement preacutevu pour quelque chose de constant peut sappliquer agrave

quelque chose de non constant) En revanche sil nexiste quune fonction correspon-

dant au type t const t ne constitue pas une correspondance exacte pour ce type t

(ce qui signifie quon ne pourra pas appliquer agrave quelque chose de constant le traitement

preacutevu pour quelque chose de non constant)

ndash On distingue le type t amp (t eacutetant un type quelconque et amp deacutesignant un transfert par reacute-

feacuterence) du type const t amp Le raisonnement preacuteceacutedent sapplique en remplaccedilant sim-

plement t par t amp2

Srsquoil existe une fonction reacutealisant une correspondance exacte la recherche srsquoarrecircte lagrave et la

fonction trouveacutee est appeleacutee agrave condition qursquoelle soit accessible (ce qui ne serait par exemple

1 Du moins pour des options de compilation donneacutees

2 En toute rigueur on distingue eacutegalement volatile t de t et volatile t amp de t amp

2 - Algorithme de recherche drsquoune fonction agrave un seul argument531

pas le cas pour une fonction priveacutee drsquoune classe A appeleacutee depuis une fonction non membre

de A) On notera qursquoagrave ce niveau un telle fonction est obligatoirement unique Dans le cas

contraire les deacuteclarations des diffeacuterentes fonctions auraient en effet eacuteteacute rejeteacutees lors de leur

compilation (par exemple vous ne pourrez jamais deacutefinir f(int) et f(const int) ou encore f(int)

et f(int amp))

22 Promotions numeacuteriquesSi la recherche preacuteceacutedente na pas abouti on effectue une nouvelle recherche en faisant inter-

venir les conversions suivantes

char signed char unsigned char short ndashgt int

unsigned short ndashgt int ou unsigned int1

enum ndashgt int

float ndashgt double

Rappelons que ces conversions ne peuvent pas ecirctre appliqueacutees agrave une transmission par reacutefeacute-

rence (T amp) sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante2 (const T amp)

Ici encore si une fonction est trouveacutee elle est obligatoirement unique

23 Conversions standardSi la recherche na toujours pas abouti on fait intervenir les conversions standard suivantes

bull type numeacuterique en un autre type numeacuterique (y compris des conversions deacutegradantes ain-

si un float conviendra lagrave ougrave un int est attendu)

bull enum en un autre type numeacuterique

bull 0 ndashgt numeacuterique

bull 0 ndashgt pointeur quelconque

bull pointeur quelconque ndashgt void 3

bull pointeur sur une classe deacuteriveacutee ndashgt pointeur sur une classe de base

Ici encore ces conversions ne peuvent pas ecirctre appliqueacutees agrave une transmission par reacutefeacuterence

(T amp) sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante4 (const T amp)

1 Selon qursquoun int suffit ou non agrave accueillir un unsigned short (il ne le peut pas lorsque short et int correspondent au

mecircme nombre de bits)

2 Le qualificatif volatile ne doit pas ecirctre employeacute dans ce cas

3 La conversion inverse nest pas preacutevue Cela est coheacuterent avec le fait quen C++ ANSI contrairement agrave ce qui se

passe en C ANSI un pointeur de type void ne peut pas ecirctre affecteacute agrave un pointeur quelconque

4 Le qualificatif volatile ne doit pas ecirctre employeacute dans ce cas

Mise en correspondance drsquoargumentsANNEXE A

532

Cette fois il est possible que plusieurs fonctions conviennent Il y a alors ambiguiumlteacute excepteacute

dans certaines situations

bull la conversion dun pointeur sur une classe deacuteriveacutee en un pointeur sur une classe de base est

preacutefeacutereacutee agrave la conversion en void

bull si C deacuterive de B et B deacuterive de A la conversion C en B est preacutefeacutereacutee agrave la conversion en

A il en va de mecircme pour la conversion C amp en B amp qui est preacutefeacutereacutee agrave la conversion en A

amp

24 Conversions deacutefinies par lutilisateurSi aucune fonction ne convient on fera intervenir les conversions deacutefinies par lutilisateur

(CDU)

Une seule CDU pourra intervenir mais elle pourra ecirctre associeacutee agrave dautres conversions

Toutefois lorsquune chaicircne de conversions peut ecirctre simplifieacutee en une chaicircne plus courte

seule cette derniegravere est consideacutereacutee Par exemple dans char ndashgt int ndashgt float et char -gt float

on ne considegravere que char -gt float Ici encore si plusieurs combinaisons de conversions exis-

tent (apregraves les eacuteventuelles simplifications eacutevoqueacutees) le compilateur refusera lappel agrave cause

de son ambiguiumlteacute

25 Fonctions agrave arguments variablesLorsquune fonction a preacutevu des arguments de types quelconques (notation ) nimporte

quel type drsquoargument effectif convient

Notez bien que cette possibiliteacute nest examineacutee quen dernier Cette remarque prendra tout

son inteacuterecirct dans le cas de fonctions agrave plusieurs arguments

26 Exception cas des champs de bitsLorsqursquoun argument effectif est un champ de bits il est consideacutereacute comme un int dans la

recherche de la meilleure fonction Si lrsquounique fonction seacutelectionneacutee reccediloit cet argument par

reacutefeacuterence (int amp) elle est rejeteacutee et lrsquoon aboutit agrave une erreur1 sauf lagrave encore srsquoil srsquoagit drsquoune

reacutefeacuterence agrave une constante (const int amp)

3 Fonctions agrave plusieurs argumentsLe compilateur recherche une fonction meilleure que toutes les autres Pour ce faire il

applique les regravegles de recherche preacuteceacutedentes agrave chacun des arguments ce qui le conduit agrave

1 On notera bien que le rejet a lieu en fin de processus en particulier aucune recherche nrsquoest faite pour trouver de

moins bonnes correspondances

4 - Fonctions membres533

seacutelectionner pour chaque argument une ou plusieurs fonctions reacutealisant la meilleure corres-

pondance Cette fois il peut y en avoir plusieurs car la deacutetermination finale de la bonne fonc-

tion nest pas encore faite (toutefois si aucune fonction nest seacutelectionneacutee pour un argument

donneacute on est deacutejagrave sucircr quaucune fonction ne conviendra) Ensuite parmi toutes les fonctions

ainsi seacutelectionneacutees le compilateur deacutetermine celle si elle existe et si elle est unique qui reacutea-

lise la meilleure correspondance cest-agrave-dire celle pour laquelle la correspondance de chaque

argument est eacutegale ou supeacuterieure agrave celle des autres1

Remarque

Les fonctions comportant un ou plusieurs arguments par deacutefaut sont traiteacutees comme si

plusieurs fonctions diffeacuterentes avaient eacuteteacute deacutefinies avec un nombre croissant darguments

4 Fonctions membresUn appel de fonction membre (non statique2) peut ecirctre consideacutereacute comme un appel dune fonc-

tion ordinaire auquel sajoute un argument effectif ayant le type de lobjet ayant effectueacute

lappel Toutefois cet argument nest pas soumis aux regravegles de correspondance dont nous

parlons ici En effet cest son type qui deacutetermine la fonction membre agrave appeler en tenant

compte eacuteventuellement

bull du meacutecanisme dheacuteritage eacutetudieacute en deacutetail au chapitre 13

bull des attributs const et volatile il est possible de distinguer une fonction membre agissant sur

des objets constants dune fonction membre agissant sur des objets non constants Une fonc-

tion membre constante peut toujours agir sur des objets non constants la reacuteciproque est

bien sucircr fausse La mecircme remarque sapplique agrave lattribut volatile

1 Cela revient agrave dire en termes ensemblistes quon considegravere lintersection des diffeacuterents ensembles formeacutes des

fonctions reacutealisant la meilleure correspondance pour chaque argument Cette intersection doit comporter exactement

un eacuteleacutement

2 Une fonction membre statique ne comporte aucun argument implicite de type classe

Annexe B

Utilisation de code eacutecrit en C

Afin de vous faciliter la reacuteutilisation de code eacutecrit en C nous reacutecapitulons ici lensemble des

incompatibiliteacutes existant entre le C ANSI et le C++ (dans ce sens) cest-agrave-dire les diffeacuterents

points accepteacutes par le C ANSI et refuseacutes par le C++ Notez que les cinq premiers points ont

eacuteteacute exposeacutes en deacutetail dans le chapitre II le dernier la eacuteteacute dans le chapitre IV Les autres cor-

respondent agrave des usages assez peu freacutequents

1 PrototypesEn C++ toute fonction non deacutefinie preacutealablement dans un fichier source ougrave elle est utiliseacutee

doit faire lobjet dune deacuteclaration sous forme dun prototype

2 Fonctions sans argumentsEn C++ une fonction sans arguments se deacutefinit (en-tecircte) et se deacuteclare (prototype) en fournis-

sant une liste vide darguments comme dans

float fct ()

3 Fonctions sans valeur de retourEn C++ une fonction sans valeur de retour se deacutefinit (en-tecircte) et se deacuteclare (prototype) obli-

gatoirement agrave laide du mot void comme dans

Utilisation de code eacutecrit en CANNEXE B

536

void fct (int double)

4 Le qualificatif constEn C++ un symbole accompagneacute dans sa deacuteclaration du qualificatif const a une porteacutee limi-

teacutee au fichier source concerneacute alors quen C ANSI il est consideacutereacute comme un symbole

externe De plus en C++ un tel symbole peut intervenir dans une expression constante (il ne

sagit toutefois plus dune incompatibiliteacute mais dune liberteacute offerte par C++)

5 Les pointeurs de type void En C++ un pointeur de type void ne peut pas ecirctre converti implicitement en un pointeur

dun autre type

6 Mots-cleacutesC++ possegravede par rapport agrave C les mots-cleacutes suppleacutementaires suivants1

bool catch class const_cast

delete dynamic_cast explicit export

false friend inline mutable

namespace new operator private

protected public reinterpret_cast static_cast

template this true throw

try typeid typename using

virtual

Voici la liste complegravete des mots cleacutes de C++ Ceux qui existent deacutejagrave en C sont en romain

ceux qui sont propres agrave C++ sont en italique A simple titre indicatif les mots cleacutes introduits

tardivement par la norme ANSI sont en gras (et en italique)

asm auto bool break case

catch char class const const_cast

continue default delete do double

dynamic_cast else enum explicit export

extern false float for friend

goto if inline int long

mutable namespace new operator private

protected public register reinterpret_cast return

1 Le mot cleacute overload a existeacute dans les versions anteacuterieures agrave la 20 Sil reste reconnu de certaines impleacutementations

en eacutetant alors sans effet il ne figure cependant pas dans la norme

7 - Les constantes de type caractegravere537

short signed sizeof static static_cast

struct switch template this throw

true try typedef typeid typename

union unsigned using virtual void

volatile wchar_t while

7 Les constantes de type caractegravereEn C++ (depuis la version 20) une constante caractegravere telle que a z ou n est de type

char alors quelle est implicitement convertie en int en C ANSI Cest ainsi que lopeacuterateur ltlt

de la classe ostream peut fonctionner correctement avec des caractegraveres (dans les versions

anteacuterieures agrave la 20 on obtenait le code numeacuterique du caractegravere)

Notez bien quune expression telle que

sizeof (a)

vaut 1 en C++ alors quelle vaut davantage (geacuteneacuteralement 2 ou 4) en C

8 Les deacutefinitions multiplesEn C ANSI il est permis de trouver plusieurs deacuteclarations dune mecircme variable dans un

fichier source Par exemple avec

int n int n

C considegravere que la premiegravere instruction est une simple deacuteclaration tandis que la seconde est

une deacutefinition cest cette derniegravere qui provoque la reacuteservation de lemplacement meacutemoire

pour n

En C++ cela est interdit La raison principale vient de ce que dans le cas ougrave de telles deacutecla-

rations porteraient sur des objets par exemple dans

point a point a

il faudrait que le compilateur distingue deacuteclaration et deacutefinition de lobjet point et quil preacute-

voie de nappeler le constructeur que dans le second cas Cela aurait eacuteteacute particuliegraverement dan-

gereux dougrave linterdiction adopteacutee

Utilisation de code eacutecrit en CANNEXE B

538

9 Linstruction gotoEn C++ une instruction goto ne peut pas faire sauter une deacuteclaration comportant un initiali-

seur (par exemple int n = 2 ) sauf si cette deacuteclaration figure dans un bloc et que ce bloc est

sauteacute complegravetement

10 Les eacutenumeacuterationsEn C++ les eacuteleacutements dune eacutenumeacuteration (mot cleacute enum) ont une porteacutee limiteacutee agrave lespace de

visibiliteacute dans lequel ils sont deacutefinis Par exemple avec

struct chose enum (rouge = 1 bleu vert)

les symboles rouge bleu et vert ne peuvent pas ecirctre employeacutes en dehors dun objet de type

chose Ils peuvent eacuteventuellement ecirctre redeacutefinis avec une signification diffeacuterente En C ces

symboles sont accessibles de toute la partie du fichier source suivant leur deacuteclaration et il

nest alors plus possible de les redeacutefinir

11 Initialisation de tableaux de caractegraveresEn C++ linitialisation de tableaux de caractegraveres par une chaicircne de mecircme longueur nest pas

possible Par exemple linstruction

char t[5] = hello

provoquera une erreur due agrave ce que t na pas une dimension suffisante pour recevoir le carac-

tegravere (0) de fin de chaicircne

En C ANSI cette mecircme deacuteclaration serait accepteacutee et le tableau t se verrait simplement ini-

tialiseacute avec les 5 caractegraveres h e l l et o (sans caractegravere de fin de chaicircne)

Notez que linstruction

char t[] = hello

convient indiffeacuteremment en C et en C++ et quelle reacuteserve dans les deux cas un tableau de 6

caractegraveres h e l l o et 0

12 Les noms de fonctionsEn C++ depuis la version 20 le compilateur attribue agrave toutes les fonctions un nom externe

baseacute dune faccedilon deacuteterministe

bull sur son nom interne

bull sur la nature de ses arguments

Si lon veut obtenir les mecircmes noms de fonction quen C on peut faire appel au mot cleacute

extern Pour plus de deacutetails voyez le paragraphe 53 du chapitre 4

Annexe C

Compleacutements sur les exceptions

Comme nous lrsquoavons examineacute au chapitre 17 le meacutecanisme proposeacute par C++ pour la gestion

des exceptions permet de poursuivre lrsquoexeacutecution du programme apregraves le traitement drsquoune

exception1 On a vu qursquoalors les diffeacuterentes sorties de blocs provoqueacutees par le transfert du

point de deacuteclenchement de lrsquoexception agrave celui de son traitement sont convenablement prises

en compte les objets automatiques entiegraverement construits au moment de la deacutetection de

lrsquoexception sont convenablement deacutetruits (avec appel de leur destructeur) srsquoils deviennent

hors de porteacutee Neacuteanmoins aucune gestion de cette sorte nrsquoexiste pour les objets ou les

emplacements alloueacutes dynamiquement Apregraves avoir illustreacute les problegravemes que cela peut

poser nous verrons comment les reacutesoudre en utilisant une technique dite de gestion des res-

sources par initialisation ou dans certains cas en recourant agrave des pointeurs intelligents

(auto_ptr)

1 Les problegravemes poseacutes par les objets automatiques

Voici un petit exemple montrant les problegravemes que peuvent poser la poursuite de lrsquoexeacutecution

apregraves deacutetection drsquoune exception Il srsquoagit drsquoune modification de la fonction f de lrsquoexemple du

paragraphe 31 du chapitre 17 il se fonde sur les mecircmes classes vect et vect_creation La

1 Rappelons toutefois qursquoil ne srsquoagit pas veacuteritablement drsquoune reprise de lrsquoexeacutecution mais simplement drsquoune

poursuite apregraves le bloc try concerneacute

Compleacutements sur les exceptionsANNEXE C

540

principale diffeacuterence vient de ce que la fonction f y alloue dynamiquement un objet de type

vect

void f(int) try v1 = new vect(5) allocation dynamique drsquoun objet v1 de type vect de 5 eacuteleacutements v1[n] = 0 OK pour 0 lt= n lt 5 exception vect_limite sinon delete v1 v1 sera convenablement deacutetruit en cas de fin normale du bloc try catch (vect_limite vl) instructions de gestion de lrsquoexception vect_limite instructions exeacutecuteacutees dans tous les cas srsquoil nrsquoy a pas eu exception v1 a eacuteteacute deacutetruit srsquoil y a eu exception v1 nrsquoa pas eacuteteacute deacutetruit

On voit que lrsquoobjet v1 nrsquoest pas deacutetruit degraves lors qursquoune exception de type vect_limite a eacuteteacute

deacuteclencheacutee Bien entendu dans cet exemple simpliste on pourrait encore preacutevoir de le faire

dans le gestionnaire catch (vect_limite) On pourrait mecircme apregraves cette destruction redeacuteclen-

cher lrsquoexception par throw En pratique les choses seront rarement aussi simples et il ne sera

pas toujours possible de savoir agrave coup sucircr quels objets doivent ecirctre deacutetruits mecircme dans le cas

drsquoun gestionnaire local

2 La technique de gestion de ressources par initialisation

Drsquoune maniegravere geacuteneacuterale on peut dire que la poursuite de lrsquoexeacutecution apregraves traitement drsquoune

exception pose un problegraveme drsquoacquisition de ressource dont la libeacuteration peut ne pas ecirctre reacutea-

liseacutee On range sous ce terme drsquoacquisition de ressource toute action qui neacutecessite une action

contraire pour la bonne poursuite des opeacuterations On peut y trouver des actions aussi diverses

que

bull creacuteation dynamique drsquoun objet

bull allocation dynamique drsquoun emplacement meacutemoire

bull ouverture drsquoun fichier

bull verrouillage drsquoun fichier en eacutecriture

bull eacutetablisssement drsquoune connexion par exemple avec un site Web

bull ouverture drsquoune de session de communication avec un utilisateur distant

Si lrsquoon souhaite que toute ressource acquise dans un programme soit convenablement libeacutereacutee

il est neacutecessaire qursquoen cas drsquoexception quelle qursquoelle soit on puisse libeacuterer les ressources

deacutejagrave acquises et uniquement celles-lagrave Comme le laisse pressentir lrsquoexemple preacuteceacutedent les

2 - La technique de gestion de ressources par initialisation541

choses peuvent devenir extrecircmement complexes degraves que le programme prend quelque impor-

tance En effet toute utilisation drsquoune ressource doit se faire dans un bloc try assorti de ges-

tionnaires interceptant toutes les exceptions possibles (les redeacuteclenchant eacuteventuellement par

throw) et capables de libeacuterer les ressources en question

En fait il existe une deacutemarche dite gestion de ressources par initialisation1 qui srsquoappuie sur

lrsquoappel automatique du destructeur des objets automatiques Elle consiste simplement agrave faire

acqueacuterir une ressource dans un constructeur drsquoune classe speacutecifiquement creacuteee agrave cet effet la

libeacuteration de la ressource se faisant dans le destructeur de cette mecircme classe Par exemple on

sera ameneacute agrave creacuteer une classe telle que

class ressource1 public ressource1 () acquisition de la ressource 1 ~ressource1 () libeacuteration de la ressource 1

Un programme ayant besoin drsquoacqueacuterir la ressource correspondante se preacutesentera ainsi

ressource 1 () acquisition de la ressource 1 par appel du constructeur de la classe ressource1

Le bloc preacuteceacutedent peut ecirctre ou non un bloc try Dans tous les cas de sortie de ce bloc (que ce

soit naturellement ou suite agrave une exception dont le gestionnaire peut se trouver dans

nrsquoimporte quel bloc englobant) il y aura appel du destructeur ~ressource1 et donc libeacuteration

de la ressource 1

Il faut cependant srsquoassurer qursquoaucun problegraveme ne risque de se poser si le constructeur de

ressource1 deacuteclenche lui-mecircme une exception Dans ce cas en effet ~ressource1 ne sera pas

appeleacute (puisqursquoen cas drsquoexception il nrsquoy a appel que des destructeurs des objets entiegraverement

creacuteeacutes) et la ressource ne sera pas libeacutereacutee Si un tel problegraveme risque drsquoapparaicirctre crsquoest proba-

blement que le constructeur associeacute agrave une ressource fait plus qursquoacqueacuterir une ressource Il

faut alors chercher agrave isoler lrsquoacquisition de ressource dans un sous-objet comme dans cet

exemple

class ressource1 public ressource1 () acquis_ressource1 () traitement agrave reacutealiser apregraves lrsquoacquisition de ressource

1 On parle souvent en anglais de RAII (Ressource Acquisition Is Initialization)

Compleacutements sur les exceptionsANNEXE C

542

class acquis_ressource1 public alloc_ressource1 () censeacute ne pas deacuteclencher drsquoexception ~alloc_ressource1 ()

Cette fois aucun problegraveme ne se pose plus si une exception est deacuteclencheacutee pendant le traite-

ment effectueacute dans ressource1 apregraves lrsquoacquisition de la ressource

3 Le concept de pointeur intelligent la classe auto_ptr

Parmi les diffeacuterentes ressources neacutecessaires agrave un programme la plus importante est geacuteneacuterale-

ment la meacutemoire Nous venons de voir comment la technique de gestion de ressources par

initialisation permet de geacuterer convenablement les situations drsquoexception La bibliothegraveque

standard du C++ propose un autre outil sous la forme de pointeurs intelligents procureacutes par le

patron de classes auto_ptr Lrsquoideacutee consiste agrave associer dans un objet de type auto_ptr un objet

pointeacute agrave la variable pointeur qui en contient lrsquoadresse si la variable devient hors de porteacutee

on deacutetruit automatiquement lrsquoobjet pointeacute Pour qursquoun tel meacutecanisme puisse ecirctre mis en

oeuvre il faut respecter une contrainte importante agrave savoir nrsquoassocier un objet donneacute qursquoagrave

une seule variable pointeur agrave la fois Crsquoest pourquoi apregraves copie drsquoobjets de type auto_ptr

seul lrsquoobjet recevant la copie reste associeacute agrave la partie pointeacutee lrsquoautre en ayant perdu le lien

(on dit parfois qursquoun seul objet de type auto_ptr est proprieacutetaire de la partie pointeacutee) Cette

particulariteacute srsquoapplique aussi bien au constructeur par recopie qursquoagrave lrsquoaffectation

Comme on peut srsquoy attendre le patron de classes auto_ptr est parameacutetreacute par le type de lrsquoobjet

pointeacute On peut construire un pointeur intelligent agrave partir de la valeur drsquoun pointeur usuel

double add auto_ptrltdoublegt apd1(add) auto_ptr sur le double pointeacute par addauto_ptrltdoublegt apd2(new double) auto_ptr sur un double qursquoon a a alloueacute dynamiquement

On peut aussi construire un pointeur intelligent sans lrsquoinitialiser

auto_ptrltdoublegt apd auto_ptr sur un double

Dans ce cas apd ne pourra ecirctre utiliseacute qursquoapregraves qursquoon lui aura affecteacute la valeur drsquoun autre

objet de type auto_ptrltdoublegt

Voici deux exemples complets de programmes illustrant lrsquoemploi de ces pointeurs

intelligents1

1 Dans les deux cas nous avons introduit artificiellement un bloc drsquoinstructions pour mieux montrer le

fonctionnement des pointeurs intelligents

3 - Le concept de pointeur intelligent la classe auto_ptr543

include ltiostreamgtinclude ltmemorygt pour la classe auto_ptrinclude ltvectorgtusing namespace std main() auto_ptrltvectorltintgt gt apvi2 int v[] = 1 2 3 4 5 auto_ptrltvectorltintgt gt apvi1(new vectorltintgt (v v+5)) (apvi1)[2] = 12 cout ltlt (apvi1)[1] ltlt ltlt (apvi1)[2] ltlt n affiche 2 12 apvi2 = apvi1 apvi1 et apvi2 pointent sur le meme vector mais seul apvi2 est proprietaire du vector pointe (apvi1)[2] = 20 OK cout ltlt (apvi2)[1] ltlt ltlt (apvi2)[2] ltlt n affiche 2 20 ici apvi1 nexiste plus mais le vector pointe appartient a vpi2 cout ltlt (apvi1)[1] conduirait a une erreur de compilation cout ltlt (apvi2)[1] ltlt ltlt (apvi2)[2] ltlt n affiche toujours 2 20 ici apvi2 nexiste plus et le vector pointe est detruit

Exemple drsquoutilisation de pointeurs intelligents (1)

include ltiostreamgtinclude ltmemorygt pour la classe auto_ptrusing namespace std class point public int x y champs exceptionnellement publics ici point(int abs=0 int ord=0) x(abs) y(ord) cout ltltconstruction point ltlt x ltlt ltlt y ltlt ltlt n ~point() cout ltltdestruction point ltlt x ltlt ltlt y ltlt ltlt n void affiche () cout ltlt coordonnees ltlt x ltlt ltlt y ltlt n

main() auto_ptrltpointgt ap1

auto_ptrltpointgt ap2 (new point(1 2)) (ap2)affiche() ou ap2-gtaffiche()

ap1 = ap2 ap1 et ap2 pointe sur le meme point mais seul ap1 en est maintenant proprietaire

ap2-gtx=12 on modifie lobjet par le biais de ap2

Compleacutements sur les exceptionsANNEXE C

544

ici ap2 nexiste plus une tentative dutilisation telle que ap2-gt affiche() serait rejetee en compilation mais lobjet pointe na pas ete detruit

ap1-gtaffiche() ap1 pointe toujours sur le point

Exemple drsquoutilisation de pointeurs intelligents (2)

Remarques

1 Les pointeurs intelligents sont utilisables en dehors du contexte de gestion des exceptions

mecircme si crsquoest dans cette situation qursquoils se reacutevegravelent le plus utile

2 Les meacutethodes exposeacutees preacuteceacutedemment pour acqueacuterir une ressource regraveglent convenable-

ment le problegraveme de leur libeacuteration Malgreacute tout il reste possible de creacuteer un objet dans

un eacutetat tel que son utilisation pose problegraveme Citons quelques exemples

ndash la creacuteation drsquoun objet comportant une partie dynamique peut avoir eacutechoueacute pour cause

de manque de meacutemoire le fait de geacuterer convenablement lrsquoacquisition de ressource

qursquoest lrsquoallocation meacutemoire nrsquoempecircche pas qursquoon risque de fournir un objet avec un

pointeur mal initialiseacute le mecircme type de problegraveme peut se poser en cas drsquoaffectation

entre objets comportant des parties dynamiques

ndash lrsquoallocation de certaines ressources neacutecessaires agrave un objet peut avoir reacuteussi alors que

drsquoautres auront eacutechoueacute

Si lrsquoon souhaite que lrsquoexeacutecution du programme puisse se poursuivre apregraves une excep-

tion il est alors conseilleacute de ne creacuteer que des objets integravegres crsquoest-agrave-dire dont lrsquoutilisa-

tion ne comporte pas de risque mecircme si lrsquoobjet est incomplet

Annexe D

Les diffeacuterentes sortesde fonctions en C++

Nous vous fournissons ici la liste des diffeacuterentes sortes de fonctions que lon peut rencontrer

en C++ en preacutecisant dans chaque cas si elle peut ecirctre deacutefinie comme fonction membre ou

amie sil existe une version par deacutefaut si elle est heacuteriteacutee et si elle peut ecirctre virtuelle

Type de fonction Membre ou amie Version par deacutefaut

Heacuteriteacutee Peut ecirctre virtuelle

constructeur membre oui non non

destructeur membre oui non oui

conversion membre non oui oui

affectation membre oui non oui

() membre non oui oui

[] membre non oui oui

-gt membre non oui oui

new membre statique non oui oui

delete membre statique non oui oui

autre opeacuterateur lun ou lautre non oui oui

autre fonction membre membre non oui oui

fonction amie amie non non non

Annexe E

Comptage de reacutefeacuterences

Nous avons vu que degraves quun objet comporte une partie dynamique il est neacutecessaire de pro-

ceacuteder agrave des copies profondes plutocirct quagrave des copies superficielles et ce aussi bien dans le

constructeur de recopie que dans lopeacuterateur daffectation Cette faccedilon de proceacuteder conduit agrave

ce que lrsquoon pourrait nommer la seacutemantique naturelle de lrsquoaffectation et de la copie Ainsi

avec

vect a(5) b(12) a contient 5 eacuteleacutements b en contient 12 a = b a et b contiennent maintenant 12 eacuteleacutements mais ils restent indeacutependantsa[2] = 12 la valeur de a[2] est modifieacutee pas celle de b[2]

Mais il est possible drsquoeacuteviter la duplication de cette partie dynamique en faisant appel agrave la

technique du compteur de reacutefeacuterences Elle consiste agrave compter en permanence le nombre

de reacutefeacuterences agrave un emplacement dynamique cest-agrave-dire le nombre de pointeurs diffeacuterents la

deacutesignant agrave un instant donneacute Dans ces conditions lorsquun objet est deacutetruit il suffit de nen

deacutetruire la partie dynamique correspondante que si son compteur de reacutefeacuterences est nul pour

eacuteviter les risques de libeacuteration multiple que nous avons souvent eacutevoqueacutes

Cette technique conduit cependant agrave une seacutemantique totalement diffeacuterente de la copie et de

lrsquoaffectation

vect a(5) b(12) a contient 5 eacuteleacutements b en contient 12 a = b a et b deacutesignent maintenant le mecircme vecteur de 12 eacuteleacutements a[i] et b[i] deacutesignent le mecircme eacuteleacutementa[2] = 12 la valeur de a[2] est modifieacutee il en va de mecircme de celle de b[2] puisqursquoil srsquoagit du mecircme eacuteleacutement

Comptage de reacutefeacuterencesANNEXE E

548

Pour mettre en œuvre cette technique deux points doivent ecirctre preacuteciseacutes

a) Lemplacement du compteur de reacutefeacuterences

A priori deux possibiliteacutes viennent agrave lesprit dans lobjet lui-mecircme ou dans la partie dyna-

mique associeacutee agrave lobjet La premiegravere solution nest guegravere exploitable car elle obligerait agrave

dupliquer ce compteur autant de fois quil y a dobjets pointant sur une mecircme zone en outre

il serait tregraves difficile deffectuer la mise agrave jour des compteurs de tous les objets deacutesignant la

mecircme zone Manifestement donc le compteur de reacutefeacuterence doit ecirctre associeacute non pas agrave un

objet mais agrave sa partie dynamique

b) Les meacutethodes devant agir sur le compteur de reacutefeacuterences

Le compteur de reacutefeacuterences doit ecirctre mis agrave jour chaque fois que le nombre dobjets deacutesignant

lemplacement correspondant risque decirctre modifieacute Cela concerne donc

bull le constructeur de recopie il doit initialiser un nouvel objet pointant sur un emplacement

deacutejagrave reacutefeacuterenceacute et donc increacutementer son compteur de reacutefeacuterences

bull lopeacuterateur daffectation une instruction telle que a = b doit

ndash deacutecreacutementer le compteur de reacutefeacuterences de lemplacement reacutefeacuterenceacute par a et proceacuteder agrave

sa libeacuteration lorsque le compteur est nul

ndash increacutementer le compteur de reacutefeacuterences de lemplacement reacutefeacuterenceacute par b

Bien entendu il est indispensable que le constructeur de recopie existe et que lopeacuterateur

daffectation soit surdeacutefini Le non-respect de lune de ces deux conditions et lutilisation des

meacutethodes par deacutefaut qui en deacutecoule entraicircneraient des recopies dobjets sans mise agrave jour des

compteurs de reacutefeacuterences

Nous vous proposons un canevas geacuteneacuteral applicable agrave toute classe de type X posseacutedant une

partie dynamique de type T Ici pour reacutealiser lassociation de la partie dynamique et du

compteur associeacute nous utilisons une structure de nom partie_dyn La partie dynamique de X

sera geacutereacutee par un pointeur sur une structure de type partie_dyn

T deacutesigne un type quelconque (eacuteventuellement classe)

struct partie_dyn structure de service pour la partie dynamique de lobjet long nref compteur de reacutefeacuterence associeacute T adr pointeur sur partie dynamique (de type T) class X membres donneacutee non dynamiques partie_dyn adyn pointeur sur partie dynamique void decremente () fonction de service - deacutecreacutemente le if (--adyn-gtnref) compteur de reacutefeacuterence et deacutetruit delete adyn-gtadr la partie dynamique si neacutecessaire delete adyn

549

public X ( ) constructeur usuel construction partie non dynamique construction partie dynamique adyn = new partie_dyn adyn-gtadr = new T adyn-gtnref = 1

X (X amp x) constructeur de recopie recopie partie non dynamique recopie partie dynamique adyn = xadyn adyn-gtnref++ increacutementation compteur reacutefeacuterences ~X () destructeur decremente () X amp operator = (X amp x) surdeacutefinition opeacuterateur affectation if (this = ampx) on ne fait rien pour a=a

traitement partie non dynamique traitement partie dynamique decremente () xadyn-gtnref++ adyn = xadyn return this

Un canevas geacuteneacuteral pour le comptage de reacutefeacuterences

Remarque

La classe auto_ptr preacutesenteacutee en Annexe C conduit agrave une autre forme de seacutemantique de

copie et drsquoaffectation on y dispose toujours de plusieurs reacutefeacuterences agrave un mecircme emplace-

ment meacutemoire mais une seule drsquoentre elles en est proprieacutetaire

En Java

La seacutemantique de lrsquoaffectation et de la copie correspond agrave celle induite par le comptage de

reacutefeacuterences

Annexe F

Les pointeurs sur des membres

C++ permet de deacutefinir ce que lrsquoon nomme des pointeurs sur des membres Il srsquoagit drsquoune

notion peu utiliseacutee en pratique ce qui justifie sa place en annexe Elle srsquoapplique theacuteorique-

ment aux membres donneacutees comme aux membres fonctions mais elle nrsquoest presque jamais

utiliseacutee dans la premiegravere situation

1 Rappels sur les pointeurs sur des fonctions en C

Le langage C permet de deacutefinir des pointeurs sur des fonctions Leur emploi permet en parti-

culier de programmer ce que lon pourrait nommer des appels variables de fonctions A

titre de rappel consideacuterez ces deacuteclarations

int f1 (char double) int f2 (char double) int ( adf) (char double)

La derniegravere signifie que adf est un pointeur sur une fonction recevant deux arguments ndash lun

de type char lautre de type double ndash et fournissant un reacutesultat de type int Les affectations

suivantes sont alors possibles

adf = f1 affecte agrave adf ladresse de la fonction f1 on peut aussi eacutecrire adf = amp f1 adf = f2 affecte agrave adf ladresse de la fonction f2

Les pointeurs sur des membresANNEXE F

552

Linstruction

( adf) (c 525)

reacutealise lappel de la fonction dont ladresse figure dans adf en lui fournissant en arguments les

valeurs c et 525

On notera que comme les autres pointeurs du C les pointeurs sur les fonctions sont forte-

ment typeacutes en ce sens que leur type preacutecise agrave la fois la nature de la valeur de retour de la

fonction et la nature de chacun de ses arguments

2 Les pointeurs sur des fonctions membresBien entendu C++ vous offre toutes les possibiliteacutes eacutevoqueacutees ci-dessus Mais il permet de

surcroicirct de les eacutetendre au cas des fonctions membres moyennant une geacuteneacuteralisation de la

syntaxe preacuteceacutedente En effet il faut pouvoir tenir compte de ce quune fonction membre se

deacutefinit

bull dune part comme une fonction ordinaire cest-agrave-dire dapregraves le type de ses arguments et de

sa valeur de retour

bull dautre part dapregraves le type de la classe agrave laquelle elle sapplique le type de lobjet layant

appeleacute constituant en quelque sorte le type dun argument suppleacutementaire

Si une classe point comporte deux fonctions membres de prototypes

void dep_hor (int)

void dep_vert (int)

la deacuteclaration

void (point adf) (int)

preacutecisera que adf est un pointeur sur une fonction membre de la classe point recevant un

argument de type int et ne renvoyant aucune valeur Les affectations suivantes seront alors

possibles

adf = pointdep_hor ou adf = amp pointdep_hor

adf = pointdep_vert

Si a est un objet de type point une instruction telle que

(aadf) (3)

provoquera pour le point a lappel de la fonction membre dont ladresse est contenue dans

adf en lui transmettant en argument la valeur 3

De mecircme si adp est lrsquoadresse drsquoun objet de type point

point adp

lrsquoinstruction

(adp -gtadf) (3)

provoquera pour le point drsquoadresse adp lappel de la fonction membre dont ladresse est con-

tenue dans adf en lui transmettant en argument la valeur 3

3 - Les pointeurs sur des membres donneacutees553

On notera que en toute rigueur un pointeur sur une fonction membre ne contient pas une

adresse au mecircme titre que nrsquoimporte quel pointeur Il srsquoagit simplement drsquoune information

permettant de localiser convenablement le membre en question agrave lrsquointeacuterieur drsquoun objet donneacute

ou drsquoun objet drsquoadresse donneacutee Crsquoest donc par abus de langage que nous parlons de lrsquoadresse

contenue dans adf

Drsquoautre part les notations a(adf) ou a-gtadf nrsquoont ici aucune signification contrairement agrave

ce qui se produirait si adf eacutetait un pointeur usuel En fait

bull lrsquoexpression adf nrsquoa pas de signification on ne pourrait pas en stocker la valeur

bull et -gt sont de nouveaux opeacuterateurs indeacutependants de et de -gt

3 Les pointeurs sur des membres donneacuteesComme nous lrsquoavons dit cette notion est tregraves rarement utiliseacutee On peut la consideacuterer comme

un cas particulier des pointeurs sur des fonctions membres

Si une classe point comporte deux membres donneacutees x et y de type int la deacuteclaration

int point adm

preacutecisera que adm est un pointeur sur un membre donneacutee de type int de la classe point

Les affectations suivantes seront alors possibles

adm = amppointx adm pointe vers le membre x de la classe pointadf = amppointy adm pointe vers le membre y de la classe point

Si a est un objet de type point lrsquoexpression aadm deacutesignera le membre drsquoadresse contenue

dans adm du point a Ces instructions seront correctes

aadm = 5 le membre drsquoadresse adm du point a reccediloit la valeur 5int n = aadm n reccediloit la valeur du membre du point a drsquoadresse adm

De mecircme si adp est lrsquoadresse drsquoun objet de type point

point adp

lrsquoexpression adp -gtadm deacutesignera le membre drsquoadresse adm pour le point dont lrsquoadresse est

contenue dans adp Ces instructions seront correctes

adp-gtadm = 5 le membre drsquoadresse adm du point drsquoadresse adp reccediloit la valeur 5int n = a-gtadm n reccediloit la valeur du membre drsquoadresse adm du point drsquoadresse adp

Bien entendu les remarques faites agrave propos de lrsquoabus de langage consistant agrave parler drsquoadresse

drsquoun membre restent valables ici Il en va de mecircme pour lrsquoexpression adm qui reste sans

signification

Les pointeurs sur des membresANNEXE F

554

Remarque

Si a est un objet de type point lrsquoaffectation suivante nrsquoa pas de signification et elle est

illeacutegale

adm = ampax incorrecte

On notera que les deux opeacuterandes de lrsquoaffectaion sont de types diffeacuterents pointeur sur

un membre entier de point pour le premier pointeur sur le membre x de lrsquoobjet a pour le

second

4 Lrsquoheacuteritage et les pointeurs sur des membresNous venons de voir comment deacuteclarer et utiliser des pointeurs sur des membres (fonctions

ou donneacutees) Voyons ce que devient cette notion dans le contexte de lheacuteritage Nous nous

limiterons au cas le moins rare celui des pointeurs sur des fonctions membres sa geacuteneacuteralisa-

tion aux pointeurs sur des membres donneacutees est triviale

Consideacuterons ces deux classes

class point class pointcol public point public public void dep_hor (int) void colore (int) void dep_vert (int)

Consideacuterons ces deacuteclarations

void (point adfp) (int) void (pointcol adfpc) (int)

Bien entendu ces affectations sont leacutegales

adfp = pointdep_hor adfp = pointdep_vert adfpc = pointcolcolore

Il en va de mecircme pour

adfpc = pointcoldep_hor adfpc = pointcoldep_vert

puisque les fonctions dep_hor et dep_vert sont eacutegalement des membres de pointcol1

Mais on peut sinterroger sur la compatibiliteacute existant entre adfp et adfpc Autrement dit

lequel peut ecirctre affecteacute agrave lautre

C++ agrave preacutevu la regravegle suivante

1 Pour le compilateur pointdep_hor et pointcoldep_hor sont de types diffeacuterents Cela nempecircche pas ces deux

symboles de deacutesigner la mecircme adresse

4 - Lrsquoheacuteritage et les pointeurs sur des membres555

Il existe une conversion implicite dun pointeur sur une fonction membre dune classe

deacuteriveacutee en un pointeur sur une fonction membre (de mecircme prototype) dune classe de

base

Pour comprendre la pertinence de cette regravegle il suffit de penser que ces pointeurs servent en

deacutefinitive agrave lrsquoappel de la fonction correspondante Le fait drsquoaccepter ici que adfpc reccediloive

une valeur du type pointeur sur une fonction membre de point (de mecircme prototype) implique

quon pourra ecirctre ameneacute agrave appeler une fonction heacuteriteacutee de point pour un objet de type point-

col1 Cela ne pose donc aucun problegraveme En revanche si lon acceptait que adfp reccediloive une

valeur du type pointeur sur une fonction membre de pointcol cela signifierait quon pourrait

ecirctre ameneacute agrave appeler nimporte quelle fonction de pointcol pour un objet de type point Mani-

festement certaines fonctions (celles deacutefinies dans pointcol cest-agrave-dire celles qui ne sont pas

heacuteriteacutees de point) risqueraient de ne pas pouvoir travailler correctement

Remarque

Si on se limite aux apparences (cest-agrave-dire si on ne cherche pas agrave en comprendre les rai-

sons profondes) cette regravegle semble diverger par rapport aux conversions implicites entre

objets ou pointeurs sur des objets ces derniegraveres se font dans le sens deacuteriveacutee ndashgt base

alors que pour les fonctions membres elles ont lieu dans le sens base ndashgt deacuteriveacutee

1 Car bien entendu une affectation telle que adfpc = adfp ne modifie pas le type de adfpc

Annexe G

Les algorithmes standard

Cette annexe fournit le rocircle exact des algorithmes proposeacutes par la bibliothegraveque standard Ils

sont classeacutes suivant les mecircmes cateacutegories que celles du chapitre 21 qui explique le fonction-

nement de la plupart dentre eux La nature des iteacuterateurs reccedilus en argument est preacuteciseacutee en

utilisant les abreacuteviations suivantes

bull IeIteacuterateur dentreacutee

bull IsIteacuterateur de sortie

bull IuIteacuterateur unidirectionnel

bull IbIteacuterateur bidirectionnel

bull IaIteacuterateur agrave accegraves direct

Nous indiquons la complexiteacute de chaque algorithme dans le cas ougrave elle nest pas triviale

Comme le fait la norme nous lexprimons en un nombre preacutecis dopeacuterations (eacuteventuellement

sous forme dun maximum) plutocirct quavec la notation de Landau moins preacutecise Pour alleacuteger

le texte nous avons convenu que lorsquune seule seacutequence est concerneacutee N deacutesigne son

nombre deacuteleacutements lorsque deux seacutequences sont concerneacutees N1 deacutesigne le nombre deacuteleacute-

ments de la premiegravere et N2 celui de la seconde Dans quelques rares cas dautres notations

seront neacutecessaires elles seront alors expliciteacutees dans le texte

Notez que par souci de simpliciteacute lorsquaucune ambiguiumlteacute nexistera nous utiliserons sou-

vent labus de langage qui consiste agrave parler des eacuteleacutements dun intervalle [deacutebut fin) plutocirct que

des eacuteleacutements deacutesigneacutes par cet intervalle Dautre part les preacutedicats ou fonctions de rappel preacute-

vus dans les algorithmes correspondent toujours agrave des objets fonction cela signifie quon

peut recourir agrave des classes fonction preacutedeacutefinies agrave ses propres classes fonction ou agrave des fonc-

tions ordinaires

Les algorithmes standardANNEXE G

558

1 Algorithmes dinitialisation de seacutequences existantes

FILL void fill (Iu deacutebut Iu fin valeur)

Place valeur dans lintervalle [deacutebut fin)

FILL_N void fill_n (Is position NbFois valeur)

Place valeur NbFois conseacutecutives agrave partir de position les emplacements cor-

respondants doivent exister

COPY Is copy (Ie deacutebut Ie fin Is position)

Copie lintervalle [deacutebut fin) agrave partir de position les emplacements corre-

spondants doivent exister la valeur de position (et seulement celle-ci) ne doit

pas appartenir agrave lintervalle [deacutebut fin) si tel est le cas on peut toujours

recourir agrave copy_backward renvoie un iteacuterateur sur la fin de lintervalle ougrave sest

faite la copie

COPY_BACKWARD Ib copy_backward (Ib deacutebut Ib fin Ib position)

Comme copy copie lintervalle [deacutebut fin) en progressant du dernier eacuteleacutement

vers le premier agrave partir de position qui deacutesigne donc lemplacement de la

premiegravere copie mais aussi la fin de lintervalle les emplacements correspon-

dants doivent exister la valeur de position (et seulement celle-ci) ne doit pas

appartenir agrave lintervalle [deacutebut fin) renvoie un iteacuterateur sur le deacutebut de linter-

valle (derniegravere valeur copieacutee) ougrave sest faite la copie cet algorithme est surtout

utile en remplacement de copy lorsque le deacutebut de lintervalle darriveacutee appar-

tient agrave lintervalle de deacutepart

GENERATE void generate (Iu deacutebut Iu fin fct_gen)

Appelle pour chacune des valeurs de lintervalle [deacutebut fin) la fonction

fct_gen et affecte la valeur fournie agrave lemplacement correspondant

GENERATE_N void generate_n (Iu deacutebut NbFois fct_gen)

Mecircme chose que generate mais lintervalle est deacutefini par sa position deacutebut et

son nombre de valeurs NbFois (la fonction fct_gen est bien appeleacutee NfFois)

SWAP_RANGES Iu swap_ranges (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2)

Echange les eacuteleacutements de lintervalle [deacutebut fin) avec lintervalle de mecircme taille

commenccedilant en deacutebut_2 Les deux intervalles ne doivent pas se chevaucher

Complexiteacute N eacutechanges

2 - Algorithmes de recherche559

2 Algorithmes de recherche FIND Ie find (Ie deacutebut Ie fin valeur)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) eacutegal agrave

valeur (au sens de ==) sil existe la valeur fin sinon (attention il ne sagit pas

neacutecessairement de end()) Complexiteacute au maximum N comparaisons deacutegal-

iteacute

FIND_IF Ie find_if (Ie deacutebut Ie fin preacutedicat_u)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) satisfai-

sant au preacutedicat unaire preacutedicat_u speacutecifieacute sil existe la valeur fin sinon

(attention il ne sagit pas neacutecessairement de end()) Complexiteacute au maximum

N appels du preacutedicat

FIND_END Iu find_end (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Fournit un iteacuterateur sur le dernier eacuteleacutement de lintervalle [deacutebut_1 fin_1) tel

que les eacuteleacutements de la seacutequence deacutebutant en deacutebut_1 soit eacutegaux (au sens de ==)

aux eacuteleacutements de lintervalle [deacutebut_2 fin_2) Si un tel eacuteleacutement nexiste pas

fournit la valeur fin_1 (attention il ne sagit pas neacutecessairement de end() Com-

plexiteacute au maximum (N1- N2 + 1) N2 comparaisons

Iu find_end (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la com-

paraison deacutegaliteacute est remplaceacutee par lapplication du preacutedicat binaire

preacutedicat_b Complexiteacute au maximum (N1- N2 + 1) N2 appels du preacutedicat

FIND_FIRST_OF

Iu find_first_of (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Recherche dans lintervalle [deacutebut_1 fin_1) le premier eacuteleacutement eacutegal (au sens

de ==) agrave lun des eacuteleacutements de lintervalle [deacutebut_2 fin_2) Fournit un iteacuterateur

sur cet eacuteleacutement sil existe la valeur de fin_1 dans le cas contraire

Complexiteacute au maximum N1 N2 comparaisons

Iu find_first_of (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Recherche dans lintervalle [deacutebut_1 fin_1) le premier eacuteleacutement satisfaisant

avec lun des eacuteleacutements de lintervalle [deacutebut_2 fin_2) au preacutedicat binaire

preacutedicat_b Fournit un iteacuterateur sur cet eacuteleacutement sil existe la valeur de fin_1

dans le cas contraire Complexiteacute au maximum N1 N2 appels du preacutedicat

Les algorithmes standardANNEXE G

560

ADJACENT_FIND

Iu adjacent_find (Iu deacutebut Iu fin)

Recherche dans lintervalle [deacutebut fin) la premiegravere occurrence de deux eacuteleacute-

ments successifs eacutegaux (==) fournit un iteacuterateur sur le premier des deux eacuteleacute-

ments eacutegaux sils existent la valeur fin sinon

Iu adjacent_find (Iu deacutebut Iu fin preacutedicat_b)

Recherche dans lintervalle [deacutebut fin) la premiegravere occurrence de deux eacuteleacute-

ments successifs satisfaisant au preacutedicat binaire preacutedicat_b fournit un iteacutera-

teur sur le premier des deux eacuteleacutements sils existent la valeur fin sinon

SEARCH Iu search (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Recherche dans lintervalle [deacutebut_1 fin_1) la premiegravere occurrence dune

seacutequence deacuteleacutements identique (==) agrave celle de lintervalle [deacutebut_2 fin_2)

Fournit un iteacuterateur sur le premier eacuteleacutement si cette occurrence si elle existe la

fin fin_1 sinon Complexiteacute au maximum N1 N2 comparaisons

Iu search (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de search avec cette diffeacuterence que

la comparaison de deux eacuteleacutements de chacune des deux seacutequences se fait par le

preacutedicat binaire preacutedicat_b au lieu de se faire par eacutegaliteacute Complexiteacute au

maximum N1 N2 appels du preacutedicat

SEARCH_N Iu search_n (Iudeacutebut Iu fin NbFois valeur)

Recherche dans lintervalle [deacutebut fin) une seacutequence de NbFois eacuteleacutements

eacutegaux (au sens de ==) agrave valeur Fournit un iteacuterateur sur le premier eacuteleacutement si

une telle seacutequence existe la valeur fin sinon Complexiteacute au maximum N

comparaisons

Iu search_n (Iudeacutebut Iu fin NbFois valeur preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la com-

paraison entre un eacuteleacutement et valeur se fait par le preacutedicat binaire preacutedicat_b au

lieu de se faire par eacutegaliteacute Complexiteacute au maximum N applications du preacutedi-

cat

3 - Algorithmes de transformation dune seacutequence561

MAX_ELEMENT

Iu max_element (Iu deacutebut Iu fin)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) qui ne soit

infeacuterieur (lt) agrave aucun des autres eacuteleacutements de lintervalle Complexiteacute exacte-

ment N-1 comparaisons

Iu max_element (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de max_element mais en utilisant le

preacutedicat binaire preacutedicat_b en lieu et place de lopeacuterateur lt Complexiteacute

exactement N-1 appels du preacutedicat

MIN_ELEMENT

Iu min_element (Iu deacutebut Iu fin)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) tel

quaucun des autres eacuteleacutements de lintervalle ne lui soit infeacuterieur (lt)

Complexiteacute exactement N-1 comparaisons

Iu min_element (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de min_element mais en utilisant le

preacutedicat binaire preacutedicat_b en lieu et place de lopeacuterateur lt Complexiteacute

exactement N-1 appels du preacutedicat

3 Algorithmes de transformation dune seacutequence

REVERSE void reverse (Ib deacutebut Ib fin)

Inverse le contenu de lintervalle [deacutebut fin) Complexiteacute exactement N2

eacutechanges

REVERSE_COPY Is reverse_copy (Ib deacutebut Ib fin Is position)

Copie lintervalle [deacutebut fin) dans lordre inverse agrave partir de position les

emplacements correspondants doivent exister attention ici position deacutesigne

donc lemplacement de la premiegravere copie et aussi le deacutebut de lintervalle ren-

voie un iteacuterateur sur la fin de lintervalle ougrave sest faite la copie Les deux inter-

valles ne doivent pas se chevaucher Complexiteacute exactement N affectations

Les algorithmes standardANNEXE G

562

REPLACE void replace (Iu deacutebut Iu fin anc_valeur nouv_valeur)

Remplace dans lintervalle [deacutebut fin) tous les eacuteleacutements eacutegaux (==) agrave

anc_valeur par nouv_valeur Complexiteacute exactement N comparaisons

REPLACE_IF void replace_if (Iu deacutebut Iu fin preacutedicat_u nouv_valeur)

Remplace dans lintervalle [deacutebut fin) tous les eacuteleacutements satisfaisant au preacutedi-

cat unaire preacutedicat_u par nouv_valeur Complexiteacute exactement N applica-

tions du preacutedicat

REPLACE_COPY

Is replace_copy (Ie deacutebut Ie fin Is position anc_valeur nouv_valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position en remplaccedilant tous les eacuteleacute-

ments eacutegaux (==) agrave anc_valeur par nouv_valeur les emplacements correspon-

dants doivent exister Fournit un iteacuterateur sur la fin de lintervalle ougrave sest faite

la copie Les deux intervalles ne doivent pas se chevaucher Complexiteacute

exactement N comparaisons

REPLACE_COPY_IF

Is replace_copy_if (Ie deacutebut Ie fin Is position preacutedicat_u nouv_valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position en remplaccedilant tous les eacuteleacute-

ments satisfaisant au preacutedicat unaire preacutedicat_u par nouv_valeur les emplace-

ments correspondants doivent exister Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Les deux intervalles ne doivent pas se chev-

aucher Complexiteacute exactement N applications du preacutedicat

ROTATE void rotate (Iu deacutebut Iu milieu Iu fin)

Effectue une permutation circulaire (vers la gauche) des eacuteleacutements de linter-

valle [deacutebut fin) dont lampleur est telle que apregraves permutation leacuteleacutement

deacutesigneacute par milieu soit venu en deacutebut Complexiteacute au maximum N eacutechanges

ROTATE_COPY Is rotate_copy (Iu deacutebut Iu milieu Iu fin Is position)

Recopie agrave partir de position les eacuteleacutements de lintervalle [deacutebut fin) affecteacutes

dune permutation circulaire deacutefinie de la mecircme faccedilon que pour rotate les

emplacements correspondants doivent exister Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Complexiteacute au maximum N affectations

3 - Algorithmes de transformation dune seacutequence563

PARTITION Ib partition (Ib deacutebut Ib fin Preacutedicat_u)

Effectue une partition de lintervalle [deacutebut fin) en se fondant sur le preacutedicat

unaire preacutedicat_u il sagit dune reacuteorganisation telle que tous les eacuteleacutements sat-

isfaisant au preacutedicat arrivent avant tous les autres Fournit un iteacuterateur it tel que

les eacuteleacutements de lintervalle [deacutebut it) satisfont au preacutedicat tandis que les eacuteleacute-

ments de lintervalle [it fin) ny satisfont pas Complexiteacute au maximum N2

eacutechanges et exactement N appels du preacutedicat

STABLE_PARTITION Ib stable_partition (Ib deacutebut Ib fin Preacutedicat_u)

Fonctionne comme partition avec cette diffeacuterence que les positions relatives

des diffeacuterents eacuteleacutements agrave linteacuterieur de chacune des deux parties soient

preacuteserveacutees Complexiteacute exactement N appels du preacutedicat et au maximum

N Log N eacutechanges (et mecircme k N si lon dispose de suffisamment de meacutemoire)

NEXT_PERMUTATION

bool next_permutation (Ib deacutebut Ib fin)

Cet algorithme reacutealise ce que lon nomme la permutation suivante des eacuteleacute-

ments de lintervalle [deacutebut fin) Il suppose que lensemble des permutations

possibles est ordonneacute agrave partir de lopeacuterateur lt dune maniegravere lexicographique

On considegravere que la permutation suivant la derniegravere possible nest rien dautre

que la premiegravere Fournit la valeur true sil existait bien une permutation suiva-

nte et la valeur false dans le cas ougrave lon est revenu agrave la premiegravere permutation

possible Complexiteacute au maximum N2 eacutechanges

bool next_permutation (Ib deacutebut Ib fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette seule diffeacuterence que

lensemble des permutations possibles et ordonneacute agrave partir du preacutedicat binaire

preacutedicat_b Complexiteacute au maximum N2 eacutechanges

PREV_PERMUTATION

bool prev_permutation (Ib deacutebut Ib fin)

bool prev_permutation (Ib deacutebut Ib fin preacutedicat_b)

Ces deux algorithmes fonctionnent comme next_permutation en inversant

simplement lordre des permutations possibles

Les algorithmes standardANNEXE G

564

RANDOM_SHUFFLE

void random_shuffle (Ia deacutebut Ia fin)

Reacutepartit au hasard les eacuteleacutements de lintervalle [deacutebut fin) Complexiteacute exact-

ement N-1 eacutechanges

void random_shuffle (Ia deacutebut Ia fin geacuteneacuterateur)

Mecircme chose que random_shuffle mais en utilisant la fonction geacuteneacuterateur pour

geacuteneacuterer des nombres au hasard Cette fonction doit fournir une valeur apparte-

nant agrave lintervalle [0 n) n eacutetant une valeur fournie en argument Complexiteacute

exactement N-1 eacutechanges

TRANSFORM

Is transform (Ie deacutebut Ie fin Is position opeacuteration_u)

Place agrave partir de position (les eacuteleacutements correspondants doivent exister) les

valeurs obtenues en appliquant la fonction unaire (agrave un argument) opeacuteration_u

agrave chacune des valeurs de lintervalle [deacutebut fin) Fournit un iteacuterateur sur la fin

de lintervalle ainsi rempli

Is transform (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Is position opeacuteration_b)

Place agrave partir de position (les eacuteleacutements correspondants doivent exister) les

valeurs obtenues en appliquant la fonction binaire (agrave deux arguments)

opeacuteration_b agrave chacune des valeurs de mecircme rang de lintervalle [deacutebut_1

fin_1) et de lintervalle de mecircme taille commenccedilant en deacutebut_2 Fournit un

iteacuterateur sur la fin de lintervalle ainsi rempli

4 Algorithmes de suppression REMOVE Iu remove (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur it tel que lintervalle [deacutebut it) contienne toutes les valeurs

initialement preacutesentes dans lintervalle [deacutebut fin) deacutebarrasseacutees de celles qui

sont eacutegales (==) agrave valeur Attention aucun eacuteleacutement nest deacutetruit tout au plus

peut-il avoir changeacute de valeur Lalgorithme est stable crsquoest-agrave-dire que les

valeurs non eacutelimineacutees conservent leur ordre relatif Complexiteacute exactement N

comparaisons

4 - Algorithmes de suppression565

REMOVE_IF Iu remove_if (Iu deacutebut Iu fin preacutedicat_u)

Fonctionne comme remove avec cette diffeacuterence que la condition deacutelimina-

tion est fournie sous forme dun preacutedicat unaire preacutedicat_u Complexiteacute

exactement N appels du preacutedicat

REMOVE_COPY Is remove_copy (Ie deacutebut Ie fin Is position valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position (les eacuteleacutements correspon-

dants doivent exister) en supprimant les eacuteleacutements eacutegaux (==) agrave valeur Fournit

un iteacuterateur sur la fin de lintervalle ougrave sest faite la copie Les deux intervalles

ne doivent pas se chevaucher Comme remove lalgorithme est stable Com-

plexiteacute exactement N comparaisons

REMOVE_COPY_IF Is remove_if (Ie deacutebut Ie fin Is position preacutedicat_u)

Fonctionne comme remove_copy avec cette diffeacuterence que la condition deacutelim-

ination est fournie sous forme dun preacutedicat unaire preacutedicat_u Complexiteacute

exactement N appels du preacutedicat

UNIQUE Iu unique (Iu deacutebut Iu fin)

Fournit un iteacuterateur it tel que lintervalle [deacutebut it) corresponde agrave lintervalle

[deacutebut fin) dans lequel les seacutequences de plusieurs valeurs conseacutecutives eacutegales

(==) sont remplaceacutees par la premiegravere Attention aucun eacuteleacutement nest deacutetruit

tout au plus peut-il avoir changeacute de place et de valeur Complexiteacute exacte-

ment N comparaisons

Iu unique (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la condi-

tion de reacutepeacutetition est fournie sous forme dun preacutedicat binaire preacutedicat_b

Complexiteacute exactement N appels du preacutedicat

UNIQUE_COPY

Is unique_copy (Ie deacutebut Ie fin Is position)

Recopie lintervalle [deacutebut fin) agrave partir de position (les eacuteleacutements correspon-

dants doivent exister) en ne conservant que la premiegravere valeur des seacutequences

de plusieurs valeurs conseacutecutives eacutegales (==) Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Les deux intervalles ne doivent pas se chev-

aucher Complexiteacute exactement N comparaisons

Les algorithmes standardANNEXE G

566

Is unique_copy (Ie deacutebut Ie fin Is position preacutedicat_b)

Fonctionne comme unique_copy avec cette diffeacuterence que la condition de

reacutepeacutetition de deux valeurs est fournie sous forme dun preacutedicat binaire

preacutedicat_u On notera que la deacutecision deacutelimination dune valeur se fait tou-

jours par comparaison avec la preacuteceacutedente et non avec la premiegravere dune

seacutequence cette remarque na en fait dimportance quau cas ougrave le preacutedicat

fourni ne serait pas transitif Complexiteacute exactement N appels du preacutedicat

5 Algorithmes de tri SORT void sort (Ia deacutebut Ia fin)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se fondant sur lopeacuterateur lt

Lalgorithme nest pas stable crsquoest-agrave-dire que lordre relatif des eacuteleacutements

eacutequivalents (au sens de lt) nest pas neacutecessairement respecteacute Complexiteacute en

moyenne N Log N comparaisons

void sort (Ia deacutebut Ia fin fct_comp)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se fondant sur le preacutedicat

binaire fct_comp Complexiteacute en moyenne N Log N appels du preacutedicat

STABLE_SORT

void stable_sort (Ia deacutebut Ia fin)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se basant sur lopeacuterateur lt

Contrairement agrave sort cet algorithme est stable Complexiteacute au maximum

N (Log N)2 comparaisons si limpleacutementation dispose dassez de meacutemoire on

peut descendre agrave N Log N comparaisons

void stable_sort (Ia deacutebut Ia fin fct_comp)

Mecircme chose que stable_sort en se basant sur le preacutedicat binaire fct_comp qui

doit correspondre agrave une relation dordre faible strict Complexiteacute au maximum

N (Log N)2 applications du preacutedicat si limpleacutementation dispose dassez de

meacutemoire on peut descendre agrave N Log N appels

PARTIAL_SORT

void partial_sort (Ia deacutebut Ia milieu Ia fin)

Reacutealise un tri partiel des eacuteleacutements de lintervalle [deacutebut fin) en se basant sur

lopeacuterateur lt et en placcedilant les premiers eacuteleacutements convenablement trieacutes dans

5 - Algorithmes de tri567

lintervalle [deacutebut milieu) (cest la taille de cet intervalle qui deacutefinit lampleur

du tri) Les eacuteleacutements de lintervalle [milieu fin) sont placeacutes dans un ordre

quelconque Aucune contrainte de stabiliteacute nest imposeacutee Complexiteacute envi-

ron N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

void partial_sort (Ia deacutebut Ia milieu Ia fin fct_comp)

Fonctionne comme partial_sort avec cette diffeacuterence quau lieu de se fonder

sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire fct_comp qui

doit correspondre agrave une relation dordre faible strict Complexiteacute environ

N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

PARTIAL_SORT_COPY

Ia partial_sort_copy (Ie deacutebut Ie fin Ia pos_deacutebut Ia pos_fin)

Place dans lintervalle [pos_deacutebut pos_fin) le reacutesultat du tri partiel ou total des

eacuteleacutements de lintervalle [deacutebut fin) Si lintervalle de destination comporte plus

deacuteleacutements que lintervalle de deacutepart ses derniers eacuteleacutements ne seront pas util-

iseacutes Fournit un iteacuterateur sur la fin de lintervalle de destination (pos_fin lor-

sque ce dernier est de taille infeacuterieure ou eacutegale agrave lintervalle dorigine) Les

deux intervalles ne doivent pas se chevaucher Complexiteacute environ N Log N

comparaisons N eacutetant le nombre deacuteleacutements effectivement trieacutes

Ia partial_sort_copy (Ie deacutebut Ie fin Ia pos_deacutebut Ia pos_fin fct_comp)

Fonctionne comme partial_sort_copy avec cette diffeacuterence quau lieu de se

fonder sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire

fct_comp qui doit correspondre agrave une relation dordre faible strict Complexiteacute

environ N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

NTH_ELEMENT

void nth_element (Ia deacutebut Ia position Ia fin)

Place dans lemplacement deacutesigneacute par position ndash qui doit donc appartenir agrave

lintervalle [deacutebut fin) ndash leacuteleacutement de lintervalle [deacutebut fin) qui se trouverait

lagrave agrave la suite dun tri Les autres eacuteleacutements de lintervalle peuvent changer de

place Complexiteacute en moyenne N comparaisons

void nth_element (Ia deacutebut Ia position Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence quau lieu de se

fonder sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire

fct_comp qui doit correspondre agrave une relation dordre faible strict Complexiteacute

en moyenne N applications du preacutedicat

Les algorithmes standardANNEXE G

568

6 Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees

NB Tous ces algorithmes peuvent fonctionner avec de simples iteacuterateurs unidirectionnels

Mais lorsque lon dispose diteacuterateurs agrave accegraves direct on peut augmenter leacutegegraverement les per-

formances dans la mesure ougrave certaines seacuteries de p increacutementations de la forme it++ peuvent

ecirctre remplaceacutees par une seule it+=p plus preacuteciseacutement on passe de O(N) agrave O(Log N) increacute-

mentations

LOWER_BOUND

Iu lower_bound (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur sur la premiegravere position ougrave valeur peut ecirctre inseacutereacutee

compte tenu de lordre induit par lopeacuterateur lt Complexiteacute au maximum

Log N+1 comparaisons

Iu lower_bound (Iu deacutebut Iu fin valeur fct_comp)

Fournit un iteacuterateur sur la premiegravere position ougrave valeur peut ecirctre inseacutereacutee

compte tenu de lordre induit par le preacutedicat binaire fct_comp Complexiteacute au

maximum Log N+1 comparaisons

UPPER_BOUND

Iu upper_bound (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur sur la derniegravere position ougrave valeur peut ecirctre inseacutereacutee compte

tenu de lordre induit par lopeacuterateur lt Complexiteacute au maximum Log N+1

comparaisons

Iu upper_bound (Iu deacutebut Iu fin valeur fct_comp)

Fournit un iteacuterateur sur la derniegravere position ougrave valeur peut ecirctre inseacutereacutee compte

tenu de lordre induit par le preacutedicat binaire fct_comp Complexiteacute au maxi-

mum Log N+1 comparaisons

EQUAL_RANGE

pair ltIu Iugt equal_range (Iu deacutebut Iu fin valeur)

Fournit le plus grand intervalle [it1 it2) tel que valeur puisse ecirctre inseacutereacutee en

nimporte quel point de cet intervalle compte tenu de lordre induit par lopeacutera-

teur lt Complexiteacute au maximum 2 Log N+1 comparaisons

6 - Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees569

pair ltIu Iugt equal_range (Iu deacutebut Iu fin valeur fct_comp)

Fonctionne comme la version preacuteceacutedente en se basant sur lordre induit par le

preacutedicat binaire fct_comp au lieu de lopeacuterateur lt

BINARY_SEARCH

bool binary_search (Iu deacutebut Iu fin valeur)

Fournit la valeur true sil existe dans lintervalle [deacutebut fin) un eacuteleacutement eacutequiv-

alent agrave valeur et la valeur false dans le cas contraire Complexiteacute au plus Log

N+2 comparaisons

bool binary_search (Iu deacutebut Iu fin valeur fct_comp)

Fournit la valeur true sil existe dans lintervalle [deacutebut fin) un eacuteleacutement eacutequiv-

alent agrave valeur (au sens de la relation induite par le preacutedicat fct_comp) et la

valeur false dans le cas contraire Complexiteacute au plus Log N+2 appels du

preacutedicat

MERGE Is merge (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Fusionne les deux intervalles [deacutebut_1 fin_1) et [deacutebut_2 fin_2) agrave partir de

position (les eacuteleacutements correspondants doivent exister) en se fondant sur lordre

induit par lopeacuterateur lt Lalgorithme est stable lordre relatif deacuteleacutements

eacutequivalents dans lun des intervalles dorigine est respecteacute dans lintervalle

darriveacutee si des eacuteleacutements eacutequivalents apparaissent dans les intervalles agrave

fusionner ceux du premier intervalle apparaissent toujours avant ceux du sec-

ond Lintervalle darriveacutee ne doit pas se chevaucher avec les intervalles dorig-

ine (en revanche rien ninterdit que les deux intervalles dorigine se

chevauchent) Complexiteacute au plus N1+N2-1 comparaisons

Is merge (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que lon se base

sur lordre induit par le preacutedicat binaire fct_comp Complexiteacute au plus

N1+N2-1 appels du preacutedicat

INPLACE_MERGE

void inplace_merge (Ib deacutebut Ib milieu Ib fin)

Fusionne les deux intervalles [deacutebut milieu) et [milieu fin) dans lintervalle

[deacutebut fin) en se basant sur lordre induit par lopeacuterateur lt Complexiteacute N-1

comparaisons si lon dispose de suffisamment de meacutemoire N Log N comparai-

sons sinon

Les algorithmes standardANNEXE G

570

void inplace_merge (Ib deacutebut Ib milieu Ib fin fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que lon se base

sur lordre induit par le preacutedicat binaire fct_comp Complexiteacute N-1 appels du

preacutedicat si lon dispose de suffisamment de meacutemoire N Log N appels sinon

7 Algorithmes agrave caractegravere numeacuterique ACCUMULATE

valeur accumulate (Ie debut Ie fin val_init)

Fournit la valeur obtenue en ajoutant (opeacuterateur +) agrave la valeur initiale val_init

la valeur de chacun des eacuteleacutements de lintervalle [deacutebut fin)

valeur accumulate (Ie debut Ie fin val_initiale fct_cumul)

Fonctionne comme la version preacuteceacutedente en la geacuteneacuteralisant lopeacuteration appli-

queacutee neacutetant plus deacutefinie par lopeacuterateur + mais par la fonction fct_cumul rece-

vant deux arguments du type des eacuteleacutements concerneacutes et fournissant un reacutesultat

de ce mecircme type (la valeur accumuleacutee courante est fournie en premier argu-

ment celle de leacuteleacutement courant en second)

INNER_PRODUCT

valeur inner_product (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 val_init)

Fournit le produit scalaire de la seacutequence des valeurs de lintervalle [deacutebut_1

fin_2) et de la seacutequence de valeurs de mecircme longueur deacutebutant en deacutebut_2

augmenteacute de la valeur initiale val_init

valeur inner_product (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 val_init

fct_cumul fct_prod)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de cumul

(+) par lappel de la fonction fct_cumul (la valeur cumuleacutee est fournie en pre-

mier argument) et lopeacuteration de produit par lappel de la fonction fct_prod (la

valeur courante du premier intervalle eacutetant fournie en premier argument)

PARTIAL_SUM

Is partial_sum (Ie deacutebut Ie fin Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) un

intervalle de mecircme taille que lintervalle [deacutebut fin) contenant les sommes

partielles du premier intervalle le premier eacuteleacutement correspond agrave la premiegravere

8 - Algorithmes agrave caractegravere ensembliste571

valeur de [deacutebut fin) le second eacuteleacutement agrave la somme des deux premiegraveres

valeurs et ainsi de suite Fournit un iteacuterateur sur la fin de lintervalle creacuteeacute

Is partial_sum (Ie deacutebut Ie fin Is position fct_cumul)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de som-

mation (+) par lappel de la fonction fct_cumul (la valeur cumuleacutee est fournie

en premier argument)

ADJACENT_DIFFERENCE

Is adjacent_difference (Ie deacutebut Ie fin Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) un

intervalle de mecircme taille que lintervalle [deacutebut fin) contenant les diffeacuterences

entre deux eacuteleacutements conseacutecutifs de ce premier intervalle leacuteleacutement de rang i

hormis le premier sobtient en faisant la diffeacuterence (opeacuterateur -) entre leacuteleacutement

de rang i et celui de rang i-1 Le premier eacuteleacutement reste inchangeacute Fournit un

iteacuterateur sur la fin de lintervalle creacuteeacute

Is adjacent_difference (Ie deacutebut Ie fin Is position fct_diff)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de dif-

feacuterence (-) par lappel de la fonction fct_diff

8 Algorithmes agrave caractegravere ensembliste INCLUDES bool includes (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2)

Fournit la valeur true si agrave toute valeur appartenant agrave lintervalle [deacutebut_1

fin_1) correspond une valeur eacutegale (==) dans lintervalle [deacutebut_2 fin_2)

avec la mecircme pluraliteacute autrement dit (si une valeur figure n fois dans le pre-

mier intervalle elle devra figurer au moins n fois dans le second intervalle)

Complexiteacute au maximum 2 N1N2-1 comparaisons

bool includes (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Complexiteacute au maximum

2 N1N2-1 appels du preacutedicat

Les algorithmes standardANNEXE G

572

SET_UNION

Is set_union (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant au moins agrave lun des deux intervalles

[deacutebut_1 fin_1) [deacutebut_2 fin_2) avec la pluraliteacute maximale si un eacuteleacutement

apparaicirct n fois dans le premier intervalle et n fois dans le second il apparaicirctra

max(n n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme

relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes

deacutequivalence de R Les deux intervalles ne doivent pas se chevaucher Fournit

un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-

1 comparaisons

Is set_union (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

SET_INTERSECTION

Is set_intersection (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant simultaneacutement aux deux intervalles

[deacutebut_1 fin_1) [deacutebut_2 fin_2) avec la pluraliteacute minimale si un eacuteleacutement

apparaicirct n fois dans le premier intervalle et n fois dans le second il apparaicirctra

min(n n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme

relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes

deacutequivalence de R Les deux intervalles ne doivent pas se chevaucher Fournit

un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-

1 comparaisons

Is set_intersection (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

8 - Algorithmes agrave caractegravere ensembliste573

SET_DIFFERENCE

Is set_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant agrave lintervalle [deacutebut_1 fin_1) sans

appartenir agrave lintervalle [deacutebut_2 fin_2) on tient compte de la pluraliteacute si un

eacuteleacutement apparaicirct n fois dans le premier intervalle et n fois dans le second il

apparaicirctra max(0 n-n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes sui-

vant la mecircme relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre

aux classes deacutequivalence de R Les deux intervalles ne doivent pas se chev-

aucher Fournit un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au max-

imum 2N1N2-1 comparaisons

Is set_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

SET_SYMMETRIC_DIFFERENCE

Is set_symetric_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is

position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant agrave lintervalle [deacutebut_1 fin_1) sans

appartenir agrave lintervalle [deacutebut_2 fin_2) ou appartenant au second sans

appartenir au premir on tient compte de la pluraliteacute si un eacuteleacutement apparaicirct n

fois dans le premier intervalle et n fois dans le second il apparaicirctra |n-n| fois

dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme relation R et

leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes deacutequivalence

de R Les deux intervalles ne doivent pas se chevaucher Fournit un iteacuterateur

sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-1 comparai-

sons

Is set_symetric_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is

position fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

Les algorithmes standardANNEXE G

574

9 Algorithmes de manipulation de tasMAKE_HEAP

void make_heap (Ia deacutebut Ia fin)

Transforme lrsquointervalle [deacutebut fin) en un tas en se fondant sur lrsquoopeacuterateur lt

Complexiteacute au maximum 3N comparaisons

void make_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum 3N comparaisons

PUSH_HEAP

void push_heap (Ia deacutebut Ia fin)

La seacutequence [debut fin-1) doit ecirctre initialement un tas valide En se fondant

sur lrsquoopeacuterateur lt lrsquoalgorithme ajoute lrsquoeacuteleacutement deacutesigneacute par fin-1 de faccedilon que

[debut fin) soit un tas Complexiteacute au maximum Log N comparaisons

void push_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum Log N comparai-

sons

SORT_HEAP

void sort_heap (Ia deacutebut Ia fin)

Transforme le tas deacutefini par lrsquointervalle [debut fin) en une seacutequence ordonneacutee

par valeurs croissantes Lrsquoalgorithme nrsquoest pas stable crsquoest-agrave-dire que lrsquoordre

relatif des eacuteleacutements eacutequivalents (au sens de lt) nrsquoest pas neacutecessairement

respecteacute Complexiteacute au maximum N Log N comparaisons

void sort_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner les valeurs Complexiteacute au maximum N Log N com-

paraisons

10 - Algorithmes divers575

POP_HEAP

void pop_heap (Ia deacutebut Ia fin)

La seacutequence [debut fin) doit ecirctre initialement un tas valide Lrsquoalgorithme

eacutechange les eacuteleacutements deacutesigneacutes par debut et fin-1 et en se fondant sur lrsquoopeacutera-

teur lt fait en sorte que [debut fin-1) soit un tas Complexiteacute au maximum 2

Log N comparaisons

void pop_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum 2 Log N comparai-

sons

10 Algorithmes divers COUNT nombre count (Ie deacutebut Ie fin valeur)

Fournit le nombre de valeurs de lintervalle [deacutebut fin) eacutegales agrave valeur (au sens

de ==)

COUNT_IF nombre count_if (Ie deacutebut Ie fin preacutedicat_u)

Fournit le nombre de valeurs de lintervalle [deacutebut fin) satisfaisant au preacutedicat

unaire preacutedicat_u

FOR_EACH fct for_each (Ie deacutebut Ie fin fct)

Applique la fonction fct agrave chacun des eacuteleacutements de lintervalle [deacutebut fin)

fournit fct en reacutesultat

EQUAL bool equal (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2)

Fournit la valeur true si tous les eacuteleacutements de lintervalle [deacutebut_1 fin_2) sont

eacutegaux (au sens de ==) aux eacuteleacutements correspondants de lintervalle de mecircme

taille commenccedilant en deacutebut_2

bool equal (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente en utilisant le preacutedicat binaire

preacutedicat_b agrave la place de lopeacuterateur ==

ITER_SWAP void iter_swap (Iu pos1 Iu pos2)

Echange les valeurs des eacuteleacutements deacutesigneacutes par les deux iteacuterateurs pos1 et pos2

Les algorithmes standardANNEXE G

576

LEXICOGRAPHICAL_COMPARE

bool lexicographical_compare (Ie deacutebut_1 Ie fin-1 Ie deacutebut_2 Ie fin_2)

Effectue une comparaison lexicographique (analogue agrave la comparaison de

deux mots dans un dictionnaire) entre les deux seacutequences [deacutebut_1 fin_1) et

[deacutebut_2 fin_2) en se basant sur lrsquoopeacuterateur lt Fournit la valeur true si la

premiegravere seacutequence apparaicirct avant la seconde Complexiteacute au plus N1N2

comparaisons

bool lexicographical_compare (Ie deacutebut_1 Ie fin-1 Ie deacutebut_2 Ie fin_2

preacutedicat_b)

Fonctionne comme la version preacuteceacutedente en utilisant le preacutedicat binaire

preacutedicat_b agrave la place de lopeacuterateur lt Complexiteacute au plus N1N2 comparai-

sons

MAX valeur max (valeur_1 valeur_2)

Fournit la plus grande des deux valeurs valeur_1 et valeur_2 (qui doivent ecirctre

drsquoun mecircme type) en se fondant sur lrsquoopeacuterateur lt

MIN valeur min (valeur_1 valeur_2)

Fournit la plus petite des deux valeurs valeur_1 et valeur_2 (qui doivent ecirctre

drsquoun mecircme type) en se fondant sur lrsquoopeacuterateur lt

Correction des exercices

Voici la correction des exercices dont leacutenonceacute est preacuteceacutedeacute de lindication (C) Bien entendu

les programmes proposeacutes doivent ecirctre consideacutereacutes comme une solution parmi dautres

Chapitre 5

Exercice 52

include ltiostreamgtusing namespace std deacuteclaration de la classe vecteur class vecteur double x y z public void initialise (double double double) void homothetie (double) void affiche () deacutefinition des fonctions membres de la classe vecteur void vecteurinitialise (double a double b double c) x = a y = b z = c

void vecteurhomothetie (double coeff) x = x coeff y = y coeff z = z coeff void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

Correction des exercices578

programme de test de la classe vecteur main() vecteur v1 v2 v1initialise (10 25 58) v1affiche () v2initialise (125 38 00) v2affiche () v1homothetie (35) v1affiche () v2 = v1 v2affiche ()

Exercice 53

include ltiostreamgtusing namespace std deacuteclaration de la classe vecteur class vecteur double x y z public vecteur (double double double) constructeur void homothetie (double) void affiche () deacutefinition des fonctions membres de la classe vecteur vecteurvecteur (double a double b double c) attention pas de void x = a y = b z = c void vecteurhomothetie (double coeff) x = x coeff y = y coeff z = z coeff void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n programme de test de la classe vecteur main() vecteur v1(10 25 58) vecteur v1 serait ici invalide vecteur v2(125 38 00) v1affiche () v2affiche () v1homothetie (35) v1affiche () v2 = v1 v2affiche ()

Chapitre 6579

Chapitre 6

Exercice 61

a) Avec des fonctions membres indeacutependantes

include ltiostreamgt

using namespace std

deacuteclaration de la classe vecteur

class vecteur

double x y z

public

vecteur () constructeur 1

vecteur (double double double) constructeur 2

void affiche ()

deacutefinition des fonctions membres de la classe vecteur

vecteurvecteur ()

x=0 y=0 z=0

vecteurvecteur (double a double b double c)

x = a y = b z = c

void vecteuraffiche ()

cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt 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

reacutesultat de type vecteur

vecteur v2(125 38 00)

ces deacuteclarations seraient ici invalides

vecteur v3 (5) vecteur v4 (25 4)

v1affiche ()

v2affiche ()

Correction des exercices580

b) Avec des fonctions membres en ligne

include ltiostreamgtusing namespace std deacuteclaration 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 ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

programme de test de la classe vecteur main() vecteur v1 v2(345) v1affiche () v2affiche ()

Exercice 62

include ltiostreamgtusing namespace std deacuteclaration 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)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c

Chapitre 6581

void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur v) return (x vx + y vy + z vz) main() programme de test de la classe vecteur vecteur v1 (123) vecteur v2 (543) v1affiche () v2affiche () int ps ps = v1prod_scal (v2) cout ltlt V1V2 = ltlt ps ltlt n ps = v2prod_scal (v1) cout ltlt V2V1 = ltlt ps ltlt n cout ltlt V1V1 = ltlt v1prod_scal (v1) ltlt n cout ltlt V2V2 = ltlt v2prod_scal (v2) ltlt n

Exercice 63

include ltiostreamgtusing namespace std

deacuteclaration 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)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur v) return (x vx + y vy + z vz)

Correction des exercices582

vecteur vecteursomme (vecteur v) vecteur res resx = x + vx resy = y + vy resz = z + vz return res

programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (v2) v3affiche () v3 = v2somme (v1) v3affiche ()

Exercice 64

a) Transmission par adresse des valeurs de type vecteur

include ltiostreamgtusing namespace std deacuteclaration 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 ) deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur adv) return (x adv-gtx + y adv-gty + z adv-gtz) on pourrait eacutecrire de faccedilon plus symeacutetrique return (this-gtx adv-gtx + this-gty adv-gty + this-gtz adv-gt z

Chapitre 6583

vecteur vecteursomme (vecteur adv) vecteur res resx = x + adv-gtx resy = y + adv-gty resz = z + adv-gtz ou pour conserver la symeacutetrie resx = this-gtx + adv-gt x return res attention on ne peut pas transmettre ladresse de res car il sagit dune variable automatique programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (ampv2) v3affiche () v3 = v2somme (ampv1) v3affiche ()

b) Transmission par reacutefeacuterence des valeurs de type vecteur

include ltiostreamgtusing namespace std deacuteclaration 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 amp) vecteur somme (vecteur amp)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

Correction des exercices584

int vecteurprod_scal (vecteur amp v) return (x vx + y vy + z vz) vecteur vecteursomme (vecteur amp v) vecteur res resx = x + vx resy = y + vy resz = z + vz return res attention on ne peut pas transmettre ladresse de res car il sagit dune variable automatique programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (v2) v3affiche () v3 = v2somme (v1) v3affiche ()

Chapitre 7

Exercice 75

include ltiostreamgtusing namespace std deacuteclaration (et deacutefinition) de la classe pile_entier ici toutes les fonctions membres sont inline const int Max = 20 class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes 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 lt dim) adr[nelem++] = p

Chapitre 7585

int depile () if (nelem gt 0) return adr[--nelem] else return 0 faute de mieux int pleine () return (nelem == dim) int vide () return (nelem == 0 )

Exercice 76

programme dessai de la classe pile_entier main() int i exemples dutilisation de piles automatiques pile_entier a(3) une pile de 3 entiers b une pile de 20 entiers (par deacutefaut) cout ltlt a pleine ltlt apleine () ltlt n cout ltlt a vide ltlt avide () ltlt n aempile (3) aempile (9) aempile (11) cout ltlt Contenu de a for (i=0 ilt3 i++) cout ltlt adepile () ltlt cout ltlt n for (i=0 ilt30 i++) bempile (10i) cout ltlt Contenu de b for (i=0 ilt30 i++) if ( bvide() ) cout ltlt bdepile () ltlt cout ltlt n

exemple dutilisation dune pile dynamique pile_entier adp = new pile_entier (5) pointeur sur une pile de 5 entiers cout ltlt pile dynamique vide ltlt adp-gtvide () ltlt n for (i=0 ilt10 i++) adp-gtempile (10i) cout ltlt Contenu de la pile dynamique for (i=0 ilt10 i++) if ( adp-gtvide() ) cout ltlt adp-gtdepile () ltlt

Exercice 78

include ltiostreamgtusing namespace std deacuteclaration (et deacutefinition) de la classe pile_entiers const int Max = 20

Correction des exercices586

class pile_entier

int dim nombre maximal dentiers de la pile

int adr adresse emplacement des dim entiers

int nelem nombre dentiers actuellement empileacutes

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 lt dim) adr[nelem++] = p

int depile ()

if (nelem gt 0) return adr[--nelem]

else return 0 faute de mieux

int pleine ()

return (nelem == dim)

int vide ()

return (nelem == 0 )

pile_entier (pile_entier amp) constructeur de recopie

pile_entierpile_entier (pile_entier amp p)

adr = new int [dim = pdim]

nelem = pnelem

int i

for (i=0 iltnelem i++) adr[i] = padr[i]

programme dessai de la classe pile_entier

main()

int i

pile_entier a(3) une pile a de 3 entiers

aempile (5) aempile (12)

pile_entier b = a une pile b eacutegale agrave a

cout ltlt Contenu de b

for (i=0 ilt3 i++) if ( bvide() ) cout ltlt bdepile () ltlt

cout ltlt n

Chapitre 9587

Chapitre 9

Exercice 93

a) Avec une fonction membre

include ltiostreamgtusing namespace std classe point avec surdeacutefinition de == comme fonction membre class point int x y public point (int abs=0 int ord=0) x=abs y=ord int operator == (point amp p) on pourrait ne pas transmettre par reacutefeacuterence return ( (px == x) ampamp (py == y) ) programme de test de la classe point main() point a(23) b(1) c(23) cout ltlt a == b ltlt (a == b) ltlt n attention parenthegraveses cout ltlt b == a ltlt (b == a) ltlt n indispensables compte tenu cout ltlt a == c ltlt (a == c) ltlt n des prioriteacutes relatives de cout ltlt c == a ltlt (c == a) ltlt n de == et de ltlt

b) Avec une fonction amie1

include ltiostreamgtusing namespace std classe point avec surdeacutefinition de == comme fonction amie class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend int operator == (point amp point amp) int operator == (point amp p point amp q) return ( (px == qx) ampamp (py == qy) )

1 Avec certains environnements il faut preacutefixer le nom de operator == de std dans son en-tecircte

Correction des exercices588

programme de test de la classe point main() point a(23) b(1) c(23) cout ltlt a == b ltlt (a == b) ltlt n attention parenthegraveses cout ltlt b == a ltlt (b == a) ltlt n indispensables compte tenu cout ltlt a == c ltlt (a == c) ltlt n des prioriteacutes relatives de cout ltlt c == a ltlt (c == a) ltlt n de == et de ltlt

Exercice 94

a) Avec des fonctions membres

include ltiostreamgtusing namespace std

la classe pile_entiers avec surdeacutefinition des opeacuterateurs lt et gt comme fonctions membre class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes

public pile_entier (int n) constructeur adr = new int [dim=n] nelem = 0 ~pile_entier () destructeur delete adr void operator lt (int n) if (nelem lt dim) adr[nelem++] = n void operator gt (int amp n ) attention amp indispensable ici if (nelem gt 0) n = adr[--nelem] programme dessai de la classe pile_entier main() int i n pile_entier a(3) a lt 3 a lt 9 a lt 11 cout ltlt Contenu de a for (i=0 ilt3 i++) a gt n cout ltlt n ltlt cout ltlt n

Chapitre 9589

b) Avec des fonctions amies

include ltiostreamgtusing namespace std la classe pile_entiers avec surdeacutefinition des opeacuterateurs lt et gt comme fonctions amies class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes public pile_entier (int n) constructeur adr = new int [dim=n] nelem = 0 ~pile_entier () destructeur delete adr friend void operator lt (pile_entier amp int) amp non indispensable friend void operator gt (pile_entier amp int amp) int amp indispensable ici void operator lt (pile_entier amp p int n) if (pnelem lt pdim) padr[pnelem++] = n void operator gt (pile_entier amp p int amp n) if (pnelem gt 0) n = padr[--pnelem]

programme dessai de la classe pile_entier main() int i n pile_entier a(3) a lt 3 a lt 9 a lt 11 cout ltlt Contenu de a for (i=0 ilt3 i++) a gt n cout ltlt n ltlt cout ltlt n

Exercice 96

include ltiostreamgtusing namespace std

class chaine int lg longueur actuelle de la chaicircne char adr adresse zone contenant la chaicircne

Correction des exercices590

public chaine () constructeur I chaine (char ) constructeur II chaine (const chaine amp) constructeur III (par recopie) ~chaine () destructeur (inline) delete adr void affiche () chaine amp operator = (const chaine amp) int operator == (chaine amp) chaine operator + (chaine amp) char amp operator [] (int)

chainechaine () constructeur I lg = 0 adr=0 chainechaine (char adc) constructeur II (agrave partir dune chaicircne C) char ad = adc lg = 0 while (ad++) lg++ calcul longueur chaicircne C adr = new char [lg] for (int i=0 iltlg i++) recopie chaicircne C adr[i] = adc[i] chainechaine (const chaine amp ch) constructeur III (par recopie) adr = new char [lg = chlg] for (int i=0 iltlg i++) adr[i] = chadr[i] void chaineaffiche () for (int i=0 iltlg i++) cout ltlt adr[i] en version lt 20 utilisez printf chaine amp chaineoperator = (const chaine amp ch) if (this = amp ch) on ne fait rien pour a=a delete adr adr = new char [lg = chlg] for (int i=0 iltlg i++) adr[i] = chadr[i] return this pour pouvoir utiliser la valeur de a=b int chaineoperator == (chaine amp ch) for (int i=0 iltlg i++) if (adr[i] = chadr[i]) return 0 return 1

Chapitre 9591

chaine chaineoperator + (chaine amp ch) attention la valeur de retour

chaine res est agrave transmettre par valeur

resadr = new char [reslg = lg + chlg]

int i

for (i=0 iltlg i++) resadr[i] = adr[i]

for (i=0 iltchlg i++) resadr[i+lg] = chadr[i]

return res

char amp chaineoperator [] (int i)

return adr[i] ici on na pas preacutevu de

veacuterification de la valeur de i

main()

chaine a cout ltlt chaine a aaffiche () cout ltlt n

chaine b(bonjour) cout ltlt chaine b baffiche () cout ltlt n

chaine c=b cout ltlt chaine c caffiche () cout ltlt n

chaine d(hello)

a = b = d

cout ltlt chaine b baffiche () cout ltlt n

cout ltlt chaine a aaffiche () cout ltlt n

cout ltlt a == b ltlt (a == b) ltlt n

chaine x(salut ) y(chegravere ) z(madame)

a = x + y + z

cout ltlt chaine a aaffiche () cout ltlt n

a = a

cout ltlt chaine a aaffiche () cout ltlt n

chaine e(xxxxxxxxxx)

for (char cr=a i=0 crltf cr++ i++ ) e[i] = cr

cout ltlt chaine e eaffiche () cout ltlt n

Exemple drsquoexeacutecution

chaine a

chaine b bonjour

chaine c bonjour

chaine b hello

chaine a hello

a == b 1

chaine a salut ch_re madame

chaine a salut ch_re madame

chaine e abcdexxxxx

Index

Aabort 385

abs 499

accegraves direct 365

iteacuterateur agrave ~ 456

accumulate (algorithme) 478 570

acos 500

acquisition de ressources 540

adaptateur

de conteneur 432

adjacent_difference (algorithme) 478 571

adjacent_find (algorithme) 466 560

adjustfield 357

affectation 162

drsquoobjets 71

de conteneur 414

et heacuteritage 273

virtuelle 316

algorithme 399

drsquoinitialisation 462 558

de copie 462

de fusion 476 568

de geacuteneacuteration de valeurs 463

de minimum ou de maximum 467

de partition 472

de permutation 469 470

de recherche 466 476 559 568

de remplacement 469

de suppression 472 564

de transformation 561

de transformation de seacutequence 468

de tri 475 566

ensembliste 479 571

numeacuterique 478 570

standard 455

alias 524

allocation dynamique 49 111 116

app 367

apply 503

arg 500

argument

adresse drsquoun objet 99

de type classe 97 99

par deacutefaut 39 94

reacutefeacuterence 31

reacutefeacuterence agrave un objet 101

asin 500

assign 414 487

at 419 486

atan 500

auto_ptr 542

C++ pour programmeurs C594

Bback 420 424 426 433

bad 349

bad_alloc 52

bad_cast 330

badbit 348

base 358

base de numeacuteration (en sortie) 338

basefield 357

basic_string 485

beg 365

begin 397 486

bibliothegraveque standard 395

bidirectionnel (iteacuterateur) 456

binary 367

binary_search (algorithme) 476 569

bits derreur 348

bitset 507

bloc try 375

bool 57

boolalpha 339 358

Ccapacity 421 486

caractegravere

de remplissage 356

deacutelimiteur 343

espace blanc 343

fin de ligne 368

invalide 22 25

seacuteparateur 23

cast 57 184 198

catch 375 378 384

cateacutegories

drsquoiteacuterateurs 457

de conteneurs 401

cerr 336

chaicircne de caractegraveres 485

champ 62

cin 21 333

class 67

classe 3 61 67 87

abstraite 317

canonique 170

fonction 404 405

fonction preacutedeacutefinie 406

forme canonique 277

virtuelle 297

virtuelle et constructeurs 298

classe amie

et patrons de fonctions 239

classe drsquoallocation

automatique 111

statique 111

classe deacuteriveacutee 247 248

conversion 265

classe patron 231

identiteacute de ~ 239

cleacute 438

clear 349 415

clog 336

commentaire 28

comparaison

de conteneurs 415

lexicographique 415

compatibiliteacute classe de base et deacuteriveacutee 264

compilation

conditionnelle 85

seacutepareacutee 83

complex 499

compteur de reacutefeacuterences 547

concateacutenation 488

conj 500

const 14 106

const_cast 57

constructeur 73 113

conversion par ~ 199

de recopie 119 132 402

de recopie et heacuteritage 270

de recopie par deacutefaut 119

en cas drsquoobjet membre 129

et classes virtuelles 298

et conversion 191

et fonction virtuelle 315

et heacuteritage 254 255

et heacuteritage multiple 293

explicit 197

priveacute 79

construction

drsquoun conteneur 402

drsquoun conteneur seacutequentiel 412

Index595

conteneur 396 400

adaptateur de ~ 432

affectation de ~ 414

associatif 401 437

cateacutegories de ~ 401

comparaison de ~ 415

construction 402

et relation drsquoordre 407

insertion drsquoeacuteleacutements 416

seacutequentiel 401 411

suppression drsquoeacuteleacutements 417

controcircle des accegraves 248 258

conversion

drsquoun type deacuteriveacute en un type de base 265

drsquoune classe en une autre 198

de pointeurs 266

deacutefinie par lrsquoutilisateur 182 532

en chaicircne 189 193

explicite 181

interdiction par explicit 197

par cast 184 185 198

par constructeur 191 199

standard 531

copie (algorithme) 462

copy (algorithme) 462 558

copy_backward (algorithme) 558

correspondance exacte 530

cos 500

cosh 500

count 447 448

count (algorithme) 575

count_if 575

cout 18 333

cshift 503

cur 365

Ddec 339 357 358

deacuteclaration

drsquoamitieacute 142

drsquoamitieacute et classes patron 239

drsquoune classe 87

en C++ 28

deacutefinition

drsquoune fonction membre 64 68

delete 49 50 117

surdeacutefinition 175

deacutelimiteur 343

deque 412 424

deacuterivation

priveacutee 262

proteacutegeacutee 263

publique 261

destructeur 73

en cas drsquoobjet membre 129

priveacute 79

virtuel 315

divides 407

dynamic_cast 329

dynamique (allocation) 111

Eefficaciteacute 403

empty 432 433 434

encapsulation 3 141

end 365 397 486

endl 359

ends 359

ensemble

algorithme 571

entreacutee standard 333

entreacutees-sorties

conversationnelles 17

eof 349

eofbit 348

equal (algorithme) 575

equal_range 447 449

equal_range (algorithme) 568

equal_to 406

erase 417 446 448 491

espace blanc 22 343

espaces

anonymes 524

de noms 56 511

exception 374

gestionnaire drsquo~ 375 380 383

standard 390

exit 380

exp 500

explicit 197

C++ pour programmeurs C596

exponentielle

notation 341

export 210 229

extern 48

Ffail 349

failbit 348

false 57

fichier

accegraves direct 365

binaire 368

connexion drsquoun flot agrave un ~ 362

modes drsquoouverture 367

pointeur 365

texte 368

fill 361 558

fill (algorithme) 465 558

fill_n (algorithme) 558

fin de ligne 368

find 444 448 489

find (algorithme) 466 559

find_end (algorithme) 559

find_first_not_of 489

find_first_of 489

find_first_of (algorithme) 466 559

find_if (algorithme) 466 559

find_last_not_of 489

find_last_of 489

first 439

fixed 341 357 358

flip 424

flot 18 21 333

connexion agrave un fichier 362

preacutedeacutefini 336

statut drsquoerreur 348

statut de formatage 356

flottante (notation) 341

flush 359

fonction

agrave arguments variables 532

assembleur 48

C 48

choix drsquoune ~ surdeacutefinie 43 46

classe ~ 406

de rappel 405

deacuteclaration de ~ 11

deacutefinition de ~ 10

en ligne 54

membre 63

objet ~ 405

patron de ~ 206

prototype drsquoune ~ 11

reacutedeacutefinition drsquoune ~ virtuelle 312

sans arguments 14

sans valeur de retour 14

surdeacutefinition drsquoune ~ 42 530

surdeacutefinition drsquoune ~ membre 91

surdeacutefinition drsquoune ~ virtuelle 313

virtuelle 305 311

virtuelle pure 318

fonction amie 142

de plusieurs classes 146

deacuteclaration 142

et classes patron 239

et espaces de noms 525

exploitation 150

indeacutependante 142 144

membre drsquoune classe 145

surdeacutefinition drsquoopeacuterateur par ~ 153

fonction membre

amie 145

arguments par deacutefaut 94

constante 107

deacutefinition 68

en ligne 95

heacuteritage 247

patron de ~ 238

pointeur sur une ~ 551

speacutecialisation 236

statique 104

surdeacutefinition 91 533

volatile 108

fonction patron 207

speacutecialisation 220

fonction virtuelle

et construteur 315

restrictions 314

fopen 367

for_each (algorithme) 575

Index597

formatage 338 356

en meacutemoire 368 493

mot drsquoeacutetat 360

statut de ~ drsquoun flot 356

forme canonique

et heacuteritage 277

free 49

freeze 369

friend 142

front 424 426 433

fseek 365

fstream 362

functional 406

fusion

algorithme 476 568

de listes 429

Ggabarit 356

gabarit de lrsquoinformation (en sortie) 339

gcount 346

generate (algorithme) 463

generate_n (algorithme) 465 558

geacuteneacuterateur drsquoopeacuterateur 409

geacuteneacuteration (algorithme) 463

gestionnaire drsquoexception 375 383

get 345

getline 346

good 349

goodbit 348

greater_equal 406

gslice 506

Hheacuteritage 3 245

appel des constructeurs 254

controcircle des accegraves 248 258

et affectation 273

et constructeur de recopie 270

et conversion de pointeurs 266

et conversions 265

et fonctions virtuelles 311

et forme canonique 277

et patron de classes 284

et typage statique 266

membre proteacutegeacute 259

multiple 291

multiple et constructeurs 293

hex 339 357 358

Iidentification de type 326

identiteacute

de classes patron 239

ifstream 364

imag 500

in 367

includes (algorithme) 571

inclusion multiple 85

initialisation

drsquoun membre donneacutee 88

drsquoun membre donneacutee statique 81

drsquoun objet 127

drsquoun tableau drsquoobjets 134

de reacutefeacuterence 38

des variables de type standard 213

par recopie 119

initialisation (algorithme) 462 558

inline 54 95

inner_product (algorithme) 478 570

inplace_merge (algorithme) 476 569

insert 417 445 490

insertion

iteacuterateur drsquo~ 458

instance 3 69

interdire

lrsquoaffectation 169

la copie 120

internal 357 358

intervalle drsquoiteacuterateur 398 457

invalidation

drsquoiteacuterateur 421

ios

adjustfield 357

app 367

basefield 357

beg 365

binary 367

cur 365

C++ pour programmeurs C598

end 365

floatfield 357

in 367

out 367

trunc 367

iostream 20 334

istream 334 343 360

istrstream 370

iter_swap (algorithme) 575

iteacuterateur 396

agrave accegraves direct 418 456

bidirectionnel 456

cateacutegories drsquo~ 456 457

drsquoinsertion 458

de flot 456 460 461

en entreacutee 456

en sortie 456

et pointeur 400

intervalle drsquo~ 457

unidirectionnel 456

iterator 397 419 426 486

Kkey_comp 442

Llrsquointervalle (algorithme) 558

left 357 358

less 406

less_equa 406

lexicographical_compare 576

ligature dynamique 305 308

list 412 426

fusion 429

tri 428

log 500

logical_and 407

logical_not 407

logical_or 407

lower_bound 447 448 449

lower_bound (algorithme) 568

Mmacro 55

make_heap 574

malloc 49

manipulateur 339 358

parameacutetrique 359

map 438

masque 504

max 503 576

max_element (algorithme) 467 561

max_size 422 424 430

maximum(recherche de ~) 467

membre

donneacutee 65

donneacutee statique 80 86

fonction 63

objet ~ 129

priveacute 68

proteacutegeacute 258

public 68

merge 429

merge (algorithme) 476 569

message 3

meacutethode 61

min 503 576

min_element (algorithme) 467 561

minimum(recherche de ~) 467

minus 407

mode drsquoouverture drsquoun fichier 367

modulus 407

multimap 448

multiset 452

Nname 326

namespace 56 512

new 49 50 117

surdeacutefinition 175

new (opeacuterateur) 175

new(nothrow) 51

next_permutation (algorithme) 470 563

noboolalpha 339 358

noshowbase 358

noshowpoint 358

Index599

noshowpos 358

noskipws 358

not_equal_to 406

notation

exponentielle 341

flottante 341

nothrow 51

nouppercase 358

nth_element (algorithme) 475 567

numeacuterique (algorithme) 570

Oobjet 2

affectation drsquo~ 71

automatique 112 539

construction 75 113

destruction 75

dynamique 116

en argument 97

en valeur de retour 102

fonction 405

initialisation 127

instance drsquo~ 69

membre 129

recopie 119

statique 112

tableau drsquo~ 133

temporaire 136

oct 339 357 358

ofstream 362

opeacuterateur

-- 161

349

() 173 349

++ 160

ltlt 334 335 352

= 162 163 316

= et heacuteritage 273

gtgt 334 343 352

de cast 184 198

delete 175

geacuteneacuterateur drsquo~ 409

new 175

surdeacutefinition 42

operator 153 154

ostream 334 360

ostrstream 369

out 367

PPOO (Programmation Orienteacutee Objet) 2

pair 439 440

paramegravetres de type

drsquoun patron de classes 231

drsquoun patron de fonctions 211 216

paramegravetres expressions

drsquoun patron de classes 233

drsquoun patron de fonctions 215 219

paramegravetres par deacutefaut

drsquoun patron de classes 238

partial_sort (algorithme) 475 566

partial_sort_copy (algorithme) 567

partial_sum (algorithme) 478 570

partition 472

partition (algorithme) 472 563

patron de classes 225

creacuteation 226

et deacuteclaration drsquoamitieacute 239

et heacuteritage 284

paramegravetres de type 231

paramegravetres expressions 233

paramegravetres par deacutefaut 238

speacutecialisation 235 237

utilisation 228

patron de fonctions

creacuteation 206

limitations 214

paramegravetres de type 211

paramegravetres expressions 215 219

speacutecialisation 220

surdeacutefinition 216

utilisation 207

pattern singleton 79

peek 347

permutation

algorithme 469 470

plus 407

pointeur

de fichier 365

et iteacuterateur 400

C++ pour programmeurs C600

intelligent 542

sur des fonctions membres 551 554

polar 500

polymorphisme 4 305 316

pop 432 433 434

pop_back 418 420 425 427

pop_front 425 427

pop_heap 575

precision 361

preacutecision

de lrsquoinformation eacutecrite 341

preacutecision numeacuterique 356

preacutedicat 405

binaire 405

en argument 405

unaire 405

prev_permutation (algorithme) 470 563

priority_queue 434

private 68

programmation structureacutee 2

protected 258

prototype 11

public 68

push 432 433 434

push_back 418 420 427

push_front 425 427

push_heap 574

put 337

putback 347

Qqueue 433

RRAII 541

random_shuffle (algorithme) 471 564

rbegin 486

rdstate 349

read 347

real 500

recherche

algorithme 466 476 559 568

dans une chaicircne 488

recopie

drsquoun objet drsquoune classe deacuteriveacutee 271

redeacutefinition

drsquoune fonction virtuelle 312

reacutefeacuterence 30 101 156

initialisation 38

reinterpret_cast 58

relation drsquoordre 407 408

remove 427

remove (algorithme) 473 564

remove_copy (algorithme) 565

remove_copy_if (algorithme) 473

remove_if 427

remove_if (algorithme) 473 565

remplacement

algorithme 469

rend 486

replace 492

replace (algorithme) 469 562

replace_copy (algorithme) 562

replace_copy_if (algorithme) 562

replace_if (algorithme) 469 562

reserve 421 486

resetiosflags 359

resize 422 486 502

reverse (algorithme) 561

reverse_copy (algorithme) 561

reverse_iterator 419 426 486

rfind 489

right 357

rotate (algorithme) 469 562

rotate_copy (algorithme) 562

Sscientific 357 358

search (algorithme) 466 560

search_n (algorithme) 466 560

second 439

section de vecteur 505

seekg 365

seekp 365

seacuteparateur 23

seacutequence 457

set 451

set_difference (algorithme) 480 573

set_intersection (algorithme) 480 572

Index601

set_new_handler 52

set_symetric_difference (algorithme) 573

set_symmetric_difference (algorithme) 480

set_terminate 385 387

set_union (algorithme) 480 572

setbase 359

setf 360

setfill 359

setiosflags 359

setprecision 359

setw 356 359

shift 503

showbase 357 358

showpoint 357 358

showpos 357 358

sin 500

singleton (motif de conception) 79

sinh 500

size 421 424 430 432 433 434 486

skipws 357 358

slice 505

sort 428

sort (algorithme) 566

sort_heap 574

sortie standard 333

speacutecialisation

drsquoun patron de classes 235

drsquoune classe 237

drsquoune fonction membre 236

de fonctions patrons 220

partielle drsquoun patron de fonctions 221

splice 430

stable_partition 472

stable_partition (algorithme) 563

stable_sort (algorithme) 475 566

stack 432

static 80 105 112

static_cast 58

statique

classe ~ 111

fonction membre 104

membre donneacutee 80

objet 112

statique (typage des objets) 266

statut drsquoerreur

drsquoun flot 348

std 56

stderr 336

stdin 333

stdio 357

stdout 333

STL 395

str 369

string 336 344 485 486

Stroustrup 1

struct 62

structure 61 67

dynamique 115

suppression (algorithme) 472 564

surdeacutefinition

drsquoopeacuterateurs 42

drsquoune fonction virtuelle 313

de fonctions 42 530

de fonctions membres 91 533

de lrsquoaffactation 162

de lrsquoopeacuterateur -- 161

de lrsquoopeacuterateur 349

de lrsquoopeacuterateur () 173 349

de lrsquoopeacuterateur ltlt 335 352

de lrsquoopeacuterateur = 163 273

de lrsquoopeacuterateur gtgt 343 352

de lrsquoopeacuterateur delete 175

de lrsquoopeacuterateur new 175

de patrons de fonctions 216

et espaces de noms 521

par fonction amie 153

par fonction membre 154

swap 415 447 487

swap_ranges (algorithme) 558

Ttableau drsquoobjets 133

tan 500

tanh 500

tas 574

tellg 365

tellp 365

terminate 385 387

this 103

throw 374 378 383

times 407

C++ pour programmeurs C602

top 432 434

transform (algorithme) 564

transformation

algorithme 561

transformation(algorithme) 468

tri

algorithme 475 566

drsquoune liste 428

true 57

trunc 367

try (bloc) 375

typage dynamique 305

typage statique 266

type

bool 57

deacutefini par lrsquoutilisateur 61

structure 61

type_info 326

typeid 326

Uunexpected 387

unidirectionnel (iteacuterateur) 456

unions 87

unique 428

unique (algorithme) 473 565

unique_copy (algorithme) 565

unitbuf 357

unsetf 360

upper__bound 449

upper_bound 447

upper_bound (algorithme) 568

uppercase 357 358

using 20 56

using (deacuteclaration) 516

using (directive) 519 523

Vval_array 499

valarray 501

value_comp 442

vecteur drsquoindice 506

vector 412 424

virtual 297 306

volatile 108

Wwidth 361

Wirth (eacutequation de ~) 2

write 337

ws 359

  • Table des matiegraveres
  • Avant-propos
  • 1 Geacuteneacuteraliteacutes concernant C++
    • 1 La Programmation Orienteacutee Objet
      • 11 Probleacutematique de la programmation
      • 12 La programmation structureacutee
      • 13 Les apports de la Programmation Orienteacutee Objet
        • 131 Objet
        • 132 Encapsulation
        • 133 Classe
        • 134 Heacuteritage
        • 135 Polymorphisme
          • 14 POO et langages
            • 2 C++ C ANSI et POO
            • 3 Les speacutecificiteacutes de C++
            • 4 C++ et la programmation orienteacutee objet
              • 2 Les incompatibiliteacutes entre C++ et C
                • 1 Les deacutefinitions de fonctions en C++
                • 2 Les prototypes en C++
                • 3 Arguments et valeur de retour drsquoune fonction
                  • 31 Points communs agrave C et C++
                  • 32 Diffeacuterences entre C et C++
                    • 321 Fonctions sans arguments
                    • 322 Fonctions sans valeur de retour
                        • 4 Le qualificatif const
                          • 41 Porteacutee
                          • 42 Utilisation dans une expression
                            • 5 Compatibiliteacute entre le type void et les autres pointeurs
                              • 3 Les entreacutees-sorties conversationnelles du C++
                                • 1 Geacuteneacuteraliteacutes
                                • 2 Affichage agrave lrsquoeacutecran
                                  • 21 Quelques exemples
                                  • 22 Le fichier en-tecircte iostream
                                  • 23 Les possibiliteacutes drsquoeacutecriture sur cout
                                    • 3 Lecture au clavier
                                      • 31 Introduction
                                      • 32 Les diffeacuterentes possibiliteacutes de lecture sur cin
                                      • 33 Exemple classique drsquoutilisation des seacuteparateurs
                                      • 34 Lecture drsquoune suite de caractegraveres
                                      • 35 Les risques induits par la lecture au clavier
                                        • 351 Manque de synchronisme entre clavier et eacutecran
                                        • 352 Blocage de la lecture
                                        • 353 Boucle infinie sur un caractegravere invalide
                                          • 4 Les speacutecificiteacutes du C++
                                            • 1 Le commentaire de fin de ligne
                                            • 2 Deacuteclarations et initialisations
                                              • 21 Regravegles geacuteneacuterales
                                              • 22 Cas des instructions structureacutees
                                                • 3 La notion de reacutefeacuterence
                                                  • 31 Transmission des arguments en C
                                                  • 32 Exemple de transmission drsquoargument par reacutefeacuterence
                                                  • 33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argument
                                                    • 331 Induction de risques indirects
                                                    • 332 Absence de conversion
                                                    • 333 Cas drsquoun argument effectif constant
                                                    • 334 Cas drsquoun argument muet constant
                                                      • 34 Transmission par reacutefeacuterence drsquoune valeur de retour
                                                        • 341 Introduction
                                                        • 342 On obtient une lvalue
                                                        • 343 Conversion
                                                        • 344 Valeur de retour et constance
                                                          • 35 La reacutefeacuterence dune maniegravere geacuteneacuterale
                                                            • 351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument
                                                            • 352 Initialisation de reacutefeacuterence
                                                                • 4 Les arguments par deacutefaut
                                                                  • 41 Exemples
                                                                  • 42 Les proprieacuteteacutes des arguments par deacutefaut
                                                                    • 5 Surdeacutefinition de fonctions
                                                                      • 51 Mise en oeuvre de la surdeacutefinition de fonctions
                                                                      • 52 Exemples de choix dune fonction surdeacutefinie
                                                                      • 53 Regravegles de recherche dune fonction surdeacutefinie
                                                                        • 531 Cas des fonctions agrave un argument
                                                                        • 532 Cas des fonctions agrave plusieurs arguments
                                                                        • 533 Le meacutecanisme de la surdeacutefinition de fonctions
                                                                            • 6 Les opeacuterateurs new et delete
                                                                              • 61 Exemples dutilisation de new
                                                                              • 62 Syntaxe et rocircle de new
                                                                              • 63 Exemples dutilisation de lopeacuterateur delete
                                                                              • 64 Syntaxe et rocircle de lopeacuterateur delete
                                                                              • 65 Lrsquoopeacuterateur new (nothrow)
                                                                              • 66 Gestion des deacutebordements de meacutemoire avec set_new_handler
                                                                                • 7 La speacutecification inline
                                                                                  • 71 Rappels concernant les macros et les fonctions
                                                                                  • 72 Utilisation de fonctions en ligne
                                                                                    • 8 Les espaces de noms
                                                                                    • 9 Le type bool
                                                                                    • 10 Les nouveaux opeacuterateurs de cast
                                                                                      • 5 Classes et objets
                                                                                        • 1 Les structures en C++
                                                                                          • 11 Rappel les structures en C
                                                                                          • 12 Deacuteclaration dune structure comportant des fonctions membres
                                                                                          • 13 Deacutefinition des fonctions membres
                                                                                          • 14 Utilisation dune structure comportant des fonctions membres
                                                                                          • 15 Exemple reacutecapitulatif
                                                                                            • 2 Notion de classe
                                                                                            • 3 Affectation drsquoobjets
                                                                                            • 4 Notions de constructeur et de destructeur
                                                                                              • 41 Introduction
                                                                                              • 42 Exemple de classe comportant un constructeur
                                                                                              • 43 Construction et destruction des objets
                                                                                              • 44 Rocircles du constructeur et du destructeur
                                                                                              • 45 Quelques regravegles
                                                                                                • 5 Les membres donneacutees statiques
                                                                                                  • 51 Le qualificatif static pour un membre donneacutee
                                                                                                  • 52 Initialisation des membres donneacutees statiques
                                                                                                  • 53 Exemple
                                                                                                    • 6 Exploitation drsquoune classe
                                                                                                      • 61 La classe comme composant logiciel
                                                                                                      • 62 Protection contre les inclusions multiples
                                                                                                      • 63 Cas des membres donneacutees statiques
                                                                                                      • 64 En cas de modification drsquoune classe
                                                                                                        • 641 La deacuteclaration des membres publics nrsquoa pas changeacute
                                                                                                        • 642 La deacuteclaration des membres publics a changeacute
                                                                                                            • 7 Les classes en geacuteneacuteral
                                                                                                              • 71 Les autres sortes de classes en C++
                                                                                                              • 72 Ce quon peut trouver dans la deacuteclaration dune classe
                                                                                                              • 73 Deacuteclaration dune classe
                                                                                                                • Exercices
                                                                                                                  • 6 Les proprieacuteteacutes des fonctions membres
                                                                                                                    • 1 Surdeacutefinition des fonctions membres
                                                                                                                      • 11 Exemple
                                                                                                                      • 12 Incidence du statut public ou priveacute drsquoune fonction membre
                                                                                                                        • 3 Les fonctions membres en ligne
                                                                                                                        • 2 Arguments par deacutefaut
                                                                                                                        • 4 Cas des objets transmis en argument drsquoune fonction membre
                                                                                                                        • 5 Mode de transmission des objets en argument
                                                                                                                          • 51 Transmission de ladresse dun objet
                                                                                                                          • 52 Transmission par reacutefeacuterence
                                                                                                                          • 53 Les problegravemes poseacutes par la transmission par valeur
                                                                                                                            • 6 Lorsqursquoune fonction renvoie un objet
                                                                                                                            • 7 Autoreacutefeacuterence le mot cleacute this
                                                                                                                            • 8 Les fonctions membres statiques
                                                                                                                            • 9 Les fonctions membres constantes
                                                                                                                              • 91 Rappels sur lrsquoutilisation de const en C
                                                                                                                              • 92 Deacutefinition drsquoune fonction membre constante
                                                                                                                              • 93 Proprieacuteteacutes drsquoune fonction membre constante
                                                                                                                                • 10 Les membres mutables
                                                                                                                                • Exercices
                                                                                                                                  • 7Construction destruction et initialisation des objets
                                                                                                                                    • 1 Les objets automatiques et statiques
                                                                                                                                      • 11 Dureacutee de vie
                                                                                                                                      • 12 Appel des constructeurs et des destructeurs
                                                                                                                                      • 13 Exemple
                                                                                                                                        • 2 Les objets dynamiques
                                                                                                                                          • 21 Les structures dynamiques
                                                                                                                                          • 22 Les objets dynamiques
                                                                                                                                            • 221 Points communs avec les structures dynamiques
                                                                                                                                            • 222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete
                                                                                                                                            • 223 Exemple
                                                                                                                                                • 3 Le constructeur de recopie
                                                                                                                                                  • 31 Preacutesentation
                                                                                                                                                    • 311 Il nexiste pas de constructeur approprieacute
                                                                                                                                                    • 312 Il existe un constructeur approprieacute
                                                                                                                                                    • 313 Lorsqursquoon souhaite interdire la contruction par recopie
                                                                                                                                                      • 32 Exemple 1 objet transmis par valeur
                                                                                                                                                        • 321 Emploi du constructeur de recopie par deacutefaut
                                                                                                                                                        • 322 Deacutefinition dun constructeur de recopie
                                                                                                                                                          • 33 Exemple 2 objet en valeur de retour dune fonction
                                                                                                                                                            • 4 Initialisation dun objet lors de sa deacuteclaration
                                                                                                                                                            • 5 Objets membres
                                                                                                                                                              • 51 Introduction
                                                                                                                                                              • 52 Mise en oeuvre des constructeurs et des destructeurs
                                                                                                                                                              • 53 Le constructeur de recopie
                                                                                                                                                                • 6 Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur
                                                                                                                                                                • 7 Les tableaux drsquoobjets
                                                                                                                                                                  • 71 Notations
                                                                                                                                                                  • 72 Constructeurs et initialiseurs
                                                                                                                                                                  • 73 Cas des tableaux dynamiques dobjets
                                                                                                                                                                    • 8 Les objets temporaires
                                                                                                                                                                    • Exercices
                                                                                                                                                                      • 8 Les fonctions amies
                                                                                                                                                                        • 1 Exemple de fonction indeacutependante amiedrsquoune classe
                                                                                                                                                                          • 2 Les diffeacuterentes situations drsquoamitieacute
                                                                                                                                                                            • 21 Fonction membre dune classe amie dune autre classe
                                                                                                                                                                            • 22 Fonction amie de plusieurs classes
                                                                                                                                                                            • 23 Toutes les fonctions dune classe amies dune autre classe
                                                                                                                                                                              • 3 Exemple
                                                                                                                                                                                • 31 Fonction amie indeacutependante
                                                                                                                                                                                • 32 Fonction amie membre dune classe
                                                                                                                                                                                  • 4 Exploitation de classes disposant de fonctions amies
                                                                                                                                                                                      • 9 La surdeacutefinition drsquoopeacuterateurs
                                                                                                                                                                                        • 1 Le meacutecanisme de la surdeacutefinitiondrsquoopeacuterateurs
                                                                                                                                                                                          • 11 Surdeacutefinition dopeacuterateur avec une fonction amie
                                                                                                                                                                                          • 12 Surdeacutefinition dopeacuterateur avec une fonction membre
                                                                                                                                                                                          • 13 Opeacuterateurs et transmission par reacutefeacuterence
                                                                                                                                                                                            • 2 La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral
                                                                                                                                                                                              • 21 Se limiter aux opeacuterateurs existants
                                                                                                                                                                                              • 22 Se placer dans un contexte de classe
                                                                                                                                                                                              • 23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateur
                                                                                                                                                                                              • 24 Cas des opeacuterateurs ++ et --
                                                                                                                                                                                              • 25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinie
                                                                                                                                                                                              • 26 Les conversions
                                                                                                                                                                                              • 27 Choix entre fonction membre et fonction amie
                                                                                                                                                                                                • 3 Exemple de surdeacutefinition de lrsquoopeacuterateur =
                                                                                                                                                                                                  • 31 Rappels concernant le constructeur par recopie
                                                                                                                                                                                                  • 32 Cas de lrsquoaffectation
                                                                                                                                                                                                  • 33 Algorithme proposeacute
                                                                                                                                                                                                  • 34 Valeur de retour
                                                                                                                                                                                                  • 35 En deacutefinitive
                                                                                                                                                                                                  • 36 Exemple de programme complet
                                                                                                                                                                                                  • 37 Lorsqursquoon souhaite interdire lrsquoaffectation
                                                                                                                                                                                                    • 4 La forme canonique dune classe
                                                                                                                                                                                                    • 5 Exemple de surdeacutefinition de lopeacuterateur [ ]
                                                                                                                                                                                                    • 6 Surdeacutefinition de lopeacuterateur ()
                                                                                                                                                                                                    • 7 Surdeacutefinition des opeacuterateurs new et delete
                                                                                                                                                                                                      • 71 Surdeacutefinition de new et delete pour une classe donneacutee
                                                                                                                                                                                                      • 72 Exemple
                                                                                                                                                                                                      • 73 Drsquoune maniegravere geacuteneacuterale
                                                                                                                                                                                                        • Exercices
                                                                                                                                                                                                          • 10 Les conversions de type deacutefinies par lrsquoutilisateur
                                                                                                                                                                                                            • 1 Les diffeacuterentes sortes de conversionsdeacutefinies par lrsquoutilisateur
                                                                                                                                                                                                            • 2 Lopeacuterateur de cast pour la conversion typeclasse ndashgt type de base
                                                                                                                                                                                                              • 21 Deacutefinition de lopeacuterateur de cast
                                                                                                                                                                                                              • 22 Exemple dutilisation
                                                                                                                                                                                                              • 23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonction
                                                                                                                                                                                                              • 24 Appel implicite de lopeacuterateur de cast dans leacutevaluationdune expression
                                                                                                                                                                                                              • 25 Conversions en chaicircne
                                                                                                                                                                                                              • 26 En cas dambiguiumlteacute
                                                                                                                                                                                                                • 3 Le constructeur pour la conversion typede base -gt type classe
                                                                                                                                                                                                                  • 31 Exemple
                                                                                                                                                                                                                  • 32 Le constructeur dans une chaicircne de conversions
                                                                                                                                                                                                                  • 33 Choix entre constructeur ou opeacuterateur daffectation
                                                                                                                                                                                                                  • 34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur
                                                                                                                                                                                                                  • 35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit
                                                                                                                                                                                                                    • 4 Les conversions drsquoun type classe en un autretype classe
                                                                                                                                                                                                                      • 41 Exemple simple dopeacuterateur de cast
                                                                                                                                                                                                                      • 42 Exemple de conversion par un constructeur
                                                                                                                                                                                                                      • 43 Pour donner une signification agrave un opeacuterateur deacutefini dans uneautre classe
                                                                                                                                                                                                                        • 5 Quelques conseils
                                                                                                                                                                                                                          • 11 Les patrons de fonctions
                                                                                                                                                                                                                            • 1 Exemple de creacuteation et drsquoutilisationdrsquoun patron de fonctions
                                                                                                                                                                                                                              • 11 Creacuteation dun patron de fonctions
                                                                                                                                                                                                                              • 12 Premiegraveres utilisations du patron de fonctions
                                                                                                                                                                                                                              • 13 Autres utilisations du patron de fonctions
                                                                                                                                                                                                                                • 131 Application au type char
                                                                                                                                                                                                                                • 132 Application agrave un type classe
                                                                                                                                                                                                                                  • 14 Contraintes drsquoutilisation drsquoun patron
                                                                                                                                                                                                                                    • 2 Les paramegravetres de type drsquoun patronde fonctions
                                                                                                                                                                                                                                      • 21 Utilisation des paramegravetres de type dans la deacutefinitiondun patron
                                                                                                                                                                                                                                      • 22 Identification des paramegravetres de type dune fonction patron
                                                                                                                                                                                                                                      • 23 Nouvelle syntaxe dinitialisation des variables des types standard
                                                                                                                                                                                                                                      • 24 Limitations des patrons de fonctions
                                                                                                                                                                                                                                        • 3 Les paramegravetres expressions drsquoun patron de fonctions
                                                                                                                                                                                                                                        • 4 Surdeacutefinition de patrons
                                                                                                                                                                                                                                          • 41 Exemples ne comportant que des paramegravetres de type
                                                                                                                                                                                                                                          • 42 Exemples comportant des paramegravetres expressions
                                                                                                                                                                                                                                            • 5 Speacutecialisation de fonctions de patron
                                                                                                                                                                                                                                              • 51 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                              • 52 Les speacutecialisations partielles
                                                                                                                                                                                                                                                • 6 Algorithme drsquoinstanciation drsquounefonction patron
                                                                                                                                                                                                                                                  • 12 Les patrons de classes
                                                                                                                                                                                                                                                    • 1 Exemple de creacuteation et drsquoutilisation dun patron de classes
                                                                                                                                                                                                                                                      • 11 Creacuteation dun patron de classes
                                                                                                                                                                                                                                                      • 12 Utilisation dun patron de classes
                                                                                                                                                                                                                                                      • 13 Contraintes drsquoutilisation drsquoun patron de classes
                                                                                                                                                                                                                                                      • 14 Exemple reacutecapitulatif
                                                                                                                                                                                                                                                        • 2 Les paramegravetres de type drsquoun patron de classes
                                                                                                                                                                                                                                                          • 21 Les paramegravetres de type dans la creacuteation dun patron de classes
                                                                                                                                                                                                                                                          • 22 Instanciation dune classe patron
                                                                                                                                                                                                                                                            • 3 Les paramegravetres expressions drsquoun patron de classes
                                                                                                                                                                                                                                                              • 31 Exemple
                                                                                                                                                                                                                                                              • 32 Les proprieacuteteacutes des paramegravetres expressions
                                                                                                                                                                                                                                                                • 4 Speacutecialisation drsquoun patron de classes
                                                                                                                                                                                                                                                                  • 41 Exemple de speacutecialisation dune fonction membre
                                                                                                                                                                                                                                                                  • 42 Les diffeacuterentes possibiliteacutes de speacutecialisation
                                                                                                                                                                                                                                                                    • 421 On peut speacutecialiser une fonction membre pour tous les paramegravetres
                                                                                                                                                                                                                                                                    • 422 On peut speacutecialiser une fonction membre ou une classe
                                                                                                                                                                                                                                                                    • 423 On peut preacutevoir des speacutecialisations partielles de patrons de classes
                                                                                                                                                                                                                                                                        • 5 Paramegravetres par deacutefaut
                                                                                                                                                                                                                                                                        • 6 Patrons de fonctions membres
                                                                                                                                                                                                                                                                        • 7 Identiteacute de classes patrons
                                                                                                                                                                                                                                                                        • 8 Classes patrons et deacuteclarations drsquoamitieacute
                                                                                                                                                                                                                                                                          • 81 Deacuteclaration de classes ou fonctions ordinaires amies
                                                                                                                                                                                                                                                                          • 82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons
                                                                                                                                                                                                                                                                          • 83 Deacuteclaration drsquoun autre patron de fonctions ou de classes
                                                                                                                                                                                                                                                                            • 9 Exemple de classe tableau agrave deux indices
                                                                                                                                                                                                                                                                              • 13 Lrsquoheacuteritage simple
                                                                                                                                                                                                                                                                                • 1 La notion drsquoheacuteritage
                                                                                                                                                                                                                                                                                • 2 Utilisation des membres de la classe de base dans une classe deacuteriveacutee
                                                                                                                                                                                                                                                                                • 3 Redeacutefinition des membres dune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 33 Redeacutefinition et surdeacutefinition
                                                                                                                                                                                                                                                                                    • 4 Appel des constructeurs et des destructeurs
                                                                                                                                                                                                                                                                                      • 41 Rappels
                                                                                                                                                                                                                                                                                      • 42 La hieacuterarchisation des appels
                                                                                                                                                                                                                                                                                      • 43 Transmission dinformations entre constructeurs
                                                                                                                                                                                                                                                                                      • 44 Exemple
                                                                                                                                                                                                                                                                                      • 45 Compleacutements
                                                                                                                                                                                                                                                                                        • 5 Controcircle des accegraves
                                                                                                                                                                                                                                                                                          • 51 Les membres proteacutegeacutes
                                                                                                                                                                                                                                                                                          • 52 Exemple
                                                                                                                                                                                                                                                                                          • 53 Inteacuterecirct du statut proteacutegeacute
                                                                                                                                                                                                                                                                                          • 54 Deacuterivation publique et deacuterivation priveacutee
                                                                                                                                                                                                                                                                                            • 541 Rappels concernant la deacuterivation publique
                                                                                                                                                                                                                                                                                            • 542 Deacuterivation priveacutee
                                                                                                                                                                                                                                                                                              • 55 Les possibiliteacutes de deacuterivation proteacutegeacutee
                                                                                                                                                                                                                                                                                              • 56 Reacutecapitulation
                                                                                                                                                                                                                                                                                                • 6 Compatibiliteacute entre classe de base et classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                  • 61 Conversion dun type deacuteriveacute en un type de base
                                                                                                                                                                                                                                                                                                  • 62 Conversion de pointeurs
                                                                                                                                                                                                                                                                                                  • 63 Limitations lieacutees au typage statique des objets
                                                                                                                                                                                                                                                                                                  • 64 Les risques de violation des protections de la classe de base
                                                                                                                                                                                                                                                                                                    • 7 Le constructeur de recopie et lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                      • 71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopie
                                                                                                                                                                                                                                                                                                      • 72 La classe deacuteriveacutee deacutefinit un constructeur de recopie
                                                                                                                                                                                                                                                                                                        • 8 Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                          • 81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur =
                                                                                                                                                                                                                                                                                                          • 82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur =
                                                                                                                                                                                                                                                                                                            • 9 Heacuteritage et forme canonique dune classe
                                                                                                                                                                                                                                                                                                            • 10 Lrsquoheacuteritage et ses limites
                                                                                                                                                                                                                                                                                                              • 101 La situation dheacuteritage
                                                                                                                                                                                                                                                                                                                • 1011 Le type du reacutesultat de lappel
                                                                                                                                                                                                                                                                                                                • 1012 Le type des arguments de f
                                                                                                                                                                                                                                                                                                                  • 102 Exemples
                                                                                                                                                                                                                                                                                                                    • 1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point
                                                                                                                                                                                                                                                                                                                    • 1022 Heacuteritage dans pointcol de la fonction coincide de point
                                                                                                                                                                                                                                                                                                                        • 11 Exemple de classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                                        • 12 Patrons de classes et heacuteritage
                                                                                                                                                                                                                                                                                                                          • 121Classe ordinaire deacuterivant dune classe patron
                                                                                                                                                                                                                                                                                                                          • 122Deacuterivation de patrons avec les mecircmes paramegravetres
                                                                                                                                                                                                                                                                                                                          • 123Deacuterivation de patrons avec introduction dun nouveau paramegravetre
                                                                                                                                                                                                                                                                                                                            • 13 Lrsquoheacuteritage en pratique
                                                                                                                                                                                                                                                                                                                              • 131Deacuterivations successives
                                                                                                                                                                                                                                                                                                                              • 132Diffeacuterentes utilisations de lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                                              • 133 Exploitation drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                                                  • 14 Lheacuteritage multiple
                                                                                                                                                                                                                                                                                                                                    • 1 Mise en oeuvre de lheacuteritage multiple
                                                                                                                                                                                                                                                                                                                                    • 2 Pour reacutegler les eacuteventuels conflits les classes virtuelles
                                                                                                                                                                                                                                                                                                                                    • 3 Appels des constructeurs et des destructeurs cas des classes virtuelles
                                                                                                                                                                                                                                                                                                                                    • 4 Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle
                                                                                                                                                                                                                                                                                                                                      • 15 Les fonctions virtuelles et le polymorphisme
                                                                                                                                                                                                                                                                                                                                        • 1 Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire
                                                                                                                                                                                                                                                                                                                                        • 2 Le meacutecanisme des fonctions virtuelles
                                                                                                                                                                                                                                                                                                                                        • 3 Autre situation ougrave la ligature dynamique est indispensable
                                                                                                                                                                                                                                                                                                                                        • 4 Les proprieacuteteacutes des fonctions virtuelles
                                                                                                                                                                                                                                                                                                                                          • 41 Leurs limitations sont celles de lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                                                          • 42 La redeacutefinition dune fonction virtuelle nest pas obligatoire
                                                                                                                                                                                                                                                                                                                                          • 43 Fonctions virtuelles et surdeacutefinition
                                                                                                                                                                                                                                                                                                                                          • 44 Le type de retour drsquoune fonction virtuelle redeacutefinie
                                                                                                                                                                                                                                                                                                                                          • 45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe
                                                                                                                                                                                                                                                                                                                                          • 46 Quelques restrictions et conseils
                                                                                                                                                                                                                                                                                                                                            • 461 Seule une fonction membre peut ecirctre virtuelle
                                                                                                                                                                                                                                                                                                                                            • 462 Un constructeur ne peut pas ecirctre virtuel
                                                                                                                                                                                                                                                                                                                                            • 463 Un destructeur peut ecirctre virtuel
                                                                                                                                                                                                                                                                                                                                            • 464 Cas particulier de lrsquoopeacuterateur drsquoaffectation
                                                                                                                                                                                                                                                                                                                                                • 5 Les fonctions virtuelles pures pour la creacuteation de classes abstraites
                                                                                                                                                                                                                                                                                                                                                • 6 Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene
                                                                                                                                                                                                                                                                                                                                                • 7 Le meacutecanisme drsquoidentification dynamique des objets
                                                                                                                                                                                                                                                                                                                                                • 8 Identification de type agrave lexeacutecution
                                                                                                                                                                                                                                                                                                                                                  • 81 Utilisation du champ name de type_info
                                                                                                                                                                                                                                                                                                                                                  • 82 Utilisation des opeacuterateurs de comparaison de type_info
                                                                                                                                                                                                                                                                                                                                                  • 83 Exemple avec des reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                    • 9 Les cast dynamiques
                                                                                                                                                                                                                                                                                                                                                      • 16 Les flots
                                                                                                                                                                                                                                                                                                                                                        • 1 Preacutesentation geacuteneacuterale de la classe ostream
                                                                                                                                                                                                                                                                                                                                                          • 11 Lopeacuterateur ltlt
                                                                                                                                                                                                                                                                                                                                                          • 12 Les flots preacutedeacutefinis
                                                                                                                                                                                                                                                                                                                                                          • 13 La fonction put
                                                                                                                                                                                                                                                                                                                                                          • 14 La fonction write
                                                                                                                                                                                                                                                                                                                                                            • 141 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                            • 142 Autres cas
                                                                                                                                                                                                                                                                                                                                                              • 15 Quelques possibiliteacutes de formatage avec ltlt
                                                                                                                                                                                                                                                                                                                                                                • 151 Action sur la base de numeacuteration
                                                                                                                                                                                                                                                                                                                                                                • 152 Action sur le gabarit de linformation eacutecrite
                                                                                                                                                                                                                                                                                                                                                                • 153 Action sur la preacutecision de lrsquoinformation eacutecrite
                                                                                                                                                                                                                                                                                                                                                                • 154 Choix entre notation flottante ou exponentielle
                                                                                                                                                                                                                                                                                                                                                                    • 2 Preacutesentation geacuteneacuterale de la classe istream
                                                                                                                                                                                                                                                                                                                                                                      • 21 Lrsquoopeacuterateur gtgt
                                                                                                                                                                                                                                                                                                                                                                        • 211 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                                        • 212 Cas des chaicircnes de caractegraveres
                                                                                                                                                                                                                                                                                                                                                                        • 213 Les types accepteacutes par gtgt
                                                                                                                                                                                                                                                                                                                                                                          • 22 La fonction get
                                                                                                                                                                                                                                                                                                                                                                          • 23 Les fonctions getline et gcount
                                                                                                                                                                                                                                                                                                                                                                          • 24 La fonction read
                                                                                                                                                                                                                                                                                                                                                                            • 241 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                                            • 242 Autres cas
                                                                                                                                                                                                                                                                                                                                                                              • 25 Quelques autres fonctions
                                                                                                                                                                                                                                                                                                                                                                                • 3 Statut drsquoerreur drsquoun flot
                                                                                                                                                                                                                                                                                                                                                                                  • 31 Les bits derreur
                                                                                                                                                                                                                                                                                                                                                                                  • 32 Actions concernant les bits derreur
                                                                                                                                                                                                                                                                                                                                                                                    • 321 Accegraves aux bits derreur
                                                                                                                                                                                                                                                                                                                                                                                    • 322 Modification du statut derreur
                                                                                                                                                                                                                                                                                                                                                                                      • 33 Surdeacutefinition des opeacuterateurs () et
                                                                                                                                                                                                                                                                                                                                                                                      • 34 Exemples
                                                                                                                                                                                                                                                                                                                                                                                        • 4 Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur
                                                                                                                                                                                                                                                                                                                                                                                          • 41 Meacutethode
                                                                                                                                                                                                                                                                                                                                                                                          • 42 Exemple
                                                                                                                                                                                                                                                                                                                                                                                            • 5 Gestion du formatage
                                                                                                                                                                                                                                                                                                                                                                                              • 51 Le statut de formatage dun flot
                                                                                                                                                                                                                                                                                                                                                                                              • 52 Description du mot deacutetat du statut de formatage
                                                                                                                                                                                                                                                                                                                                                                                              • 53 Action sur le statut de formatage
                                                                                                                                                                                                                                                                                                                                                                                                • 531 Les manipulateurs non parameacutetriques
                                                                                                                                                                                                                                                                                                                                                                                                • 532 Les manipulateurs parameacutetriques
                                                                                                                                                                                                                                                                                                                                                                                                • 533 Les fonctions membres
                                                                                                                                                                                                                                                                                                                                                                                                    • 6 Connexion drsquoun flot agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 61 Connexion dun flot de sortie agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 62 Connexion dun flot dentreacutee agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 63 Les possibiliteacutes daccegraves direct
                                                                                                                                                                                                                                                                                                                                                                                                      • 64 Les diffeacuterents modes douverture dun fichier
                                                                                                                                                                                                                                                                                                                                                                                                        • 7 Les anciennes possibiliteacutes de formatage en meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                          • 71 La classe ostrstream
                                                                                                                                                                                                                                                                                                                                                                                                          • 72 La classe istrstream
                                                                                                                                                                                                                                                                                                                                                                                                              • 17 La gestion des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                • 1 Premier exemple drsquoexception
                                                                                                                                                                                                                                                                                                                                                                                                                  • 11 Comment lancer une exception linstruction throw
                                                                                                                                                                                                                                                                                                                                                                                                                  • 12 Utilisation dun gestionnaire dexception
                                                                                                                                                                                                                                                                                                                                                                                                                  • 13 Reacutecapitulatif
                                                                                                                                                                                                                                                                                                                                                                                                                    • 2 Second exemple
                                                                                                                                                                                                                                                                                                                                                                                                                    • 3 Le meacutecanisme de gestion des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                      • 31 Poursuite de lexeacutecution du programme
                                                                                                                                                                                                                                                                                                                                                                                                                      • 32 Prise en compte des sorties de blocs
                                                                                                                                                                                                                                                                                                                                                                                                                        • 4 Choix du gestionnaire
                                                                                                                                                                                                                                                                                                                                                                                                                          • 41 Le gestionnaire reccediloit toujours une copie
                                                                                                                                                                                                                                                                                                                                                                                                                          • 42 Regravegles de choix drsquoun gestionnaire drsquoexception
                                                                                                                                                                                                                                                                                                                                                                                                                          • 43 Le cheminement des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                          • 44 Redeacuteclenchement drsquoune exception
                                                                                                                                                                                                                                                                                                                                                                                                                            • 5 Speacutecification dinterface la fonction unexpected
                                                                                                                                                                                                                                                                                                                                                                                                                            • 6 Les exceptions standard
                                                                                                                                                                                                                                                                                                                                                                                                                              • 61 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                              • 62 Les exceptions deacuteclencheacutees par la bibliothegraveque standard
                                                                                                                                                                                                                                                                                                                                                                                                                              • 63 Les exceptions utilisables dans un programme
                                                                                                                                                                                                                                                                                                                                                                                                                              • 64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exception
                                                                                                                                                                                                                                                                                                                                                                                                                                • 641 Exemple 1
                                                                                                                                                                                                                                                                                                                                                                                                                                • 642 Exemple 2
                                                                                                                                                                                                                                                                                                                                                                                                                                  • 18 Geacuteneacuteraliteacutes sur la bibliothegraveque standard
                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Notions de conteneur diteacuterateur et dalgorithme
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Notion de conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 12 Notion diteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 13 Parcours dun conteneur avec un iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                        • 131 Parcours direct
                                                                                                                                                                                                                                                                                                                                                                                                                                        • 132 Parcours inverse
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 14 Intervalle diteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 15 Notion dalgorithme
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 16 Iteacuterateurs et pointeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Les diffeacuterentes sortes de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Conteneurs et structures de donneacutees classiques
                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Les diffeacuterentes cateacutegories de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Les conteneurs dont les eacuteleacutements sont des objets
                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 31 Construction copie et affectation
                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 32 Autres opeacuterations
                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 4 Efficaciteacute des opeacuterations sur des conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Fonctions preacutedicats et classes fonctions
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 51 Fonction unaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 52 Preacutedicats
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 53 Classes et objets fonctions
                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 531 Utilisation dobjet fonction comme fonction de rappel
                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 532 Classes fonction preacutedeacutefinies
                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 6 Conteneurs algorithmes et relation dordre
                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 61 Introduction
                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 62 Proprieacuteteacutes agrave respecter
                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 7 Les geacuteneacuterateurs dopeacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 19 Les conteneurs seacutequentiels
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Fonctionnaliteacutes communes aux conteneurs vector list et deque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Construction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 111 Construction dun conteneur vide
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 112 Construction avec un nombre donneacute deacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 114 Construction agrave partir dune seacutequence
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 115 Construction agrave partir dun autre conteneur de mecircme type
                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 12 Modifications globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 121 Opeacuterateur daffectation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 122 La fonction membre assign
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 123 La fonction clear
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 124 La fonction swap
                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Comparaison de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 131 Lopeacuterateur ==
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 132 Lopeacuterateur lt
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 133 Exemples
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 14 Insertion ou suppression deacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 141 Insertion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 142 Suppression
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 143 Cas des insertionssuppressions en fin pop_back et push_back
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 2 Le conteneur vector
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 21 Accegraves aux eacuteleacutements existants
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 211 Accegraves par iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 212 Accegraves par indice
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 213 Cas de laccegraves au dernier eacuteleacutement
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 23 Gestion de lemplacement meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 231 Introduction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 232 Invalidation diteacuterateurs ou de reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 233 Outils de gestion de lemplacement meacutemoire dun vecteur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 24 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 25 Cas particulier des vecteurs de booleacuteens
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 3 Le conteneur deque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 31 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 32 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 4 Le conteneur list
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 41 Accegraves aux eacuteleacutements existants
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 42 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 421 Suppression des eacuteleacutements de valeur donneacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 422 Suppression des eacuteleacutements reacutepondant agrave une condition
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 43 Opeacuterations globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 431 Tri dune liste
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 432 Suppression des eacuteleacutements en double
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 433 Fusion de deux listes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 434 Transfert dune partie de liste dans une autre
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 44 Gestion de lemplacement meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 45 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Les adaptateurs de conteneur queue stack et priority_queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 51 Ladaptateur stack
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 52 Ladaptateur queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 53 Ladaptateur priority_queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 20 Les conteneurs associatifs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 Le conteneur map
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 11 Exemple introductif
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 12 Le patron de classes pair
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Construction dun conteneur de type map
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 131 Constructions utilisant la relation dordre par deacutefaut
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 132 Choix de lordre intrinsegraveque du conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 133 Pour connaicirctre la relation dordre utiliseacutee par un conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 134 Conseacutequences du choix de lordre dun conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 14 Accegraves aux eacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 141 Accegraves par lopeacuterateur [ ]
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 142 Accegraves par iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 143 Recherche par la fonction membre find
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 15 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 151 Insertions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 152 Suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 16 Gestion meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 17 Autres possibiliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 18 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Le conteneur multimap
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Le conteneur set
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 31 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 32 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 33 Le conteneur set et lensemble matheacutematique
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 4 Le conteneur multiset
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Conteneurs associatifs et algorithmes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 21 Les algorithmes standard
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 1 Notions geacuteneacuterales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 11 Algorithmes et iteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 12 Les cateacutegories diteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 121 Iteacuterateur en entreacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 122 Iteacuterateur en sortie
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 123 Hieacuterarchie des cateacutegories diteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Algorithmes et seacutequences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 14 Iteacuterateur dinsertion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 15 Iteacuterateur de flot
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 151 Iteacuterateur de flot de sortie
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 152 Iteacuterateur de flot dentreacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 2 Algorithmes dinitialisation de seacutequences existantes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 21 Copie dune seacutequence dans une autre
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 22 Geacuteneacuteration de valeurs par une fonction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 3 Algorithmes de recherche
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 32 Algorithmes de recherche de maximum ou de minimum
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 4 Algorithmes de transformation dune seacutequence
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 41 Remplacement de valeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 42 Permutations de valeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 421 Rotation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 422 Geacuteneacuteration de permutations
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 423 Permutations aleacuteatoires
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 43 Partitions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Algorithmes dits de suppression
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 6 Algorithmes de tris
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 7 Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 71 Algorithmes de recherche binaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 72 Algorithmes de fusion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 8 Algorithmes agrave caractegravere numeacuterique
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 9 Algorithmes agrave caractegravere ensembliste
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 10 Algorithmes de manipulation de tas
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 22 La classe string
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Construction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 3 Opeacuterations globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 4 Concateacutenation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 5 Recherche dans une chaicircne
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 51 Recherche dune chaicircne ou dun caractegravere
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 52 Recherche dun caractegravere preacutesent ou absent dune suite
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 6 Insertions suppressions et remplacements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 61 Insertions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 62 Suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 63 Remplacements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 7 Les possibiliteacutes de formatage en meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 71 La classe ostringstream
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 72 La classe istringstream
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 721 Preacutesentation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 722 Utilisation pour fiabiliser les lectures au clavier
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 23 Les outils numeacuteriques
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 La classe complex
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 La classe valarray et les classes associeacutees
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Constructeurs des classes valarray
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Lrsquoopeacuterateur []
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 23 Affectation et changement de taille
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 24 Calcul vectoriel
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 25 Seacutelection de valeurs par masque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 26 Sections de vecteurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 27 Vecteurs drsquoindices
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 La classe bitset
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 24 Les espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Creacuteation drsquoespaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Exemple de creacuteation drsquoun nouvel espace de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 12 Exemple avec deux espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 13 Espace de noms et fichier en-tecircte
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 14 Instructions figurant dans un espace de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 15 Creacuteation increacutementale drsquoespaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 2 Les instructions using
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 21 La deacuteclaration using pour les symboles
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 211 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 212 Masquage et ambiguiumlteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 La directive using pour les espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Espaces de noms et surdeacutefinition
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 4 Imbrication des espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 5 Transitiviteacute de la directive using
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 6 Les alias
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 7 Les espaces anonymes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 8 Espaces de noms et deacuteclaration drsquoamitieacute
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • Annexes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe A Mise en correspondance darguments
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe B Utilisation de code eacutecrit en C
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe C Compleacutements sur les exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe D Les diffeacuterentes sortes de fonctions en C++
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe E Comptage de reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe F Les pointeurs sur des membres
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe G Les algorithmes standard
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • Correction des exercices
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • Index
Page 2: C++ pour les programmeurs C - bibliotheque.pssfp.net

C++pour les

programmeursC

delannoy C++ titre 30907 2041 Page 2

CHEZ LE MEcircME EacuteDITEUR

Du mecircme auteur

C Delannoy ndash Exercices en langage C++ Ndeg12201 3e eacutedition 2007 336 pages

C Delannoy ndash Apprendre le C++ Ndeg12135 2007 760 pages

C Delannoy ndash Programmer en Java (Java 5 et 6) Ndeg12232 5e eacutedition 780 pages + CD-Rom

C Delannoy ndash Exercices en Java (Java 5) Ndeg11989 2e eacutedition 2006 330 pages

C Delannoy ndash Langage C Ndeg11123 1998 944 pages (reacuteeacutedition au format semi-poche)

C Delannoy ndash Programmer en langage C Avec exercices corrigeacutes Ndeg11072 1996 280 pages

C Delannoy ndash Exercices en langage C Ndeg11105 1997 260 pages

Autres ouvrages dans la mecircme collection

P Roques ndash UML 2 par la pratique Cours et exercices Ndeg12014 5e eacutedition 2006 360 pages

X Blanc I MounIeR ndash UML 2 pour les deacuteveloppeurs Cours et exercices corrigeacutes Ndeg12029 2006 218 pages

H BeRsInI I Wellesz ndash Lrsquoorienteacute objet Cours et exercices en UML 2 avec PHP Java Python C et C++ Ndeg12084 3e eacutedition 2007 520 pages

J engels ndash XHTML et CSS cours et exercices Ndeg11637 2005 350 pages

J engels ndash PHP 5 cours et exercicesNdeg11407 2005 518 pages

Autres ouvrages

I HoRton ndash Visual C++ 6 Avec un CD-Rom contenant le produit Microsoft Visual C++ 6 Introductory Edition Ndeg9043 1999 1 250 pages

G leBlanc ndash C et NET 20 Ndeg11778 2006 700 pages

E DasPet et C PIeRRe de geyeR ndash PHP 5 avanceacute Ndeg12167 4e eacutedition 2007 780 pages

a goncalves ndash Cahier du programmeur Java EE5 Ndeg12038 2007 330 pages

c PoRteneuve ndash Bien deacutevelopper pour le Web 20 Ndeg12028 2006 560 pages

Claude Delannoy

C++pour les

programmeursC

delannoy C++ titre 30907 2041 Page 1

compositeur
Fichier en piegravece jointe
9782212122312jpg

EacuteDITIONS EYROLLES61 bd Saint-Germain75240 Paris Cedex 05

wwweditions-eyrollescom

Le code de la proprieacuteteacute intellectuelle du 1er juillet 1992 interdit en effet expresseacutement la photocopie agrave usage collectif sans autorisation des ayants droit Or cette pratique srsquoest geacuteneacuteraliseacutee notamment dans les eacutetablissements drsquoenseignement provoquant une baisse brutale des achats de livres au point que la possibiliteacute mecircme pour les auteurs de creacuteer des œuvres nouvelles et de les faire eacutediter correctement est aujourdrsquohui menaceacuteeEn application de la loi du 11 mars 1957 il est interdit de reproduire inteacutegralement ou partiellement le

preacutesent ouvrage sur quelque support que ce soit sans autorisation de lrsquoeacutediteur ou du Centre Franccedilais drsquoExploitation du Droit de Copie 20 rue des Grands-Augustins 75006 Pariscopy Groupe Eyrolles 1993-2004 pour le texte de la preacutesente eacuteditioncopy Groupe Eyrolles 2007 pour la nouvelle preacutesentation (nouveau titre) ISBN 978-2-212-12231-2

6e eacutedition 2004 2e tirage 2007 avec nouvelle preacutesentation

Deacutepocirct leacutegal Septembre 2007Ndeg drsquoeacutediteur 7703

Table des matiegraveres

Avant-propos XXIII

Chapitre 1 Geacuteneacuteraliteacutes concernant C++ 1

1 - La Programmation Orienteacutee Objet 1

11 Probleacutematique de la programmation 1

12 La programmation structureacutee 2

13 Les apports de la Programmation Orienteacutee Objet 2

131 Objet 2

132 Encapsulation 3

133 Classe 3

134 Heacuteritage 3

135 Polymorphisme 4

14 POO et langages 4

2 - C++ C ANSI et POO 5

3 - Les speacutecificiteacutes de C++ 5

4 - C++ et la programmation orienteacutee objet 6

Chapitre 2 Les incompatibiliteacutes entre C++ et C 9

1 - Les deacutefinitions de fonctions en C++ 10

2 - Les prototypes en C++ 10

3 - Arguments et valeur de retour drsquoune fonction 13

31 Points communs agrave C et C++ 13

C++ pour programmeurs CVI

32 Diffeacuterences entre C et C++ 13

321 Fonctions sans arguments 14

322 Fonctions sans valeur de retour 14

4 - Le qualificatif const 14

41 Porteacutee 14

42 Utilisation dans une expression 15

5 - Compatibiliteacute entre le type void et les autres pointeurs 16

Chapitre 3 Les entreacutees-sorties conversationnelles du C++ 17

1 - Geacuteneacuteraliteacutes 17

2 - Affichage agrave lrsquoeacutecran 18

21 Quelques exemples 18

22 Le fichier en-tecircte iostream 20

23 Les possibiliteacutes drsquoeacutecriture sur cout 20

3 - Lecture au clavier 21

31 Introduction 21

32 Les diffeacuterentes possibiliteacutes de lecture sur cin 22

33 Exemple classique drsquoutilisation des seacuteparateurs 23

34 Lecture drsquoune suite de caractegraveres 23

35 Les risques induits par la lecture au clavier 24

351 Manque de synchronisme entre clavier et eacutecran 24

352 Blocage de la lecture 25

353 Boucle infinie sur un caractegravere invalide 25

Chapitre 4 Les speacutecificiteacutes du C++ 27

1 - Le commentaire de fin de ligne 28

2 - Deacuteclarations et initialisations 28

21 Regravegles geacuteneacuterales 28

22 Cas des instructions structureacutees 29

3 - La notion de reacutefeacuterence 30

31 Transmission des arguments en C 30

32 Exemple de transmission drsquoargument par reacutefeacuterence 31

33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argument 33

331 Induction de risques indirects 33

332 Absence de conversion 34

333 Cas drsquoun argument effectif constant 34

334 Cas drsquoun argument muet constant 35

34 Transmission par reacutefeacuterence drsquoune valeur de retour 35

341 Introduction 35

342 On obtient une lvalue 36

343 Conversion 36

344 Valeur de retour et constance 37

Table des matiegraveresVII

35 La reacutefeacuterence dune maniegravere geacuteneacuterale 37

351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument 38

352 Initialisation de reacutefeacuterence 38

4 - Les arguments par deacutefaut 39

41 Exemples 39

42 Les proprieacuteteacutes des arguments par deacutefaut 41

5 - Surdeacutefinition de fonctions 42

51 Mise en œuvre de la surdeacutefinition de fonctions 42

52 Exemples de choix dune fonction surdeacutefinie 43

53 Regravegles de recherche dune fonction surdeacutefinie 46

531 Cas des fonctions agrave un argument 46

532 Cas des fonctions agrave plusieurs arguments 47

533 Le meacutecanisme de la surdeacutefinition de fonctions 47

6 - Les opeacuterateurs new et delete 49

61 Exemples dutilisation de new 49

62 Syntaxe et rocircle de new 50

63 Exemples dutilisation de lopeacuterateur delete 50

64 Syntaxe et rocircle de lopeacuterateur delete 51

65 Lrsquoopeacuterateur new (nothrow) 51

66 Gestion des deacutebordements de meacutemoire avec set_new_handler 52

7 - La speacutecification inline 53

71 Rappels concernant les macros et les fonctions 53

72 Utilisation de fonctions en ligne 54

8 - Les espaces de noms 56

9 - Le type bool 57

10 - Les nouveaux opeacuterateurs de cast 57

Chapitre 5 Classes et objets 61

1 - Les structures en C++ 62

11 Rappel les structures en C 62

12 Deacuteclaration dune structure comportant des fonctions membres 63

13 Deacutefinition des fonctions membres 64

14 Utilisation dune structure comportant des fonctions membres 65

15 Exemple reacutecapitulatif 66

2 - Notion de classe 67

3 - Affectation drsquoobjets 70

4 - Notions de constructeur et de destructeur 72

41 Introduction 72

42 Exemple de classe comportant un constructeur 73

43 Construction et destruction des objets 75

44 Rocircles du constructeur et du destructeur 76

45 Quelques regravegles 79

C++ pour programmeurs CVIII

5 - Les membres donneacutees statiques 80

51 Le qualificatif static pour un membre donneacutee 80

52 Initialisation des membres donneacutees statiques 81

53 Exemple 82

6 - Exploitation drsquoune classe 83

61 La classe comme composant logiciel 83

62 Protection contre les inclusions multiples 85

63 Cas des membres donneacutees statiques 86

64 En cas de modification drsquoune classe 86

641 La deacuteclaration des membres publics nrsquoa pas changeacute 86

642 La deacuteclaration des membres publics a changeacute 87

7 - Les classes en geacuteneacuteral 87

71 Les autres sortes de classes en C++ 87

72 Ce quon peut trouver dans la deacuteclaration dune classe 87

73 Deacuteclaration dune classe 88

Chapitre 6 Les proprieacuteteacutes des fonctions membres 91

1 - Surdeacutefinition des fonctions membres 91

11 Exemple 92

12 Incidence du statut public ou priveacute drsquoune fonction membre 93

2 - Arguments par deacutefaut 94

3 - Les fonctions membres en ligne 95

4 - Cas des objets transmis en argument drsquoune fonction membre 97

5 - Mode de transmission des objets en argument 99

51 Transmission de ladresse dun objet 99

52 Transmission par reacutefeacuterence 101

53 Les problegravemes poseacutes par la transmission par valeur 102

6 - Lorsqursquoune fonction renvoie un objet 102

7 - Autoreacutefeacuterence le mot cleacute this 103

8 - Les fonctions membres statiques 104

9 - Les fonctions membres constantes 106

91 Rappels sur lrsquoutilisation de const en C 106

92 Deacutefinition drsquoune fonction membre constante 107

93 Proprieacuteteacutes drsquoune fonction membre constante 107

10 - Les membres mutables 109

Chapitre 7 Construction destruction et initialisation des objets 111

1 - Les objets automatiques et statiques 112

11 Dureacutee de vie 112

12 Appel des constructeurs et des destructeurs 113

13 Exemple 113

Table des matiegraveresIX

2 - Les objets dynamiques 115

21 Les structures dynamiques 115

22 Les objets dynamiques 116

221 Points communs avec les structures dynamiques 116

222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete 117

223 Exemple 117

3 - Le constructeur de recopie 118

31 Preacutesentation 118

311 Il nexiste pas de constructeur approprieacute 119

312 Il existe un constructeur approprieacute 119

313 Lorsqursquoon souhaite interdire la contruction par recopie 120

32 Exemple 1 objet transmis par valeur 121

321 Emploi du constructeur de recopie par deacutefaut 121

322 Deacutefinition dun constructeur de recopie 123

33 Exemple 2 objet en valeur de retour dune fonction 125

4 - Initialisation dun objet lors de sa deacuteclaration 127

5 - Objets membres 129

51 Introduction 129

52 Mise en œuvre des constructeurs et des destructeurs 129

53 Le constructeur de recopie 132

6 - Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur 132

7 - Les tableaux drsquoobjets 133

71 Notations 133

72 Constructeurs et initialiseurs 134

73 Cas des tableaux dynamiques dobjets 135

8 - Les objets temporaires 136

Chapitre 8 Les fonctions amies 141

1 - Exemple de fonction indeacutependante amie drsquoune classe 142

2 - Les diffeacuterentes situations drsquoamitieacute 144

21 Fonction membre dune classe amie dune autre classe 145

22 Fonction amie de plusieurs classes 146

23 Toutes les fonctions dune classe amies dune autre classe 147

3 - Exemple 147

31 Fonction amie indeacutependante 148

32 Fonction amie membre dune classe 149

4 - Exploitation de classes disposant de fonctions amies 150

Chapitre 9 La surdeacutefinition drsquoopeacuterateurs 151

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs 152

11 Surdeacutefinition dopeacuterateur avec une fonction amie 153

12 Surdeacutefinition dopeacuterateur avec une fonction membre 154

13 Opeacuterateurs et transmission par reacutefeacuterence 156

C++ pour programmeurs CX

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral 157

21 Se limiter aux opeacuterateurs existants 157

22 Se placer dans un contexte de classe 158

23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateur 159

24 Cas des opeacuterateurs ++ et -- 160

25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinie 161

26 Les conversions 162

27 Choix entre fonction membre et fonction amie 163

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur = 163

31 Rappels concernant le constructeur par recopie 163

32 Cas de lrsquoaffectation 164

33 Algorithme proposeacute 165

34 Valeur de retour 167

35 En deacutefinitive 167

36 Exemple de programme complet 167

37 Lorsqursquoon souhaite interdire lrsquoaffectation 169

4 - La forme canonique dune classe 170

5 - Exemple de surdeacutefinition de lopeacuterateur [ ] 171

6 - Surdeacutefinition de lopeacuterateur () 173

7 - Surdeacutefinition des opeacuterateurs new et delete 174

71 Surdeacutefinition de new et delete pour une classe donneacutee 175

72 Exemple 175

73 Drsquoune maniegravere geacuteneacuterale 177

Chapitre 10 Les conversions de type deacutefinies par lrsquoutilisateur 181

1 - Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur 182

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base 184

21 Deacutefinition de lopeacuterateur de cast 184

22 Exemple dutilisation 184

23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonction 185

24 Appel implicite de lopeacuterateur de cast dans leacutevaluation dune expression 187

25 Conversions en chaicircne 188

26 En cas dambiguiumlteacute 190

3 - Le constructeur pour la conversion type de base -gt type classe 191

31 Exemple 191

32 Le constructeur dans une chaicircne de conversions 193

33 Choix entre constructeur ou opeacuterateur daffectation 193

34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur 195

35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit 197

4 - Les conversions drsquoun type classe en un autre type classe 198

41 Exemple simple dopeacuterateur de cast 198

42 Exemple de conversion par un constructeur 199

43 Pour donner une signification agrave un opeacuterateur deacutefini dans une autre classe 200

5 - Quelques conseils 203

Table des matiegraveresXI

Chapitre 11 Les patrons de fonctions 205

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions 206

11 Creacuteation dun patron de fonctions 206

12 Premiegraveres utilisations du patron de fonctions 207

13 Autres utilisations du patron de fonctions 208

131 Application au type char 208

132 Application agrave un type classe 209

14 Contraintes drsquoutilisation drsquoun patron 210

2 - Les paramegravetres de type drsquoun patron de fonctions 211

21 Utilisation des paramegravetres de type dans la deacutefinition dun patron 211

22 Identification des paramegravetres de type dune fonction patron 212

23 Nouvelle syntaxe dinitialisation des variables des types standard 213

24 Limitations des patrons de fonctions 214

3 - Les paramegravetres expressions drsquoun patron de fonctions 215

4 - Surdeacutefinition de patrons 216

41 Exemples ne comportant que des paramegravetres de type 216

42 Exemples comportant des paramegravetres expressions 219

5 - Speacutecialisation de fonctions de patron 220

51 Geacuteneacuteraliteacutes 220

52 Les speacutecialisations partielles 221

6 - Algorithme drsquoinstanciation drsquoune fonction patron 222

Chapitre 12 Les patrons de classes 225

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes 226

11 Creacuteation dun patron de classes 226

12 Utilisation dun patron de classes 228

13 Contraintes drsquoutilisation drsquoun patron de classes 228

14 Exemple reacutecapitulatif 229

2 - Les paramegravetres de type drsquoun patron de classes 231

21 Les paramegravetres de type dans la creacuteation dun patron de classes 231

22 Instanciation dune classe patron 231

3 - Les paramegravetres expressions drsquoun patron de classes 233

31 Exemple 233

32 Les proprieacuteteacutes des paramegravetres expressions 235

4 - Speacutecialisation drsquoun patron de classes 235

41 Exemple de speacutecialisation dune fonction membre 236

42 Les diffeacuterentes possibiliteacutes de speacutecialisation 237

421 On peut speacutecialiser une fonction membre pour tous les paramegravetres 237

422 On peut speacutecialiser une fonction membre ou une classe 237

423 On peut preacutevoir des speacutecialisations partielles de patrons de classes 237

5 - Paramegravetres par deacutefaut 238

6 - Patrons de fonctions membres 238

C++ pour programmeurs CXII

7 - Identiteacute de classes patrons 239

8 - Classes patrons et deacuteclarations drsquoamitieacute 239

81 Deacuteclaration de classes ou fonctions ordinaires amies 239

82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons 240

83 Deacuteclaration drsquoun autre patron de fonctions ou de classes 241

9 - Exemple de classe tableau agrave deux indices 241

Chapitre 13 Lrsquoheacuteritage simple 245

1 - La notion drsquoheacuteritage 246

2 - Utilisation des membres de la classe de base dans une classe deacuteriveacutee 248

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee 250

31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacutee 250

32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacutee 252

33 Redeacutefinition et surdeacutefinition 252

4 - Appel des constructeurs et des destructeurs 254

41 Rappels 254

42 La hieacuterarchisation des appels 255

43 Transmission dinformations entre constructeurs 255

44 Exemple 256

45 Compleacutements 258

5 - Controcircle des accegraves 258

51 Les membres proteacutegeacutes 259

52 Exemple 259

53 Inteacuterecirct du statut proteacutegeacute 260

54 Deacuterivation publique et deacuterivation priveacutee 261

541 Rappels concernant la deacuterivation publique 261

542 Deacuterivation priveacutee 262

55 Les possibiliteacutes de deacuterivation proteacutegeacutee 263

56 Reacutecapitulation 264

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee 264

61 Conversion dun type deacuteriveacute en un type de base 265

62 Conversion de pointeurs 266

63 Limitations lieacutees au typage statique des objets 266

64 Les risques de violation des protections de la classe de base 269

7 - Le constructeur de recopie et lrsquoheacuteritage 270

71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopie 271

72 La classe deacuteriveacutee deacutefinit un constructeur de recopie 271

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage 273

81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur = 273

82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur = 274

9 - Heacuteritage et forme canonique dune classe 277

Table des matiegraveresXIII

10 - Lrsquoheacuteritage et ses limites 278

101 La situation dheacuteritage 278

1011 Le type du reacutesultat de lappel 279

1012 Le type des arguments de f 279

102 Exemples 280

1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point 280

1022 Heacuteritage dans pointcol de la fonction coincide de point 280

11 - Exemple de classe deacuteriveacutee 281

12 - Patrons de classes et heacuteritage 284

121 Classe ordinaire deacuterivant dune classe patron 285

122 Deacuterivation de patrons avec les mecircmes paramegravetres 286

123 Deacuterivation de patrons avec introduction drsquoun nouveau paramegravetre 286

13 - Lrsquoheacuteritage en pratique 287

131 Deacuterivations successives 287

132 Diffeacuterentes utilisations de lrsquoheacuteritage 289

133 Exploitation drsquoune classe deacuteriveacutee 289

Chapitre 14 Lheacuteritage multiple 291

1 - Mise en œuvre de lheacuteritage multiple 292

2 - Pour reacutegler les eacuteventuels conflits les classes virtuelles 296

3 - Appels des constructeurs et des destructeurs cas des classes virtuelles 298

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle 300

Chapitre 15 Les fonctions virtuelles et le polymorphisme 305

1 - Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire 306

2 - Le meacutecanisme des fonctions virtuelles 306

3 - Autre situation ougrave la ligature dynamique est indispensable 308

4 - Les proprieacuteteacutes des fonctions virtuelles 311

41 Leurs limitations sont celles de lrsquoheacuteritage 311

42 La redeacutefinition dune fonction virtuelle nest pas obligatoire 312

43 Fonctions virtuelles et surdeacutefinition 313

44 Le type de retour drsquoune fonction virtuelle redeacutefinie 313

45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe 314

46 Quelques restrictions et conseils 314

461 Seule une fonction membre peut ecirctre virtuelle 314

462 Un constructeur ne peut pas ecirctre virtuel 315

463 Un destructeur peut ecirctre virtuel 315

464 Cas particulier de lrsquoopeacuterateur drsquoaffectation 316

5 - Les fonctions virtuelles pures pour la creacuteation de classes abstraites 317

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene 319

7 - Le meacutecanisme drsquoidentification dynamique des objets 324

C++ pour programmeurs CXIV

8 - Identification de type agrave lexeacutecution 326

81 Utilisation du champ name de type_info 326

82 Utilisation des opeacuterateurs de comparaison de type_info 328

83 Exemple avec des reacutefeacuterences 328

9 - Les cast dynamiques 329

Chapitre 16 Les flots 333

1 - Preacutesentation geacuteneacuterale de la classe ostream 335

11 Lopeacuterateur ltlt 335

12 Les flots preacutedeacutefinis 336

13 La fonction put 337

14 La fonction write 337

141 Cas des caractegraveres 337

142 Autres cas 337

15 Quelques possibiliteacutes de formatage avec ltlt 338

151 Action sur la base de numeacuteration 338

152 Action sur le gabarit de linformation eacutecrite 339

153 Action sur la preacutecision de lrsquoinformation eacutecrite 341

154 Choix entre notation flottante ou exponentielle 341

2 - Preacutesentation geacuteneacuterale de la classe istream 342

21 Lrsquoopeacuterateur gtgt 343

211 Cas des caractegraveres 343

212 Cas des chaicircnes de caractegraveres 344

213 Les types accepteacutes par gtgt 344

22 La fonction get 345

23 Les fonctions getline et gcount 345

24 La fonction read 347

241 Cas des caractegraveres 347

242 Autres cas 347

25 Quelques autres fonctions 347

3 - Statut drsquoerreur drsquoun flot 348

31 Les bits derreur 348

32 Actions concernant les bits derreur 348

321 Accegraves aux bits derreur 349

322 Modification du statut derreur 349

33 Surdeacutefinition des opeacuterateurs () et 349

34 Exemples 350

4 - Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur 352

41 Meacutethode 352

42 Exemple 353

5 - Gestion du formatage 355

51 Le statut de formatage dun flot 356

52 Description du mot deacutetat du statut de formatage 357

Table des matiegraveresXV

53 Action sur le statut de formatage 358

531 Les manipulateurs non parameacutetriques 358

532 Les manipulateurs parameacutetriques 359

533 Les fonctions membres 360

6 - Connexion drsquoun flot agrave un fichier 362

61 Connexion dun flot de sortie agrave un fichier 362

62 Connexion dun flot dentreacutee agrave un fichier 364

63 Les possibiliteacutes daccegraves direct 365

64 Les diffeacuterents modes douverture dun fichier 367

7 - Les anciennes possibiliteacutes de formatage en meacutemoire 368

71 La classe ostrstream 369

72 La classe istrstream 370

Chapitre 17 La gestion des exceptions 373

1 - Premier exemple drsquoexception 374

11 Comment lancer une exception linstruction throw 374

12 Utilisation dun gestionnaire dexception 375

13 Reacutecapitulatif 376

2 - Second exemple 378

3 - Le meacutecanisme de gestion des exceptions 380

31 Poursuite de lexeacutecution du programme 380

32 Prise en compte des sorties de blocs 382

4 - Choix du gestionnaire 382

41 Le gestionnaire reccediloit toujours une copie 383

42 Regravegles de choix drsquoun gestionnaire drsquoexception 383

43 Le cheminement des exceptions 384

44 Redeacuteclenchement drsquoune exception 386

5 - Speacutecification dinterface la fonction unexpected 387

6 - Les exceptions standard 390

61 Geacuteneacuteraliteacutes 390

62 Les exceptions deacuteclencheacutees par la bibliothegraveque standard 390

63 Les exceptions utilisables dans un programme 391

64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exception 391

641 Exemple 1 392

642 Exemple 2 393

Chapitre 18 Geacuteneacuteraliteacutes sur la bibliothegraveque standard 395

1 - Notions de conteneur diteacuterateur et dalgorithme 395

11 Notion de conteneur 396

12 Notion diteacuterateur 396

13 Parcours dun conteneur avec un iteacuterateur 397

131 Parcours direct 397

132 Parcours inverse 398

C++ pour programmeurs CXVI

14 Intervalle diteacuterateur 398

15 Notion dalgorithme 399

16 Iteacuterateurs et pointeurs 400

2 - Les diffeacuterentes sortes de conteneurs 400

21 Conteneurs et structures de donneacutees classiques 400

22 Les diffeacuterentes cateacutegories de conteneurs 401

3 - Les conteneurs dont les eacuteleacutements sont des objets 401

31 Construction copie et affectation 402

32 Autres opeacuterations 403

4 - Efficaciteacute des opeacuterations sur des conteneurs 403

5 - Fonctions preacutedicats et classes fonctions 404

51 Fonction unaire 404

52 Preacutedicats 405

53 Classes et objets fonctions 405

531 Utilisation dobjet fonction comme fonction de rappel 405

532 Classes fonction preacutedeacutefinies 406

6 - Conteneurs algorithmes et relation dordre 407

61 Introduction 407

62 Proprieacuteteacutes agrave respecter 408

7 - Les geacuteneacuterateurs dopeacuterateurs 409

Chapitre 19 Les conteneurs seacutequentiels 411

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque 412

11 Construction 412

111 Construction dun conteneur vide 412

112 Construction avec un nombre donneacute deacuteleacutements 412

113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur 412

114 Construction agrave partir dune seacutequence 413

115 Construction agrave partir dun autre conteneur de mecircme type 413

12 Modifications globales 413

121 Opeacuterateur daffectation 414

122 La fonction membre assign 414

123 La fonction clear 415

124 La fonction swap 415

13 Comparaison de conteneurs 415

131 Lopeacuterateur == 415

132 Lopeacuterateur lt 416

133 Exemples 416

14 Insertion ou suppression deacuteleacutements 416

141 Insertion 417

142 Suppression 417

143 Cas des insertionssuppressions en fin pop_back et push_back 418

Table des matiegraveresXVII

2 - Le conteneur vector 418

21 Accegraves aux eacuteleacutements existants 419

211 Accegraves par iteacuterateur 419

212 Accegraves par indice 419

213 Cas de laccegraves au dernier eacuteleacutement 420

22 Insertions et suppressions 420

23 Gestion de lemplacement meacutemoire 420

231 Introduction 420

232 Invalidation diteacuterateurs ou de reacutefeacuterences 421

233 Outils de gestion de lemplacement meacutemoire dun vecteur 421

24 Exemple 422

25 Cas particulier des vecteurs de booleacuteens 423

3 - Le conteneur deque 424

31 Preacutesentation geacuteneacuterale 424

32 Exemple 425

4 - Le conteneur list 426

41 Accegraves aux eacuteleacutements existants 426

42 Insertions et suppressions 427

421 Suppression des eacuteleacutements de valeur donneacutee 427

422 Suppression des eacuteleacutements reacutepondant agrave une condition 427

43 Opeacuterations globales 428

431 Tri dune liste 428

432 Suppression des eacuteleacutements en double 428

433 Fusion de deux listes 429

434 Transfert dune partie de liste dans une autre 430

44 Gestion de lemplacement meacutemoire 430

45 Exemple 431

5 - Les adaptateurs de conteneur queue stack et priority_queue 432

51 Ladaptateur stack 432

52 Ladaptateur queue 433

53 Ladaptateur priority_queue 434

Chapitre 20 Les conteneurs associatifs 437

1 - Le conteneur map 438

11 Exemple introductif 438

12 Le patron de classes pair 440

13 Construction dun conteneur de type map 440

131 Constructions utilisant la relation dordre par deacutefaut 441

132 Choix de lordre intrinsegraveque du conteneur 441

133 Pour connaicirctre la relation dordre utiliseacutee par un conteneur 442

134 Conseacutequences du choix de lordre dun conteneur 443

14 Accegraves aux eacuteleacutements 443

141 Accegraves par lopeacuterateur [ ] 443

142 Accegraves par iteacuterateur 443

143 Recherche par la fonction membre find 444

C++ pour programmeurs CXVIII

15 Insertions et suppressions 444

151 Insertions 445

152 Suppressions 446

16 Gestion meacutemoire 446

17 Autres possibiliteacutes 447

18 Exemple 447

2 - Le conteneur multimap 448

21 Preacutesentation geacuteneacuterale 448

22 Exemple 449

3 - Le conteneur set 451

31 Preacutesentation geacuteneacuterale 451

32 Exemple 451

33 Le conteneur set et lensemble matheacutematique 452

4 - Le conteneur multiset 452

5 - Conteneurs associatifs et algorithmes 453

Chapitre 21 Les algorithmes standard 455

1 - Notions geacuteneacuterales 455

11 Algorithmes et iteacuterateurs 455

12 Les cateacutegories diteacuterateurs 456

121 Iteacuterateur en entreacutee 456

122 Iteacuterateur en sortie 456

123 Hieacuterarchie des cateacutegories diteacuterateurs 457

13 Algorithmes et seacutequences 457

14 Iteacuterateur dinsertion 458

15 Iteacuterateur de flot 460

151 Iteacuterateur de flot de sortie 460

152 Iteacuterateur de flot dentreacutee 461

2 - Algorithmes dinitialisation de seacutequences existantes 462

21 Copie dune seacutequence dans une autre 462

22 Geacuteneacuteration de valeurs par une fonction 463

3 - Algorithmes de recherche 466

31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire 466

32 Algorithmes de recherche de maximum ou de minimum 467

4 - Algorithmes de transformation dune seacutequence 468

41 Remplacement de valeurs 469

42 Permutations de valeurs 469

421 Rotation 469

422 Geacuteneacuteration de permutations 470

423 Permutations aleacuteatoires 471

43 Partitions 472

5 - Algorithmes dits de suppression 472

6 - Algorithmes de tris 474

Table des matiegraveresXIX

7 - Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees 476

71 Algorithmes de recherche binaire 476

72 Algorithmes de fusion 476

8 - Algorithmes agrave caractegravere numeacuterique 478

9 - Algorithmes agrave caractegravere ensembliste 479

10 - Algorithmes de manipulation de tas 480

Chapitre 22 La classe string 485

1 - Geacuteneacuteraliteacutes 486

2 - Construction 486

3 - Opeacuterations globales 487

4 - Concateacutenation 488

5 - Recherche dans une chaicircne 488

51 Recherche dune chaicircne ou dun caractegravere 489

52 Recherche dun caractegravere preacutesent ou absent dune suite 489

6 - Insertions suppressions et remplacements 490

61 Insertions 490

62 Suppressions 491

63 Remplacements 492

7 - Les possibiliteacutes de formatage en meacutemoire 493

71 La classe ostringstream 494

72 La classe istringstream 495

721 Preacutesentation 495

722 Utilisation pour fiabiliser les lectures au clavier 495

Chapitre 23 Les outils numeacuteriques 499

1 - La classe complex 499

2 - La classe valarray et les classes associeacutees 501

21 Constructeurs des classes valarray 501

22 Lrsquoopeacuterateur [] 502

23 Affectation et changement de taille 502

24 Calcul vectoriel 502

25 Seacutelection de valeurs par masque 504

26 Sections de vecteurs 505

27 Vecteurs drsquoindices 506

3 - La classe bitset 507

Chapitre 24 Les espaces de noms 511

1 - Creacuteation drsquoespaces de noms 511

11 Exemple de creacuteation drsquoun nouvel espace de noms 512

12 Exemple avec deux espaces de noms 513

C++ pour programmeurs CXX

13 Espace de noms et fichier en-tecircte 514

14 Instructions figurant dans un espace de noms 514

15 Creacuteation increacutementale drsquoespaces de noms 515

2 - Les instructions using 516

21 La deacuteclaration using pour les symboles 516

211 Preacutesentation geacuteneacuterale 516

212 Masquage et ambiguiumlteacutes 518

22 La directive using pour les espaces de noms 519

3 - Espaces de noms et surdeacutefinition 521

4 - Imbrication des espaces de noms 523

5 - Transitiviteacute de la directive using 523

6 - Les alias 524

7 - Les espaces anonymes 524

8 - Espaces de noms et deacuteclaration drsquoamitieacute 525

Annexes 527

Annexe A Mise en correspondance drsquoarguments 529

1 - Deacutetermination des fonctions candidates 529

2 - Algorithme de recherche drsquoune fonction agrave un seul argument 530

21 Recherche dune correspondance exacte 530

22 Promotions numeacuteriques 531

23 Conversions standard 531

24 Conversions deacutefinies par lutilisateur 532

25 Fonctions agrave arguments variables 532

26 Exception cas des champs de bits 532

3 - Fonctions agrave plusieurs arguments 533

4 - Fonctions membres 533

Annexe B Utilisation de code eacutecrit en C 535

1 - Prototypes 535

2 - Fonctions sans arguments 535

3 - Fonctions sans valeur de retour 535

4 - Le qualificatif const 536

5 - Les pointeurs de type void 536

6 - Mots cleacutes 536

7 - Les constantes de type caractegravere 537

8 - Les deacutefinitions multiples 537

9 - Linstruction goto 538

10 - Les eacutenumeacuterations 538

Table des matiegraveresXXI

11 - Initialisation de tableaux de caractegraveres 538

12 - Les noms de fonctions 538

Annexe C Compleacutements sur les exceptions 539

1 - Les problegravemes poseacutes par les objets automatiques 539

2 - La technique de gestion de ressources par initialisation 540

3 - Le concept de pointeur intelligent la classe auto_ptr 542

Annexe D Les diffeacuterentes sortes de fonctions en C++ 545

Annexe E Comptage de reacutefeacuterences 547

Annexe F Les pointeurs sur des membres 551

1 - Rappels sur les pointeurs sur des fonctions en C 551

2 - Les pointeurs sur des fonctions membres 552

3 - Les pointeurs sur des membres donneacutees 553

4 - Lrsquoheacuteritage et les pointeurs sur des membres 554

Annexe G Les algorithmes standard 557

1 - Algorithmes dinitialisation de seacutequences existantes 558

2 - Algorithmes de recherche 559

3 - Algorithmes de transformation dune seacutequence 561

4 - Algorithmes de suppression 564

5 - Algorithmes de tri 566

6 - Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees 568

7 - Algorithmes agrave caractegravere numeacuterique 570

8 - Algorithmes agrave caractegravere ensembliste 571

9 - Algorithmes de manipulation de tas 574

10 - Algorithmes divers 575

Correction des exercices 577

Index 593

Avant-propos

1 Historique de C++La programmation orienteacutee objet (en abreacutegeacute POO) est doreacutenavant universellement recon-

nue pour les avantages qursquoelle procure Notamment elle ameacuteliore largement la productiviteacute

des deacuteveloppeurs la robustesse la portabiliteacute et lrsquoextensibiliteacute de leurs programmes Enfin et

surtout elle permet de deacutevelopper des composants logiciels entiegraverement reacuteutilisables

Un certain nombre de langages dits langages orienteacutes objet (LOO) ont eacuteteacute deacutefinis de tou-

tes piegraveces pour appliquer les concepts de POO Crsquoest ainsi que sont apparus dans un premier

temps des langages comme Smalltalk Simula ou Eiffel puis plus reacutecemment Java Le lan-

gage C++ quant agrave lui a eacuteteacute conccedilu suivant une deacutemarche quelque peu diffeacuterente par B

Stroustrup (ATampT) son objectif a eacuteteacute en effet dadjoindre au langage C un certain nombre

de speacutecificiteacutes lui permettant dappliquer les concepts de POO Ainsi C++ preacutesente-t-il sur

un vrai LOO loriginaliteacute decirctre fondeacute sur un langage reacutepandu Ceci laisse au programmeur

toute liberteacute dadopter un style plus ou moins orienteacute objet en se situant entre les deux extrecirc-

mes que constituent la poursuite dune programmation classique dune part une pure POO

dautre part Si une telle liberteacute preacutesente le risque de ceacuteder dans un premier temps agrave la faci-

liteacute en meacutelangeant les genres (la POO ne renie pas la programmation classique - elle lenri-

chit) elle permet eacutegalement une transition en douceur vers la POO pure avec tout le

beacuteneacutefice quon peut en escompter agrave terme

De sa conception jusquagrave sa normalisation le langage C++ a quelque peu eacutevolueacute Initiale-

ment un certain nombre de publications de ATampT ont servi de reacutefeacuterence du langage Les der-

niegraveres en date sont la version 20 en 1989 les versions 21 et 3 en 1991 Crsquoest cette derniegravere

qui a servi de base au travail du comiteacute ANSI lequel sans la remettre en cause la enrichie de

Avant-proposAVANT-PROPOS

XXIV

quelques extensions et surtout de composants standard originaux se preacutesentant sous forme de

fonctions et de classes geacuteneacuteriques qursquoon deacutesigne souvent par le sigle STL1 La norme deacutefini-

tive de C++ a eacuteteacute publieacutee par lANSI et par lISO en 1998 et a fait lobjet dune reacutevision

publieacutee en 2003 sous la reacutefeacuterence ISO 148822003

2 Objectifs et structure de lrsquoouvrageCet ouvrage a eacuteteacute speacutecifiquement conccedilu pour tous ceux qui posseacutedant deacutejagrave une pratique du

langage C2 souhaitent maicirctriser la programmation orienteacutee objet en C++ Il srsquoadresse agrave la

fois aux eacutetudiants aux deacuteveloppeurs et aux enseignants en informatique

Conccedilu sous forme drsquoun cours complet il expose progressivement agrave la fois

bull les diffeacuterentes notions fondamentales de la POO et la faccedilon dont elles srsquoexpriment en C++

(classes et objets meacutethodes constructeur destructeur heacuteritage polymorphisme)

bull les speacutecificiteacutes non orienteacutees objet du langage C++ crsquoest-agrave-dire celles qui permettent agrave

C++ drsquoecirctre un C ameacutelioreacute (reacutefeacuterence argument par deacutefaut surdeacutefinition de fonctions fonc-

tions en ligne espaces de noms)

bull les speacutecificiteacutes orienteacutees objet du C++ fonctions amies surdeacutefinition drsquoopeacuterateurs patrons

de classes et de fonctions heacuteritage multiple flots bibliothegraveque standard

Chacune de ces notions est illustreacutee systeacutematiquement par un programme complet assorti

dun exemple dexeacutecution montrant comment la mettre en œuvre dans un contexte reacuteel Celui-

ci peut eacutegalement servir agrave une prise de connaissance intuitive ou agrave une reacutevision rapide de la

notion en question agrave une expeacuterimentation directe dans votre propre environnement de travail

ou encore de point de deacutepart agrave une expeacuterimentation personnelle

Les chapitres les plus importants ont eacuteteacute doteacutes dexercices3 comportant

bull des suggestions de manipulations destineacutees agrave mieux vous familiariser avec votre

environnement par effet dentraicircnement elles vous feront probablement imaginer dautres

expeacuterimentations de votre cru

bull des programmes agrave reacutediger dans ce cas un exemple de correction est fourni en fin de volu-

me

Lrsquoaspect didactique a eacuteteacute privileacutegieacute sans pour autant nuire agrave lrsquoexhaustiviteacute de lrsquoouvrage

Nous couvrons lrsquoensemble de la programmation en C++ des notions fondamentales de la

POO jusqursquoaux aspects tregraves speacutecifiques au langage (mais neacuteanmoins fondamentaux) afin

1 Standard Template Library

2 Le cas eacutecheacuteant on pourra trouver un cours complet de langage C dans Programmer en langage C ou une reacutefeacuterence

exhaustive de sa norme dans Langage C du mecircme auteur chez le mecircme eacutediteur

3 De nombreux autres exercices peuvent ecirctre trouveacutes dans Exercices en langage C++ du mecircme auteur chez le mecircme

eacutediteur

3 - Lrsquoouvrage la norme de C++ C et JavaXXV

de rendre le lecteur parfaitement opeacuterationnel dans la conception le deacuteveloppement et la

mise au point de ses propres classes Crsquoest ainsi que nous avons soigneusement eacutetudieacute les

conseacutequences de la liberteacute qursquooffre C++ de choisir le mode de gestion de la meacutemoire alloueacutee

aux objets (automatique ou dynamique)1 De mecircme nous avons largement insisteacute sur le rocircle

du constructeur de recopie ainsi que sur la redeacutefinition de lopeacuterateur daffectation eacuteleacutements

qui conduisent agrave la notion de classe canonique Toujours dans le mecircme esprit nous avons

pris soin de bien deacutevelopper les notions indispensables que sont la ligature dynamique et les

classes abstraites lesquelles deacutebouchent sur la notion la plus puissante du langage quest le

polymorphisme De mecircme la STL a eacuteteacute eacutetudieacutee en deacutetail apregraves avoir pris soin drsquoexposer

preacutealablement drsquoune part les notions de classes et de fonctions geacuteneacuteriques drsquoautre part celles

de conteneur diteacuterateur et dalgorithmes qui conditionnent la bonne utilisation de la plupart

de ses composants

3 Lrsquoouvrage la norme de C++ C et JavaCet ouvrage est entiegraverement fondeacute sur la norme ANSIISO du langage C++ Degraves le deacutebut le

lecteur est sensibiliseacute aux quelques incompatibiliteacutes existant entre C++ et C de sorte qursquoil

pourra reacuteutiliser convenablement en C++ du code eacutecrit en C Drsquoautre part compte tenu de la

populariteacute du langage Java nous avons introduit de nombreuses remarques titreacutees En Java

Elles mettent lrsquoaccent sur les diffeacuterences majeures existant entre Java et C++ Elles seront

utiles au lecteur qui apregraves la maicirctrise du C++ souhaitera aborder lrsquoeacutetude de Java

Cet ouvrage correspond en fait agrave une refonte des eacuteditions preacuteceacutedentes de Programmer en

C++ Nous continuons drsquoy mentionner les apports de la norme par rapport agrave la version 3 du

langage publieacutee en 1991 ainsi que les quelques diffeacuterences avec les versions anteacuterieures

Ces remarques initialement preacutevues pour faciliter lrsquoutilisation drsquoanciens environnements de

programmation deviennent de moins en moins pertinentes mais dans la mesure ougrave elles ne

pertubent pas lrsquoapprentissage du langage nous avons preacutefeacutereacute les conserver pour leur carac-

tegravere historique en particulier elles mettent en avant les points deacutelicats du langage pour les-

quels la genegravese a eacuteteacute quelque peu difficile

1 Certains langages objet dont Java gegraverent tous les objets de maniegravere dynamique

1

Geacuteneacuteraliteacutes concernant C++

Le langage C++ a eacuteteacute conccedilu agrave partir de 1982 par Bjarne Stroustrup (ATampT Bell Laboratories)

avec un objectif preacutecis ajouter au langage C des classes analogues agrave celles du langage

Simula Il srsquoagissait donc de greffer sur un langage classique des possibiliteacutes de Program-

mation Orienteacutee Objet Avant de vous preacutesenter le reacutesultat auquel a abouti B Stroustrup

commenccedilons par examiner succinctement ce qursquoest la Programmation Orienteacutee Objet

1 La Programmation Orienteacutee Objet

11 Probleacutematique de la programmationJusqursquoagrave maintenant lrsquoactiviteacute de programmation a toujours susciteacute des reacuteactions diverses

allant jusqursquoagrave la contradiction totale Pour certains en effet il ne srsquoagit que drsquoun jeu de cons-

truction enfantin dans lequel il suffit drsquoenchaicircner des instructions eacuteleacutementaires (en nombre

restreint) pour parvenir agrave reacutesoudre nrsquoimporte quel problegraveme ou presque Pour drsquoautres au

contraire il srsquoagit de produire (au sens industriel du terme) des logiciels avec des exigences

de qualiteacute qursquoon tente de mesurer suivant certains critegraveres notamment

bull lrsquoexactitude aptitude drsquoun logiciel agrave fournir les reacutesultats voulus dans des conditions nor-

males drsquoutilisation (par exemple donneacutees correspondant aux speacutecifications)

bull la robustesse aptitude agrave bien reacuteagir lorsque lrsquoon srsquoeacutecarte des conditions normales

drsquoutilisation

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

2

bull lrsquoextensibiliteacute faciliteacute avec laquelle un programme pourra ecirctre adapteacute pour satisfaire agrave une

eacutevolution des speacutecifications

bull la reacuteutilisabiliteacute possibiliteacute drsquoutiliser certaines parties (modules) du logiciel pour reacutesoudre

un autre problegraveme

bull la portabiliteacute faciliteacute avec laquelle on peut exploiter un mecircme logiciel dans diffeacuterentes

impleacutementations

bull lrsquoefficience temps drsquoexeacutecution taille meacutemoire

La contradiction nrsquoest souvent qursquoapparente et essentiellement lieacutee agrave lrsquoimportance des projets

concerneacutes Par exemple il est facile drsquoeacutecrire un programme exact et robuste lorsqursquoil com-

porte une centaine drsquoinstructions il en va tout autrement lorsqursquoil srsquoagit drsquoun projet de dix

hommes-anneacutees De mecircme les aspects extensibiliteacute et reacuteutilisabiliteacute nrsquoauront guegravere

drsquoimportance dans le premier cas alors qursquoils seront probablement cruciaux dans le second

ne serait-ce que pour des raisons eacuteconomiques

12 La programmation structureacuteeLa programmation structureacutee a manifestement fait progresser la qualiteacute de la production des

logiciels Mais avec le recul il faut bien reconnaicirctre que ses propres fondements lui impo-

saient des limitations naturelles En effet la programmation structureacutee reposait sur ce que

lrsquoon nomme souvent lrsquoeacutequation de Wirth agrave savoir

Algorithmes + Structures de donneacutees = Programmes

Bien sucircr elle a permis de structurer les programmes et partant drsquoen ameacuteliorer lrsquoexactitude et

la robustesse On avait espeacutereacute qursquoelle permettrait eacutegalement drsquoen ameacuteliorer lrsquoextensibiliteacute et

la reacuteutilisabiliteacute Or en pratique on srsquoest aperccedilu que lrsquoadaptation ou la reacuteutilisation drsquoun logi-

ciel conduisait souvent agrave casser le module inteacuteressant et ceci parce qursquoil eacutetait neacutecessaire de

remettre en cause une structure de donneacutees Preacuteciseacutement ce type de difficulteacutes eacutemane direc-

tement de lrsquoeacutequation de Wirth qui deacutecouple totalement les donneacutees des proceacutedures agissant

sur ces donneacutees

13 Les apports de la Programmation Orienteacutee Objet

131 ObjetCrsquoest lagrave qursquointervient la Programmation Orienteacutee Objet (en abreacutegeacute POO) fondeacutee justement

sur le concept drsquoobjet agrave savoir une association des donneacutees et des proceacutedures (qursquoon appelle

alors meacutethodes) agissant sur ces donneacutees Par analogie avec lrsquoeacutequation de Wirth on pourrait

dire que lrsquoeacutequation de la POO est

Meacutethodes + Donneacutees = Objet

1 - La Programmation Orienteacutee Objet3

132 Encapsulation

Mais cette association est plus qursquoune simple juxtaposition En effet dans ce que lrsquoon pour-

rait qualifier de POO pure1 on reacutealise ce que lrsquoon nomme une encapsulation des don-

neacutees Cela signifie qursquoil nrsquoest pas possible drsquoagir directement sur les donneacutees drsquoun objet il

est neacutecessaire de passer par lrsquointermeacutediaire de ses meacutethodes qui jouent ainsi le rocircle drsquointer-

face obligatoire On traduit parfois cela en disant que lrsquoappel drsquoune meacutethode est en fait

lrsquoenvoi drsquoun message agrave lrsquoobjet

Le grand meacuterite de lrsquoencapsulation est que vu de lrsquoexteacuterieur un objet se caracteacuterise unique-

ment par les speacutecifications2 de ses meacutethodes la maniegravere dont sont reacuteellement implanteacutees les

donneacutees eacutetant sans importance On deacutecrit souvent une telle situation en disant qursquoelle reacutealise

une abstraction des donneacutees (ce qui exprime bien que les deacutetails concrets drsquoimpleacutementation

sont cacheacutes) A ce propos on peut remarquer qursquoen programmation structureacutee une proceacutedure

pouvait eacutegalement ecirctre caracteacuteriseacutee (de lrsquoexteacuterieur) par ses speacutecifications mais que faute

drsquoencapsulation lrsquoabstraction des donneacutees nrsquoeacutetait pas reacutealiseacutee

Lrsquoencapsulation des donneacutees preacutesente un inteacuterecirct manifeste en matiegravere de qualiteacute de logiciel

Elle facilite consideacuterablement la maintenance une modification eacuteventuelle de la structure

des donneacutees drsquoun objet nrsquoa drsquoincidence que sur lrsquoobjet lui-mecircme les utilisateurs de lrsquoobjet

ne seront pas concerneacutes par la teneur de cette modification (ce qui nrsquoeacutetait bien sucircr pas le cas

avec la programmation structureacutee) De la mecircme maniegravere lrsquoencapsulation des donneacutees facilite

grandement la reacuteutilisation drsquoun objet

133 Classe

En POO apparaicirct geacuteneacuteralement le concept de classe3 qui correspond simplement agrave la geacuteneacute-

ralisation de la notion de type que lrsquoon rencontre dans les langages classiques En effet une

classe nrsquoest rien drsquoautre que la description drsquoun ensemble drsquoobjets ayant une structure de

donneacutees commune4 et disposant des mecircmes meacutethodes Les objets apparaissent alors comme

des variables drsquoun tel type classe (en POO on dit aussi qursquoun objet est une instance de sa

classe)

134 Heacuteritage

Un autre concept important en POO est celui drsquoheacuteritage Il permet de deacutefinir une nouvelle

classe agrave partir drsquoune classe existante (qursquoon reacuteutilise en bloc ) agrave laquelle on ajoute de nou-

1 Nous verrons en effet que les concepts de la POO peuvent ecirctre appliqueacutes drsquoune maniegravere plus ou moins rigou-

reuse En particulier en C++ lrsquoencapsulation ne sera pas obligatoire ce qui ne veut pas dire qursquoelle ne soit pas sou-

haitable

2 Noms arguments et rocircles

3 Dans certains langages (Turbo Pascal par exemple) le mot classe est remplaceacute par objet et le mot objet par varia-

ble

4 Bien entendu seule la structure est commune les donneacutees eacutetant propres agrave chaque objet En revanche les meacutetho-

des sont effectivement communes agrave lrsquoensemble des objets drsquoune mecircme classe

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

4

velles donneacutees et de nouvelles meacutethodes La conception de la nouvelle classe dite qui

heacuterite des proprieacuteteacutes et des aptitudes de lrsquoancienne peut ainsi srsquoappuyer sur des reacutealisations

anteacuterieures parfaitement au point et les speacutecialiser agrave volonteacute Comme on peut srsquoen douter

lrsquoheacuteritage facilite largement la reacuteutilisation de produits existants drsquoautant plus qursquoil peut ecirctre

reacuteiteacutereacute autant de fois que neacutecessaire (la classe C peut heacuteriter de B qui elle-mecircme heacuterite

de A)1

135 Polymorphisme

Geacuteneacuteralement en POO une classe deacuteriveacutee peut redeacutefinir (crsquoest-agrave-dire modifier) certaines

des meacutethodes heacuteriteacutees de sa classe de base Cette possibiliteacute est la cleacute de ce que lrsquoon nomme

le polymorphisme crsquoest-agrave-dire la possibiliteacute de traiter de la mecircme maniegravere des objets de

types diffeacuterents pour peu qursquoils soient tous de classes deacuteriveacutees de la mecircme classe de base

Plus preacuteciseacutement on utilise chaque objet comme srsquoil eacutetait de cette classe de base mais son

comportement effectif deacutepend de sa classe effective (deacuteriveacutee de cette classe de base) en par-

ticulier de la maniegravere dont ses propres meacutethodes ont eacuteteacute redeacutefinies Le polymorphisme ameacute-

liore lrsquoextensibiliteacute des programmes en permettant drsquoajouter de nouveaux objets dans un

sceacutenario preacuteeacutetabli et eacuteventuellement eacutecrit avant drsquoavoir connaissance du type effectif de ces

objets

14 POO et langagesNous venons drsquoeacutenoncer les grands principes de la POO sans nous attacher agrave un langage par-

ticulier

Or manifestement certains langages peuvent ecirctre conccedilus (de toutes piegraveces) pour appliquer agrave

la lettre ces principes et reacutealiser ce que nous nommons de la POO pure Crsquoest par exem-

ple le cas de Simula Smalltalk ou plus reacutecemment Eiffel ou Java Le mecircme pheacutenomegravene a eu

lieu en son temps pour la programmation structureacutee avec Pascal

A lrsquoopposeacute on peut toujours tenter drsquoappliquer avec plus ou moins de bonheur ce que nous

aurions tendance agrave nommer une philosophie POO agrave un langage classique (Pascal C)

On retrouve lagrave une ideacutee comparable agrave celle qui consistait agrave appliquer les principes de la pro-

grammation structureacutee agrave des langages comme Fortran ou Basic

Le langage C++ se situe agrave mi-chemin entre ces deux points de vue Il a en effet eacuteteacute obtenu en

ajoutant agrave un langage classique (C) les outils permettant de mettre en œuvre tous les princi-

pes de la POO Programmer en C++ va donc plus loin qursquoadopter une philosophie POO en

C mais moins loin que de faire de la POO pure avec Eiffel

La solution adopteacutee par B Stroustrup a le meacuterite de preacuteserver lrsquoexistant (compatibiliteacute avec

C++ de programmes deacutejagrave eacutecrits en C) elle permet eacutegalement une transition en douceur de

la programmation structureacutee vers la POO En revanche elle nrsquoimpose nullement lrsquoapplica-

1 En C++ les techniques de meacutethodes virtuelles eacutelargissent encore plus la porteacutee de lrsquoheacuteritage mais il nrsquoest pas

possible pour lrsquoinstant drsquoen faire percevoir lrsquointeacuterecirct

2 - C++ C ANSI et POO5

tion stricte des principes de POO Comme vous le verrez en C++ rien ne vous empecircchera

(sauf votre bon sens ) de faire cohabiter des objets (dignes de ce nom parce que reacutealisant

une parfaite encapsulation de leurs donneacutees) avec des fonctions classiques reacutealisant des effets

de bord sur des variables globales

2 C++ C ANSI et POOPreacuteceacutedemment nous avons dit drsquoune faccedilon quelque peu simpliste que C++ se preacutesentait

comme un sur-ensemble du langage C offrant des possibiliteacutes de POO Il nous faut main-

tenant nuancer cette affirmation car il existe quelques incompatibiliteacutes entre le C et le C++

tels qursquoils sont deacutefinis par leurs normes respectives Celles-ci comme nous le verrons sont

neacuteanmoins mineures elles sont pour la plupart dues agrave la diffeacuterence drsquoesprit des deux langa-

ges ainsi qursquoagrave la toleacuterance dont a fait preuve la norme ANSI du C en cherchant agrave preacuteserver

lrsquoexistant (certaines toleacuterances ont disparu en C++)

Drsquoautre part les extensions du C++ par rapport au C ANSI ne sont pas toutes veacuteritablement

lieacutees agrave la POO Certaines pourraient en effet ecirctre ajouteacutees avec profit au langage C sans

qursquoil devienne pour autant orienteacute objet1

En fait nous pourrions caracteacuteriser C++ par cette formule

C++ = C + E + S + P

bull C deacutesigne le C norme ANSI

bull E repreacutesente les eacutecarts de C++ par rapport agrave la norme ANSI de C

bull S repreacutesente les speacutecificiteacutes de C++ qui ne sont pas veacuteritablement axeacutees sur la POO

bull P repreacutesente les possibiliteacutes de POO

Les principaux eacutecarts par rapport agrave la norme sont deacutecrits au chapitre 2 ils sont accompa-

gneacutes de rappels concernant la norme C ANSI Ils concernent essentiellement

bull les deacutefinitions de fonctions en-tecirctes prototypes arguments et valeur de retour

bull la porteacutee du qualificatif const

bull les compatibiliteacutes entre pointeurs

3 Les speacutecificiteacutes de C++Comme nous lrsquoavons dit C++ preacutesente par rapport au C ANSI des extensions qui ne sont

pas veacuteritablement orienteacutees POO Elles seront deacutecrites au chapitre 4 En voici un bref

reacutesumeacute

1 Drsquoailleurs certaines extensions de C++ par rapport agrave la premiegravere deacutefinition du C ont eacuteteacute introduites dans le C

ANSI (prototypes fonctions agrave arguments variables)

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

6

bull nouvelle forme de commentaire (en fin de ligne)

bull plus grande liberteacute dans lrsquoemplacement des deacuteclarations

bull notion de reacutefeacuterence facilitant la mise en œuvre de la transmission drsquoarguments par adresse

bull surdeacutefinition des fonctions attribution drsquoun mecircme nom agrave diffeacuterentes fonctions la recon-

naissance de la fonction reacuteellement appeleacutee se faisant drsquoapregraves le type et le nombre des argu-

ments figurant dans lrsquoappel (on parle parfois de signature)

bull nouveaux opeacuterateurs de gestion dynamique de la meacutemoire new et delete

bull possibiliteacute de deacutefinir des fonctions en ligne (inline) ce qui accroicirct la vitesse drsquoexeacutecution

sans perdre pour autant le formalisme des fonctions

4 C++ et la programmation orienteacutee objetLes possibiliteacutes de POO repreacutesentent bien sucircr lrsquoessentiel de lrsquoapport de C++

C++ dispose de la notion de classe (geacuteneacuteralisation de la notion de type deacutefini par lrsquoutilisa-

teur) Une classe comportera

bull la description drsquoune structure de donneacutees

bull des meacutethodes

Sur le plan du vocabulaire C++ utilise des termes qui lui sont propres On parle en effet de

bull membres donneacutees pour deacutesigner les diffeacuterents membres de la structure de donneacutees asso-

cieacutee agrave une classe

bull fonctions membres pour deacutesigner les meacutethodes

A partir drsquoune classe on pourra instancier des objets (nous dirons geacuteneacuteralement creacuteer des

objets)

bull soit par des deacuteclarations usuelles (de type classe)

bull soit par allocation dynamique en faisant appel au nouvel opeacuterateur new

C++ permet lrsquoencapsulation des donneacutees mais il ne lrsquoimpose pas On peut le regretter mais il

ne faut pas perdre de vue que par sa conception mecircme (extension de C) le C++ ne peut pas

ecirctre un langage de POO pure Bien entendu il reste toujours possible au concepteur de faire

preuve de rigueur en srsquoastreignant agrave certaines regravegles telles que lrsquoencapsulation absolue

Comme la plupart des langages objets C++ permet de deacutefinir ce que lrsquoon nomme des cons-

tructeurs de classe Un constructeur est une fonction membre particuliegravere qui est exeacutecuteacutee au

moment de la creacuteation drsquoun objet de la classe Le constructeur peut notamment prendre en

charge lrsquoinitialisation drsquoun objet au sens le plus large du terme crsquoest-agrave-dire sa mise dans un

eacutetat initial permettant son bon fonctionnement ulteacuterieur il peut srsquoagir de banales initialisa-

tions de membres donneacutees mais eacutegalement drsquoune preacuteparation plus eacutelaboreacutee correspondant au

deacuteroulement drsquoinstructions voire drsquoune allocation dynamique drsquoemplacements neacutecessaires agrave

4 - C++ et la programmation orienteacutee objet7

lrsquoutilisation de lrsquoobjet Lrsquoexistence drsquoun constructeur garantit que lrsquoobjet sera toujours initia-

liseacute ce qui constitue manifestement une seacutecuriteacute

De maniegravere similaire une classe peut disposer drsquoun destructeur fonction membre exeacutecuteacutee

au moment de la destruction drsquoun objet Celle-ci preacutesentera surtout un inteacuterecirct dans le cas

drsquoobjets effectuant des allocations dynamiques drsquoemplacements ces derniers pourront ecirctre

libeacutereacutes par le destructeur

Une des originaliteacutes de C++ par rapport agrave drsquoautres langages de POO reacuteside dans la possibi-

liteacute de deacutefinir des fonctions amies drsquoune classe Il srsquoagit de fonctions usuelles (qui ne sont

donc pas des fonctions membres drsquoune classe) qui sont autoriseacutees (par une classe) agrave acceacuteder

aux donneacutees (encapsuleacutees) de la classe Certes le principe drsquoencapsulation est violeacute mais

uniquement par des fonctions ducircment autoriseacutees agrave le faire

La classe est un type deacutefini par lrsquoutilisateur La notion de surdeacutefinition drsquoopeacuterateurs va per-

mettre de doter cette classe drsquoopeacuterations analogues agrave celles que lrsquoon rencontre pour les types

preacutedeacutefinis Par exemple on pourra deacutefinir une classe complexe (destineacutee agrave repreacutesenter des

nombres complexes) et la munir des opeacuterations drsquoaddition de soustraction de multiplication

et de division Qui plus est ces opeacuterations pourront utiliser les symboles existants + -

C dispose de possibiliteacutes de conversions explicites ou implicites C++ permet de les eacutelargir

aux types deacutefinis par lrsquoutilisateur que sont les classes Par exemple on pourra donner un sens

agrave la conversion int -gt complexe ou agrave la conversion complexe -gt float (complexe eacutetant une

classe)

Naturellement C++ dispose de lrsquoheacuteritage et mecircme de possibiliteacutes dites drsquoheacuteritage multiple

permettant agrave une classe drsquoheacuteriter simultaneacutement de plusieurs autres Le polymorphisme est

mis en place sur la demande explicite du programmeur par le biais de ce que lrsquoon nomme

(curieusement) des fonctions virtuelles (en Java le polymorphisme est natif et le program-

meur nrsquoa donc pas agrave srsquoen preacuteoccuper)

En matiegravere drsquoentreacutees-sorties C++ comporte de nouvelles possibiliteacutes fondeacutees sur la notion de

flot Leurs avantages sur les entreacutees-sorties de C sont en particulier

bull la simpliciteacute drsquoutilisation

bull une taille meacutemoire reacuteduite (on nrsquointroduit que ce qui est utile)

bull la possibiliteacute de leur donner un sens pour les types deacutefinis par lrsquoutilisateur que sont les clas-

ses (gracircce au meacutecanisme de surdeacutefinition drsquoopeacuterateur)

Bien qursquoelles soient lieacutees agrave lrsquoaspect POO nous ferons une premiegravere preacutesentation de ces

nouvelles possibiliteacutes drsquoentreacutees-sorties degraves le chapitre 3 Cela nous permettra de reacutealiser rapi-

dement des programmes dans lrsquoesprit du C++

Dans ses derniegraveres versions (et a fortiori dans sa norme ANSI) le C++ a eacuteteacute doteacute de la notion

de patron Un patron permet de deacutefinir des modegraveles utilisables pour geacuteneacuterer diffeacuterentes clas-

ses ou diffeacuterentes fonctions qualifieacutees parfois de geacuteneacuteriques mecircme si cette geacuteneacutericiteacute nrsquoest

pas totalement inteacutegreacutee dans le langage lui-mecircme comme crsquoest par exemple le cas avec

ADA

Geacuteneacuteraliteacutes concernant C++CHAPITRE 1

8

Enfin la norme ANSI a notablement accru le contenu de la bibliothegraveque standard de C++

qui vient compleacuteter celle du C toujours disponible En particulier on y trouve de nombreux

patrons de classes et de fonctions permettant de mettre en œuvre les structures de donneacutees les

plus importantes (vecteurs dynamiques listes chaicircneacutees chaicircnes) et les algorithmes les plus

usuels eacutevitant ainsi drsquoavoir agrave reacuteinventer la roue agrave la moindre occasion

2

Les incompatibiliteacutesentre C++ et C

A priori le langage C++ peut ecirctre consideacutereacute comme une extension du langage C Tout pro-

gramme eacutecrit en C devrait donc pouvoir ecirctre traduit correctement par un compilateur C++ et

son exeacutecution devrait alors fournir les mecircmes reacutesultats que ceux obtenus en utilisant un com-

pilateur C

Si ce point de vue correspond effectivement au souhait du concepteur du langage C++ en

pratique un certain nombre drsquoincompatibiliteacutes avec le C ANSI ont subsisteacute inheacuterentes agrave

lrsquoesprit dans lequel les deux langages ont eacuteteacute conccedilus

Nous allons deacutecrire ici les incompatibiliteacutes les plus importantes en particulier celles qui se

reacuteveacuteleraient quasiment agrave coup sucircr dans la mise au point de vos premiers programmes C++

Par ailleurs quelques autres incompatibiliteacutes mineures seront abordeacutees au cours des pro-

chains chapitres Elles seront toutes reacutecapituleacutees en Annexe B

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

10

1 Les deacutefinitions de fonctions en C++Suivant la norme ANSI il existe en C deux faccedilons de deacutefinir1 une fonction Supposez que

nous ayons agrave deacutefinir une fonction nommeacutee fexple fournissant une valeur de retour2 de type

double et recevant deux arguments lrsquoun de type int lrsquoautre de type double Nous pouvons

pour cela proceacuteder de lrsquoune des deux faccedilons suivantes

double fexple (u v) double fexple (int u double v)int u double v corps de la fonction corps de la fonction

La premiegravere forme eacutetait la seule preacutevue par la deacutefinition initiale de Kernighan et Ritchie La

seconde a eacuteteacute introduite par la norme ANSI qui nrsquoa toutefois pas exclu lrsquoancienne3

Le langage C++ nrsquoaccepte quant agrave lui que la seconde forme

double fexple (int u double v) corps de la fonction

Remarque

Comme en C ANSI lorsqursquoune fonction fournit une valeur de type int le mot int peut

ecirctre omis dans lrsquoen-tecircte Cependant nous ne vous conseillons guegravere drsquoemployer cette

possibiliteacute qui nuit agrave la lisibiliteacute des programmes

2 Les prototypes en C++Nous venons de voir que le C++ eacutetait plus restrictif que le C ANSI en matiegravere de deacutefinition

de fonctions Il en va de mecircme pour les deacuteclarations de fonctions En C ANSI lorsque vous

utilisiez une fonction qui nrsquoavait pas eacuteteacute deacutefinie auparavant dans le mecircme fichier source

vous pouviez

bull ne pas la deacuteclarer (on consideacuterait alors que sa valeur de retour eacutetait de type int)

bull la deacuteclarer en ne preacutecisant que le type de la valeur de retour par exemple

double fexple

1 Ne confondez pas la deacutefinition drsquoune fonction et sa deacuteclaration La premiegravere correspond agrave la description agrave

lrsquoaide drsquoinstructions C de ce que fait une fonction La seconde correspond agrave une simple information (nom de la

fonction et eacuteventuellement type des arguments et de la valeur de retour) fournie au compilateur

2 On parle eacutegalement de reacutesultat fourni par la fonction de valeur retourneacutee

3 Dans le seul but de rendre compatible avec la norme des anciens programmes ou des anciens compilateurs

2 - Les prototypes en C++11

bull la deacuteclarer agrave lrsquoaide de ce que lrsquoon nomme un prototype par exemple

double fexple (int double)

En C++ un appel de fonction ne sera accepteacute que si le compilateur connaicirct le type des argu-

ments et celui de sa valeur de retour Cela signifie que la fonction en question doit avoir fait

lrsquoobjet drsquoune deacuteclaration sous la forme drsquoun prototype (ou agrave la rigueur avoir eacuteteacute preacuteala-

blement deacutefinie dans le mecircme fichier source1)

Nrsquooubliez pas que chaque fois que le compilateur rencontre un appel de fonction il compare

les types des arguments effectifs avec ceux des arguments muets correspondants2 En cas de

diffeacuterence il met en place les conversions neacutecessaires pour que la fonction reccediloive des argu-

ments du bon type Les conversions possibles ne se limitent pas aux conversions non deacutegra-

dantes (telles que char -gt double int -gt long) En effet elles comportent toutes les

conversions autoriseacutees lors drsquoune affectation On peut donc y rencontrer des conversions

deacutegradantes telles que int -gt char double -gt float double -gt int

Voici un exemple illustrant ce point

double fexple (int double) deacuteclaration 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

Exemple de conversions de types lors de lrsquoappel drsquoune fonction

Lorsque la deacutefinition de la fonction et sa deacuteclaration (sous forme drsquoun prototype) figurent

dans le mecircme fichier source le compilateur est en mesure de veacuterifier la coheacuterence entre lrsquoen-

tecircte de la fonction et le prototype Srsquoil nrsquoy a pas correspondance de types (exacte cette fois)

on obtient une erreur de compilation Voici un exemple correct

1 Toutefois mecircme dans ce cas le prototype reste conseilleacute notamment pour eacuteviter tout problegraveme en cas drsquoeacuteclate-

ment du fichier source

2 Nous supposons que le compilateur connaicirct le type des arguments de la fonction ce qui est toujours le cas en C++

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

12

double fexple (int double) deacuteclaration de fexple main()

deacutefinition de fexple double fexple (int u double v) corps de la fonction

En revanche celui-ci conduit agrave une erreur de compilation

double fexple (int float) deacuteclaration de fexple main() deacutefinition de fexple double fexple (int u double v) erreur de compilation corps de la fonction

Bien entendu si la deacutefinition de la fonction et sa deacuteclaration (donc son utilisation1) ne figu-

rent pas dans le mecircme fichier source aucun controcircle ne peut plus ecirctre effectueacute par le compi-

lateur En geacuteneacuteral agrave partir du moment ougrave lrsquoon doit utiliser une fonction en dehors du fichier

ougrave elle est deacutefinie (ou agrave partir de plusieurs fichiers source diffeacuterents) on place son prototype

dans un fichier en-tecircte ce dernier est incorporeacute en cas de besoin par la directive include

ce qui eacutevite tout risque de faute drsquoeacutecriture du prototype

Remarques

1 Comme en C la porteacutee du prototype est limiteacutee agrave

ndash la partie du fichier source situeacutee agrave la suite de sa deacuteclaration si elle figure agrave un niveau

global crsquoest-agrave-dire en dehors de toute deacutefinition de fonction2 crsquoeacutetait le cas du proto-

type de fexple dans nos preacuteceacutedents exemples

ndash la fonction dans laquelle il figure dans le cas contraire

2 Le prototype peut prendre une forme plus eacutetoffeacutee3 dans laquelle figurent eacutegalement des

noms drsquoarguments Ainsi le prototype de notre fonction fexple du deacutebut du

paragraphe 2 pourrait eacutegalement srsquoeacutecrire

double fexple (int a double x)

1 A moins qursquoon ne lrsquoait deacuteclareacutee sans lrsquoutiliser ce qui arrive freacutequemment lorsque lrsquoon fait appel agrave des fichiers en-

tecircte

2 Y compris la fonction main

3 On parle alors parfois de prototype complet par opposition agrave prototype reacuteduit

3 - Arguments et valeur de retour drsquoune fonction13

ou encore

double fexple (int u double v)

Dans ce cas les noms drsquoarguments (a et x dans le premier exemple u et v dans le

second) ne jouent aucun rocircle Ils sont purement et simplement ignoreacutes par le compila-

teur de sorte que ces prototypes restent parfaitement eacutequivalents aux preacuteceacutedents On

peut trouver un inteacuterecirct agrave cette possibiliteacute lorsque lrsquoon souhaite accompagner ce proto-

type de commentaires deacutecrivant le rocircle des diffeacuterents arguments (cela peut srsquoaveacuterer pra-

tique dans le cas ougrave lrsquoon place ce prototype dans un fichier en-tecircte)

3 Arguments et valeur de retour drsquoune fonction

31 Points communs agrave C et C++En C++ comme en C ANSI les arguments drsquoune fonction ainsi que la valeur de retour

peuvent

bull ne pas exister

bull ecirctre une valeur scalaire drsquoun des types de base (caractegraveres entiers flottants pointeurs)

bull ecirctre une valeur de type structure

La derniegravere possibiliteacute a eacuteteacute introduite dans le langage C par la norme ANSI Nous verrons

qursquoen C++ elle se geacuteneacuteralise aux objets de type classe Pour lrsquoinstant notez simplement qursquoil

subsiste en C++ comme en C ANSI une dispariteacute entre les tableaux et les structures puisque

bull il est possible de transmettre la valeur drsquoune structure aussi bien en argument qursquoen valeur

de retour

bull il nrsquoest pas possible de faire de mecircme avec les tableaux

Notez qursquoil srsquoagit lagrave drsquoune dispariteacute difficile agrave reacutesorber compte tenu de la volonteacute des con-

cepteurs du langage C de rendre eacutequivalents le nom drsquoun tableau et son adresse

Bien entendu il est toujours possible de transmettre lrsquoadresse drsquoun tableau et cette remarque

vaut eacutegalement pour une structure

32 Diffeacuterences entre C et C++En fait ces diffeacuterences ne portent que sur la syntaxe des en-tecirctes et des prototypes des fonc-

tions et uniquement dans deux cas preacutecis

bull fonctions sans arguments

bull fonctions sans valeur de retour

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

14

321 Fonctions sans argumentsAlors qursquoen C ANSI on peut employer le mot void pour deacutefinir (en-tecircte) ou deacuteclarer (proto-

type) une fonction sans argument en C++ on fournit une liste vide Ainsi lagrave ougrave en C on

deacuteclarait

float fct (void)

on deacuteclarera en C++

float fct ( )

322 Fonctions sans valeur de retourEn C ANSI on peut utiliser le mot void pour deacutefinir (en-tecircte) ou deacuteclarer (prototype) une

fonction sans valeur de retour En C++ on doit absolument le faire comme dans cet

exemple

void fct (int double)

La deacuteclaration

fct (int double)

conduirait C++ agrave consideacuterer que fct fournit une valeur de retour de type int (voir la remarque

du paragraphe 1)

4 Le qualificatif constLa norme C ANSI a introduit le qualificatif const Il permet de speacutecifier qursquoun symbole cor-

respond agrave quelque chose dont la valeur ne doit pas changer ce qui peut permettre au com-

pilateur de signaler les tentatives de modification (lorsque cela lui est possible )

Si cela reste vrai en C++ un certain nombre de diffeacuterences importantes apparaissent qui con-

cernent la porteacutee du symbole concerneacute et son utilisation dans une expression

41 PorteacuteeLorsque const srsquoapplique agrave des variables locales automatiques aucune diffeacuterence nrsquoexiste

entre C et C++ la porteacutee eacutetant limiteacutee au bloc ou agrave la fonction concerneacutee par la deacuteclaration

En revanche lorsque const srsquoapplique agrave une variable globale C++ limite la porteacutee du sym-

bole au fichier source contenant la deacuteclaration (comme srsquoil avait reccedilu lrsquoattribut static) C

nrsquoimposait aucune limitation

Pourquoi cette diffeacuterence La principale raison reacuteside dans lrsquoideacutee qursquoavec la regravegle adopteacutee

par C++ il devient plus facile de remplacer certaines instructions define par des deacuteclarations

de constantes Ainsi lagrave ougrave en C vous proceacutediez de cette faccedilon

define N 8 define N 3

fichier 1 fichier 2

4 - Le qualificatif const15

vous pouvez en C++ proceacuteder ainsi

const int N = 8 const int N = 3

fichier 1 fichier 2

En C vous auriez obtenu une erreur au moment de lrsquoeacutedition de liens Vous auriez pu lrsquoeacuteviter

bull soit en deacuteclarant N static dans au moins un des deux fichiers (ou mieux dans les deux)

static const int N = 8 static const int N = 3

Cela aurait alors eacuteteacute parfaitement eacutequivalent agrave ce que fait C++ avec les premiegraveres

deacuteclarations

bull soit si N avait eu la mecircme valeur dans les deux fichiers en placcedilant dans le second fichier

extern const int N

Mais dans ce cas il ne se serait plus agi drsquoun remplacement de define

42 Utilisation dans une expressionRappelons que lrsquoon nomme expression constante une expression dont la valeur est calculeacutee

lors de la compilation Ainsi avec

const int p = 3

lrsquoexpression

2 p 5

nrsquoest pas une expression constante en C alors qursquoelle en est une en C++

Ce point est particuliegraverement sensible dans les deacuteclarations de tableaux (statiques ou automa-

tiques) dont les dimensions doivent obligatoirement ecirctre des expressions constantes (mecircme

pour les tableaux automatiques le compilateur doit connaicirctre la taille agrave reacuteserver sur la pile )

Ainsi les instructions

const int nel = 15 double t1 [nel + 1] t2[2 nel] [nel]

seront accepteacutees en C++ alors qursquoelles eacutetaient refuseacutees en C

Remarques

1 En toute rigueur la possibiliteacute que nous venons de deacutecrire ne constitue pas une incompa-

tibiliteacute entre C et C++ puisqursquoil srsquoagit drsquoune faciliteacute suppleacutementaire

2 Drsquoune maniegravere geacuteneacuterale C++ a eacuteteacute conccedilu pour limiter au maximum lrsquoemploi des direc-

tives du preacuteprocesseur (on devrait pouvoir se contenter de include et des directives

drsquoinclusion conditionnelle) Les modifications apporteacutees au qualificatif const vont

effectivement dans ce sens1

1 Encore faut-il que le programmeur C++ accepte de changer les habitudes qursquoil avait ducirc prendre en C (faute de

pouvoir faire autrement)

Les incompatibiliteacutes entre C++ et CCHAPITRE 2

16

5 Compatibiliteacute entre le type void et les autres pointeurs

En C ANSI le type geacuteneacuterique void est compatible avec les autres types pointeurs et ce

dans les deux sens Ainsi avec ces deacuteclarations

void gen int adi

ces deux affectations sont leacutegales en C ANSI

gen = adi adi = gen

Elles font intervenir des conversions implicites agrave savoir

int -gt void pour la premiegravere

void -gt int pour la seconde

En C++ seule la conversion drsquoun pointeur quelconque en void peut ecirctre implicite Ainsi

avec les deacuteclarations preacuteceacutedentes seule lrsquoaffectation

gen = adi

est accepteacutee Bien entendu il reste toujours possible de faire appel explicitement agrave la conver-

sion void -gt int en utilisant lrsquoopeacuterateur de cast

adi = (int ) gen

Remarque

On peut dire que la conversion drsquoun pointeur de type quelconque en void revient agrave ne

srsquointeacuteresser qursquoagrave lrsquoadresse correspondant au pointeur en ignorant son type En revanche

la conversion inverse de void en un pointeur de type donneacute revient agrave associer (peut-ecirctre

arbitrairement ) un type agrave une adresse Manifestement cette seconde possibiliteacute est plus

dangereuse que la premiegravere elle peut mecircme obliger le compilateur agrave introduire des modi-

fications de lrsquoadresse de deacutepart dans le seul but de respecter certaines contraintes drsquoali-

gnement (lieacutees au type drsquoarriveacutee) Crsquoest la raison pour laquelle cette conversion ne fait

plus partie des conversions implicites en C++

3

Les entreacutees-sortiesconversationnelles du C++

C++ dispose de toutes les routines offertes par la bibliothegraveque standard du C ANSI Mais il

comporte eacutegalement de nouvelles possibiliteacutes dentreacutees-sorties Celles-ci reposent sur les

notions de flots et de surdeacutefinition dopeacuterateur que nous naborderons quulteacuterieurement

Il ne serait pas judicieux cependant dattendre que vous ayez eacutetudieacute ces diffeacuterents points pour

commencer agrave eacutecrire des programmes complets reacutedigeacutes dans lesprit de C++ Cest pourquoi

nous allons vous preacutesenter ces nouvelles possibiliteacutes dentreacutees-sorties dans ce chapitre de

maniegravere assez informelle en nous limitant agrave ce que nous nommons laspect conversationnel

agrave savoir

bull la lecture sur lentreacutee standard geacuteneacuteralement le clavier

bull lrsquoeacutecriture sur la sortie standard geacuteneacuteralement lrsquoeacutecran

1 GeacuteneacuteraliteacutesLes routines (fonctions et macros) de la bibliothegraveque standard du C ANSI1 sont utilisables

en C++ en particulier celles relatives aux entreacutees-sorties pour ce faire il vous suffit

1 Lun des grands meacuterites de cette norme est de deacutefinir outre le langage C lui-mecircme les caracteacuteristiques dun certain

nombre de routines formant ce que lon nomme la bibliothegraveque standard

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

18

dinclure les fichiers en-tecircte habituels1 pour obtenir les prototypes et autres deacuteclarations

neacutecessaires agrave leur bonne utilisation

Mais C++ dispose en outre de possibiliteacutes dentreacutees-sorties ayant les caracteacuteristiques

suivantes

bull simpliciteacute dutilisation en particulier on pourra souvent saffranchir de la notion de for-

mat si chegravere aux fonctions de la famille printf ou scanf

bull diminution de la taille du module objet correspondant alors que par exemple un seul appel

de printf introduit obligatoirement dans le module objet un ensemble dinstructions en cou-

vrant toutes les eacuteventualiteacutes lemploi des nouvelles possibiliteacutes offertes par C++ nrsquointrodui-

ra que les seules instructions neacutecessaires

bull possibiliteacutes extensibles aux types que vous deacutefinirez vous-mecircme sous forme de classes

Nous allons examiner ces possibiliteacutes en nous limitant agrave lrsquoaspect conversationnel crsquoest-agrave-dire

agrave la lecture sur lrsquoentreacutee standard et agrave lrsquoaffichage sur la sortie standard

2 Affichage agrave lrsquoeacutecran

21 Quelques exemplesAvant deacutetudier les diffeacuterentes possibiliteacutes offertes par C++ examinons quelques exemples

Exemple 1Lagrave ougrave en C on eacutecrivait

printf (bonjour)

en C++ on utilisera

cout ltlt bonjour

Linterpreacutetation deacutetailleacutee de cette instruction neacutecessiterait des connaissances qui ne seront

introduites quulteacuterieurement Pour linstant il vous suffit de retenir les points suivants

bull cout deacutesigne un flot de sortie preacutedeacutefini associeacute agrave lentreacutee standard du C (stdout)

bull ltlt est un opeacuterateur dont lopeacuterande de gauche (ici cout) est un flot et lopeacuterande de droi-

te une expression de type quelconque Linstruction preacuteceacutedente peut ecirctre interpreacuteteacutee com-

me ceci le flot cout reccediloit la valeur bonjour

1 Toutefois la norme de C++ a preacutevu que les noms de ces fichiers soient preacutefixeacutes par c et que le suffixe h disparaisse

Par exemple on trouvera ltcstdiogt au lieu de ltstdiohgt

2 - Affichage agrave lrsquoeacutecran19

Exemple 2

Consideacuterons ces instructions

int n = 25

cout ltlt valeur

cout ltlt n

Elles affichent le reacutesultat suivant

valeur 25

Vous constatez que nous avons utiliseacute le mecircme opeacuterateur ltlt pour envoyer sur le flot cout

dabord une information de type chaicircne ensuite une information de type entier Le rocircle de

lopeacuterateur ltlt est manifestement diffeacuterent dans les deux cas dans le premier on a transmis

les caractegraveres de la chaicircne dans le second on a proceacutedeacute agrave un formatage1 pour convertir une

valeur binaire entiegravere en une suite de caractegraveres Cette possibiliteacute dattribuer plusieurs signifi-

cations agrave un mecircme opeacuterateur correspond agrave ce que lon nomme en C++ la surdeacutefinition dopeacute-

rateur (que nous aborderons en deacutetail au chapitre 9)

Exemple 3

Dans les exemples preacuteceacutedents nous avions utiliseacute une instruction diffeacuterente pour chaque

information transmise au flot cout En fait les deux instructions

cout ltlt valeur

cout ltlt n

peuvent se condenser en une seule

cout ltlt valeur ltlt n

Lagrave encore linterpreacutetation exacte de cette possibiliteacute sera fournie ulteacuterieurement mais dores

et deacutejagrave nous pouvons dire quelle reacuteside dans deux points

bull lopeacuterateur ltlt est associatif de gauche agrave droite comme lrsquoopeacuterateur drsquoorigine

bull le reacutesultat fourni par lopeacuterateur ltlt quand il reccediloit un flot en premier opeacuterande est ce mecircme

flot apregraves quil a reccedilu linformation concerneacutee

Ainsi linstruction preacuteceacutedente est eacutequivalente agrave

(cout ltlt valeur ) ltlt n

Celle-ci peut sinterpreacuteter comme ceci

bull dans un premier temps le flot cout reccediloit la chaicircne valeur

bull dans un deuxiegraveme temps le flot cout ltlt valeur cest-agrave-dire le flot cout augmenteacute de

bonjour reccediloit la valeur de n

Si cette interpreacutetation ne vous paraicirct pas eacutevidente il vous suffit dadmettre pour linstant

quune instruction telle que

cout ltlt ----- ltlt ----- ltlt ----- ltlt -----

1 Ici ce formatage est implicite dans le cas de printf on laurait expliciteacute (d)

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

20

permet denvoyer sur le flot cout les informations symboliseacutees par des traits dans lordre ougrave

elles apparaissent

22 Le fichier en-tecircte iostreamEn C lrsquoutilisation de fonctions telles que printf ou scanf neacutecessitait lrsquoincorporation du fichier

en-tecircte ltstdiohgt qui contenait les deacuteclaration approprieacutees De faccedilon comparable les deacutecla-

rations neacutecessaires agrave lrsquoutilisation des entreacutees-sorties speacutecifiques agrave C++ figurent dans un

fichier en-tecircte de nom ltiostreamgt Cependant lrsquoutilisation des symboles deacuteclareacutes dans ce

fichier iostream fait appel agrave la notion drsquoespace de noms introduite elle-aussi par la norme

Cette notion sera preacutesenteacutee sommairement au chapitre 4 et eacutetudieacutee plus en deacutetail au chapitre

24 Pour lrsquoinstant sachez qursquoelle oblige agrave introduire dans votre programme une instruction de

deacuteclaration using dont la porteacutee se deacutefinit comme celle de toute deacuteclaration et qui se preacute-

sente ainsi

using namespace std on utilisera les symboles deacutefinis dans lrsquoespace de noms standard srsquoappelant std

Remarque

Avant la norme on utilisait un fichier nommeacute ltiostreamhgt et lrsquoinstruction using nrsquoexis-

tait pas Certains environnements fonctionnent encore ainsi Parfois il faut recourir agrave

ltiostreamgt sans utiliser using1 (qui pourrait provoquer une erreur de compilation)

23 Les possibiliteacutes drsquoeacutecriture sur coutNous venons de voir des exemples deacutecriture de chaicircnes et dentiers Dune maniegravere geacuteneacuterale

vous pouvez utiliser lopeacuterateur ltlt pour envoyer sur cout la valeur dune expression de lun

des types suivants

bull type de base quelconque (caractegravere entier signeacute ou non flottant)

bull chaicircne de caractegraveres (char ) on obtient laffichage des caractegraveres constituant la chaicircne

bull pointeur autre que char on obtient ladresse correspondante (en hexadeacutecimal) si on

veut obtenir ladresse dune chaicircne de caractegraveres et non les caractegraveres quelle contient on

peut toujours convertir cette chaicircne (de type char ) en void

Voici un exemple complet de programme illustrant ces possibiliteacutes accompagneacute drsquoun exem-

ple drsquoexeacutecution dans un environnement PC2

1 Ces impleacutementations acceptent geacuteneacuteralement using pour les fichiers en-tecircte relatifs aux composants standard

2 Lrsquoimpleacutementation nrsquointervient ici que dans lrsquoaffichage de pointeurs

3 - Lecture au clavier21

include ltiostreamgtusing namespace std main() int n = 25 long p = 250000 unsigned q = 63000 char c = a float x = 123456789 double y = 123456789e16 char ch = bonjour int ad = amp n

cout ltlt valeur de n ltlt n ltlt n cout ltlt valeur de p ltlt p ltlt n cout ltlt caractere c ltlt c ltlt n cout ltlt valeur de q ltlt q ltlt n cout ltlt valeur de x ltlt x ltlt n cout ltlt valeur de y ltlt y ltlt n cout ltlt chaine ch ltlt ch ltlt n cout ltlt adresse de n ltlt ad ltlt n cout ltlt adresse de ch ltlt (void ) ch ltlt n

valeur de n 25valeur de p 250000caractere c avaleur de q 63000valeur de x 123457valeur de y 123457e+017chaine ch bonjouradresse de n 006AFDF4adresse de ch 0046D0D4

Les possibiliteacutes drsquoeacutecriture sur cout

3 Lecture au clavier

31 IntroductionDe mecircme quil existe un flot de sortie preacutedeacutefini cout associeacute agrave la sortie standard du C (stdout)

il existe un flot dentreacutee preacutedeacutefini nommeacute cin associeacute agrave lentreacutee standard du C (stdin) De

mecircme que lopeacuterateur ltlt permet denvoyer des informations sur un flot de sortie (donc en

particulier sur cout) lopeacuterateur gtgt permet de recevoir1 de linformation en provenance dun

flot dentreacutee (donc en particulier de cin)

1 On dit aussi extraire

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

22

Par exemple linstruction (n eacutetant de type int)

cin gtgt n

demandera de lire des caractegraveres sur le flot cin et de les convertir en une valeur de type int

Dune maniegravere geacuteneacuterale

cin gtgt n gtgt p

sera eacutequivalent agrave

(cin gtgt n) gtgt p

Pour donner une interpreacutetation imageacutee (et peu formelle) analogue agrave celle fournie pour cout

nous pouvons dire que la valeur de n est dabord extraite du flot cin ensuite la valeur de p

est extraite du flot cin gtgt n (comme pour ltlt le reacutesultat de lopeacuterateur gtgt est un flot) cest-

agrave-dire de ce quest devenu le flot cin apregraves quon en a extrait la valeur de n

32 Les diffeacuterentes possibiliteacutes de lecture sur cinDune maniegravere geacuteneacuterale vous pouvez utiliser lopeacuterateur gtgt pour acceacuteder agrave des informations

de type de base quelconque (signeacute ou non pour les types entiers) ou agrave des chaicircnes de caractegrave-

res1 (char ) Comme avec scanf ou getchar les caractegraveres frappeacutes au clavier sont apregraves vali-

dation par une fin de ligne enregistreacutes dans un tampon La lecture se fait dans ce tampon qui

est reacutealimenteacute en cas de besoin drsquoinformations suppleacutementaires Les informations du tampon

non exploiteacutees lors drsquoune lecture restent disponibles pour la lecture suivante

Par ailleurs une bonne part des conventions danalyse des caractegraveres lus sont les mecircmes que

celles employeacutees par scanf Ainsi

bull les diffeacuterentes informations sont seacutepareacutees par un ou plusieurs caractegraveres parmi ceux-ci2 es-

pace tabulation horizontale (t) ou verticale (v) fin de ligne (n) ou encore changement de

page (f)3

bull un caractegravere invalide pour lusage quon doit en faire (un point pour un entier une lettre

pour un nombre) arrecircte lexploration du flot comme si lon avait rencontreacute un seacuteparateur

mais ce caractegravere invalide sera agrave nouveau pris en compte lors dune prochaine lecture

En revanche contrairement agrave ce qui se produisait pour scanf la lecture dun caractegravere sur cin

commence par sauter les seacuteparateurs aussi nest-il pas possible de lire directement ces

caractegraveres seacuteparateurs Nous verrons comment y parvenir dans le chapitre consacreacute aux flots

1 Il nest pas preacutevu de lire la valeur dun pointeur en pratique cela naurait guegravere dinteacuterecirct et de plus preacutesenterait de

grand risques

2 On les appelle parfois des espaces-blancs (de langlais white spaces)

3 Dans les environnements PC la fin de ligne est repreacutesenteacutee par deux caractegraveres conseacutecutifs elle nrsquoen reste pas

moins vue par le programme comme un seul et unique caractegravere (n) cette remarque vaut en fait pour tous les fichiers

de type texte comme on le verra dans le chapitre consacreacute aux flots

3 - Lecture au clavier23

33 Exemple classique drsquoutilisation des seacuteparateursLe programme suivant illustre une situation classique dans laquelle la gestion des caractegraveres

seacuteparateurs ne pose pas de problegraveme particulier

include ltiostreamgtusing namespace std main() int n float x char t[81] do cout ltlt donnez un entier une chaine et un flottant cin gtgt n gtgt t gtgt x cout ltlt merci pour ltlt n ltlt ltlt t ltlt et ltlt x ltlt n while (n)

donnez un entier une chaine et un flottant 15 bonjour 825merci pour 15 bonjour et 825donnez un entier une chaine et un flottant 15

bonjour

825merci pour 15 bonjour et 825donnez un entier une chaine et un flottant 0 bye 0merci pour 0 bye et 0

Usage classique des seacuteparateurs

34 Lecture drsquoune suite de caractegraveresLrsquoexemple suivant montre que la faccedilon dont C++ gegravere les seacuteparateurs peut srsquoaveacuterer deacuterou-

tante lorsque lrsquoon est ameneacute agrave lire une suite de caractegraveres

include ltiostreamgtusing namespace std main() char tc[129] pour conserver les caractegraveres lus sur cin int i = 0 position courante dans le tableau tc

cout ltlt donnez une suite de caracteres terminee par un point n do cin gtgt tc[i] attention pas de test de deacutebordement dans tc while (tc[i++] = ) cout ltlt nnVoici les caracteres effectivement lus n i=0

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

24

do cout ltlt tc[i] while (tc[i++] = )

donnez une suite de caracteres terminee par un point Voyez comme

C++pose quelques problegravemeslors de la lecture dune

suite de caractegraveres

Voici les caracteres effectivement lus VoyezcommeC++posequelquesproblegravemeslorsdelalecturedunesuitedecaractegraveres

Quand on cherche agrave lire une suite de caractegraveres

35 Les risques induits par la lecture au clavierNous vous proposons deux exemples montrant que en C++ comme en C on peut dans cer-

tains cas aboutir agrave

bull un manque de synchronisme apparent entre le clavier et lrsquoeacutecran

bull un blocage de la lecture par un caractegravere invalide

bull une boucle infinie due agrave la preacutesence drsquoun caractegravere invalide

351 Manque de synchronisme entre clavier et eacutecran

Cet exemple illustre lrsquoexistence drsquoun tampon On y voit comment une lecture peut utiliser

une information non exploiteacutee par la preacuteceacutedente Ici lrsquoutilisateur nrsquoa pas agrave reacutepondre agrave la ques-

tion poseacutee agrave la troisiegraveme ligne

include ltiostreamgtusing namespace std main() int n p cout ltlt donnez une valeur pour n cin gtgt n cout ltlt merci pour ltlt n ltlt n cout ltlt donnez une valeur pour p cin gtgt p cout ltlt merci pour ltlt p ltlt n

3 - Lecture au clavier25

donnez une valeur pour n 12 25merci pour 12donnez une valeur pour p merci pour 25

Quand le clavier et lrsquoeacutecran semblent mal synchroniseacutes

352 Blocage de la lecture

Voyez cet exemple qui montre comment une maladresse de lrsquoutilisateur (ici frappe drsquoune let-

tre au lieu drsquoun chiffre) peut entraicircner un comportement deacuteconcertant du programme

include ltiostreamgtusing namespace std main() int n = 12 char c = rsquoarsquo cout ltlt donnez un entier et un caractere n cin gtgt n gtgt c cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n cout ltlt donnez un caractere cin gtgt c cout ltlt merci pour ltlt c

donnez un entier et un caractere x 25merci pour 4467164 et adonnez un caractere merci pour a

Clavier bloqueacute par un caractegravere invalide

Lors de la premiegravere lecture de n lrsquoopeacuterateur gtgt a rencontreacute le caractegravere x manifestement

invalide Comme il nrsquoeacutetait alors pas capable de fabriquer une valeur entiegravere il a laisseacute la

valeur de n inchangeacutee et il a bloqueacute la lecture Ainsi la tentative de lecture ulteacuterieure drsquoun

caractegravere dans c nrsquoa pas deacutebloqueacute la situation la lecture eacutetant bloqueacutee la valeur de c est res-

teacutee inchangeacutee (le flot est resteacute bloqueacute et drsquoautres tentatives de lecture seraient traiteacutees de la

sorte)

353 Boucle infinie sur un caractegravere invalide

Ce petit exemple montre comment une maladresse lors de lrsquoexeacutecution (ici frappe drsquoune lettre

pour un chiffre) peut entraicircner le bouclage drsquoun programme

include ltiostreamgtusing namespace std

Les entreacutees-sorties conversationnelles du C++CHAPITRE 3

26

main() int n do cout ltlt donnez un nombre entier cin gtgt n cout ltlt voici son carre ltlt nn ltlt n while (n)

donnez un nombre entier 3voici son carre 9donnez un nombre entier agravevoici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9donnez un nombre entier voici son carre 9

Boucle infinie sur un caractegravere invalide

Ici il faudra interrompre lrsquoexeacutecution du programme suivant une deacutemarche approprieacutee deacutepen-

dant de lrsquoenvironnement

Remarque

Il est possible drsquoameacuteliorer le comportement des programmes preacuteceacutedents Pour ce faire il

est neacutecessaire de faire appel agrave des eacuteleacutements qui seront preacutesenteacutes plus tard dans cet

ouvrage Nous verrons comment tester lrsquoeacutetat drsquoun flot et le deacutebloquer au paragraphe 3 du

chapitre 16 et mecircme geacuterer convenablement les lectures en utilisant un formatage en

meacutemoire au paragraphe 72 du chapitre 22

4

Les speacutecificiteacutes du C++

Le langage C++ dispose dun certain nombre de speacutecificiteacutes qui ne sont pas veacuteritablement

axeacutees sur la POO Il sagit essentiellement des suivantes

bull nouvelle forme de commentaire (en fin de ligne)

bull emplacement libre des deacuteclarations

bull notion de reacutefeacuterence

bull arguments par deacutefaut dans les deacuteclarations des fonctions

bull surdeacutefinition de fonctions

bull opeacuterateurs new et delete

bull fonctions en ligne (inline)

bull nouveaux opeacuterateurs de cast

bull existence drsquoun type booleacuteen bool

bull notion drsquoespace de noms

Dune maniegravere geacuteneacuterale ces possibiliteacutes seront pour la plupart souvent utiliseacutees conjointe-

ment avec celles de POO Cest ce qui justifie que nous les exposions degraves maintenant

Les speacutecificiteacutes du C++CHAPITRE 4

28

1 Le commentaire de fin de ligneEn C ANSI un commentaire peut ecirctre introduit en nimporte quel endroit ougrave un espace est

autoriseacute1 en le faisant preacuteceacuteder de et suivre de Il peut alors eacuteventuellement seacutetendre sur

plusieurs lignes

En C++ vous pouvez en outre utiliser des commentaires de fin de ligne en introduisant les

deux caractegraveres Dans ce cas tout ce qui est situeacute entre et la fin de la ligne est un com-

mentaire Notez que cette nouvelle possibiliteacute napporte quun surcroicirct de confort et de

seacutecuriteacute en effet une ligne telle que

cout ltlt bonjourn formule de politesse

peut toujours ecirctre eacutecrite ainsi

cout ltlt bonjourn formule de politesse

Vous pouvez mecircler (volontairement ou non ) les deux formules Dans ce cas notez que

dans

partie1 partie2 partie3

le commentaire ouvert par ne se termine quau prochain donc partie1 et partie2 sont

des commentaires tandis que partie3 est consideacutereacute comme appartenant aux instructions De

mecircme dans

partie1 partie2 partie3 partie4

le commentaire introduit par srsquoeacutetend jusqursquoagrave la fin de la ligne Il concerne donc partie2

partie3 et partie 4

Remarques

1 Le commentaire de fin de ligne constitue le seul cas ougrave la fin de ligne joue un rocircle signifi-

catif autre que celui dun simple seacuteparateur

2 Si lon utilise systeacutematiquement le commentaire de fin de ligne on peut alors faire

appel agrave et pour inhiber un ensemble dinstructions (contenant eacuteventuellement des

commentaires) en phase de mise au point

2 Deacuteclarations et initialisations

21 Regravegles geacuteneacuteralesC++ savegravere plus souple que le C ANSI en matiegravere de deacuteclarations Plus preacuteciseacutement en C++

il nest plus obligatoire de regrouper au deacutebut les deacuteclarations effectueacutees au sein dune fonc-

tion ou au sein dun bloc Celles-ci peuvent ecirctre effectueacutees ougrave bon vous semble pour peu

1 Donc en pratique nimporte ougrave pourvu quon ne coupe pas en deux un identificateur ou une chaicircne constante

2 - Deacuteclarations et initialisations29

quelles apparaissent avant que lon en ait besoin leur porteacutee reste limiteacutee agrave la partie du bloc

ou de la fonction suivant leur deacuteclaration

Par ailleurs les expressions utiliseacutees pour initialiser une variable scalaire peuvent ecirctre quel-

conques alors quen C elles ne peuvent faire intervenir que des variables dont la valeur est

connue degraves lentreacutee dans la fonction concerneacutee

Voici un exemple incorrect en C ANSI et accepteacute en C++

main() int n n = int q = 2n - 1

La deacuteclaration tardive de q permet de linitialiser1 avec une expression dont la valeur neacutetait

pas connue lors de lentreacutee dans la fonction (ici main)

22 Cas des instructions structureacuteesLinstruction suivante est accepteacutee en C++

for (int i=0 )

Lagrave encore la variable i a eacuteteacute deacuteclareacutee seulement au moment ougrave lon en avait besoin Sa porteacutee

est dapregraves la norme limiteacutee au bloc reacutegi par linstruction for On notera quil nexiste aucune

faccedilon deacutecrire des instructions eacutequivalentes en C

Cette possibiliteacute sapplique agrave toutes les instructions structureacutees crsquoest-agrave-dire aux instructions

for switch while et dowhile

Remarque

Le rocircle de ces deacuteclarations agrave linteacuterieur dinstructions structureacutees na eacuteteacute fixeacute que tardive-

ment par la norme ANSI Dans les versions anteacuterieures ce genre de deacuteclaration eacutetait cer-

tes autoriseacute mais tout se passait comme si elle figurait agrave lexteacuterieur du bloc ainsi

lexemple preacuteceacutedent eacutetait interpreacuteteacute comme si lon avait eacutecrit

int i

for (i=0 )

1 Noubliez pas quen C (comme en C++) il est possible dinitialiser une variable automatique scalaire agrave laide dune

expression quelconque

Les speacutecificiteacutes du C++CHAPITRE 4

30

3 La notion de reacutefeacuterenceEn C les arguments et la valeur de retour dune fonction sont transmis par valeur Pour simu-

ler en quelque sorte ce qui se nomme transmission par adresse dans dautres langages il est

alors neacutecessaire de jongler avec les pointeurs (la transmission se fait toujours par valeur

mais dans ce cas il sagit de la valeur dun pointeur) En C++ le principal inteacuterecirct de la notion

de reacutefeacuterence est quelle permet de laisser le compilateur mettre en œuvre les bonnes instruc-

tions pour assurer un transfert par adresse Pour mieux vous en faire saisir linteacuterecirct nous

vous proposons de vous rappeler comment il fallait proceacuteder en C

31 Transmission des arguments en C

Exemple 1Consideacuterons lrsquoexemple suivant qui illustre le fait qursquoen C les arguments sont toujours trans-

mis par valeur

include ltiostreamgtusing namespace std main()

void echange (int int) int n=10 p=20 cout ltlt avant appel ltlt n ltlt ltlt p ltlt n echange (n p) cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int a int b)

int c cout ltlt debut echange ltlt a ltlt ltlt b ltlt n c = a a = b b = c cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20debut echange 10 20fin echange 20 10apres appel 10 20

Les arguments sont transmis par valeur

Lors de lappel drsquoechange il y a transmission des valeurs de n et de p on peut consideacuterer que

la fonction les a recopieacutees dans des emplacements locaux correspondant agrave ses arguments for-

mels a et b et quelle a effectivement travailleacute sur ces copies

3 - La notion de reacutefeacuterence31

Exemple 2

Bien entendu il est toujours possible de programmer une fonction echange pour quelle opegravere

sur des variables de la fonction qui lappelle il suffit tout simplement de lui fournir en argu-

ment ladresse de ces variables comme dans lexemple suivant

include ltiostreamgt

using namespace std

main()

void echange (int int )

int n=10 p=20

cout ltlt avant appel ltlt n ltlt ltlt p ltlt n

echange (ampn ampp)

cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int a int b)

int c

cout ltlt debut echange ltlt a ltlt ltlt b ltlt n

c = a a = b b = c

cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20

debut echange 10 20

fin echange 20 10

apres appel 20 10

Mise en œuvre par le programmeur dune transmission par adresse

Notez bien les diffeacuterences entre les deux exemples agrave la fois dans leacutecriture de la fonction

echange mais aussi dans son appel Ce dernier point signifie que lutilisateur de la fonction

(qui nest pas toujours celui qui la eacutecrite) doit savoir sil faut lui transmettre une variable ou

son adresse1

32 Exemple de transmission drsquoargument par reacutefeacuterenceC++ permet de demander au compilateur de prendre lui-mecircme en charge la transmission des

arguments par adresse on parle alors de transmission dargument par reacutefeacuterence Le pro-

gramme ci-dessous montre comment appliquer un tel meacutecanisme agrave notre fonction echange

1 Certes ici si lon veut que la fonction echange puisse faire correctement son travail le choix simpose Mais il

nen va pas toujours ainsi

Les speacutecificiteacutes du C++CHAPITRE 4

32

include ltiostreamgt

using namespace std

main()

void echange (int amp int amp)

int n=10 p=20

cout ltlt avant appel ltlt n ltlt ltlt p ltlt n

echange (n p) attention ici pas de ampn ampp

cout ltlt apres appel ltlt n ltlt ltlt p ltlt n

void echange (int amp a int amp b)

int c

cout ltlt debut echange ltlt a ltlt ltlt b ltlt n

c = a a = b b = c

cout ltlt fin echange ltlt a ltlt ltlt b ltlt n

avant appel 10 20

deacutebut echange 10 20

fin echange 20 10

apregraves appel 20 10

Utilisation de la transmission darguments par reacutefeacuterence en C++

Dans linstruction

void echange (int amp a int amp b)

la notation int amp a signifie que a est une information de type int transmise par reacutefeacuterence

Notez bien que dans la fonction echange on utilise simplement le symbole a pour deacutesigner

cette variable dont la fonction aura reccedilu effectivement ladresse (et non la valeur) il nest

plus utile (et ce serait une erreur ) de faire appel agrave lopeacuterateur dindirection

Autrement dit il suffit davoir fait ce choix de transmission par reacutefeacuterence au niveau de

len-tecircte de la fonction pour que le processus soit entiegraverement pris en charge par le com-

pilateur1

Le mecircme pheacutenomegravene sapplique au niveau de lutilisation de la fonction Il suffit en effet

davoir speacutecifieacute dans le prototype les arguments (ici les deux) que lon souhaite voir trans-

mis par reacutefeacuterence Au niveau de lappel

echange (n p)

nous navons plus agrave nous preacuteoccuper du mode de transmission utiliseacute

1 Cette possibiliteacute est analogue agrave lutilisation du mot cleacute var dans len-tecircte dune proceacutedure en Pascal

3 - La notion de reacutefeacuterence33

Remarques

1 Nous avons parleacute de transmission par reacutefeacuterence drsquoun argument Mais on peut eacutegalement

dire qursquoon transmet agrave une fonction la reacutefeacuterence agrave un argument effectif cela traduit mieux

le fait que lrsquoinformation fournie agrave la fonction est bien lrsquoadresse drsquoun emplacement Mais

en comparaison avec la transmission par pointeurs ce mode de transmission offre une

certaine protection en effet la reacutefeacuterence agrave une variable ne peut pas ecirctre utiliseacutee directe-

ment (volontairement ou par erreur) pour acceacuteder agrave des emplacements voisins comme on

le ferait avec une adresse reccedilue par le biais drsquoun pointeur1

2 Lorsquon doit transmettre en argument la reacutefeacuterence agrave un pointeur on est ameneacute agrave utili-

ser ce genre deacutecriture

int amp adr adr est une reacutefeacuterence agrave un pointeur sur un int

En Java

La notion de reacutefeacuterence existe en Java mais elle est entiegraverement transparente au program-

meur Plus preacuteciseacutement les variables drsquoun type de base sont transmises par valeur tandis

que les objets sont transmis par reacutefeacuterence Il reste cependant possible de creacuteer explicite-

ment une copie drsquoun objet en utilisant une meacutethode approprieacutee dite de clonage

33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argumentLa transmission par reacutefeacuterence drsquoun argument entraicircne un certain nombre de conseacutequences qui

nrsquoexistaient pas dans le cas de la transmission par valeur ou lorsqursquoon transmettait lrsquoadresse

drsquoun emplacement par le biais drsquoun pointeur

331 Induction de risques indirectsComme on lrsquoa vu sur lrsquoexemple preacuteceacutedent la transmission darguments par reacutefeacuterence simpli-

fie leacutecriture de la fonction correspondante Le choix du mode de transmission par reacutefeacuterence

est fait au moment de leacutecriture de la fonction concerneacutee Lutilisateur de la fonction na plus agrave

sen soucier ensuite si ce nest au niveau de la deacuteclaration du prototype de la fonction

(dailleurs ce prototype proviendra en geacuteneacuteral dun fichier en-tecircte)

En contrepartie lemploi de la transmission par reacutefeacuterence accroicirct les risques drsquoeffets de

bord non deacutesireacutes En effet lorsquil appelle une fonction lutilisateur ne sait plus sil trans-

met au bout du compte la valeur ou ladresse dun argument (la mecircme notation pouvant deacutesi-

gner lune ou lautre des deux possibiliteacutes) Il risque donc de modifier une variable dont il

pensait navoir transmis quune copie de la valeur

1 Il reste cependant possible drsquoaffecter agrave un pointeur lrsquoadresse de la variable dont on a reccedilu la reacutefeacuterence

Les speacutecificiteacutes du C++CHAPITRE 4

34

332 Absence de conversionDegraves lors qursquoune fonction a preacutevu une transmission par reacutefeacuterence les possibiliteacutes de conver-

sion preacutevues en cas de transmission par valeur disparaissent Voyez cet exemple

void f (int amp n) f reccediloit la reacutefeacuterence agrave un entierfloat x f(x) appel illeacutegal

A partir du moment ougrave la fonction reccediloit directement lrsquoadresse drsquoun emplacement qursquoelle

considegravere comme contenant un entier qursquoelle peut eacuteventuellement modifier il va de soi qursquoil

nrsquoest plus possible drsquoeffectuer une quelconque conversion de la valeur qui srsquoy trouve

La transmission par reacutefeacuterence impose donc agrave un argument effectif drsquoecirctre une lvalue du

type preacutevu pour lrsquoargument muet Nous verrons cependant au paragraphe 334 que les

arguments muets constants feront exception agrave cette regravegle et que dans ce cas des conversions

seront possibles

Remarque

Avec le prototype preacuteceacutedent de f lappel fct (ampn) serait rejeteacute En effet une reacutefeacuterence

nrsquoest pas un pointeur mecircme si au bout du compte lrsquoinformation transmise agrave la fonction

est une adresse En particulier lrsquousage qui est fait dans la traduction des instructions de la

fonction nrsquoest pas le mecircme dans le cas drsquoun pointeur on utilise directement sa valeur

quitte agrave mentionner une indirection avec lrsquoopeacuterateur avec une reacutefeacuterence lrsquoindirection

est ajouteacutee automatiquement par le compilateur

333 Cas drsquoun argument effectif constantSupposons quune fonction fct ait pour prototype

void fct (int amp)

Le compilateur refusera alors un appel de la forme suivante (n eacutetant de type int)

fct (3) incorrect f ne peut pas modifier une constante

Il en ira de mecircme pour

const int c = 15 fct (c) incorrect f ne peut pas modifier une constante

Ces refus sont logigues En effet si les appels preacuteceacutedents eacutetaient accepteacutes ils conduiraient agrave

fournir agrave fct ladresse dune constante (3 ou c) dont elle pourrait tregraves bien modifier la valeur1

1 On verra cependant au paragraphe 334 qursquoune telle transmission sera autoriseacutee si la fonction a effectivement preacutevu

dans son en-tecircte de travailler sur une constante

3 - La notion de reacutefeacuterence35

334 Cas drsquoun argument muet constant

En revanche consideacuterons une fonction de prototype

void fct1 (const int amp)

La deacuteclaration const int amp correspond agrave une reacutefeacuterence agrave une constante1 Les appels suivants

seront corrects

const int c = 15 fct1 (3) correct ici fct1 (c) correct ici

Lacceptation de ces instructions se justifie cette fois par le fait que fct a preacutevu de recevoir

une reacutefeacuterence agrave quelque chose de constant le risque de modification eacutevoqueacute preacuteceacutedemment

nexiste donc plus (du moins en theacuteorie car les possibiliteacutes de veacuterification du compilateur ne

sont pas complegravetes)

Qui plus est un appel tel fct1 (exp) (exp deacutesignant une expression quelconque) sera accepteacute

quel que soit le type de exp En effet dans ce cas il y a creacuteation dune variable temporaire (de

type int) qui recevra le reacutesultat de la conversion de exp en int Par exemple

void fct1 (const int amp) float x fct1 (x) correct f reccediloit la reacutefeacuterence agrave une variable temporaire contenant le reacutesultat de la conversion de x en int

En deacutefinitive lrsquoutilisation de const pour un argument muet transmis par reacutefeacuterence est lourde

de conseacutequences Certes comme on srsquoy attend cela amegravene le compilateur agrave verifier la cons-

tance de lrsquoargument concerneacute au sein de la fonction Mais de surcroicirct on autorise la creacuteation

drsquoune copie de lrsquoargument effectif (preacuteceacutedeacutee drsquoune conversion) degraves lors que ce dernier est

constant et drsquoun type diffeacuterent de celui attendu2

Cette remarque prendra encore plus drsquoacuiteacute dans le cas ougrave lrsquoargument en question sera un

objet

34 Transmission par reacutefeacuterence drsquoune valeur de retour

341 Introduction

Le meacutecanisme que nous venons dexposer pour la transmission des arguments sapplique agrave la

valeur de retour dune fonction Il est cependant moins naturel Consideacuterons ce petit

exemple

1 Contrairement agrave un pointeur une reacutefeacuterence est toujours constante de sorte que la deacuteclaration int const amp nrsquoa aucun

sens il nrsquoen allait pas de mecircme pour int const qui deacutesignait un pointeur constant sur un entier

2 Dans le cas drsquoune constante du mecircme type la norme laisse lrsquoimpleacutementation libre drsquoen faire ou non une copie

Geacuteneacuteralement la copie nrsquoest faite que pour les constantes drsquoun type scalaire

Les speacutecificiteacutes du C++CHAPITRE 4

36

int amp f () return n on suppose ici n de type int

Un appel de f provoquera la transmission en retour non plus drsquoune valeur mais de la reacutefeacute-

rence de n Cependant si lrsquoon utilise f drsquoune faccedilon usuelle

int p p = f() affecte agrave p la valeur situeacutee agrave la reacutefeacuterence fournie par f

une telle transmission ne semble guegravere preacutesenter drsquointeacuterecirct par rapport agrave une transmission par

valeur

Qui plus est il est neacutecessaire que n ne soit pas locale agrave la fonction sous peine de reacutecupeacuterer

une reacutefeacuterence (adresse) agrave quelque chose qui nrsquoexiste plus1

Effectivement on conccediloit qursquoon a plus rarement besoin de recevoir une reacutefeacuterence drsquoune

fonction que de lui en fournir

342 On obtient une lvalueDegraves lors qursquoune fonction renvoie une reacutefeacuterence il devient possible drsquoutiliser son appel

comme une lvalue Voyez cet exemple

int amp f () int n float x

f() = 2 n + 5 agrave la reacutefeacuterence fournie par f on range la valeur de lrsquoexpression 2n+5 de type intf() = x agrave la reacutefeacuterence fournie par f on range la valeur de x apregraves conversion en int

Le principal inteacuterecirct de la transmission par reacutefeacuterence drsquoune valeur de retour napparaicirctra que

lorsque nous eacutetudierons la surdeacutefinition dopeacuterateurs En effet dans certains cas il sera indis-

pensable quun opeacuterateur (en fait une fonction) fournisse une lvalue en reacutesultat Ce sera preacute-

ciseacutement le cas de lrsquoopeacuterateur []

343 ConversionContrairement agrave ce qui se produisait pour les arguments aucune contrainte drsquoexactitude de

type ne pegravese sur une valeur de retour car il reste toujours possible de la soumettre agrave une con-

version avant de lrsquoutiliser

1 Cette erreur srsquoapparente agrave celle due agrave la transmission en valeur de retour drsquoun pointeur sur une variable locale Elle

est encore plus difficile agrave deacutetecter dans la mesure ougrave le seul moment ougrave lrsquoon peut utiliser la reacutefeacuterence concerneacutee est

lrsquoappel lui-mecircme (alors qursquoun pointeur peut ecirctre utiliseacute agrave volonteacute) dans un environnement ne modifiant pas la

valeur drsquoune variable lors de sa destruction aucune erreur ne se manifeste ce nrsquoest que lors du portage dans un

environnement ayant un comportement diffeacuterent que les choses deviennent catastrophiques

3 - La notion de reacutefeacuterence37

inf amp f () float x x = f() OK on convertira en int la valeur situeacutee agrave la reacutefeacuterence reccedilue en retour de f

Nous verrons au paragraphe 344 qursquoil nrsquoen va plus de mecircme lorsque la valeur de retour est

une reacutefeacuterence agrave une constante

344 Valeur de retour et constance Si une fonction preacutevoit dans son en-tecircte un retour par reacutefeacuterence elle ne pourra pas mention-

ner de constante dans lrsquoinstruction return En effet si tel eacutetait le cas on prendrait le risque

que la fonction appelante modifie la valeur en question

int n=3 variable globalefloat x=35 idemint amp f1 () return 5 interdit return n OK return x interdit

Une exception a lieu lorsque lrsquoen-tete mentionne une reacutefeacuterence agrave une constante Dans ce cas

si return mentionne une constante on renverra la reacutefeacuterence drsquoune copie de cette constante

preacuteceacutedeacutee drsquoune eacuteventuelle conversion

const int amp f2 () return 5 OK on renvoie la reacutefeacuterence agrave une copie temporaire return n OK return x OK on renvoie la reacutefeacuterence agrave un int temporaire obtenu par conversion de la valeur de x

Mais on notera qursquoune telle reacutefeacuterence agrave une constante ne pourra plus ecirctre utiliseacutee comme une

lvalue

const int amp f () int n float x f() = 2 n + 5 erreur f() nrsquoest pas une lvaluef() = x idem

35 La reacutefeacuterence dune maniegravere geacuteneacuteraleNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Lessentiel concernant la notion de reacutefeacuterence a eacuteteacute preacutesenteacute dans les paragraphes preacuteceacutedents

Cependant en toute rigueur la notion de reacutefeacuterence peut intervenir en dehors de la notion

dargument ou de valeur de retour Crsquoest ce que nous allons examiner ici

Les speacutecificiteacutes du C++CHAPITRE 4

38

351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument

Dune maniegravere geacuteneacuterale il est possible de deacuteclarer un identificateur comme reacutefeacuterence dune

autre variable Consideacuterez par exemple ces instructions

int n

int amp p = n

La seconde signifie que p est une reacutefeacuterence agrave la variable n Ainsi dans la suite n et p deacutesigne-

ront le mecircme emplacement meacutemoire Par exemple avec

n = 3

cout ltlt p

nous obtiendrons la valeur 3

Remarque

Il nrsquoest pas possible de deacutefinir des pointeurs sur des reacutefeacuterences ni des tableaux de reacutefeacuteren-

ces

352 Initialisation de reacutefeacuterence

La deacuteclaration

int amp p = n

est en fait une deacuteclaration de reacutefeacuterence (ici p) accompagneacutee dune initialisation (agrave la reacutefeacuterence

de n) Dune faccedilon geacuteneacuterale il nest pas possible de deacuteclarer une reacutefeacuterence sans linitialiser

comme dans

int amp p incorrect car pas dinitialisation

Notez bien quune fois deacuteclareacutee (et initialiseacutee) une reacutefeacuterence ne peut plus ecirctre modifieacutee

Dailleurs aucun meacutecanisme nest preacutevu agrave cet effet si ayant deacuteclareacute int amp p=n vous eacutecri-

vez p=q il sagit obligatoirement de laffectation de la valeur de q agrave lemplacement de reacutefeacute-

rence p et non de la modification de la reacutefeacuterence q

On ne peut pas initialiser une reacutefeacuterence avec une constante La deacuteclaration suivante est

incorrecte

int amp n = 3 incorrecte

Cela est logique puisque si cette instruction eacutetait accepteacutee elle reviendrait agrave initialiser n avec

une reacutefeacuterence agrave la valeur (constante) 3 Dans ces conditions linstruction suivante conduirait

agrave modifier la valeur de la constante 3

n = 5

En revanche il est possible de deacutefinir des reacutefeacuterences constantes1 qui peuvent alors ecirctre initia-

liseacutees par des constantes Ainsi la deacuteclaration suivante est-elle correcte

const int amp n = 3

1 Depuis la version 3 de C++

4 - Les arguments par deacutefaut39

Elle geacutenegravere une variable temporaire (ayant une dureacutee de vie imposeacutee par lemplacement de la

deacuteclaration) contenant la valeur 3 et place sa reacutefeacuterence dans n On peut dire que tout se passe

comme si vous aviez eacutecrit

int temp = 3 int amp n = temp

avec cette diffeacuterence que dans le premier cas vous navez pas explicitement accegraves agrave la varia-

ble temporaire

Enfin les deacuteclarations suivantes sont encore correctes

float x const int amp n = x

Elles conduisent agrave la creacuteation drsquoune variable temporaire contenant le reacutesultat de la conversion

de x en int et placent sa reacutefeacuterence dans n Ici encore tout se passe comme si vous aviez eacutecrit

ceci (sans toutefois pouvoir acceacuteder agrave la variable temporaire temp)

float x int temp = x const int amp n = temp

Remarque

En toute rigueur lrsquoappel drsquoune fonction conduit agrave une initialisation des arguments

muets Dans le cas drsquoune reacutefeacuterence ce sont donc les regravegles que nous venons de deacutecrire qui

sont utiliseacutees Il en va de mecircme pour une valeur de retour On retrouve ainsi le comporte-

ment deacutecrit aux paragraphes 33 et 34

4 Les arguments par deacutefaut

41 ExemplesEn C ANSI il est indispensable que lappel dune fonction contienne autant darguments que

la fonction en attend effectivement C++ permet de saffranchir en partie de cette regravegle gracircce

agrave un meacutecanisme dattribution de valeurs par deacutefaut agrave des arguments

Exemple 1Consideacuterez lexemple suivant

include ltiostreamgtusing namespace std main() int n=10 p=20 void fct (int int=12) proto avec une valeur par deacutefaut fct (n p) appel normal fct (n) appel avec un seul argument fct() serait ici rejeteacute

Les speacutecificiteacutes du C++CHAPITRE 4

40

void fct (int a int b) en-tecircte habituelle

cout ltlt premier argument ltlt a ltlt n

cout ltlt second argument ltlt b ltlt n

premier argument 10

second argument 20

premier argument 10

second argument 12

Exemple de deacutefinition de valeur par deacutefaut pour un argument

La deacuteclaration de fct ici dans la fonction main est reacutealiseacutee par le prototype

void fct (int int = 12)

La deacuteclaration du second argument apparaicirct sous la forme

int = 12

Celle-ci preacutecise au compilateur que en cas dabsence de ce second argument dans un eacuteven-

tuel appel de fct il lui faudra faire comme si lappel avait eacuteteacute effectueacute avec cette valeur

Les deux appels de fct illustrent le pheacutenomegravene Notez quun appel tel que

fct ( )

serait rejeteacute agrave la compilation puisquici il neacutetait pas preacutevu de valeur par deacutefaut pour le pre-

mier argument de fct

Exemple 2

Voici un second exemple dans lequel nous avons preacutevu des valeurs par deacutefaut pour tous les

arguments de fct

include ltiostreamgt

using namespace std

main()

int n=10 p=20

void fct (int=0 int=12) proto avec deux valeurs par deacutefaut

fct (n p) appel normal

fct (n) appel avec un seul argument

fct () appel sans argument

void fct (int a int b) en-tecircte habituelle

cout ltlt premier argument ltlt a ltlt n

cout ltlt second argument ltlt b ltlt n

4 - Les arguments par deacutefaut41

premier argument 10

second argument 20

premier argument 10

second argument 12

premier argument 0

second argument 12

Exemple de deacutefinition de valeurs par deacutefaut pour plusieurs arguments

42 Les proprieacuteteacutes des arguments par deacutefautLorsquune deacuteclaration preacutevoit des valeurs par deacutefaut les arguments concerneacutes doivent obli-

gatoirement ecirctre les derniers de la liste

Par exemple une deacuteclaration telle que

float fexple (int = 5 long int = 3)

est interdite En fait une telle interdiction relegraveve du pur bon sens En effet si cette deacutecla-

ration eacutetait accepteacutee lappel suivant

fexple (10 20)

pourrait ecirctre interpreacuteteacute aussi bien comme

fexple (5 10 20)

que comme

fexple (10 20 3)

Notez bien que le meacutecanisme proposeacute par C++ revient agrave fixer les valeurs par deacutefaut dans la

deacuteclaration de la fonction et non dans sa deacutefinition Autrement dit ce nest pas le concep-

teur de la fonction qui deacutecide des valeurs par deacutefaut mais lutilisateur Une conseacutequence

immeacutediate de cette particulariteacute est que les arguments soumis agrave ce meacutecanisme et les valeurs

correspondantes peuvent varier dune utilisation agrave une autre en pratique toutefois ce point

ne sera guegravere exploiteacute ne serait-ce que parce que les deacuteclarations de fonctions sont en geacuteneacute-

ral figeacutees une fois pour toutes dans un fichier en-tecircte

Nous verrons que les arguments par deacutefaut se reacuteveacuteleront particuliegraverement preacutecieux lorsquil

sagira de fabriquer ce que lon nomme le constructeur dune classe

Remarques

1 Si lon souhaite attribuer une valeur par deacutefaut agrave un argument de type pointeur on prendra

garde de seacuteparer par au moins un espace les caractegraveres et = dans le cas contraire ils

seraient interpreacuteteacutes comme lopeacuterateur daffectation = ce qui conduirait agrave une erreur

Les speacutecificiteacutes du C++CHAPITRE 4

42

2 Les valeurs par deacutefaut ne sont pas neacutecessairement des expressions constantes Elles ne

peuvent toutefois pas faire intervenir de variables locales1

En Java

Les arguments par deacutefaut nrsquoexistent pas en Java

5 Surdeacutefinition de fonctionsDune maniegravere geacuteneacuterale on parle de surdeacutefinition2 lorsquun mecircme symbole possegravede plu-

sieurs significations diffeacuterentes le choix de lune des significations se faisant en fonction du

contexte Cest ainsi que C comme la plupart des langages eacutevolueacutes utilise la surdeacutefinition

dun certain nombre dopeacuterateurs Par exemple dans une expression telle que

a + b

la signification du + deacutepend du type des opeacuterandes a et b suivant le cas il pourra sagir dune

addition dentiers ou dune addition de flottants De mecircme le symbole peut deacutesigner sui-

vant le contexte une multiplication dentiers de flottants ou une indirection3

Un des grands atouts de C++ est de permettre la surdeacutefinition de la plupart des opeacuterateurs

(lorsquils sont associeacutes agrave la notion de classe) Lorsque nous eacutetudierons cet aspect nous ver-

rons quil repose en fait sur la surdeacutefinition de fonctions Cest cette derniegravere possibiliteacute que

nous proposons deacutetudier ici pour elle-mecircme

Pour pouvoir employer plusieurs fonctions de mecircme nom il faut bien sucircr un critegravere (autre

que le nom) permettant de choisir la bonne fonction En C++ ce choix est baseacute (comme pour

les opeacuterateurs citeacutes preacuteceacutedemment en exemple) sur le type des arguments Nous commence-

rons par vous preacutesenter un exemple complet montrant comment mettre en œuvre la surdeacutefini-

tion de fonctions Nous examinerons ensuite diffeacuterentes situations dappel dune fonction

surdeacutefinie avant deacutetudier les regravegles deacutetailleacutees qui preacutesident au choix de la bonne fonction

51 Mise en œuvre de la surdeacutefinition de fonctionsNous allons deacutefinir et utiliser deux fonctions nommeacutees sosie La premiegravere posseacutedera un argu-

ment de type int la seconde un argument de type double ce qui les diffeacuterencie bien lune de

lautre Pour que lrsquoexeacutecution du programme montre clairement la fonction effectivement

appeleacutee nous introduisons dans chacune une instruction daffichage approprieacutee Dans le pro-

1 Ni la valeur this pour les fonctions membres (this sera eacutetudieacute au chapitre 5)

2 De overloading parfois traduit par surcharge

3 On parle parfois de deacutereacutefeacuterence cela correspond agrave des situations telles que

int a

a = 5

5 - Surdeacutefinition de fonctions43

gramme dessai nous nous contentons dappeler successivement la fonction surdeacutefinie sosie

une premiegravere fois avec un argument de type int une seconde fois avec un argument de type

double

include ltiostreamgtusing namespace std

void sosie (int) les prototypesvoid sosie (double)

main() le programme de test int n=5

double x=25 sosie (n) sosie (x) void sosie (int a) la premiegravere fonction cout ltlt sosie numero I a = ltlt a ltlt n void sosie (double a) la deuxiegraveme fonction cout ltlt sosie numero II a = ltlt a ltlt n

sosie numero I a = 5sosie numero II a = 25

Exemple de surdeacutefinition de la fonction sosie

Vous constatez que le compilateur a bien mis en place lappel de la bonne fonction sosie au

vu de la liste darguments (ici reacuteduite agrave un seul)

52 Exemples de choix dune fonction surdeacutefinieNotre preacuteceacutedent exemple eacutetait simple dans la mesure ougrave nous appelions toujours la fonction

sosie avec un argument ayant exactement lun des types preacutevus dans les prototypes (int ou

double) On peut se demander ce qui se produirait si nous lappelions par exemple avec un

argument de type char long ou pointeur ou si lon avait affaire agrave des fonctions comportant

plusieurs arguments

Avant de preacutesenter les regravegles de deacutetermination dune fonction surdeacutefinie examinons tout

dabord quelques situations assez intuitives

Les speacutecificiteacutes du C++CHAPITRE 4

44

Exemple 1void sosie (int) sosie Ivoid sosie (double) sosie IIchar c float y sosie(c) appelle sosie I apregraves conversion de c en intsosie(y) appelle sosie II apregraves conversion de y en doublesosie(d) appelle sosie I apregraves conversion de d en int

Exemple 2void affiche (char ) affiche Ivoid affiche (void ) affiche IIchar ad1 double ad2 affiche (ad1) appelle affiche Iaffiche (ad2) appelle affiche II apregraves conversion de ad2 en void

Exemple 3void essai (int double) essai Ivoid essai (double int) essai IIint n p double z char c essai(nz) appelle essai Iessai(cz) appelle essai I apregraves conversion de c en intessai(np) erreur de compilation

Compte tenu de son ambiguiumlteacute le dernier appel conduit agrave une erreur de compilation En effet

deux possibiliteacutes existent ici convertir p en double sans modifier n et appeler essai I ou au

contraire convertir n en double sans modifier p et appeler essai II

Exemple 4void test (int n=0 double x=0) test Ivoid test (double y=0 int p=0) test IIint n double z test(nz) appelle test Itest(zn) appelle test IItest(n) appelle test Itest(z) appelle test IItest() erreur de compilation compte tenu de lrsquoambiguiumlteacute

Exemple 5

Avec ces deacuteclarations

void truc (int) truc Ivoid truc (const int) truc II

vous obtiendrez une erreur de compilation En effet C++ na pas preacutevu de distinguer int de

const int Cela se justifie par le fait que les deux fonctions truc recevant une copie de linfor-

5 - Surdeacutefinition de fonctions45

mation agrave traiter il nrsquoy a aucun risque de modifier la valeur originale Notez bien qursquoici

lrsquoerreur tient agrave la seule preacutesence des deacuteclarations de chose indeacutependamment drsquoun appel quel-

conque

Exemple 6

En revanche consideacuterez maintenant ces deacuteclarations

void chose (int ) chose Ivoid chose (const int ) chose IIint n = 3 const p = 5

Cette fois la distinction entre int et const int est justifieacutee En effet on peut tregraves bien preacute-

voir que chose I modifie la valeur de la lvalue1 dont elle reccediloit ladresse tandis que chose II

nen fait rien Cette distinction est possible en C+ de sorte que

chose (ampn) appelle chose Ichose (ampp) appelle chose II

Exemple 7

Les reflexions de lrsquoexemple preacuteceacutedent agrave propos des pointeurs srsquoappliquent aux reacutefeacuterences

void chose (int amp) chose Ivoid chose (const int amp) chose IIint n = 3 const int p = 5 chose (n) appelle chose Ichose (p) appelle chose II

Remarque

En dehors de la situation examineacutee ici on notera que le mode de transmission (reacutefeacuterence

ou valeur) nrsquointervient pas dans le choix drsquoune fonction surdeacutefinie Par exemple les

deacuteclarations suivantes conduiraient agrave une erreur de compilation due agrave leur ambiguiumlteacute

(indeacutependamment de tout appel de chose)

void chose (int amp) void chose (int)

Exemple 8

Lrsquoexemple preacuteceacutedent a montreacute comment on pouvait distinguer entre deux fonctions agissant

lrsquoune sur une reacutefeacuterence lrsquoautre sur une reacutefeacuterence constante Mais lrsquoutilisation de reacutefeacuterences

possegravede des conseacutequences plus subtiles comme le montrent ces exemples (revoyez eacuteventuel-

lement le paragraphe 334)

1 Rappelons quon nomme lvalue la reacutefeacuterence agrave quelque chose dont on peut modifier la valeur Ce terme provient de

la contraction de left value qui deacutesigne quelque chose qui peut apparaicirctre agrave gauche dun opeacuterateur daffectation

Les speacutecificiteacutes du C++CHAPITRE 4

46

void chose (int amp) chose Ivoid chose (const int amp) chose IIint n float x chose (n) appelle chose Ichose (2) appelle chose II apregraves copie eacuteventuelle de 2 dans un entier1 temporaire dont la reacutefeacuterence sera transmise agrave chosechose (x) appelle chose II apregraves conversion de la valeur de x en un entier temporaire dont la reacutefeacuterence sera transmise agrave chose

53 Regravegles de recherche dune fonction surdeacutefiniePour linstant nous vous preacutesenterons plutocirct la philosophie geacuteneacuterale ce qui sera suffisant

pour leacutetude des chapitres suivants Au cours de cet ouvrage nous serons ameneacute agrave vous

apporter des informations compleacutementaires De plus lensemble de toutes ces regravegles sont

reprises en Annexe A

531 Cas des fonctions agrave un argument

Le compilateur recherche la meilleure correspondance possible Bien entendu pour pou-

voir deacutefinir ce quest cette meilleure correspondance il faut quil dispose dun critegravere deacuteva-

luation Pour ce faire il est preacutevu diffeacuterents niveaux de correspondance

1) Correspondance exacte on distingue bien les uns des autres les diffeacuterents types de base

en tenant compte de leur eacuteventuel attribut de signe2 de plus comme on la vu dans les

exemples preacuteceacutedents lattribut const peut intervenir dans le cas de pointeurs ou de reacutefeacuteren-

ces

2) Correspondance avec promotions numeacuteriques cest-agrave-dire essentiellement

char et short ndashgt int

float ndashgt double

Rappelons qursquoun argument transmis par reacutefeacuterence ne peut ecirctre soumis agrave aucune conver-

sion sauf lorsqursquoil srsquoagit de la reacutefeacuterence agrave une constante

3) Conversions dites standard il sagit des conversions leacutegales en C++ cest-agrave-dire de celles

qui peuvent ecirctre imposeacutees par une affectation (sans opeacuterateur de cast) cette fois il peut

sagir de conversions deacutegradantes puisque notamment toute conversion dun type numeacute-

rique en un autre type numeacuterique est accepteacutee

Dautres niveaux sont preacutevus en particulier on pourra faire intervenir ce que lon nomme

des conversions deacutefinies par lutilisateur (CDU) qui ne seront eacutetudieacutees qursquoau

chapitre 10

1 Comme lrsquoautorise la norme lrsquoimpleacutementation est libre de faire ou non une copie dans ce cas

2 Attention en C++ char est diffeacuterent de signed char et de unsigned char

5 - Surdeacutefinition de fonctions47

Lagrave encore un argument transmis par reacutefeacuterence ne pourra ecirctre soumis agrave aucune conversion

sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante

La recherche sarrecircte au premier niveau ayant permis de trouver une correspondance qui doit

alors ecirctre unique Si plusieurs fonctions conviennent au mecircme niveau de correspondance il y

a erreur de compilation due agrave lambiguiumlteacute rencontreacutee Bien entendu si aucune fonction ne

convient agrave aucun niveau il y a aussi erreur de compilation

532 Cas des fonctions agrave plusieurs arguments

Lideacutee geacuteneacuterale est quil doit se deacutegager une fonction meilleure que toutes les autres Pour

ce faire le compilateur seacutelectionne pour chaque argument la ou les fonctions qui reacutealisent

la meilleure correspondance (au sens de la hieacuterarchie deacutefinie ci-dessus) Parmi lensemble des

fonctions ainsi seacutelectionneacutees il choisit celle (si elle existe et si elle est unique) qui reacutealise

pour chaque argument une correspondance au moins eacutegale agrave celle de toutes les autres fonc-

tions1

Si plusieurs fonctions conviennent lagrave encore on aura une erreur de compilation due agrave lambi-

guiumlteacute rencontreacutee De mecircme si aucune fonction ne convient il y aura erreur de compilation

Notez que les fonctions comportant un ou plusieurs arguments par deacutefaut sont traiteacutees

comme si plusieurs fonctions diffeacuterentes avaient eacuteteacute deacutefinies avec un nombre croissant

darguments

533 Le meacutecanisme de la surdeacutefinition de fonctions

Jusquici nous avons examineacute la maniegravere dont le compilateur faisait le choix de la bonne

fonction en raisonnant sur un seul fichier source agrave la fois Mais il serait tout agrave fait

envisageable

bull de compiler dans un premier temps un fichier source contenant la deacutefinition de nos deux

fonctions nommeacutees sosie

bull dutiliser ulteacuterieurement ces fonctions dans un autre fichier source en nous contentant den

fournir les prototypes

Or pour que cela soit possible leacutediteur de liens doit ecirctre en mesure deffectuer le lien entre le

choix opeacutereacute par le compilateur et la bonne fonction figurant dans un autre module objet

Cette reconnaissance est baseacutee sur la modification par le compilateur des noms externes

des fonctions celui-ci fabrique un nouveau nom fondeacute dune part sur le nom interne de la

fonction dautre part sur le nombre et la nature de ses arguments

Il est tregraves important de noter que ce meacutecanisme sapplique agrave toutes les fonctions quelles

soient surdeacutefinies ou non (il est impossible de savoir si une fonction compileacutee dans un fichier

source sera surdeacutefinie dans un autre) On voit donc quun problegraveme se pose degraves que lon sou-

haite utiliser dans un programme C++ une fonction eacutecrite et compileacutee en C (ou dans un autre

1 Ce qui revient agrave dire quil considegravere lintersection des ensembles constitueacutes des fonctions reacutealisant la meilleure

correspondance pour chacun des arguments

Les speacutecificiteacutes du C++CHAPITRE 4

48

langage utilisant les mecircmes conventions dappels de fonction notamment lassembleur ou le

Fortran) En effet une telle fonction ne voit pas son nom modifieacute suivant le meacutecanisme eacutevo-

queacute Une solution existe toutefois deacuteclarer une telle fonction en faisant preacuteceacuteder son proto-

type de la mention extern C Par exemple si nous avons eacutecrit et compileacute en C une fonction

den-tecircte

double fct (int n char c)

et que nous souhaitons lrsquoutiliser dans un programme C++ il nous suffira de fournir son pro-

totype de la faccedilon suivante

extern C double fct (int char)

Remarques

1 Il existe une forme collective de la deacuteclaration extern qui se preacutesente ainsi

extern C void exple (int) double chose (int char float)

2 Le problegraveme eacutevoqueacute pour les fonctions C (assembleur ou Fortran) se pose a priori

pour toutes les fonctions de la bibliothegraveque standard C que lon reacuteutilise en C++ En

fait dans la plupart des environnements cet aspect est automatiquement pris en charge

au niveau des fichiers en-tecircte correspondants (ils contiennent des deacuteclarations extern

conditionnelles)

3 Il est possible drsquoemployer au sein drsquoun mecircme programme C++ une fonction C (assem-

bleur ou Fortran) et une ou plusieurs autres fonctions C++ de mecircme nom (mais drsquoargu-

ments diffeacuterents) Par exemple nous pouvons utiliser dans un programme C++ la

fonction fct preacuteceacutedente et deux fonctions C++ drsquoen-tecircte

void fct (double x) void fct (float y)

en proceacutedant ainsi

extern C void fct (int) void fct (double) void fct (float)

Suivant la nature de lrsquoargument drsquoappel de fct il y aura bien appel de lrsquoune des trois

fonctions fct Notez qursquoil nrsquoest pas possible de mentionner plusieurs fonctions C de

nom fct

En Java

La surdeacutefinition des fonctions existe en Java Les regravegles de recherche de la bonne fonc-

tion sont extrecircmement simples car il existe peu de possibiliteacutes de conversions implicites

6 - Les opeacuterateurs new et delete49

6 Les opeacuterateurs new et deleteEn langage C la gestion dynamique de meacutemoire fait appel agrave des fonctions de la bibliothegraveque

standard telles que malloc et free Bien entendu comme toutes les fonctions standard celles-

ci restent utilisables en C++

Mais dans le contexte de la Programmation Orienteacutee Objet C++ a introduit deux nouveaux

opeacuterateurs new et delete particuliegraverement adapteacutes agrave la gestion dynamique dobjets Ces opeacute-

rateurs peuvent eacutegalement ecirctre utiliseacutes pour des variables classiques1 Dans ces conditions

par souci dhomogeacuteneacuteiteacute et de simpliciteacute il est plus raisonnable en C++ dutiliser systeacutemati-

quement ces opeacuterateurs que lon ait affaire agrave des variables classiques ou agrave des objets Cest

pourquoi nous vous les preacutesentons degraves maintenant

61 Exemples dutilisation de new

Exemple 1Avec la deacuteclaration

int ad

linstruction

ad = new int

permet dallouer lespace meacutemoire neacutecessaire pour un eacuteleacutement de type int et daffecter agrave ad

ladresse correspondante En C vous auriez obtenu le mecircme reacutesultat en eacutecrivant (lopeacuterateur

de cast ici int eacutetant facultatif)

ad = (int ) malloc (sizeof (int))

Comme les deacuteclarations ont un emplacement libre en C++ vous pouvez mecircme deacuteclarer la

variable ad au moment ougrave vous en avez besoin en eacutecrivant par exemple

int ad = new int

Exemple 2Avec la deacuteclaration

char adc

linstruction

adc = new char[100]

alloue lemplacement neacutecessaire pour un tableau de 100 caractegraveres et place ladresse (de

deacutebut) dans adc En C vous auriez obtenu le mecircme reacutesultat en eacutecrivant

adc = (char ) malloc (100)

1 Un objet eacutetant en fait une variable dun type particulier

Les speacutecificiteacutes du C++CHAPITRE 4

50

62 Syntaxe et rocircle de newLrsquoopeacuterateur unaire (agrave un seul opeacuterande) new sutilise ainsi

new type

ougrave type repreacutesente un type absolument quelconque Il fournit comme reacutesultat un pointeur (de

type type) sur lemplacement correspondant lorsque lallocation a reacuteussi

Lrsquoopeacuterateur new accepte eacutegalement une syntaxe de la forme

new type [n]

ougrave n deacutesigne une expression entiegravere quelconque (non neacutegative) Cette instruction alloue alors

lemplacement neacutecessaire pour n eacuteleacutements du type indiqueacute si lrsquoopeacuteration a reacuteussi elle fournit

en reacutesultat un pointeur (toujours de type type ) sur le premier eacuteleacutement de ce tableau

La norme de C++ preacutevoit quen cas deacutechec new deacuteclenche ce que lon nomme une exception

de type bad_alloc Ce meacutecanisme de gestion des exceptions est eacutetudieacute en deacutetail au chapitre

17 Vous verrez que si rien nest preacutevu par le programmeur pour traiter une exception le pro-

gramme sinterrompt

Il est cependant possible de demander agrave new de se comporter diffeacuteremment en cas drsquoeacutechec

comme nous le verrons aux paragraphes 65 et 66

Remarque

En toute rigueur new peut ecirctre utiliseacute pour allouer un emplacement pour un tableau agrave plu-

sieurs dimensions par exemple

new type [n] [10]

Dans ce cas new fournit un pointeur sur des tableaux de 10 entiers (dont le type se note

type () [10]) Drsquoune maniegravere geacuteneacuterale la premiegravere dimension peut ecirctre une expression

entiegravere quelconque les autres doivent obligatoirement ecirctre des expressions constantes

Cette possibiliteacute est rarement utiliseacutee en pratique

En Java

Il existe eacutegalement un opeacuterateur new Mais il ne srsquoapplique pas aux types de base il est

reacuteserveacute aux objets

63 Exemples dutilisation de lopeacuterateur deleteLorsque lon souhaite libeacuterer un emplacement alloueacute preacutealablement par new on doit absolu-

ment utiliser lopeacuterateur delete Ainsi pour libeacuterer les emplacements creacuteeacutes dans les exemples

du paragraphe 61 on eacutecrit

delete ad

6 - Les opeacuterateurs new et delete51

pour lemplacement alloueacute par

ad = new int

et

delete adc

pour lemplacement alloueacute par

adc = new char [100]

64 Syntaxe et rocircle de lopeacuterateur deleteLa syntaxe usuelle de lopeacuterateur delete est la suivante (adresse eacutetant une expression devant

avoir comme valeur un pointeur sur un emplacement alloueacute par new)

delete adresse

Notez bien que le comportement du programme nest absolument pas deacutefini lorsque

bull vous libeacuterez par delete un emplacement deacutejagrave libeacutereacute nous verrons que des preacutecautions

devront ecirctre prises lorsque lon deacutefinit des constructeurs et des destructeurs de certains

objets

bull vous fournissez agrave delete une mauvaise adresse ou un pointeur obtenu autrement que par

new (malloc par exemple)

Remarque

Il existe une autre syntaxe de delete de la forme delete [] adresse qui nintervient que

dans le cas de tableaux dobjets et dont nous parlerons au paragraphe 7 du chapitre 7

65 Lrsquoopeacuterateur new (nothrow)Comme lrsquoa montreacute le paragraphe 62 new deacuteclenche une exception bad_alloc en cas

drsquoeacutechec Dans les versions drsquoavant la norme new fournissait (comme malloc) un pointeur nul

en cas drsquoeacutechec Avec la norme on peut retrouver ce comportement en utilisant au lieu de

new lrsquoopeacuterateur new(stdnothrow) (std est superflu degraves lors qursquoon a bien deacuteclareacute cet

espace de nom par using)

A titre drsquoexemple voici un programme qui alloue des emplacements pour des tableaux

dentiers dont la taille est fournie en donneacutee et ce jusquagrave ce quil ny ait plus suffisam-

ment de place (notez quici nous utilisons toujours la mecircme variable adr pour recevoir

les diffeacuterentes adresses des tableaux ce qui dans un programme reacuteel ne serait probable-

ment pas acceptable)

include ltcstdlibgt ancien ltstdlibhgt pour exitinclude ltiostreamgtusing namespace std

Les speacutecificiteacutes du C++CHAPITRE 4

52

main() long taille int adr int nbloc cout ltlt Taille souhaitee cin gtgt taille for (nbloc=1 nbloc++) adr = new (nothrow) int [taille] if (adr==0) cout ltlt manque de memoire n exit (-1) cout ltlt Allocation bloc numero ltlt nbloc ltlt n

Taille souhaitee 4000000Allocation bloc numero 1Allocation bloc numero 2Allocation bloc numero 3 manque de memoire

Exemple drsquoutilisation de new(nothrow)

66 Gestion des deacutebordements de meacutemoire avec set_new_handler

Comme on lrsquoa vu au paragraphe 62 new deacuteclenche une exception bad_alloc en cas drsquoeacutechec

Mais il est eacutegalement possible de deacutefinir une fonction de votre choix et de demander quelle

soit appeleacutee en cas de manque de meacutemoire Il vous suffit pour cela dappeler la fonction

set_new_handler en lui fournissant en argument ladresse de la fonction que vous avez preacute-

vue pour traiter le cas de manque de meacutemoire Voici comment nous pourrions adapter

lrsquoexemple preacuteceacutedent

include ltcstdlibgt ancien ltstdlibhgt pour exitinclude ltnewgt pour set_new_handler (parfois ltnewhgt)include ltiostreamgtusing namespace std

main() void deborde () proto fonction appeleacutee en cas manque meacutemoire set_new_handler (deborde) long taille int adr int nbloc cout ltlt Taille de bloc souhaitee (en entiers) cin gtgt taille

7 - La speacutecification inline53

for (nbloc=1 nbloc++) adr = new int [taille] cout ltlt Allocation bloc numero ltlt nbloc ltlt n

void deborde () fonction appeleacutee en cas de manque meacutemoire cout ltlt Memoire insuffisanten cout ltlt Abandon de lexecutionn exit (-1)

Taille de bloc souhaitee (en entiers) 4000000Allocation bloc numero 1Allocation bloc numero 2Allocation bloc numero 3Memoire insuffisante pour allouer 16000000 octetsAbandon de lexecutionPress any key to continue

Exemple drsquoutilisation de set_new_handler

7 La speacutecification inline

71 Rappels concernant les macros et les fonctionsEn langage C vous savez quil existe deux notions assez voisines agrave savoir les macros et les

fonctions Une macro et une fonction sutilisent apparemment de la mecircme faccedilon en faisant

suivre leur nom dune liste drsquoarguments entre parenthegraveses Cependant

bull les instructions correspondant agrave une macro sont incorporeacutees agrave votre programme1 chaque

fois que vous lappelez

bull les instructions correspondant agrave une fonction sont geacuteneacutereacutees une seule fois2 agrave chaque ap-

pel il y aura seulement mise en place des instructions neacutecessaires pour eacutetablir la liaison en-

tre le programme3 et la fonction sauvegarde de leacutetat courant (valeurs de certains

registres par exemple) recopie des valeurs des arguments branchement avec conservation

de ladresse de retour recopie de la valeur de retour restauration de leacutetat courant et retour

dans le programme Toutes ces instructions neacutecessaires agrave la mise en œuvre de lappel de la

1 En toute rigueur lincorporation est reacutealiseacutee au niveau du preacuteprocesseur lequel introduit les instructions en langage

C correspondant agrave lexpansion de la macro ces instructions peuvent dailleurs varier dun appel agrave un autre

2 Par le compilateur cette fois sous forme dinstructions en langage machine

3 En toute rigueur il faudrait plutocirct parler de fonction appelante

Les speacutecificiteacutes du C++CHAPITRE 4

54

fonction nexistent pas dans le cas de la macro On peut donc dire que la fonction permet de

gagner de lespace meacutemoire en contrepartie dune perte de temps dexeacutecution Bien entendu

la perte de temps sera dautant plus faible que la fonction sera de taille importante

bull contrairement aux fonctions les macros peuvent entraicircner des effets de bord indeacutesirables

ou du moins impreacutevus Voici deux exemples

- Si une macro introduit de nouvelles variables celles-ci peuvent interfeacuterer avec dautres

variables de mecircme nom Ce risque nexiste pas avec une fonction sauf si lon utilise vo-

lontairement cette fois des variables globales

- Une macro deacutefinie par

carre(x) x x

et appeleacutee par

carre(a++)

geacuteneacuterera les instructions

a++ a++

qui increacutementent deux fois la variable a

En C lorsque lon a besoin dune fonction courte et que le temps drsquoexeacutecution est primordial

on fait geacuteneacuteralement appel agrave une macro malgreacute les inconveacutenients que cela implique En C++

il existe une solution plus satisfaisante utiliser une fonction en ligne (inline)

72 Utilisation de fonctions en ligneUne fonction en ligne se deacutefinit et sutilise comme une fonction ordinaire agrave la seule diffeacute-

rence quon fait preacuteceacuteder son en-tecircte de la speacutecification inline En voici un exemple

include ltcmathgt ancien ltmathhgt pour sqrtinclude ltiostreamgtusing namespace std deacutefinition drsquoune fonction en ligne inline double norme (double vec[3]) int i double s = 0

for (i=0 ilt3 i++) s+= vec[i] vec[i] return sqrt(s) exemple drsquoutilisation main() double v1[3] v2[3] int i for (i=0 ilt3 i++) v1[i] = i v2[i] = 2i-1

7 - La speacutecification inline55

cout ltlt norme de v1 ltlt norme(v1) ltlt n cout ltlt norme de v2 ltlt norme(v2) ltlt n

norme de v1 223607norme de v2 331662

Exemple de deacutefinition et dutilisation dune fonction en ligne

La fonction norme a pour but de calculer la norme dun vecteur agrave trois composantes quon lui

fournit en argument

La preacutesence du mot inline demande au compilateur de traiter la fonction norme diffeacuteremment

dune fonction ordinaire A chaque appel de norme le compilateur devra incorporer au sein

du programme les instructions correspondantes (en langage machine1) Le meacutecanisme habi-

tuel de gestion de lappel et du retour nexistera plus (il ny a plus besoin de sauvegardes

recopies) ce qui permet une eacuteconomie de temps En revanche les instructions correspon-

dantes seront geacuteneacutereacutees agrave chaque appel ce qui consommera une quantiteacute de meacutemoire croissant

avec le nombre dappels

Il est tregraves important de noter que par sa nature mecircme une fonction en ligne doit ecirctre deacutefinie

dans le mecircme fichier source que celui ougrave on lutilise Elle ne peut plus ecirctre compileacutee

seacutepareacutement Cela explique quil nrsquoest pas neacutecessaire de deacuteclarer une telle fonction (sauf si

elle est utiliseacutee au sein dun fichier source avant drsquoecirctre deacutefinie) Ainsi on ne trouve pas dans

notre exemple de deacuteclaration telle que

double norme (double)

Cette absence de possibiliteacute de compilation seacutepareacutee constitue une contrepartie notable aux

avantages offerts par la fonction en ligne En effet pour quune mecircme fonction en ligne

puisse ecirctre partageacutee par diffeacuterents programmes il faudra absolument la placer dans un fichier

en-tecircte2 (comme on le fait avec une macro)

Comparaison entre macro fonction et fonction en ligne

1 Notez quil sagit bien ici dun travail effectueacute par le compilateur lui-mecircme alors que dans le cas dune macro un

travail comparable eacutetait effectueacute par le preacuteprocesseur

2 A moins den eacutecrire plusieurs fois la deacutefinition ce qui ne serait pas raisonnable compte tenu des risques derreurs

que cela comporte

Avantages Inconveacutenients

Macro - Eacuteconomie de temps dexeacutecution

- Perte despace meacutemoire- Risque deffets de bord non deacutesireacutes- Pas de compilation seacutepareacutee possible

Fonction - Eacuteconomie despace meacutemoire- Compilation seacutepareacutee possible

- Perte de temps dexeacutecution

Fonction en ligne - Eacuteconomie de temps dexeacutecution

- Perte despace meacutemoire- Pas de compilation seacutepareacutee possible

Les speacutecificiteacutes du C++CHAPITRE 4

56

Remarque

La deacuteclaration inline constitue une demande effectueacutee aupregraves du compilateur Ce dernier

peut eacuteventuellement (par exemple si la fonction est volumineuse) ne pas lintroduire en

ligne et en faire une fonction ordinaire De mecircme si vous utilisez quelque part (au sein du

fichier source concerneacute) ladresse dune fonction deacuteclareacutee inline le compilateur en fera

une fonction ordinaire (dans le cas contraire il serait incapable de lui attribuer une

adresse et encore moins de mettre en place un eacuteventuel appel dune fonction situeacutee agrave cette

adresse)

8 Les espaces de nomsLorsque lon doit utiliser plusieurs bibliothegraveques dans un programme on peut ecirctre confronteacute

au problegraveme dit de pollution de lespace des noms lieacute agrave ce quun mecircme identificateur peut

tregraves bien avoir eacuteteacute utiliseacute par plusieurs bibliothegraveques Le mecircme problegraveme peut se poser agrave un

degreacute moindre toutefois lors du deacuteveloppement de gros programmes Cest la raison pour

laquelle la norme ANSI du C++ a introduit le concept drsquoespace de noms Il sagit simple-

ment de donner un nom agrave un espace de deacuteclarations en proceacutedant ainsi

namespace une_bibli deacuteclarations usuelles

Pour se reacutefeacuterer agrave des identificateurs deacutefinis dans cet espace de noms on utilisera une instruc-

tion using

using namespace une_bibli ici les identificateurs de une_bibli sont connus

On peut lever lambiguiumlteacute risquant dapparaicirctre lorsquon utilise plusieurs espaces de noms

comportant des identificateurs identiques il suffit pour cela de faire appel agrave lopeacuterateur de

reacutesolution de porteacutee par exemple

une_biblipoint on se reacutefegravere agrave lidentificateur point de lespace de noms une_bibli

On peut aussi utiliser linstruction using pour faire un choix permanent

using une_biblipoint doreacutenavant lidentificateur point employeacute seul correspondra agrave celui deacutefini dans lespace de noms une_bibli

Tous les identificateurs des fichiers en-tecircte standard sont deacutefinis dans lrsquoespace de noms std

aussi est-il neacutecessaire de recourir systeacutematiquement agrave lrsquoinstruction

using namespace std utilisation des fichiers en-tecircte standard

Geacuteneacuteralement cette instruction figurera agrave un niveau global comme nous lrsquoavons fait dans les

exemples preacuteceacutedents En revanche elle ne peut apparaicirctre que si lrsquoespace de noms qursquoelle

mentionne existe deacutejagrave en pratique cela signifie que cette instruction sera placeacutee apregraves

lrsquoinclusion des fichiers en-tecircte

9 - Le type bool57

Ces quelques consideacuterations seront suffisantes pour lrsquoinstant Les espaces de noms seront

eacutetudieacutes en deacutetail au chapitre 24

Remarque

Certains environnements ne respectent pas encore la norme sur le plan des espaces de

noms Lrsquoinstruction using peut alors ecirctre indisponible En geacuteneacuteral dans de tels environne-

ments les fichiers en-tecircte sont encore suffixeacutes par h Certains environnements permettent

drsquoutiliser indiffeacuteremment ltiostreamgt avec using ou ltiostreamhgt sans using1

9 Le type boolCe type est tout naturellement formeacute de deux valeurs noteacutees true et false En theacuteorie les

reacutesultats des comparaisons ou des combinaisons logiques doivent ecirctre de ce type Toutefois

il existe des conversions implicites

bull de bool en numeacuterique true devenant 1 et false devenant 0

bull de numeacuterique (y compris flottant) en bool toute valeur non nulle devenant true et zeacutero de-

venant false

Dans ces conditions tout se passe finalement comme si bool eacutetait un type eacutenumeacutereacute ainsi

deacutefini

typedef enum false=0 true bool

En deacutefinitive ce type bool sert surtout agrave apporter plus de clarteacute aux programmes sans remet-

tre en cause quoi que ce soit

10 Les nouveaux opeacuterateurs de castEn C++ comme en C il est possible de reacutealiser des conversions explicites agrave laide dun opeacutera-

teur de cast Les conversions accepteacutees comportent naturellement toutes les conversions

implicites leacutegales auxquelles sajoutent quelques autres pouvant ecirctre deacutegradantes ou deacutepen-

dantes de limpleacutementation

La norme ANSI de C++ a conserveacute ces possibiliteacutes tout en proposant de nouveaux opeacutera-

teurs de cast plus eacutevocateurs de la nature de la conversion et de sa portabiliteacute eacuteventuelle Ils

sont formeacutes comme les opeacuterateurs classiques agrave laide du type souhaiteacute compleacuteteacute dun mot cleacute

preacutecisant le type de conversion

bull const_cast pour ajouter ou supprimer agrave un type lun des modificateurs const ou volatile (les

types de deacutepart et drsquoarriver ne devant diffeacuterer que par ces modificateurs)

1 Une telle instruction using provoquera une erreur si aucun fichier en-tecircte se reacutefeacuterant agrave lrsquoespace de noms std nrsquoa eacuteteacute

inclus Ce sera notamment le cas si on se limite agrave ltiostreamhgt

Les speacutecificiteacutes du C++CHAPITRE 4

58

bull reinterpret_cast pour les conversions dont le reacutesultat deacutepend de limpleacutementation typique-

ment il sagit des conversions dentier vers pointeur et de pointeur vers entier

bull static_cast pour les conversions indeacutependantes de limpleacutementation En fait les conversions

de pointeur vers pointeur entrent dans cette cateacutegorie malgreacute les diffeacuterences qui peuvent ap-

paraicirctre agrave cause des contraintes dalignement propres agrave chaque impleacutementation

Voici quelques exemples commenteacutes

include ltiostreamgtusing namespace std

main () int n = 12 const int ad1 = ampn int ad2 ad2 = (int ) ad1 ancienne forme conseilleacutee (ad2 = ad1 serait rejeteacutee) ad2 = const_cast ltint gt (ad1) forme ANSI conseilleacutee ad1 = ad2 leacutegale ad1 = (const int ) ad2 forme ancienne conseilleacutee ad1 = const_cast ltconst int gt (ad2) forme ANSI conseilleacutee

const int p = 12 const int const ad3 = ampp int ad4

ad4 = (int ) ad3 ancienne forme conseilleacutee (ad4 = ad3 serait rejeteacutee) ad4 = const_cast ltint gt (ad3) forme ANSI conseilleacutee

Exemples dutilisation de lopeacuterateur const_cast ltgt

include ltiostreamgtusing namespace std

main () long n int adi adi = (int ) n ancienne forme conseilleacutee (adi = n serait rejeteacutee) adi = reinterpret_cast ltint gt (n) forme ANSI conseilleacutee

n = (long) adi ancienne forme conseilleacutee (n = adi serait rejeteacutee)

10 - Les nouveaux opeacuterateurs de cast59

n = reinterpret_cast ltlonggt (adi) forme ANSI conseilleacutee

int p p = n accepteacutee p = (int) n ancienne forme conseilleacutee p = static_cast ltintgt (n) forme ANSI conseilleacutee

Exemples dutilisation des opeacuterateurs reinterpret_cast ltgt et static_cast

Remarque

Ces nouveaux opeacuterateurs napportent aucune possibiliteacute de conversion suppleacutementaire Il

nen ira pas de mecircme de lopeacuterateur dynamic_cast eacutetudieacute au chapitre 15

5

Classes et objets

Avec ce chapitre nous abordons veacuteritablement les possibiliteacutes de POO de C++ Comme

nous lavons dit dans le premier chapitre celles-ci reposent entiegraverement sur le concept de

classe Une classe est la geacuteneacuteralisation de la notion de type deacutefini par lutilisateur1 dans

lequel se trouvent associeacutees agrave la fois des donneacutees (membres donneacutees) et des meacutethodes (fonc-

tions membres) En POO pure les donneacutees sont encapsuleacutees et leur accegraves ne peut se faire

que par le biais des meacutethodes C++ vous autorise agrave nrsquoencapsuler quune partie des donneacutees

dune classe (cette deacutemarche reste cependant fortement deacuteconseilleacutee) Il existe mecircme un type

particulier correspondant agrave la geacuteneacuteralisation du type structure du C dans lequel sont effecti-

vement associeacutees des donneacutees et des meacutethodes mais sans aucune encapsulation

En pratique ce nouveau type structure du C++ sera rarement employeacute sous cette forme geacuteneacute-

raliseacutee En revanche sur le plan conceptuel il correspond agrave un cas particulier de la classe il

sagit en effet dune classe dans laquelle aucune donneacutee nest encapsuleacutee Cest pour cette rai-

son que nous commencerons par preacutesenter le type structure de C++ (mot cleacute struct) ce qui

nous permettra dans un premier temps de nous limiter agrave la faccedilon de mettre en œuvre lasso-

ciation des donneacutees et des meacutethodes Nous ne verrons qursquoensuite comment sexprime lencap-

sulation au sein dune classe (mot cleacute class)

Comme une classe (ou une structure) nest quun simple type deacutefini par lutilisateur les objets

possegravedent les mecircmes caracteacuteristiques que les variables ordinaires en particulier en ce qui

concerne leurs diffeacuterentes classes dallocation (statique automatique dynamique) Cepen-

dant pour rester simple et nous consacrer au concept de classe nous ne consideacutererons dans

1 En C les types deacutefinis par lutilisateur sont les structures les unions et les eacutenumeacuterations

Classes et objetsCHAPITRE 5

62

ce chapitre que des objets automatiques (deacuteclareacutes au sein dune fonction quelconque) ce qui

correspond au cas le plus naturel Ce nest qursquoau chapitre 7 que nous aborderons les autres

classes dallocation des objets

Par ailleurs nous introduirons ici les notions tregraves importantes de constructeur et de destruc-

teur (il ny a guegravere dobjets inteacuteressants qui ny fassent pas appel) Lagrave encore compte tenu de

la richesse de cette notion et de son interfeacuterence avec dautres (comme les classes dalloca-

tion) il vous faudra attendre la fin du chapitre 7 pour en connaicirctre toutes les possibiliteacutes

Nous eacutetudierons ensuite ce qursquoon nomme les membres donneacutees statiques ainsi que la

maniegravere de les intialiser Enfin ce premier des trois chapitres consacreacutes aux classes nous per-

mettra de voir comment exploiter une classe en C++ en recourant aux possibiliteacutes de compi-

lation seacutepareacutee

1 Les structures en C++

11 Rappel les structures en CEn C une deacuteclaration telle que

struct point int x int y

deacutefinit un type structure nommeacute point (on dit aussi un modegravele de structure nommeacute point ou

parfois par abus de langage la structure point1) Quant agrave x et y on dit que ce sont des champs

ou des membres2 de la structure point

On deacuteclare ensuite des variables du type point par des instructions telles que

struct point a b

Celle-ci reacuteserve lemplacement pour deux structures nommeacutees a et b de type point Laccegraves

aux membres (champs) de a ou de b se fait agrave laide de lopeacuterateur point () par exemple ay

deacutesigne le membre y de la structure a

En C++ nous allons pouvoir dans une structure associer aux donneacutees constitueacutees par ses

membres des meacutethodes quon nommera fonctions membres Rappelons que puisque les

donneacutees ne sont pas encapsuleacutees dans la structure une telle association est relativement arti-

ficielle et son principal inteacuterecirct est de preacuteparer agrave la notion de classe

1 Dans ce cas il y a ambiguiumlteacute car le mecircme mot structure deacutesignera agrave la fois un type et des objets dun type structure

Comme le contexte permet geacuteneacuteralement de trancher nous utiliserons souvent ce terme

2 Cest plutocirct ce dernier terme que lon emploiera en C++

1 - Les structures en C++63

12 Deacuteclaration dune structure comportant des fonctions membres

Supposons que nous souhaitions associer agrave la structure point preacuteceacutedente trois fonctions

bull initialise pour attribuer des valeurs aux coordonneacutees dun point

bull deplace pour modifier les coordonneacutees dun point

bull affiche pour afficher un point ici nous nous contenterons par souci de simpliciteacute daffi-

cher les coordonneacutees du point

Voici comment nous pourrions deacuteclarer notre structure point

------------ Deacuteclaration du type point ------------- struct point deacuteclaration classique des donneacutees int x int y deacuteclaration des fonctions membre (meacutethodes) void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration dune structure comportant des meacutethodes

Outre la deacuteclaration classique des donneacutees1 apparaissent les deacuteclarations (en-tecirctes) de nos

trois fonctions Notez bien que la deacutefinition de ces fonctions ne figure pas agrave ce niveau de sim-

ple deacuteclaration elle sera reacutealiseacutee par ailleurs comme nous le verrons un peu plus loin

Ici nous avons preacutevu que la fonction membre initialise recevra en arguments deux valeurs de

type int A ce niveau rien nrsquoindique dit lusage qui sera fait de ces deux valeurs Ici bien

entendu nous avons eacutecrit len-tecircte de initialise en ayant agrave lesprit lideacutee quelle affecterait aux

membres x et y les valeurs reccedilues en arguments Les mecircmes remarques srsquoappliquent aux deux

autres fonctions membres

Vous vous attendiez peut-ecirctre agrave trouver pour chaque fonction membre un argument suppleacute-

mentaire preacutecisant la structure (variable) sur laquelle elle doit opeacuterer2 Nous verrons com-

ment cette information sera automatiquement fournie agrave la fonction membre lors de son appel

1 On parle parfois de variables par analogie avec les fonctions membres

2 Pour quune telle information ne soit pas neacutecessaire il faudrait dupliquer les fonctions membres en autant

dexemplaires quil y a de structures de type point ce qui serait particuliegraverement inefficace

Classes et objetsCHAPITRE 5

64

13 Deacutefinition des fonctions membresElle se fait par une deacutefinition (presque) classique de fonction Voici ce que pourrait ecirctre la

deacutefinition de initialise

void pointinitialise (int abs int ord)

x = abs

y = ord

Dans len-tecircte le nom de la fonction est

pointinitialise

Le symbole correspond agrave ce que lon nomme lopeacuterateur de reacutesolution de porteacutee lequel

sert agrave modifier la porteacutee drsquoun identificateur Ici il signifie que lidentificateur initialise con-

cerneacute est celui deacutefini dans point En labsence de ce preacutefixe (point) nous deacutefinirions

effectivement une fonction nommeacutee initialise mais celle-ci ne serait plus associeacutee agrave point il

sagirait dune fonction ordinaire nommeacutee initialise et non plus de la fonction membre ini-

tialise de la structure point

Si nous examinons maintenant le corps de la fonction initialise nous trouvons une

affectation

x = abs

Le symbole abs deacutesigne classiquement la valeur reccedilue en premier argument Mais x quant agrave

lui nest ni un argument ni une variable locale En fait x deacutesigne le membre x correspondant

au type point (cette association eacutetant reacutealiseacutee par le point de len-tecircte) Quelle sera preacuteciseacute-

ment la structure1 concerneacutee Lagrave encore nous verrons comment cette information sera trans-

mise automatiquement agrave la fonction initialise lors de son appel

Nous ninsistons pas sur la deacutefinition des deux autres fonctions membres vous trouverez ci-

dessous lensemble des deacutefinitions des trois fonctions

----- Deacutefinition des fonctions membres du type point ----

include ltiostreamgt

using namespace std

void pointinitialise (int abs int ord)

x = abs y = ord

void pointdeplace (int dx int dy)

x += dx y += dy

1 Ici le terme structure est bien synonyme de variable de type structure

1 - Les structures en C++65

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

Deacutefinition des fonctions membres

Les instructions ci-dessus ne peuvent pas ecirctre compileacutees seules Elles neacutecessitent lrsquoincorpora-

tion des instructions de deacuteclaration correspondantes preacutesenteacutees au paragraphe 12 Celles-ci

peuvent figurer dans le mecircme fichier ou mieux faire lrsquoobjet drsquoun fichier en-tecircte seacutepareacute

14 Utilisation dune structure comportant des fonctions membresDisposant du type point tel quil vient drsquoecirctre deacuteclareacute au paragraphe 12 et deacutefini au paragra-

phe 13 nous pouvons deacuteclarer autant de structures de ce type que nous le souhaitons Par

exemple

point a b 1

deacuteclare deux structures nommeacutees a et b chacune posseacutedant des membres x et y et disposant

des trois meacutethodes initialise deplace et affiche A ce propos nous pouvons dores et deacutejagrave

remarquer que si chaque structure dispose en propre de chacun de ses membres il nen va pas

de mecircme des fonctions membres celles-ci ne sont geacuteneacutereacutees2 quune seule fois (le contraire

conduirait manifestement agrave un gaspillage de meacutemoire )

Laccegraves aux membres x et y de nos structures a et b pourrait se deacuterouler comme en C ainsi

pourrions-nous eacutecrire

ax = 5

Ce faisant nous acceacutederions directement aux donneacutees sans passer par lintermeacutediaire des

meacutethodes Certes nous ne respecterions pas le principe dencapsulation mais dans ce cas

preacutecis (de structure et pas encore de classe) ce serait accepteacute en C++3

On procegravede de la mecircme faccedilon pour lappel dune fonction membre Ainsi

ainitialise (52)

signifie appeler la fonction membre initialise pour la structure a en lui transmettant en

arguments les valeurs 5 et 2 Si lon fait abstraction du preacutefixe a cet appel est analogue agrave un

appel classique de fonction Bien entendu cest justement ce preacutefixe qui va preacuteciser agrave la fonc-

tion membre quelle est la structure sur laquelle elle doit opeacuterer Ainsi linstruction

x = abs

1 Ou struct point a b le mot struct est facultatif en C++

2 Exception faite des fonctions en ligne

3 Ici justement les fonctions membres preacutevues pour notre structure point permettent de respecter le principe

dencapsulation

Classes et objetsCHAPITRE 5

66

de pointinitialise placera dans le champ x de la structure a la valeur reccedilue pour abs (cest-agrave-

dire 5)

Remarques

1 Un appel tel que ainitialise (52) pourrait ecirctre remplaceacute par

ax = 5 ay = 2

Nous verrons preacuteciseacutement quil nen ira plus de mecircme dans le cas dune (vraie) classe

pour peu quon y ait convenablement encapsuleacute les donneacutees

2 En jargon POO on dit eacutegalement que ainitialise (5 2) constitue lenvoi dun mes-

sage (initialise accompagneacute des informations 5 et 2) agrave lobjet a

15 Exemple reacutecapitulatifVoici un programme reprenant la deacuteclaration du type point la deacutefinition de ses fonctions

membres et un exemple drsquoutilisation dans la fonction main

include ltiostreamgtusing namespace std ------------ Deacuteclaration du type point ------------- struct point deacuteclaration classique des donneacutees int x int y deacuteclaration des fonctions membres (meacutethodes) void initialise (int int) void deplace (int int) void affiche ()

----- Deacutefinition des fonctions membres du type point ---- void pointinitialise (int abs int ord) x = abs y = ord void pointdeplace (int dx int dy) x += dx y += dy void pointaffiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n main() point a b ainitialise (5 2) aaffiche () adeplace (-2 4) aaffiche () binitialise (1-1) baffiche ()

2 - Notion de classe67

Je suis en 5 2

Je suis en 3 6

Je suis en 1 -1

Exemple de deacutefinition et dutilisation du type point

Remarques

1 La syntaxe mecircme de lappel dune fonction membre fait que celle-ci reccediloit obligatoire-

ment un argument implicite du type de la structure correspondante Une fonction membre

ne peut pas ecirctre appeleacutee comme une fonction ordinaire Par exemple cette instruction

initialise (31)

sera rejeteacutee agrave la compilation (agrave moins quil nexiste par ailleurs une fonction ordinaire

nommeacutee initialise)

2 Dans la deacuteclaration dune structure il est permis (mais geacuteneacuteralement peu conseilleacute)

dintroduire les donneacutees et les fonctions dans un ordre quelconque (nous avons systeacute-

matiquement placeacute les donneacutees avant les fonctions)

3 Dans notre exemple de programme complet nous avons introduit

ndash la deacuteclaration du type point

ndash la deacutefinition des fonctions membres

ndash la fonction (main) utilisant le type point

Mais bien entendu il serait possible de compiler seacutepareacutement le type point crsquoest drsquoailleurs

ainsi que lrsquoon pourra reacuteutiliser un composant logiciel Nous y reviendrons au

paragraphe 6

4 Il reste possible de deacuteclarer des structures geacuteneacuteraliseacutees anonymes mais cela est tregraves peu

utiliseacute

2 Notion de classeComme nous lavons deacutejagrave dit en C++ la structure est un cas particulier de la classe Plus preacute-

ciseacutement une classe sera une structure dans laquelle seulement certains membres etou fonc-

tions membres seront publics cest-agrave-dire accessibles de lexteacuterieur les autres membres

eacutetant dits priveacutes

La deacuteclaration dune classe est voisine de celle dune structure En effet il suffit

bull de remplacer le mot cleacute struct par le mot cleacute class

Classes et objetsCHAPITRE 5

68

bull de preacuteciser quels sont les membres publics (fonctions ou donneacutees) et les membres priveacutes en

utilisant les mots cleacutes public et private

Par exemple faisons de notre preacuteceacutedente structure point une classe dans laquelle tous les

membres donneacutees sont priveacutes et toutes les fonctions membres sont publiques Sa deacuteclaration

serait simplement la suivante

------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes private facultatif (voir remarque 4) int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration dune classe

Ici les membres nommeacutes x et y sont priveacutes tandis que les fonctions membres nommeacutees ini-

tialise deplace et affiche sont publiques

En ce qui concerne la deacutefinition des fonctions membres dune classe elle se fait exactement

de la mecircme maniegravere que celle des fonctions membres dune structure (quil sagisse de fonc-

tions publiques ou priveacutees) En particulier ces fonctions membres ont accegraves agrave lensemble des

membres (publics ou priveacutes) de la classe

Lutilisation dune classe se fait eacutegalement comme celle dune structure A titre indicatif voici

ce que devient le programme du paragraphe 15 lorsque lon remplace la structure point par la

classe point telle que nous venons de la deacutefinir

include ltiostreamgtusing namespace std ------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes private int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

2 - Notion de classe69

----- Deacutefinition des fonctions membres de la classe point ----

void pointinitialise (int abs int ord)

x = abs y = ord

void pointdeplace (int dx int dy)

x = x + dx y = y + dy

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

-------- Utilisation de la classe point --------

main()

point a b

ainitialise (5 2) aaffiche ()

adeplace (-2 4) aaffiche ()

binitialise (1-1) baffiche ()

Exemple de deacutefinition et dutilisation dune classe (point)

Remarques

1 Dans le jargon de la POO on dit que a et b sont des instances de la classe point ou

encore que ce sont des objets de type point crsquoest geacuteneacuteralement ce dernier terme que

nous utiliserons

2 Dans notre exemple tous les membres donneacutees de point sont priveacutes ce qui correspond

agrave une encapsulation complegravete des donneacutees Ainsi une tentative dutilisation directe (ici

au sein de la fonction main) du membre a

ax = 5

conduirait agrave un diagnostic de compilation (bien entendu cette instruction serait accep-

teacutee si nous avions fait de x un membre public)

En geacuteneacuteral on cherchera agrave respecter le principe dencapsulation des donneacutees quitte agrave

preacutevoir des fonctions membres approprieacutees pour y acceacuteder

3 Dans notre exemple toutes les fonctions membres eacutetaient publiques Il est tout agrave fait

possible den rendre certaines priveacutees Dans ce cas de telles fonctions ne seront plus

accessibles de lrsquoexteacuterieur de la classe Elles ne pourront ecirctre appeleacutees que par dautres

fonctions membres

Classes et objetsCHAPITRE 5

70

4 Les mots cleacutes public et private peuvent apparaicirctre agrave plusieurs reprises dans la deacutefinition

dune classe comme dans cet exemple

class X private public private

Si aucun de ces deux mots napparaicirct au deacutebut de la deacutefinition tout se passe comme si

private y avait eacuteteacute placeacute Cest pourquoi la preacutesence de ce mot neacutetait pas indispensable

dans la deacutefinition de notre classe point

Si aucun de ces deux mots napparaicirct dans la deacutefinition dune classe tous ses membres

seront priveacutes donc inaccessibles Cela sera rarement utile

5 Si lon rend publics tous les membres dune classe on obtient leacutequivalent dune struc-

ture Ainsi ces deux deacuteclarations deacutefinissent le mecircme type point

struct point class point int x public int y int x void initialise () int y void initialise ()

6 Par la suite en lrsquoabsence de preacutecisions suppleacutementaires nous utiliserons le mot classe

pour deacutesigner indiffeacuteremment une vraie classe (class) ou une structure (struct) voire

une union (union) dont nous parlerons un peu plus loin1 De mecircme nous utiliserons le

mot objet pour deacutesigner des instances de ces diffeacuterents types

7 En toute rigueur il existe un troisiegraveme mot protected (proteacutegeacute) qui sutilise de la mecircme

maniegravere que les deux autres il sert agrave deacutefinir un statut intermeacutediaire entre public et

priveacute lequel nintervient que dans le cas de classes deacuteriveacutees Nous en reparlerons au

chapitre 13

8 On peut deacutefinir des classes anonymes comme on pouvait deacutefinir des structures anony-

mes

3 Affectation drsquoobjetsEn C il est possible daffecter agrave une structure la valeur dune autre structure de mecircme type

Ainsi avec les deacuteclarations suivantes

1 La situation de loin la plus reacutepandue restant celle du type class

3 - Affectation drsquoobjets71

struct point int x int y struct point a b

vous pouvez tout agrave fait eacutecrire

a = b

Cette instruction recopie lensemble des valeurs des champs de b dans ceux de a Elle joue le

mecircme rocircle que

ax = bx ay = by

Comme on peut srsquoy attendre cette possibiliteacute srsquoeacutetend aux structures geacuteneacuteraliseacutees (avec fonc-

tions membres) preacutesenteacutees preacuteceacutedemment avec la mecircme signification que pour les structures

usuelles Mais elle srsquoeacutetend aussi aux (vrais) objets de mecircme type Elle correspond tout natu-

rellement agrave une recopie des valeurs des membres donneacutees1 que ceux-ci soient publics ou

non Ainsi avec ces deacuteclarations (notez quici nous avons preacutevu artificiellement x priveacute et y

public)

class point int x public int y point a b

linstruction

b = a

provoquera la recopie des valeurs des membres x et y de a dans les membres correspondants

de b

Contrairement agrave ce qui a eacuteteacute dit pour les structures il nest plus possible ici de remplacer cette

instruction par

bx = ax by = ay

En effet si la deuxiegraveme affectation est leacutegale puisque ici y est public la premiegravere ne lest pas

car x est priveacute2 On notera bien que

1 Les fonctions membres nont aucune raison drsquoecirctre concerneacutees

2 Sauf si laffectation bx = ax eacutetait eacutecrite au sein dune fonction membre de la classe point

Lrsquoaffectation a = b est toujours leacutegale quel que soit le statut (public ou priveacute) des membres donneacutees On peut consideacuterer qursquoelle ne viole pas le principe drsquoencapsu-lation dans la mesure ougrave les donneacutees priveacutees de b (les copies de celles de a apregraves affectation) restent toujours inaccessibles de maniegravere directe

Classes et objetsCHAPITRE 5

72

Remarque

Le rocircle de lopeacuterateur = tel que nous venons de le deacutefinir (recopie des membres donneacutees)

peut paraicirctre naturel ici En fait il ne lest que pour des cas simples Nous verrons des cir-

constances ougrave cette banale recopie saveacuterera insuffisante Ce sera notamment le cas degraves

quun objet comportera des pointeurs sur des emplacements dynamiques la recopie en

question ne concernera pas cette partie dynamique de lobjet elle sera superficielle

Nous reviendrons ulteacuterieurement sur ce point fondamental qui ne trouvera de solution

satisfaisante que dans la surdeacutefinition (pour la classe concerneacutee) de lopeacuterateur = (ou

eacuteventuellement dans lrsquointerdiction de son utilisation)

En Java

En C++ on peut dire que la seacutemantique drsquoaffectation drsquoobjets correspond agrave une recopie

de valeur En Java il srsquoagit simplement drsquoune recopie de reacutefeacuterence apregraves affectation on

se retrouve alors en preacutesence de deux reacutefeacuterences sur un mecircme objet

4 Notions de constructeur et de destructeur

41 IntroductionA priori les objets1 suivent les regravegles habituelles concernant leur initialisation par deacutefaut

seuls les objets statiques voient leurs donneacutees initialiseacutees agrave zeacutero En geacuteneacuteral il est donc

neacutecessaire de faire appel agrave une fonction membre pour attribuer des valeurs aux donneacutees dun

objet Cest ce que nous avons fait pour notre type point avec la fonction initialise

Une telle deacutemarche oblige toutefois agrave compter sur lutilisateur de lobjet pour effectuer lappel

voulu au bon moment En outre si le risque ne porte ici que sur des valeurs non deacutefinies il

nen va plus de mecircme dans le cas ougrave avant mecircme drsquoecirctre utiliseacute un objet doit effectuer un cer-

tain nombre drsquoopeacuterations neacutecessaires agrave son bon fonctionnement par exemple allocation

dynamique de meacutemoire2 veacuterification drsquoexistence de fichier ou ouverture connexion agrave un site

Web Labsence de proceacutedure drsquoinitialisation peut alors devenir catastrophique

C++ offre un meacutecanisme tregraves performant pour traiter ces problegravemes le constructeur Il

sagit dune fonction membre (deacutefinie comme les autres fonctions membres) qui sera appeleacutee

automatiquement agrave chaque creacuteation dun objet Ceci aura lieu quelle que soit la classe dallo-

cation de lobjet statique automatique ou dynamique Notez que les objets automatiques

1 Au sens large du terme

2 Ne confondez pas un objet dynamique avec un objet (par exemple automatique) qui salloue dynamiquement de la

meacutemoire Une situation de ce type sera eacutetudieacutee au prochain chapitre

4 - Notions de constructeur et de destructeur73

auxquels nous nous limitons ici sont creacuteeacutes par une deacuteclaration Ceux de classe dynamique

seront creacuteeacutes par new (nous y reviendrons au chapitre 7)

Un objet pourra aussi posseacuteder un destructeur crsquoest-agrave-dire une fonction membre appeleacutee

automatiquement au moment de la destruction de lobjet Dans le cas des objets automati-

ques la destruction de lobjet a lieu lorsque lon quitte le bloc ou la fonction ougrave il a eacuteteacute

deacuteclareacute

Par convention le constructeur se reconnaicirct agrave ce quil porte le mecircme nom que la classe

Quant au destructeur il porte le mecircme nom que la classe preacuteceacutedeacute drsquoun tilde (~)

42 Exemple de classe comportant un constructeurConsideacuterons la classe point preacuteceacutedente et transformons simplement notre fonction membre

initialise en un constructeur en la renommant point (dans sa deacuteclaration et dans sa deacutefinition)

La deacuteclaration de notre nouvelle classe point se preacutesente alors ainsi

class point deacuteclaration des membres priveacutes int x int y public deacuteclaration des membres publics point (int int) constructeur void deplace (int int) void affiche ()

Deacuteclaration drsquoune classe (point) munie dun constructeur

Comment utiliser cette classe A priori vous pourriez penser que la deacuteclaration suivante

convient toujours

point a

En fait agrave partir du moment ougrave un constructeur est deacutefini il doit pouvoir ecirctre appeleacute (automa-

tiquement) lors de la creacuteation de lobjet a Ici notre constructeur a besoin de deux arguments

Ceux-ci doivent obligatoirement ecirctre fournis dans notre deacuteclaration par exemple

point a(13)

Cette contrainte est en fait un excellent garde-fou

A titre dexemple voici comment pourrait ecirctre adapteacute le programme du paragraphe 2 pour

quil utilise maintenant notre nouvelle classe point

Agrave partir du moment ougrave une classe possegravede un constructeur il nrsquoest plus possible de creacuteer un objet sans fournir les arguments requis par son constructeur (sauf si ce dernier ne possegravede aucun argument )

Classes et objetsCHAPITRE 5

74

include ltiostreamgtusing namespace std ------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes int x int y deacuteclaration des membres publics public point (int int) constructeur void deplace (int int) void affiche () ----- Deacutefinition des fonctions membre de la classe point ---- pointpoint (int abs int ord) x = abs y = ord void pointdeplace (int dx int dy) x = x + dx y = y + dy void pointaffiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n -------- Utilisation de la classe point -------- main() point a(52) aaffiche () adeplace (-2 4) aaffiche () point b(1-1) baffiche ()

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

Exemple dutilisation dune classe (point) munie dun constructeur

Remarques

1 Supposons que lrsquoon deacutefinisse une classe point disposant drsquoun constructeur sans argument

Dans ce cas la deacuteclaration drsquoobjets de type point continuera de srsquoeacutecrire de la mecircme

maniegravere que si la classe ne disposait pas de constructeur

point a deacuteclaration utilisable avec un constructeur sans argument

4 - Notions de constructeur et de destructeur75

Certes la tentation est grande drsquoeacutecrire par analogie avec lrsquoutilisation drsquoun constructeur

comportant des arguments

point a() incorrect

En fait cela repreacutesenterait la deacuteclaration drsquoune fonction nommeacutee a ne recevant aucun

argument et renvoyant un reacutesultat de type point En soi ce ne serait pas une erreur

mais il est eacutevident que toute tentative drsquoutiliser le symbole a comme un objet conduirait

agrave une erreur

2 Nous verrons dans le prochain chapitre que comme toute fonction (membre ou ordi-

naire) un constructeur peut ecirctre surdeacutefini ou posseacuteder des arguments par deacutefaut

3 Lorsqursquoune classe ne deacutefinit aucun constructeur tout se passe en fait comme si elle dis-

posait drsquoun constructeur par deacutefaut ne faisant rien On peut alors dire que lorsqursquoune

classe nrsquoa pas deacutefini de constructeur la creacuteation des objets correspondants se fait en

utilissant ce constructeur par deacutefaut Nous retrouverons drsquoailleurs le mecircme pheacutenomegravene

dans le cas du constructeur de recopie avec cette diffeacuterence toutefois que le construc-

teur par deacutefaut aura alors une action preacutecise

43 Construction et destruction des objetsNous vous proposons ci-dessous un petit programme mettant en eacutevidence les moments ougrave

sont appeleacutes respectivement le constructeur et le destructeur dune classe Nous y deacutefinissons

une classe nommeacutee test ne comportant que ces deux fonctions membres celles-ci affichent

un message nous fournissant ainsi une trace de leur appel En outre le membre donneacutee num

initialiseacute par le constructeur nous permet drsquoidentifier lobjet concerneacute (dans la mesure ougrave

nous nous sommes arrangeacute pour quaucun des objets creacuteeacutes ne contienne la mecircme valeur)

Nous creacuteons des objets automatiques1 de type test agrave deux endroits diffeacuterents dans la fonc-

tion main dune part dans une fonction fct appeleacutee par main dautre part

include ltiostreamgtusing namespace std class test public int num test (int) deacuteclaration constructeur ~test () deacuteclaration destructeur testtest (int n) deacutefinition constructeur num = n cout ltlt ++ Appel constructeur - num = ltlt num ltlt n

1 Rappelons quici nous nous limitons agrave ce cas

Classes et objetsCHAPITRE 5

76

test~test () deacutefinition destructeur cout ltlt -- Appel destructeur - num = ltlt num ltlt n main() void fct (int) test a(1) for (int i=1 ilt=2 i++) fct(i) void fct (int p) test x(2p) notez lexpression (non constante) 2p

++ Appel constructeur - num = 1++ Appel constructeur - num = 2-- Appel destructeur - num = 2++ Appel constructeur - num = 4-- Appel destructeur - num = 4-- Appel destructeur - num = 1

Construction et destruction des objets

44 Rocircles du constructeur et du destructeurDans les exemples preacuteceacutedents le rocircle du constructeur se limitait agrave une initialisation de lobjet

agrave laide des valeurs quil avait reccedilues en arguments Mais le travail reacutealiseacute par le constructeur

peut ecirctre beaucoup plus eacutelaboreacute Voici un programme exploitant une classe nommeacutee hasard

dans laquelle le constructeur fabrique dix valeurs entiegraveres aleacuteatoires quil range dans le mem-

bre donneacutee val (ces valeurs sont comprises entre zeacutero et la valeur qui lui est fournie en

argument)

include ltiostreamgtinclude ltcstdlibgt pour la fonction rand using namespace std class hasard int val[10] public hasard (int) void affiche () hasardhasard (int max) constructeur il tire 10 valeurs au hasard rappel rand fournit un entier entre 0 et RAND_MAX int i for (i=0 ilt10 i++) val[i] = double (rand()) RAND_MAX max void hasardaffiche () pour afficher les 10 valeurs int i for (i=0 ilt10 i++) cout ltlt val[i] ltlt cout ltlt n

4 - Notions de constructeur et de destructeur77

main() hasard suite1 (5) suite1affiche () hasard suite2 (12) suite2affiche ()

0 2 0 4 2 2 1 4 4 32 10 8 6 3 0 1 4 1 1

Un constructeur de valeurs aleacuteatoires

En pratique on preacutefeacuterera drsquoailleurs disposer dune classe dans laquelle le nombre de valeurs

(ici fixeacute agrave dix) pourra ecirctre fourni en argument du constructeur Dans ce cas il est preacutefeacuterable

que lespace (variable) soit alloueacute dynamiquement au lieu decirctre surdimensionneacute Il est alors

tout naturel de faire effectuer cette allocation dynamique par le constructeur lui-mecircme Les

donneacutees de la classe hasard se limiteront ainsi agrave

class hasard int nbval nombre de valeurs int val pointeur sur un tableau de valeurs

Bien sucircr il faudra preacutevoir que le constructeur reccediloive en argument outre la valeur maximale

le nombre de valeurs souhaiteacutees

Par ailleurs agrave partir du moment ougrave un emplacement a eacuteteacute alloueacute dynamiquement il faut se

soucier de sa libeacuteration lorsquil sera devenu inutile Lagrave encore il paraicirct tout naturel de con-

fier ce travail au destructeur de la classe

Voici comment nous pourrions adapter en ce sens lrsquoexemple preacuteceacutedent

include ltiostreamgtinclude ltcstdlibgt pour la fonction rand using namespace std class hasard int nbval nombre de valeurs int val pointeur sur les valeurs public hasard (int int) constructeur ~hasard () destructeur void affiche () hasardhasard (int nb int max) int i val = new int [nbval = nb] for (i=0 iltnb i++) val[i] = double (rand()) RAND_MAX max

Classes et objetsCHAPITRE 5

78

hasard~hasard ()

delete val

void hasardaffiche () pour afficher les nbavl valeurs

int i

for (i=0 iltnbval i++) cout ltlt val[i] ltlt

cout ltlt n

main()

hasard suite1 (10 5) 10 valeurs entre 0 et 5

suite1affiche ()

hasard suite2 (6 12) 6 valeurs entre 0 et 12

suite2affiche ()

0 2 0 4 2 2 1 4 4 3

2 10 8 6 3 0

Exemple de classe dont le constructeur effectue une allocation dynamique de meacutemoire

Dans le constructeur linstruction

val = new [nbval = nb]

joue le mecircme rocircle que

nbval = nb

val = new [nbval]

Remarques

1 Ne confondez pas une allocation dynamique effectueacutee au sein dune fonction membre

dun objet (souvent le constructeur) avec une allocation dynamique dun objet dont nous

parlerons plus tard

2 Lorsquun constructeur se contente dattribuer des valeurs initiales aux donneacutees dun

objet le destructeur est rarement indispensable En revanche il le devient degraves que

comme dans notre exemple lobjet est ameneacute (par le biais de son constructeur ou

dautres fonctions membres) agrave allouer dynamiquement de la meacutemoire

3 Comme nous lavons deacutejagrave mentionneacute degraves quune classe contient comme dans notre

dernier exemple des pointeurs sur des emplacements alloueacutes dynamiquement laffecta-

tion entre objets de mecircme type ne concerne pas ces parties dynamiques geacuteneacuteralement

cela pose problegraveme et la solution passe par la surdeacutefinition de lopeacuterateur = Autrement

dit la classe hasard deacutefinie dans le dernier exemple ne permettrait pas de traiter correc-

tement laffectation dobjets de ce type

4 - Notions de constructeur et de destructeur79

45 Quelques regraveglesUn constructeur peut comporter un nombre quelconque drsquoarguments eacuteventuellement aucun

Par deacutefinition un constructeur ne renvoie pas de valeur aucun type ne peut figurer devant

son nom (dans ce cas preacutecis la preacutesence de void est une erreur)

Par deacutefinition un destructeur ne peut pas disposer drsquoarguments et ne renvoie pas de valeur

Lagrave encore aucun type ne peut figurer devant son nom (et la preacutesence de void est une erreur)

En theacuteorie constructeurs et destructeurs peuvent ecirctre publics ou priveacutes En pratique agrave moins

drsquoavoir de bonnes raisons de faire le contraire il vaut mieux les rendre publics

On notera que si un destructeur est priveacute il ne pourra plus ecirctre appeleacute directement ce qui

nrsquoest geacuteneacuteralement pas grave dans la mesure ougrave cela est rarement utile

En revanche la privatisation drsquoun constructeur a de lourdes conseacutequences puisqursquoil ne sera

plus utilisable sauf par des fonctions membres de la classe elle-mecircme

Informations compleacutementaires

Voici quelques circonstances ougrave un constructeur priveacute peut se justifier

ndash la classe concerneacutee ne sera pas utiliseacutee telle quelle car elle est destineacutee agrave donner nais-

sance par heacuteritage agrave des classes deacuteriveacutees qui quant agrave elles pourront disposer drsquoun

constructeur public (nous reviendrons plus tard sur cette situation dite de classe abs-

traite)

ndash la classe dispose drsquoautres constructeurs (nous verrons bientocirct qursquoun constructeur peut

ecirctre surdeacutefini) dont au moins un est public

ndash on cherche agrave mettre en œuvre un motif de conception1 particulier le singleton il

srsquoagit de faire en sorte qursquoune mecircme classe ne puisse donner naissance qursquoagrave un seul ob-

jet et que toute tentative de creacuteation drsquoun nouvel objet se contente de renvoyer la reacutefeacute-

rence de cet unique objet Dans ce cas on peut preacutevoir un constructeur priveacute (de corps

vide) dont la preacutesence fait qursquoil est impossible de creacuteer explicitement des objets du type

(du moins si ce constructeur nrsquoest pas surdeacutefini) La creacuteation drsquoobjets se fait alors par

appel drsquoune fonction membre qui reacutealise elle-mecircme les allocations neacutecessaires crsquoest-

agrave-dire le travail drsquoun constructeur habituel et qui en outre srsquoassure de lrsquouniciteacute de

lrsquoobjet

En Java

Le constructeur possegravede les mecircmes proprieacuteteacutes qursquoen C++ et une classe peut ne pas com-

porter de constructeur Mais en Java les membres donneacutees sont toujours initialiseacutes par

deacutefaut (valeur nulle) et ils peuvent eacutegalement ecirctre initialiseacutes lors de leur deacuteclaration (la

1 Pattern en anglais

Classes et objetsCHAPITRE 5

80

mecircme valeur eacutetant alors attribueacutee agrave tous les objets du type) Ces deux possiliteacutes (initiali-

sation par deacutefaut et initialisation explicite) nrsquoexistent pas en C++ comme nous le verrons

plus tard de sorte qursquoil est pratiquement toujours neacutecessaire de preacutevoir un constructeur

mecircme dans des situations drsquoinitialisation simple

5 Les membres donneacutees statiques

51 Le qualificatif static pour un membre donneacuteeA priori lorsque dans un mecircme programme on creacutee diffeacuterents objets dune mecircme classe cha-

que objet possegravede ses propres membres donneacutees Par exemple si nous avons deacutefini une

classe exple1 par

class exple1

int n

float x

une deacuteclaration telle que

exple1 a b

conduit agrave une situation que lon peut scheacutematiser ainsi

Une faccedilon (parmi dautres) de permettre agrave plusieurs objets de partager des donneacutees consiste agrave

deacuteclarer avec le qualificatif static les membres donneacutees quon souhaite voir exister en un seul

exemplaire pour tous les objets de la classe Par exemple si nous deacutefinissons une classe

exple2 par

class exple2

static int n

float x

la deacuteclaration

exple2 a b

an

ax

bn

bx

Objet a Objet b

5 - Les membres donneacutees statiques81

conduit agrave une situation que lon peut scheacutematiser ainsi

On peut dire que les membres donneacutees statiques sont des sortes de variables globales dont la

porteacutee est limiteacutee agrave la classe

52 Initialisation des membres donneacutees statiquesPar leur nature mecircme les membres donneacutees statiques nexistent quen un seul exemplaire

indeacutependamment des objets de la classe (mecircme si aucun objet de la classe na encore eacuteteacute

creacuteeacute) Dans ces conditions leur initialisation ne peut plus ecirctre faite par le constructeur de la

classe

On pourrait penser quil est possible dinitialiser un membre statique lors de sa deacuteclaration

comme dans

class exple2 static int n = 2 erreur

En fait cela nest pas permis car compte tenu des possibiliteacutes de compilation seacutepareacutee le

membre statique risquerait de se voir reacuteserver diffeacuterents emplacements1 dans diffeacuterents

modules objet

Un membre statique doit donc ecirctre initialiseacute explicitement (agrave lexteacuterieur de la deacuteclaration de

la classe) par une instruction telle que

int exple2n = 5

Cette deacutemarche est utilisable aussi bien pour les membres statiques priveacutes que publics

Par ailleurs contrairement agrave ce qui se produit pour une variable ordinaire un membre stati-

que nest pas initialiseacute par deacutefaut agrave zeacutero

Remarque

Depuis la norme les membres statiques constants peuvent eacutegalement ecirctre initialiseacutes au

moment de leur deacuteclaration Mais il reste quand mecircme neacutecessaire de les deacuteclarer agrave lrsquoexteacute-

an

ax

Objet a Objet b

bx

bn

1 On retrouve le mecircme pheacutenomegravene pour les variables globales en langage C elles peuvent ecirctre deacuteclareacutees plusieurs

fois mais elles ne doivent ecirctre deacutefinies quune seule fois

Classes et objetsCHAPITRE 5

82

rieur de la classe (sans valeur cette fois) pour provoquer la reacuteservation de lrsquoemplacement

meacutemoire correspondant Par exemple

class exple3 static const int n=5 initialisation OK dpeuis la norme ANSI const int exple3n deacuteclaration indispensable (sans valeur)

53 ExempleVoici un exemple de programme exploitant cette possibiliteacute dans une classe nommeacutee

cpte_obj afin de connaicirctre agrave tout moment le nombre dobjets existants Pour ce faire nous

avons deacuteclareacute avec lattribut statique le membre ctr Sa valeur est increacutementeacutee de 1 agrave chaque

appel du constructeur et deacutecreacutementeacutee de 1 agrave chaque appel du destructeur

include ltiostreamgtusing namespace std

class cpte_obj static int ctr compteur du nombre dobjets creacuteeacutes

public cpte_obj () ~cpte_obj () int cpte_objctr = 0 initialisation du membre statique ctrcpte_objcpte_obj () constructeur cout ltlt ++ construction il y a maintenant ltlt ++ctr ltlt objetsn cpte_obj~cpte_obj () destructeur cout ltlt -- destruction il reste maintenant ltlt --ctr ltlt objetsn 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

6 - Exploitation drsquoune classe83

++ construction il y a maintenant 2 objets-- destruction il reste maintenant 1 objets-- destruction il reste maintenant 0 objets

Exemple dutilisation de membre statique

Remarque

En C le terme statique avait deacutejagrave deux significations de classe statique ou de porteacutee

limiteacutee au fichier source1 En C++ lorsquil sapplique aux membres dune classe il en

possegravede donc une troisiegraveme indeacutependant dune quelconque instance de la classe Nous

verrons au prochain chapitre quil pourra sappliquer aux fonctions membres avec la

mecircme signification

En Java

Les membres donneacutees statiques existent eacutegalement en Java et on utilise le mot cleacute static

pour leur deacuteclaration (crsquoest drsquoailleurs la seule signification de ce mot cleacute) Comme en

C++ ils peuvent ecirctre initialiseacutes lors de leur deacuteclaration mais ils peuvent aussi lrsquoecirctre par

le biais drsquoun bloc drsquoinitialisation qui contient alors des instructions exeacutecutables ce que ne

permet pas C++

6 Exploitation drsquoune classe

61 La classe comme composant logicielJusqursquoici nous avions regroupeacute au sein drsquoun mecircme programme trois sortes drsquoinstructions

destineacutees agrave

bull la deacuteclaration de la classe

bull la deacutefinition de la classe

bull lrsquoutilisation de la classe

En pratique on aura souvent inteacuterecirct agrave deacutecoupler la classe de son utilisation Crsquoest tout natu-

rellement ce qui se produira avec une classe drsquointeacuterecirct geacuteneacuteral utiliseacutee comme un composant

seacutepareacute des diffeacuterentes applications

1 Du moins quand on lemployait pour deacutesigner ce qui eacutetait qualifieacute par le mot cleacute static

Classes et objetsCHAPITRE 5

84

On sera alors geacuteneacuteralement ameneacute agrave isoler les seules instructions de deacuteclaration de la classe

dans un fichier en-tecircte (extension h) qursquoil suffira drsquoinclure (par include) pour compiler

lrsquoapplication

Par exemple le concepteur de la classe point du paragraphe 42 pourra creacuteer le fichier en-tecircte

suivant

class point deacuteclaration des membres priveacutes

int x int y

public deacuteclaration des membres publics point (int int) constructeur

void deplace (int int) void affiche ()

Fichier en-tecircte pour la classe point

Si ce fichier se nomme pointh le concepteur fabriquera alors un module objet en compilant

la deacutefinition de la classe point

include ltiostreamgt

include pointh pour introduire les deacuteclarations de la classe pointusing namespace std

----- Deacutefinition des fonctions membre de la classe point ----

pointpoint (int abs int ord) x = abs y = ord

void pointdeplace (int dx int dy) x = x + dx y = y + dy

void pointaffiche ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n

Fichier agrave compiler pour obtenir le module objet de la classe point

Pour faire appel agrave la classe point au sein drsquoun programme lrsquoutilisateur proceacutedera alors ainsi

bull il inclura la deacuteclaration de la classe point dans le fichier source contenant son programme

par une directive telle que

include pointh

6 - Exploitation drsquoune classe85

bull il incorporera le module objet correspondant au moment de lrsquoeacutedition de liens de son propre

programme En principe agrave ce niveau la plupart des eacutediteurs de liens nrsquointroduisent que les

fonctions reacuteellement utiliseacutees de sorte qursquoil ne faut pas craindre de preacutevoir trop de meacutethodes

pour une classe

Parfois on trouvera plusieurs classes diffeacuterentes au sein drsquoun mecircme module objet et drsquoun

mecircme fichier en-tecircte de faccedilon comparable agrave ce qui se produit avec les fonctions de la biblio-

thegraveque standard1 Lagrave encore en geacuteneacuteral seules les fonctions reacuteellement utiliseacutees seront incor-

poreacutees agrave lrsquoeacutedition de liens de sorte qursquoil est toujours possible drsquoeffectuer des regroupements

de classes posseacutedant quelques affiniteacutes

Signalons que bon nombre drsquoenvironnements disposent drsquooutils2 permettant de prendre auto-

matiquement en compte les deacutependances existant entre les diffeacuterents fichiers sources et les

diffeacuterents fichiers objets concerneacutes dans ce cas lors drsquoune modification quelle qursquoelle soit

seules les compilations neacutecessaires sont effectueacutees

Remarque

Comme une fonction ordinaire une fonction membre peut ecirctre deacuteclareacutee sans qursquoon nrsquoen

fournisse de deacutefinition Si le programme fait appel agrave cette fonction membre ce nrsquoest qursquoagrave

lrsquoeacutedition de liens qursquoon srsquoapercevra de son absence En revanche si le programme nrsquouti-

lise pas cette fonction membre lrsquoeacutedition de liens se deacuteroulera normalement car il nrsquointro-

duit que les fonctions effectivement appeleacutees

62 Protection contre les inclusions multiplesPlus tard nous verrons quil existe diffeacuterentes circonstances pouvant amener lutilisateur

dune classe agrave inclure plusieurs fois un mecircme fichier en-tecircte lors de la compilation dun mecircme

fichier source (sans mecircme quil nen ait conscience ) Ce sera notamment le cas dans les

situations dobjets membres et de classes deacuteriveacutees

Dans ces conditions on risque daboutir agrave des erreurs de compilation lieacutees tout simplement agrave

la redeacutefinition de la classe concerneacutee

En geacuteneacuteral on reacuteglera ce problegraveme en proteacutegeant systeacutematiquement tout fichier en-tecircte des

inclusions multiples par une technique de compilation conditionnelle comme dans

ifndef POINT_H

define POINT_H

deacuteclaration de la classe point

endif

1 Avec cette diffeacuterence que dans le cas des fonctions standard on nrsquoa pas agrave speacutecifier les modules objets concerneacutes

au moment de lrsquoeacutedition de liens

2 On parle souvent de projet de fichier projet de fichier make

Classes et objetsCHAPITRE 5

86

Le symbole deacutefini pour chaque fichier en-tecircte sera choisi de faccedilon agrave eacuteviter tout risque de dou-

blons Ici nous avons choisi le nom de la classe (en majuscules) suffixeacute par _H

63 Cas des membres donneacutees statiquesNous avons vu (paragraphe 52) quun membre donneacutee statique doit toujours ecirctre initialiseacute

explicitement Degraves quon est ameneacute agrave consideacuterer une classe comme un composant seacutepareacute le

problegraveme se pose alors de savoir dans quel fichier source placer une telle initialisation

fichier en-tecircte fichier deacutefinition de la classe fichier utilisateur (dans notre exemple du para-

graphe 53 ce problegraveme ne se posait pas car nous navions quun seul fichier source)

On pourrait penser que le fichier en-tecircte est un excellent candidat pour cette initialisation degraves

lors quil est proteacutegeacute contre les inclusions multiples En fait il nen est rien en effet si lutili-

sateur compile seacutepareacutement plusieurs fichiers source utilisant la mecircme classe plusieurs

emplacements seront geacuteneacutereacutes pour le mecircme membre statique et en principe leacutedition de liens

deacutetectera cette erreur

Comme par ailleurs il nest guegravere raisonnable de laisser lutilisateur initialiser lui-mecircme un

membre statique on voit qursquoen deacutefinitive

64 En cas de modification drsquoune classeA priori lorsqursquoune classe est consideacutereacutee comme un composant logiciel crsquoest qursquoelle est au

point et ne devrait plus ecirctre modifieacutee Si une modification srsquoavegravere neacutecessaire malgreacute tout il

faut envisager deux situations assez diffeacuterentes

641 La deacuteclaration des membres publics nrsquoa pas changeacuteCrsquoest ce qui se produit lorsqursquoon se limite agrave des modifications internes nrsquoayant acune reacuteper-

cussion sur la maniegravere drsquoutiliser la classe (son interface avec lrsquoexteacuterieur reste la mecircme) Il

peut srsquoagir de transformation de structures de donneacutees encapsuleacutees (priveacutees) de modification

drsquoalgorithmes de traitement

Dans ce cas les programmes utilisant la classe nrsquoont pas agrave ecirctre modifieacutes Neacuteanmoins il

doivent ecirctre recompileacutes avec le nouveau fichier en-tecircte correspondant1 On proceacutedera

ensuite agrave une eacutedition de liens en incorporant le nouveau module objet

On voit donc que C++ permet une maintenance facile drsquoune classe agrave laquelle on souhaite

apporter des modifications internes (corrections drsquoerreurs ameacutelioration des performances)

nrsquoatteignant pas la speacutecification de son interface

Il est conseilleacute de preacutevoir lrsquoinitialisation des membres donneacutees statiques dans le fichier contenant la deacutefinition de la classe

1 Une telle limitation nrsquoexiste pas dans tous les langages de POO En C++ elle se justifie par le besoin qursquoa le

compilateur de connaicirctre la taille des objets (statiques ou automatiques) pour leur allouer un emplacement

7 - Les classes en geacuteneacuteral87

642 La deacuteclaration des membres publics a changeacute

Ici il est clair que les programmes utilisant la classe risquent de neacutecessiter des modifications

Cette situation devra bien sucircr ecirctre eacuteviteacutee dans la mesure du possible Elle doit ecirctre consideacutereacutee

comme une faute de conception de la classe Nous verrons drsquoailleurs que ces problegravemes pour-

ront souvent ecirctre reacutesolus par lrsquoutilisation du meacutecanisme drsquoheacuteritage qui permet drsquoadapter une

classe (censeacutee ecirctre au point) sans la remettre en cause

7 Les classes en geacuteneacuteralNous apportons ici quelques compleacutements drsquoinformation sur des situations peu usuelles

71 Les autres sortes de classes en C++Nous avons deacutejagrave eu loccasion de dire que C++ qualifiait de classe les types deacutefinis par

struct et class La caracteacuteristique dune classe au sens large que lui donne C++1 est dasso-

cier au sein dun mecircme type des membres donneacutees et des fonctions membres

Pour C++ les unions sont aussi des classes Ce type peut donc disposer de fonctions mem-

bres Notez bien que comme pour le type struct les donneacutees correspondantes ne peuvent pas

se voir attribuer un statut particulier elles sont de fait publiques

Remarque

C++ emploie souvent le mot classe pour deacutesigner indiffeacuteremment un type class struct ou

union De mecircme on parle souvent drsquoobjet pour deacutesigner des variables de lrsquoun de ces trois

types Cet abus de langage semble assez licite dans la mesure ougrave ces trois types jouis-

sent pratiquement des mecircmes proprieacuteteacutes notamment au niveau de lrsquoheacuteritage toutefois

seul le type class permet lrsquoencapsulation des donneacutees Lorsqursquoil sera neacutecessaire drsquoecirctre

plus preacutecis nous parlerons de vraie classe pour deacutesigner le type class

72 Ce quon peut trouver dans la deacuteclaration dune classeEn dehors des deacuteclarations de fonctions membres la plupart des instructions figurant dans

une deacuteclaration de classe seront des deacuteclarations de membres donneacutees dun type quelconque

Neacuteanmoins on peut eacutegalement y rencontrer des deacuteclarations de type y compris dautres types

classes dans ce cas leur porteacutee est limiteacutee agrave la classe (mais on peut recourir agrave lrsquoopeacuterateur de

reacutesolution de porteacutee ) comme dans cet exemple

1 Et non la POO dune maniegravere geacuteneacuterale qui associe lencapsulation des donneacutees agrave la notion de classe

Classes et objetsCHAPITRE 5

88

class A

public

class B classe B deacuteclareacutee dans la classe A

main()

A a

AB b deacuteclaration drsquoun objet b du type de la classe B de A

En pratique cette situation se rencontre peu souvent

Par ailleurs il nest pas possible dinitialiser un membre donneacutee dune classe lors de sa

deacuteclaration Cette interdiction est justifieacutee pour au moins deux raisons

bull une telle initialisation risquerait de faire double emploi avec le constructeur

bull une telle initialisation constituerait une deacutefinition du membre correspondant (et non plus une

simple deacuteclaration) or cette deacutefinition risquerait dapparaicirctre plusieurs fois en cas de com-

pilation seacutepareacutee ce qui est illeacutegal1

En revanche la deacuteclaration de membres donneacutees constants2 est autoriseacutee comme dans

class exple

int n membre donneacutee usuel

const int p membre donneacutee constant - initialisation impossible

agrave ce niveau

Dans ce cas on notera bien que chaque objet du type exple posseacutedera un membre p Crsquoest ce

qui explique qursquoil ne soit pas possible dinitialiser le membre constant au moment de sa

deacuteclaration3 Pour y parvenir la seule solution consistera agrave utiliser une syntaxe particuliegravere

du constructeur (qui devient donc obligatire) telle quelle sera preacutesenteacutee au paragraphe 5 du

chapitre 7 (relatif aux objets membres)

73 Deacuteclaration dune classeLa plupart du temps les classes seront deacuteclareacutees agrave un niveau global Neacuteanmoins il est permis

de deacuteclarer des classes locales agrave une fonction Dans ce cas leur porteacutee est naturellement limi-

teacutee agrave cette fonction (cest bien ce qui en limite linteacuterecirct)

1 On retrouve le mecircme pheacutenomegravene pour les membres donneacutees statiques et pour les variables globales en langage C

ils peuvent ecirctre deacuteclareacutes plusieurs fois mais ils ne doivent ecirctre deacutefinis quune seule fois

2 Ne confondez pas la notion de membre donneacutee constant (chaque objet en possegravede un sa valeur ne peut pas ecirctre

modifieacutee) et la notion de membre donneacutee statique (tous les objets dune mecircme classe partagent le mecircme sa valeur

peut changer)

3 Sauf comme on lrsquoa vu au paragraphe 52 srsquoil srsquoagit drsquoun membre statique constant dans ce cas ce membre est

unique pour tous les objets de la classe

7 - Les classes en geacuteneacuteral89

ExercicesNB les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 Expeacuterimentez (eacuteventuellement sur un exemple de ce chapitre) la compilation seacutepareacutee

dune classe (creacuteation dun module objet et dun fichier en-tecircte) et son utilisation au

sein dun programme

2 (C) Ecrivez une classe vecteur (de type class et non struct) comportant

bull comme membres donneacutees priveacutes trois composantes de type double

bull comme fonctions membres publiques

ndash initialise pour attribuer des valeurs aux composantes

ndash homothetie pour multiplier les composantes par une valeur fournie en argu-

ment

ndash affiche pour afficher les composantes du vecteur

3 (C) Ecrivez une classe vecteur analogue agrave la preacuteceacutedente dans laquelle la fonction initia-

lise est remplaceacutee par un constructeur

4 Expeacuterimentez la creacuteation drsquoun fichier en-tecircte et drsquoun module objet rassemblant deux

classes diffeacuterentes

5 Veacuterifiez que lorsqursquoune classe comporte un membre donneacutee statique ce dernier peut

ecirctre utiliseacute mecircme lorsquaucun objet de ce type na eacuteteacute deacuteclareacute

6 Mettez en eacutevidence les problegravemes poseacutes par laffectation entre objets comportant une

partie dynamique Pour ce faire utilisez la classe hasard du second exemple du para-

graphe 44 en ajoutant simplement des instructions affichant ladresse contenue dans

val dans le constructeur dune part dans le destructeur dautre part Vous constaterez

quavec ces deacuteclarations

hasard h1(10 3)

hasard h2(20 5)

une instruction telle que

h2 = h1

nentraicircne pas toutes les recopies escompteacutees et que de surcroicirct elle conduit agrave libeacuterer

deux fois le mecircme emplacement (en fin de fonction)

6

Les proprieacuteteacutes desfonctions membres

Le chapitre preacuteceacutedent vous a preacutesenteacute les concepts fondamentaux de classe dobjet de cons-

tructeur et de destructeur Ici nous allons eacutetudier un peu plus en deacutetail lapplication aux fonc-

tions membres des possibiliteacutes offertes par C++ pour les fonctions ordinaires surdeacutefinition

arguments par deacutefaut fonction en ligne transmission par reacutefeacuterence

Nous verrons eacutegalement comment une fonction membre peut recevoir en argument outre

lobjet layant appeleacute (transmis implicitement) un ou plusieurs objets de type classe Ici nous

nous limiterons au cas dobjets de mecircme type que la classe dont la fonction est membre les

autres situations correspondant agrave une violation du principe dencapsulation ne seront exami-

neacutees que plus tard dans le cadre des fonctions amies

Nous verrons ensuite comment acceacuteder au sein dune fonction membre agrave ladresse de lobjet

layant appeleacute en utilisant le mot cleacute this

Enfin nous examinerons les cas particuliers des fonctions membres statiques et des fonctions

membres constantes ainsi que lemploi de pointeurs sur des fonctions membres

1 Surdeacutefinition des fonctions membresNous avons deacutejagrave vu comment C++ nous autorise agrave surdeacutefinir les fonctions ordinaires Cette

possibiliteacute sapplique eacutegalement aux fonctions membres dune classe y compris au construc-

teur (mais pas au destructeur puisquil ne possegravede pas drsquoarguments)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

92

11 ExempleVoyez cet exemple dans lequel nous surdeacutefinissons

bull le constructeur point le choix du bon constructeur se faisant ici suivant le nombre

drsquoarguments

ndash 0 argument les deux coordonneacutees attribueacutees au point construit sont toutes deux nulles

ndash 1 argument il sert de valeur commune aux deux coordonneacutees

ndash 2 arguments cest le cas usuel que nous avions deacutejagrave rencontreacute

bull la fonction affiche de maniegravere quon puisse lappeler

ndash sans argument comme auparavant

ndash avec un argument de type chaicircne dans ce cas elle affiche le texte correspondant avant

les coordonneacutees du point

include ltiostreamgtusing namespace std 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 chaicircne) pointpoint () constructeur 1 x = 0 y = 0 pointpoint (int abs) constructeur 2 x = y = abs pointpoint (int abs int ord) constructeur 3 x = abs y = ord void pointaffiche () fonction affiche 1 cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n void pointaffiche (char message) fonction affiche 2 cout ltlt message affiche () main() point a appel constructeur 1 aaffiche () appel fonction affiche 1 point b (5) appel constructeur 2 baffiche (Point b - ) appel fonction affiche 2 point c (3 12) appel constructeur 3 caffiche (Hello ---- ) appel fonction affiche 2

1 - Surdeacutefinition des fonctions membres93

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple de surdeacutefinition de fonctions membres (point et affiche)

Remarques

1 En utilisant les possibiliteacutes drsquoarguments par deacutefaut il est souvent possible de diminuer le

nombre de fonctions surdeacutefinies Cest le cas ici pour la fonction affiche comme nous le

verrons dailleurs dans le paragraphe suivant

2 Ici dans la fonction affiche(char ) nous faisons appel agrave lautre fonction membre affi-

che() En effet une fonction membre peut toujours en appeler une autre (quelle soit

publique ou non) Une fonction membre peut mecircme sappeler elle-mecircme dans la

mesure ougrave lon a preacutevu le moyen de rendre fini le processus de reacutecursiviteacute qui en

deacutecoule

12 Incidence du statut public ou priveacute drsquoune fonction membreMais par rapport agrave la surdeacutefinition des fonctions indeacutependantes il faut maintenant tenir

compte de ce qursquoune fonction membre peut ecirctre priveacutee ou publique Or en C++

Condiseacuterez cet exemple

class A public void f(int n)

private void f(char c)

main()

int n char c A a

af(c)

Lrsquoappel af(c) amegravene le compilateur agrave consideacuterer les deux fonctions f(int) et f(char) et ceci

indeacutependamment de leur statut (public pour la premiegravere priveacute pour la seconde) Lrsquoalgorithme

de recherche de la meilleure fonction conclut alors que f(char) est la meilleure fonction et

qursquoelle est unique Mais comme celle-ci est priveacutee elle ne peut pas ecirctre appeleacutee depuis une

fonction exteacuterieure agrave la classe et lrsquoappel est rejeteacute (et ceci malgreacute lrsquoexistence de f(int) qui

aurait pu convenir) Rappelons que

bull si f(char) est deacutefinie publique elle serait bien appeleacutee par af(c)

bull si f(char) nrsquoest pas deacutefinie du tout af(c) appellerait f(int)

Le statut priveacute ou public drsquoune fonction nrsquointervient pas dans les fonctions consideacute-reacutees En revanche si la meilleure fonction trouveacutee est priveacutee elle ne pourra pas ecirctre appeleacutee (sauf si lrsquoappel figure dans une autre fonction membre de la classe)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

94

En Java

Contrairement agrave ce qui se passe en C++ le statut priveacute ou public drsquoune fonction membre

est bien pris en compte dans le choix des fonctions acceptables Dans ce dernier exem-

ple af(c) appellerait bien f(int) apregraves conversion de c en int comme si la fonction priveacutee

f(int) nrsquoeacutexistait pas

2 Arguments par deacutefautComme les fonctions ordinaires les fonctions membres peuvent disposer drsquoarguments par

deacutefaut Voici comment nous pourrions modifier lexemple preacuteceacutedent pour que notre classe

point ne possegravede plus quune seule fonction affiche disposant drsquoun seul argument de type

chaicircne Celui-ci indique le message agrave afficher avant les valeurs des coordonneacutees et sa valeur

par deacutefaut est la chaicircne vide

include ltiostreamgtusing namespace std 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 deacutefaut) pointpoint () constructeur 1 x = 0 y = 0 pointpoint (int abs) constructeur 2

x = y = abs pointpoint (int abs int ord) constructeur 3 x = abs y = ord void pointaffiche (char message) fonction affiche cout ltlt message ltlt Je suis en ltlt x ltlt ltlt y ltlt n

main() point a appel constructeur 1 aaffiche () point b (5) appel constructeur 2 baffiche (Point b - ) point c (3 12) appel constructeur 3 caffiche (Hello ---- )

3 - Les fonctions membres en ligne95

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple dutilisation drsquoarguments par deacutefaut dans une fonction membre

Remarque

Ici nous avons remplaceacute deux fonctions surdeacutefinies par une seule fonction ayant un argu-

ment par deacutefaut Bien entendu cette simplification nest pas toujours possible Par exem-

ple ici nous ne pouvons pas lappliquer agrave notre constructeur point En revanche si nous

avions preacutevu que dans le constructeur point agrave un seul argument ce dernier repreacutesente

simplement labscisse du point auquel on aurait alors attribueacute une ordonneacutee nulle nous

aurions pu deacutefinir un seul constructeur

pointpoint (int abs = 0 int ord = 0) x = abs y = ord

3 Les fonctions membres en ligneNous avons vu que C++ permet de deacutefinir des fonctions en ligne Ceci accroicirct lefficience

dun programme dans le cas de fonctions courtes Lagrave encore cette possibiliteacute sapplique aux

fonctions membres moyennant cependant une petite nuance concernant sa mise en œuvre

En effet pour rendre en ligne une fonction membre on peut

bull soit fournir directement la deacutefinition de la fonction dans la deacuteclaration mecircme de la classe

dans ce cas le qualificatif inline na pas agrave ecirctre utiliseacute

bull soit proceacuteder comme pour une fonction ordinaire en fournissant une deacutefinition en dehors de

la deacuteclaration de la classe dans ce cas le qualificatif inline doit apparaicirctre agrave la fois devant

la deacuteclaration et devant len-tecircte

Voici comment nous pourrions rendre en ligne les trois constructeurs de notre preacuteceacutedent

exemple en adoptant la premiegravere maniegravere

include ltiostreamgtusing namespace std 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 = )

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

96

void pointaffiche (char message) fonction affiche cout ltlt message ltlt Je suis en ltlt x ltlt ltlt y ltlt n

main() point a appel constructeur 1 aaffiche () point b (5) appel constructeur 2 baffiche (Point b - ) point c (3 12) appel constructeur 3 caffiche (Hello ---- )

Je suis en 0 0Point b - Je suis en 5 5Hello ---- Je suis en 3 12

Exemple de fonctions membres en ligne

Remarques

1 Voici comment se serait preacutesenteacutee la deacuteclaration de notre classe si nous avions deacuteclareacute

nos fonctions membres en ligne agrave la maniegravere des fonctions ordinaires (ici nous navons

mentionneacute quun constructeur)

class point public inline point ()

inline pointpoint() x = 0 y = 0

2 Si nous navions eu besoin que dun seul constructeur avec arguments par deacutefaut

(comme dans la remarque du preacuteceacutedent paragraphe) nous aurions pu tout aussi bien le

rendre en ligne avec la premiegravere deacutemarche (deacutefinition de fonction inteacutegreacutee dans la

deacuteclaration de la classe) nous aurions alors speacutecifieacute les valeurs par deacutefaut directement

dans len-tecircte

class point point (int abs = 0 int ord = 0) x = abs y = ord

Nous utiliserons dailleurs un tel constructeur dans lexemple du paragraphe suivant

4 - Cas des objets transmis en argument drsquoune fonction membre97

3 Par sa nature mecircme la deacutefinition dune fonction en ligne doit obligatoirement ecirctre con-

nue du compilateur lorsquil traduit le programme qui lutilise Cette condition est obli-

gatoirement reacutealiseacutee lorsque lon utilise la premiegravere deacutemarche En revanche ce nest

plus vrai avec la seconde en geacuteneacuteral dans ce cas on placera les deacutefinitions des fonc-

tions en ligne agrave la suite de la deacuteclaration de la classe dans le mecircme fichier en-tecircte

Dans tous les cas on voit toutefois que lutilisateur dune classe (qui disposera obliga-

toirement du fichier en-tecircte relatif agrave une classe) pourra toujours connaicirctre la deacutefinition

des fonctions en ligne le fournisseur dune classe ne pourra jamais avoir la certitude

quun utilisateur de cette classe ne tentera pas de les modifier Ce risque nexiste pas

pour les autres fonctions membres (degraves lors que lutilisateur ne dispose que du module

objet relatif agrave la classe)

4 Cas des objets transmis en argument drsquoune fonction membre

Dans les exemples preacuteceacutedents les fonctions membres recevaient

bull un argument implicite du type de leur classe agrave savoir ladresse de lobjet layant appeleacute

bull un certain nombre drsquoarguments qui eacutetaient dun type ordinaire (cest-agrave-dire autre que classe)

Mais une fonction membre peut outre largument implicite recevoir un ou plusieurs argu-

ments du type de sa classe Par exemple supposez que nous souhaitions au sein dune classe

point introduire une fonction membre nommeacutee coincide chargeacutee de deacutetecter la coiumlncidence

eacuteventuelle de deux points Son appel au sein dun programme se preacutesentera obligatoirement

comme pour toute fonction membre sous la forme

acoincide ()

a eacutetant un objet de type point

Il faudra donc impeacuterativement transmettre le second point en argument en supposant quil se

nomme b cela nous conduira agrave un appel de la forme

acoincide (b)

ou ici compte tenu de la symeacutetrie du problegraveme

bcoincide (a)

Voyons maintenant plus preacuteciseacutement comment eacutecrire la fonction coincide Voici ce que peut

ecirctre son en-tecircte en supposant quelle fournit une valeur de retour entiegravere (1 en cas de coiumlnci-

dence 0 dans le cas contraire)

int pointcoincide (point pt)

Dans coincide nous devons donc comparer les coordonneacutees de lobjet fourni implicitement

lors de son appel (ses membres sont deacutesigneacutes comme dhabitude par x et y) avec celles de

lobjet fourni en argument dont les membres sont deacutesigneacutes par ptx et pty Le corps de coin-

cide se preacutesentera donc ainsi

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

98

if ((ptx == x) ampamp (pty == y)) return 1 else return 0

Voici un exemple complet de programme dans lequel nous avons limiteacute les fonctions mem-

bres de la classe point agrave un constructeur et agrave coincide

include ltiostreamgtusing namespace std 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 pointcoincide (point pt) if ( (ptx == x) ampamp (pty == y) ) return 1 else return 0 remarquez la dissymeacutetrie des notations ptx et xmain() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(b) ltlt ou ltlt bcoincide(a) ltlt n cout ltlt b et c ltlt bcoincide(c) ltlt ou ltlt ccoincide(b) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple dobjet transmis en argument agrave une fonction membre

On pourrait penser qursquoon viole le principe drsquoencapsulation dans la mesure ougrave lorsqursquoon

appelle la fonction coincide pour lrsquoobjet a (dans acoincide(b)) elle est autoriseacutee agrave acceacuteder

aux donneacutees de b En fait en C++ nrsquoimporte quelle fonction membre drsquoune classe peut acceacute-

der agrave nrsquoimporte quel membre (public ou priveacute) de nrsquoimporte quel objet de cette classe On

traduit souvent cela en disant que

Remarques

1 Nous aurions pu eacutecrire coincide de la maniegravere suivante

return ((ptx == x) ampamp (pty == y))

En C++ lrsquouniteacute drsquoencapsulation est la classe (et non pas lrsquoobjet )

5 - Mode de transmission des objets en argument99

2 En theacuteorie on peut dire que la coiumlncidence de deux points est symeacutetrique en ce sens

que lordre dans lequel on considegravere les deux points est indiffeacuterent Or cette symeacutetrie ne

se retrouve pas dans la deacutefinition de la fonction coincide pas plus que dans son appel

Cela provient de la transmission en argument implicite de lobjet appelant la fonction

Nous verrons que lrsquoutilisation drsquoune fonction amie permet de retrouver cette symeacute-

trie

3 Notez bien que lrsquouniteacute drsquoencapsulation est la classe concerneacutee pas toutes les classes

existantes Ainsi si A et B sont deux classes diffeacuterentes une fonction membre de A ne

peut heureusement pas acceacuteder aux membres priveacutes drsquoun objet de classe B (pas plus

que ne le pourrait une fonction ordinaire main par exemple) bien entendu elle peut

toujours acceacuteder aux membres publics Nous verrons plus tard qursquoil est possible agrave une

fonction (ordinaire ou membre) de saffranchir de cette interdiction (et donc cette fois

de violer veacuteritablement le principe dencapsulation) par des deacuteclarations damitieacute appro-

prieacutees

En Java

Lrsquouniteacute drsquoencapsulation est eacutegalement la classe

5 Mode de transmission des objets en argument

Dans lrsquoexemple preacuteceacutedent lobjet pt eacutetait transmis classiquement agrave coincide agrave savoir par

valeur Preacuteciseacutement cela signifie donc que lors de lappel

acoincide (b)

les valeurs des donneacutees de b sont recopieacutees dans un emplacement (de type point) local agrave coin-

cide (nommeacute pt)

Comme pour nimporte quel argument ordinaire il est possible de preacutevoir den transmettre

ladresse plutocirct que la valeur ou de mettre en place une transmission par reacutefeacuterence Exami-

nons ces deux possibiliteacutes

51 Transmission de ladresse dun objetIl est possible de transmettre explicitement en argument ladresse dun objet Rappelons que

dans un tel cas on ne change pas le mode de transmission de largument (contrairement agrave ce

qui se produit avec la transmission par reacutefeacuterence) on se contente de transmettre une valeur

qui se trouve ecirctre une adresse et quil faut donc interpreacuteter en conseacutequence dans la fonction

(notamment en employant lopeacuterateur dindirection ) A titre dexemple voici comment nous

pourrions modifier la fonction coincide du paragraphe preacuteceacutedent

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

100

int pointcoincide (point adpt) if (( adpt -gt x == x) ampamp (adpt -gt y == y)) return 1 else return 0

Compte tenu de la dissymeacutetrie naturelle de notre fonction membre cette eacutecriture nest guegravere

choquante Par contre lappel de coincide (au sein de main) le devient davantage

acoincide (ampb)

ou

bcoincide (ampa)

Voici le programme complet ainsi modifieacute

include ltiostreamgtusing namespace std 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 pointcoincide (point adpt) if ( (adpt-gtx == x) ampamp (adpt-gty == y) ) return 1 else return 0

main() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(ampb) ltlt ou ltlt bcoincide(ampa) ltlt n cout ltlt b et c ltlt bcoincide(ampc) ltlt ou ltlt ccoincide(ampb) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple de transmission de ladresse dun objet agrave une fonction membre

Remarque

Noubliez pas quagrave partir du moment ougrave vous fournissez ladresse dun objet agrave une fonction

membre celle-ci peut en modifier les valeurs (elle a accegraves agrave tous les membres sil sagit

dun objet de type de sa classe aux seuls membres publics dans le cas contraire) Si vous

craignez de tels effets de bord au sein de la fonction membre concerneacutee vous pouvez tou-

jours employer le qualificatif const Ainsi ici len-tecircte de coincide aurait pu ecirctre

int pointcoincide (const point adpt)

5 - Mode de transmission des objets en argument101

en modifiant parallegravelement son prototype

int coincide (const point )

Notez toutefois quune telle preacutecaution ne peut pas ecirctre prise avec largument implicite

quest lobjet ayant appeleacute la fonction Ainsi dans coincide muni de len-tecircte ci-dessus

vous ne pourriez plus modifier adpt -gt x mais vous pourriez toujours modifier x Lagrave

encore lrsquoutilisation drsquoune fonction amie permettra drsquoassurer lrsquoeacutegaliteacute de traitement des

deux arguments en particulier au niveau de leur constance

52 Transmission par reacutefeacuterenceComme nous lavons vu lemploi des reacutefeacuterences permet de mettre en place une transmission

par adresse sans avoir agrave en prendre en charge soi-mecircme la gestion Elle simplifie dautant

leacutecriture de la fonction concerneacutee et ses diffeacuterents appels Voici une adaptation de coincide

dans laquelle son argument est transmis par reacutefeacuterence

include ltiostreamgtusing namespace std 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 amp) une fonction membre coincide int pointcoincide (point amp pt) if ( (ptx == x) ampamp (pty == y) ) return 1 else return 0 main() Un petit programme dessai point a b(1) c(10) cout ltlt a et b ltlt acoincide(b) ltlt ou ltlt bcoincide(a) ltlt n cout ltlt b et c ltlt bcoincide(c) ltlt ou ltlt ccoincide(b) ltlt n

a et b 0 ou 0b et c 1 ou 1

Exemple de transmission par reacutefeacuterence dun objet agrave une fonction membre

Remarque

La remarque preacuteceacutedente (en fin de paragraphe 51) sur les risques deffets de bord sappli-

que eacutegalement ici Le qualificatif const pourrait y intervenir de maniegravere analogue

int pointcoincide (const point amp pt)

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

102

53 Les problegravemes poseacutes par la transmission par valeurNous avons deacutejagrave vu que laffectation dobjets pouvait poser des problegravemes dans le cas ougrave ces

objets posseacutedaient des pointeurs sur des emplacements alloueacutes dynamiquement Ces poin-

teurs eacutetaient effectivement recopieacutes mais il nen allait pas de mecircme des emplacements poin-

teacutes Le transfert drsquoarguments par valeur preacutesente les mecircmes risques dans la mesure ougrave il

sagit eacutegalement dune simple recopie

De mecircme que le problegraveme poseacute par laffectation peut ecirctre reacutesolu par la surdeacutefinition de cet

opeacuterateur celui poseacute par le transfert par valeur peut ecirctre reacutegleacute par lemploi dun constructeur

particulier nous vous montrerons comment degraves le prochain chapitre

Dune maniegravere geacuteneacuterale dailleurs nous verrons que les problegravemes poseacutes par les objets conte-

nant des pointeurs se ramegravenent effectivement agrave laffectation et agrave lrsquoinitialisation1 dont la

recopie en cas de transmission par valeur constitue un cas particulier

6 Lorsqursquoune fonction renvoie un objetCe que nous avons dit agrave propos des arguments dune fonction membre sapplique eacutegalement agrave

sa valeur de retour Cette derniegravere peut ecirctre un objet et on peut choisir entre

bull transmission par valeur

bull transmission par adresse

bull transmission par reacutefeacuterence

Cet objet pourra ecirctre

bull du mecircme type que la classe auquel cas la fonction aura accegraves agrave ses membres priveacutes

bull dun type diffeacuterent de la classe auquel cas la fonction naura accegraves quagrave ses membres publics

La transmission par valeur suscite la mecircme remarque que preacuteceacutedemment par deacutefaut elle se

fait par simple recopie de lobjet Pour les objets comportant des pointeurs sur des emplace-

ments dynamiques il faudra preacutevoir un constructeur particulier (dinitialisation)

En revanche la transmission dune adresse ou la transmission par reacutefeacuterence risquent de poser

un problegraveme qui nexistait pas pour les arguments Si une fonction transmet ladresse ou la

reacutefeacuterence dun objet il vaut mieux eacuteviter quil sagisse dun objet local agrave la fonction cest-agrave-

dire de classe automatique En effet dans ce cas lemplacement de cet objet sera libeacutereacute2 degraves

la sortie de la fonction la fonction appelante reacutecupeacuterera ladresse de quelque chose nexistant

plus vraiment3 Nous reviendrons plus en deacutetail sur ce point dans le chapitre consacreacute agrave la

surdeacutefinition dopeacuterateurs

1 Bien que cela napparaisse pas toujours clairement en C il est tregraves important de noter qursquoen C++ affectation et

initialisation sont deux choses diffeacuterentes

2 Comme nous le verrons en deacutetail au chapitre suivant il y aura appel du destructeur sil existe

7 - Autoreacutefeacuterence le mot cleacute this103

A titre dexemple voici une fonction membre nommeacutee symetrique qui pourrait ecirctre introduite

dans une classe point pour fournir en retour un point symeacutetrique de celui layant appeleacute

point pointsymetrique ( ) point res resx = -x resy = -y return res

Vous constatez quil a eacuteteacute neacutecessaire de creacuteer un objet automatique res au sein de la fonction

Comme nous lavons expliqueacute ci-dessus il ne serait pas conseilleacute den preacutevoir une transmis-

sion par reacutefeacuterence en utilisant cet en-tecircte

point amp pointsymetrique ( )

7 Autoreacutefeacuterence le mot cleacute thisNous avons eu souvent loccasion de dire quune fonction membre dune classe reccediloit une

information lui permettant dacceacuteder agrave lobjet layant appeleacute Le terme information bien

quil soit relativement flou nous a suffi pour expliquer tous les exemples rencontreacutes jusquici

Mais nous navions pas besoin de manipuler explicitement ladresse de lobjet en question Or

il existe des circonstances ougrave cela devient indispensable Songez par exemple agrave la gestion

dune liste chaicircneacutee dobjets de mecircme nature pour eacutecrire une fonction membre inseacuterant un

nouvel objet (supposeacute transmis en argument implicite) il faudra bien placer son adresse dans

lobjet preacuteceacutedent de la liste

Pour reacutesoudre de tels problegravemes C++ a preacutevu le mot cleacute this Celui-ci utilisable unique-

ment au sein dune fonction membre deacutesigne un pointeur sur lobjet layant appeleacute

Ici il serait preacutematureacute de deacutevelopper lexemple de liste chaicircneacutee dont nous venons de parler

nous vous proposons un exemple deacutecole dans la classe point la fonction affiche fournit

ladresse de lobjet layant appeleacute

include ltiostreamgtusing namespace std 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 pointaffiche () cout ltlt Adresse ltlt this ltlt - Coordonnees ltlt x ltlt ltlt y ltlt n

3 Dans certaines impleacutementations un emplacement libeacutereacute nest pas remis agrave zeacutero Ainsi on peut avoir lillusion que

cela marche si lon se contente dexploiter lobjet immeacutediatement apregraves lappel de la fonction

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

104

main() Un petit programme dessai point a(5) b(315) aaffiche () baffiche ()

Adresse 006AFDF0 - Coordonnees 5 0Adresse 006AFDE8 - Coordonnees 3 15

Exemple dutilisation de this

Remarques

A titre purement indicatif la fonction coincide du paragraphe 51 pourrait seacutecrire

int pointcoincide (point adpt) if ((this -gt x == adpt -gt x) ampamp (this -gt y == adpt -gt y)) return 1 else return 0

La symeacutetrie du problegraveme y apparaicirct plus clairement Ce serait moins le cas si lon eacutecri-

vait ainsi la fonction coincide du paragraphe 4

int pointcoincide (point pt) if ((this -gt x == ptx)) ampamp (this -gt y == pty)) return 1 else return 0

En Java

Le mot cleacute this existe eacutegalement en Java avec une signification voisine il deacutesigne lrsquoobjet

ayant appeleacute une fonction membre au lieu de son adresse en C++ (de toute faccedilon la

notion de pointeur nrsquoexiste pas en Java)

8 Les fonctions membres statiquesNous avons deacutejagrave vu (paragraphe 5 du chapitre 5) comment C++ permet de deacutefinir des mem-

bres donneacutees statiques Ceux-ci existent en un seul exemplaire (pour une classe donneacutee)

indeacutependamment des objets de leur classe

Dune maniegravere analogue on peut imaginer que certaines fonctions membres dune classe

aient un rocircle totalement indeacutependant dun quelconque objet ce serait notamment le cas dune

fonction qui se contenterait dagir sur des membres donneacutees statiques

On peut certes toujours appeler une telle fonction en la faisant porter artificiellement sur un

objet de la classe et ce bien que ladresse de cet objet ne soit absolument pas utile agrave la fonc-

tion En fait il est possible de rendre les choses plus lisibles et plus efficaces en deacuteclarant sta-

8 - Les fonctions membres statiques105

tique (mot cleacute static) la fonction membre concerneacutee Dans ce cas en effet son appel ne

neacutecessite plus que le nom de la classe correspondante (accompagneacute naturellement de lopeacute-

rateur de reacutesolution de porteacutee) Comme pour les membres statiques une telle fonction mem-

bre statique peut mecircme ecirctre appeleacutee lorsquil nexiste aucun objet de sa classe

Voici un exemple de programme illustrant lemploi dune fonction membre statique il sagit

de lexemple preacutesenteacute au paragraphe 53 du chapitre 5 dans lequel nous avons introduit une

fonction membre statique nommeacutee compte affichant simplement le nombre dobjets de sa

classe

include ltiostreamgtusing namespace std class cpte_obj static int ctr compteur (statique) du nombre dobjets creacuteeacutes public cpte_obj () ~cpte_obj() static void compte () pour afficher le nombre dobjets creacuteeacutes int cpte_objctr = 0 initialisation du membre statique ctrcpte_objcpte_obj () constructeur cout ltlt ++ construction il y a maintenant ltlt ++ctr ltlt objetsn cpte_obj~cpte_obj () destructeur cout ltlt -- destruction il reste maintenant ltlt --ctr ltlt objetsn void cpte_objcompte () cout ltlt appel compte il y a ltlt ctr ltlt objetsn main() void fct () cpte_objcompte () appel de la fonction membre statique compte alors quaucun objet de sa classe nexiste cpte_obj a cpte_objcompte () fct () cpte_objcompte () cpte_obj b cpte_objcompte () 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

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

106

++ 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

appel compte il y a 2 objets

-- destruction il reste maintenant 1 objets

-- destruction il reste maintenant 0 objets

Deacutefinition et utilisation dune fonction membre statique

En Java

Les fonctions membres statiques existent eacutegalement en Java et elles se deacuteclarent agrave lrsquoaide

du mecircme mot cleacute static

9 Les fonctions membres constantes

91 Rappels sur lrsquoutilisation de const en CEn langage C le qualificatif const peut servir agrave deacutesigner une variable dont on souhaite que la

valeur neacutevolue pas Le compilateur est ainsi en mesure de rejeter deacuteventuelles tentatives de

modification de cette variable Par exemple avec cette deacuteclaration

const int n=20

linstruction suivante sera incorrecte

n = 12 incorrecte n nrsquoest pas une lvalue

De la mecircme maniegravere on ne peut modifier la valeur drsquoun argument muet deacuteclareacute constant

dans lrsquoen-tecircte drsquoune fonction

void f(const int n) ou mecircme void f(const int amp n) - voir remarque

n++ incorrect n nrsquoest pas une lvalue

Remarque

Ne confondez pas un argument muet deacuteclareacute const et un argument effectif deacuteclareacute const

Dans le premier cas la deacuteclaration const constitue une sorte de contrat le program-

meur de la fonction srsquoengage agrave ne pas en modifier la valeur et ce mecircme si au bout du

compte la fonction travaille sur une copie de la valeur de lrsquoargument effectif (ce qui est le

cas avec la transmission par valeur avec une reacutefeacuterence agrave une constante )

9 - Les fonctions membres constantes107

92 Deacutefinition drsquoune fonction membre constanteC++ eacutetend ce concept de constance des variables aux classes ce qui signifie quon peut deacutefi-

nir des objets constants Encore faut-il comprendre ce que lon entend par lagrave En effet dans

le cas dune variable ordinaire le compilateur peut assez facilement identifier les opeacuterations

interdites (celles qui peuvent en modifier la valeur) En revanche dans le cas dun objet les

choses sont moins faciles car les opeacuterations sont geacuteneacuteralement reacutealiseacutees par les fonctions

membres Cela signifie que lutilisateur doit preacuteciser parmi ces fonctions membres lesquel-

les sont autoriseacutees agrave opeacuterer sur des objets constants Il le fera en utilisant le mot const dans

leur deacuteclaration comme dans cet exemple de deacutefinition dune classe point

class point int x y public point () void affiche () const void deplace ()

Remarque

La remarque du paragraphe 91 agrave propos des arguments muets constants srsquoapplique

encore ici Il ne faut pas confondre un argument muet deacuteclareacute const et un argument effec-

tif deacuteclareacute const

93 Proprieacuteteacutes drsquoune fonction membre constanteLe fait de speacutecifier que la fonction affiche est constante a deux conseacutequences

1 Elle est utilisable pour un objet deacuteclareacute constant

Ici nous avons speacutecifieacute que la fonction affiche eacutetait utilisable pour un point constant En

revanche la fonction deplace qui na pas fait lobjet dune deacuteclaration const ne le sera pas

Ainsi avec ces deacuteclarations

point a const point c

les instructions suivantes seront correctes

aaffiche () caffiche () adeplace ()

En revanche celle-ci sera rejeteacutee par le compilateur

cdeplace () incorrecte c est constant alors que deplace ne lrsquoest pas

La mecircme remarque srsquoappliquerait agrave un objet reccedilu en argument

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

108

void f (const point p) ou mecircme void f(const point amp p) - voir remarque paffiche () OK pdeplace () incorrecte

2 Les instructions figurant dans sa deacutefinition ne doivent pas modifier la valeur des membres

de lrsquoobjet point

class point int x y public void affiche () const x++ erreur car affiche a eacuteteacute deacuteclareacutee const

Les membres statiques font naturellement exception agrave cette regravegle car ils ne sont pas associeacutes

agrave un objet particulier

class compte static int n public void test() const n++ OK bien que test soit deacuteclareacutee constante car n est un membre statique

Remarques

1 Le meacutecanisme que nous venons dexposer sapplique aux fonctions membres volatiles et

aux objets volatiles (mot cleacute volatile) Il suffit de transposer tout ce qui vient drsquoecirctre dit en

remplaccedilant le mot cleacute const par le mot cleacute volatile

2 Il est possible de surdeacutefinir une fonction membre en se fondant sur la preacutesence ou

labsence du qualificatif const Ainsi dans la classe point preacuteceacutedente nous pouvons

deacutefinir ces deux fonctions

void affiche () const affiche I void affiche () affiche II

Avec ces deacuteclarations

point a const point c

linstruction aaffiche () appellera la fonction II tandis que caffiche () appellera la fonc-

tion I

On notera bien que si seule la fonction void affiche() est deacutefinie elle ne pourra en aucun

cas ecirctre appliqueacutee agrave un objet constant une instruction telle que caffiche() serait alors

rejeteacutee en compilation En revanche si seule la fonction const void affiche() est deacutefinie

10 - Les membres mutables109

elle pourra ecirctre appliqueacutee indiffeacuteremment agrave des objets constants ou non Une telle atti-

tude est logique

ndash on ne court aucun risque en traitant un objet non constant comme sil eacutetait constant

ndash en revanche il serait dangereux de faire agrave un objet constant ce quon a preacutevu de faire agrave

un objet non constant

3 Pour pouvoir deacuteclarer un objet constant il faut ecirctre sucircr que le concepteur de la classe

correspondante a eacuteteacute exhaustif dans le recencement des fonctions membres constantes

(crsquoest-agrave-dire deacuteclareacutees avec le qualificatif const) Dans le cas contraire on risque de ne

plus pouvoir appliquer certaines fonctionnaliteacutes agrave un tel objet constant Par exemple on

ne pourra pas appliquer la meacutethode affiche agrave un objet constant de type point si celle-ci

nrsquoa pas effectivement eacuteteacute deacuteclareacutee constante dans la classe

En Java

La notion de fonction membre constante nrsquoexiste pas en Java

10 Les membres mutablesUne fonction membre constante ne peut pas modifier les valeurs de membres non statiques

La norme a jugeacute que cette restriction pouvait parfois srsquoaveacuterer trop contraignante Elle a intro-

duit le qualificatif mutable pour deacutesigner des champs dont on accepte la modification mecircme

par des fonctions membres constantes Voici un petit exemple

class truc int x y mutable int n n est modifiable par une fonction membre constante void f() x = 5 n++ rien de nouveau ici void f1() const n++ OK car n est deacuteclareacute mutable x = 5 erreur f1 est const et x nrsquoest pas mutable

Comme on peut srsquoy attendre les membres publics deacuteclareacutes avec le qualificatif mutable sont

modifiables par affectation

class truc2 public int n mutable int p const truc c cn = 5 erreur lrsquoobjet c est constant et n nrsquoest pas mutablecp = 5 OK lrsquoobjet c est constant mais p est mutable

Les proprieacuteteacutes des fonctions membresCHAPITRE 6

110

En Java

En Java il nrsquoexiste pas de membres constants a fortiori il ne peut y avoir de membres

mutables

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 (C) Ecrivez une classe vecteur comportant

bull trois composantes de type double (priveacutees)

bull une fonction affiche

bull deux constructeurs

ndash lun sans arguments initialisant chaque composante agrave 0

ndash lautre avec 3 arguments repreacutesentant les composantes

a) avec des fonctions membres indeacutependantes

b) avec des fonctions membres en ligne

2 (C) Ajoutez agrave la premiegravere classe vecteur preacuteceacutedente une fonction membre nommeacutee

prod_scal fournissant en reacutesultat le produit scalaire de deux vecteurs

3 (C) Ajoutez agrave la classe vecteur preacuteceacutedente (exercice 2) une fonction membre nommeacutee

somme permettant de calculer la somme de deux vecteurs

4 (C) Modifiez la classe vecteur preacuteceacutedente (exercice 3) de maniegravere que toutes les transmis-

sions de valeurs de type vecteur aient lieu

a) par adresse

b) par reacutefeacuterence

7

Construction destructionet initialisation des objets

En langage C une variable peut ecirctre creacuteeacutee de deux faccedilons

bull par une deacuteclaration elle est alors de classe automatique ou statique sa dureacutee de vie est

parfaitement deacutefinie par la nature et lemplacement de sa deacuteclaration

bull en faisant appel agrave des fonctions de gestion dynamique de la meacutemoire (malloc calloc

free) elle est alors dite dynamique sa dureacutee de vie est controcircleacutee par le programme

En langage C++ on retrouvera ces trois classes agrave la fois pour les variables ordinaires et pour

les objets avec cette diffeacuterence que la gestion dynamique fera appel aux opeacuterateurs new et

delete

Dans ce chapitre nous eacutetudierons ces diffeacuterentes possibiliteacutes de creacuteation (donc aussi de des-

truction) des objets Nous commencerons par examiner la creacuteation et la destruction des objets

automatiques et statiques deacutefinis par une deacuteclaration Puis nous montrerons comment creacuteer et

utiliser des objets dynamiques dune maniegravere comparable agrave celle employeacutee pour creacuteer des

variables dynamiques ordinaires en faisant appel agrave une syntaxe eacutelargie de lopeacuterateur new

Nous aborderons ensuite la notion de constructeur de recopie qui intervient dans les situa-

tions dites drsquoinitialisation dun objet cest-agrave-dire lorsquil est neacutecessaire de reacutealiser une

copie dun objet existant Nous verrons quil existe trois situations de ce type transmission

de la valeur dun objet en argument dune fonction transmission de la valeur dun objet en

reacutesultat dune fonction initialisation dun objet lors de sa deacuteclaration par un objet de mecircme

Construction destruction et initialisation des objetsCHAPITRE 7

112

type cette derniegravere possibiliteacute neacutetant quun cas particulier dinitialisation dun objet au

moment de sa deacuteclaration

Puis nous examinerons le cas des objets membres cest-agrave-dire le cas ougrave un type classe pos-

segravede des membres donneacutees eux-mecircme dun type classe Nous aborderons rapidement le cas

du tableau dobjets notion dautant moins importante quun tel tableau nest pas lui-mecircme un

objet

Enfin nous fournirons quelques indications concernant les objets dits temporaires cest-agrave-

dire pouvant ecirctre creacuteeacutes au fil du deacuteroulement du programme1 sans que le programmeur lait

explicitement demandeacute

1 Les objets automatiques et statiquesNous examinons seacutepareacutement

bull leur dureacutee de vie cest-agrave-dire le moment ougrave ils sont creacuteeacutes et celui ougrave ils sont deacutetruits

bull les eacuteventuels appels des constructeurs et des destructeurs

11 Dureacutee de vieLes regravegles sappliquant aux variables ordinaires se transposent tout naturellement aux objets

Les objets automatiques sont ceux creacuteeacutes par une deacuteclaration

bull dans une fonction ceacutetait le cas dans les exemples des chapitres preacuteceacutedents Lrsquoobjet est

creacuteeacute lors de la rencontre de sa deacuteclaration laquelle peut tregraves bien en C++ ecirctre situeacutee apregraves

dautres instructions exeacutecutables2 Il est deacutetruit agrave la fin de lexeacutecution de la fonction

bull dans un bloc lrsquoobjet est aussi creacuteeacute lors de la rencontre de sa deacuteclaration (lagrave encore celle-

ci peut ecirctre preacuteceacutedeacutee au sein de ce bloc dautres instructions exeacutecutables) il est deacutetruit lors

de la sortie du bloc

Les objets statiques sont ceux creacuteeacutes par une deacuteclaration situeacutee

bull en dehors de toute fonction

bull dans une fonction mais assortie du qualificatif static

Les objets statiques sont creacuteeacutes avant le deacutebut de lexeacutecution de la fonction main et deacutetruits

apregraves la fin de son exeacutecution

1 En C il existe deacutejagrave des variables temporaires mais leur existence a moins drsquoimportance que celle des objets

temporaires en C++

2 La distinction entre instruction exeacutecutable et instruction de deacuteclaration nest pas toujours possible dans un langage

comme C++ qui accepte par exemple une instruction telle que

double adr = new double [nelem = 2 n+1]

1 - Les objets automatiques et statiques113

12 Appel des constructeurs et des destructeursRappelons que si un objet possegravede un constructeur sa deacuteclaration (lorsque comme nous le

supposons pour linstant elle ne contient pas drsquoinitialiseur) doit obligatoirement comporter

les arguments correspondants Par exemple si une classe point comporte le constructeur de

prototype

point (int int)

les deacuteclarations suivantes seront incorrectes

point a incorrect le constructeur attend deux argumentspoint b (3) incorrect (mecircme raison)

Celle-ci en revanche conviendra

point a(1 7) correct car le constructeur possegravede deux arguments

Sil existe plusieurs constructeurs il suffit que la deacuteclaration comporte les arguments requis

par lun dentre eux Ainsi si une classe point comporte les constructeurs suivants

point ( ) constructeur 1point (int int) constructeur 2

la deacuteclaration suivante sera rejeteacutee

point a(5) incorrect aucun constructeur agrave un argument

Mais celles-ci conviendront

point a correct appel du constructeur 1point b(1 7) correct appel du constructeur 2

En ce qui concerne la chronologie on peut dire que

bull le constructeur est appeleacute apregraves la creacuteation de lrsquoobjet

bull le destructeur est appeleacute avant la destruction de lobjet

Remarque

Une deacuteclaration telle que

point a attention point a () serait une deacuteclaration drsquoune fonction a

est acceptable dans deux situations fort diffeacuterentes

ndash il nexiste pas de constructeur de point

ndash il existe un constructeur de point sans argument

13 ExempleVoici un exemple de programme mettant en eacutevidence la creacuteation et la destruction dobjets sta-

tiques et automatiques Nous avons deacutefini une classe nommeacutee point dans laquelle le cons-

tructeur et le destructeur affichent un message permettant de repeacuterer

Construction destruction et initialisation des objetsCHAPITRE 7

114

bull le moment de leur appel

bull lrsquoobjet concerneacute (nous avons fait en sorte que chaque objet de type point possegravede des valeurs

diffeacuterentes)

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs int ord) constructeur (inline)

x = abs y = ord

cout ltlt ++ Construction dun point ltlt x ltlt ltlt y ltlt n

~point () destructeur (inline)

cout ltlt -- Destruction du point ltlt x ltlt ltlt y ltlt n

point a(11) un objet statique de classe point

main()

cout ltlt Debut main n

point b(1010) un objet automatique de classe point

int i

for (i=1 ilt=3 i++)

cout ltlt Boucle tour numero ltlt i ltlt n

point b(i2i) objets creacuteeacutes dans un bloc

cout ltlt Fin main n

++ Construction dun point 1 1

Debut main

++ Construction dun point 10 10

Boucle tour numero 1

++ Construction dun point 1 2

-- Destruction du point 1 2

Boucle tour numero 2

++ Construction dun point 2 4

-- Destruction du point 2 4

Boucle tour numero 3

++ Construction dun point 3 6

-- Destruction du point 3 6

Fin main

2 - Les objets dynamiques115

-- Destruction du point 10 10-- Destruction du point 1 1

Construction et destruction dobjets statiques et automatiques

Remarque

Lexistence de constructeurs et de destructeurs conduit agrave des traitements qui napparais-

sent pas explicitement dans les instructions du programme Par exemple ici une deacuteclara-

tion banale telle que

point b(10 10)

entraicircne laffichage dun message

Qui plus est un certain nombre drsquoopeacuterations se deacuteroulent avant le deacutebut ou apregraves lexeacute-

cution de la fonction main1 On pourrait agrave la limite concevoir une fonction main ne

comportant que des deacuteclarations (ce qui serait le cas de notre exemple si nous suppri-

mions linstruction daffichage du tour de boucle) et reacutealisant malgreacute tout un certain

traitement

2 Les objets dynamiquesNous avons deacutejagrave vu comment creacuteer utiliser et deacutetruire des variables dynamiques scalaires (ou

des tableaux de telles variables) en C++ Bien entendu ces possibiliteacutes srsquoeacutetendent aux struc-

tures et aux objets Nous commencerons par les structures ce qui nous permettra un certain

nombre de rappels sur lutilisation des structures dynamiques en C

21 Les structures dynamiquesSupposez que nous ayons deacutefini la structure suivante

struct chose int x double y int t [5]

et que adr soit un pointeur sur des eacuteleacutements de ce type cest-agrave-dire deacuteclareacute en C par

struct chose adr

1 En toute rigueur il en va deacutejagrave de mecircme dans le cas dun programme C (ouverture ou fermeture de fichiers par

exemple) mais il ne sagit pas alors de tacircches programmeacutees explicitement par lauteur du programme dans le cas de

C++ il sagit de tacircches programmeacutees par le concepteur de la classe concerneacutee

Construction destruction et initialisation des objetsCHAPITRE 7

116

ou plus simplement en C++ par

chose adr

Linstruction

adr = new chose

reacutealise une allocation dynamique despace meacutemoire pour un eacuteleacutement de type chose et affecte

son adresse au pointeur adr

Laccegraves aux diffeacuterents champs de cette structure se fait agrave laide de lopeacuterateur -gt Ainsi adr -

gt y deacutesignera le second champ Rappelons que cette notation est en fait eacutequivalente agrave (adr)

y

Lespace meacutemoire ainsi alloueacute pourra ecirctre libeacutereacute par

delete adr

22 Les objets dynamiquesVoyons tout dabord ce quil y a de commun entre la creacuteation dynamique dobjets et celle de

structures avant deacutetudier les nouvelles possibiliteacutes de lopeacuterateur new

221 Points communs avec les structures dynamiquesLe meacutecanisme que nous venons deacutevoquer sapplique aux objets (au sens large) lorsquils ne

possegravedent pas de constructeur Ainsi si nous deacutefinissons le type point suivant

class point

int x y

public

void initialise (int int)

void deplace (int int)

void affiche ( )

et si nous deacuteclarons

point adr

nous pourrons creacuteer dynamiquement un emplacement de type point (qui contiendra donc ici

la place pour deux entiers) et affecter son adresse agrave adr par

adr = new point

Laccegraves aux fonctions membres de lrsquoobjet pointeacute par adr se fera par des appels de la forme

adr -gt initialise (1 3)

adr -gt affiche ( )

ou eacuteventuellement sans utiliser lopeacuterateur -gt par

( adr)initialise (1 3)

( adr)affiche ( )

Si lrsquoobjet contenait des membres donneacutees publics on y acceacutederait de faccedilon comparable

Quant agrave la suppression de lrsquoobjet en question elle se fera ici encore par

delete adr

2 - Les objets dynamiques117

222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete

Nous avons deacutejagrave vu que la philosophie de C++ consiste agrave faire du constructeur (degraves lors quil

existe) un passage obligeacute lors de la creacuteation dun objet Il en va de mecircme pour le destructeur

lors de la destruction dun objet

Cette philosophie sapplique eacutegalement aux objets dynamiques Plus preacuteciseacutement

bull Apregraves lallocation dynamique de lemplacement meacutemoire requis lopeacuterateur new appelle-

ra un constructeur de lrsquoobjet ce constructeur sera deacutetermineacute par la nature des arguments

qui figurent agrave la suite de son appel comme dans

new point (2 5)

On peut dire que le constructeur appeleacute est le mecircme que celui qui aurait eacuteteacute appeleacute par une

deacuteclaration telle que

a = point (2 5)

Bien entendu sil nexiste pas de constructeur ou sil existe un constructeur sans argument

la syntaxe

new point ou new point ()

sera accepteacutee En revanche si tous les constructeurs possegravedent au moins un argument cette

syntaxe sera rejeteacutee

On retrouve lagrave en deacutefinitive les mecircmes regravegles que celles sappliquant agrave la deacuteclaration dun

objet

bull Avant la libeacuteration de lemplacement meacutemoire correspondant lopeacuterateur delete appellera

le destructeur

223 Exemple

Voici un exemple de programme qui creacutee dynamiquement un objet de type point dans la

fonction main et qui le deacutetruit dans une fonction fct (appeleacutee par main) Les messages affi-

cheacutes permettent de mettre en eacutevidence les moments auxquels sont appeleacutes le constructeur et

le destructeur

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) constructeur x=abs y=ord cout ltlt ++ Appel Constructeur n ~point () destructeur (en fait inutile ici) cout ltlt -- Appel Destructeur n

Construction destruction et initialisation des objetsCHAPITRE 7

118

main() void fct (point ) prototype fonction fct point adr cout ltlt Debut main n adr = new point (37) creacuteation dynamique dun objet fct (adr) cout ltlt Fin main n void fct (point adp) cout ltlt Debut fct n delete adp destruction de cet objet cout ltlt Fin fct n

Debut main ++ Appel Constructeur Debut fct -- Appel Destructeur Fin fct Fin main

Exemple de creacuteation dynamique dobjets

En Java

Il nrsquoexiste qursquoune seule maniegravere de geacuterer la meacutemoire alloueacutee agrave un objet agrave savoir de

maniegravere dynamique Les emplacements sont alloueacutes explicitement en faisant appel agrave une

meacutethode nommeacutee eacutegalement new En revanche leur libeacuteration se fait automatiquement

gracircce agrave un ramasse-miettes destineacute agrave reacutecupeacuterer les emplacements qui ne sont plus reacutefeacuteren-

ceacutes

3 Le constructeur de recopie

31 PreacutesentationNous avons vu comment C++ garantissait lappel dun constructeur pour un objet creacuteeacute par une

deacuteclaration ou par new Ce point est fondamental puisquil donne la certitude quun objet ne

pourra ecirctre creacuteeacute sans avoir eacuteteacute placeacute dans un eacutetat initial convenable (du moins jugeacute comme

tel par le concepteur de lrsquoobjet)

Mais il existe des circonstances dans lesquelles il est neacutecessaire de construire un objet mecircme

si le programmeur na pas preacutevu de constructeur pour cela La situation la plus freacutequente est

celle ougrave la valeur dun objet doit ecirctre transmise en argument agrave une fonction Dans ce cas il est

3 - Le constructeur de recopie119

neacutecessaire de creacuteer dans un emplacement local agrave la fonction un objet qui soit une copie de

largument effectif Le mecircme problegraveme se pose dans le cas dun objet renvoyeacute par valeur

comme reacutesultat dune fonction il faut alors creacuteer dans un emplacement local agrave la fonction

appelante un objet qui soit une copie du reacutesultat Nous verrons quil existe une troisiegraveme

situation de ce type agrave savoir le cas ougrave un objet est initialiseacute lors de sa deacuteclaration avec un

autre objet de mecircme type

Dune maniegravere geacuteneacuterale on regroupe ces trois situations sous le nom dinitialisation par

recopie1 Une initialisation par recopie dun objet est donc la creacuteation dun objet par recopie

dun objet existant de mecircme type

Pour reacutealiser une telle initialisation C++ a preacutevu dutiliser un constructeur particulier dit

constructeur de recopie2 (nous verrons plus loin la forme exacte quil doit posseacuteder) Si un

tel constructeur nexiste pas un traitement par deacutefaut est preacutevu on peut dire de faccedilon eacutequi-

valente quon utilise un constructeur de recopie par deacutefaut

En deacutefinitive on peut dire que dans toute situation dinitialisation par recopie il y toujours

appel dun constructeur de recopie mais il faut distinguer deux cas principaux et un cas parti-

culier

311 Il nexiste pas de constructeur approprieacute

Il y alors appel dun constructeur de recopie par deacutefaut geacuteneacutereacute automatiquement par le

compilateur Ce constructeur se contente deffectuer une copie de chacun des membres On

retrouve lagrave une situation analogue agrave celle qui est mise en place (par deacutefaut) lors dune affecta-

tion entre objets de mecircme type Elle posera donc les mecircmes problegravemes pour les objets conte-

nant des pointeurs sur des emplacements dynamiques On aura simplement affaire agrave une

copie superficielle cest-agrave-dire que seules les valeurs des pointeurs seront recopieacutees les

emplacements pointeacutes ne le seront pas ils risquent alors par exemple drsquoecirctre deacutetruits deux

fois

312 Il existe un constructeur approprieacute

Vous pouvez fournir explicitement dans votre classe un constructeur de recopie Il doit

alors sagir dun constructeur disposant drsquoun seul argument3 du type de la classe et transmis

obligatoirement par reacutefeacuterence Cela signifie que son en-tecircte doit ecirctre obligatoirement de lune

de ces deux formes (si la classe concerneacutee se nomme point)

point (point amp) point (const point amp)

Dans ce cas ce constructeur est appeleacute de maniegravere habituelle apregraves la creacuteation de lobjet

Bien entendu aucune recopie nest faite de faccedilon automatique pas mecircme une recopie super-

1 Nous aurions pu nous limiter au terme initialisation sil nexistait pas des situations ougrave lon peut initialiser un objet

avec une valeur ou un objet dun type diffeacuterent

2 En anglais copy constructor

3 En toute rigueur la norme ANSI du C++ accepte eacutegalement un constructeur disposant drsquoarguments

suppleacutementaires pourvu qursquoils possegravedent des valeurs par deacutefaut

Construction destruction et initialisation des objetsCHAPITRE 7

120

ficielle contrairement agrave la situation preacuteceacutedente cest agrave ce constructeur de prendre en charge

linteacutegraliteacute du travail (copie superficielle et copie profonde)

313 Lorsqursquoon souhaite interdire la contruction par recopie

On a vu que la copie par deacutefaut des objets contenant des pointeurs nrsquoeacutetait pas satisfaisante

Dans certains cas plutocirct que de munir une classe du constructeur de recopie voulu le con-

cepteur pourra chercher agrave interdire la copie des objets de cette classe Il dispose alors pour

cela de diffeacuterentes possibiteacutes

Par exemple comme nous venons de le voir un constructeur priveacute nrsquoest pas appelable par un

utilisateur de la classe On peut aussi utiliser la possibliteacute offerte par C++ de deacuteclarer une

fonction sans en fournir de deacutefinition dans ce cas toute tentative de copie (mecircme par une

fonction membre cette fois) sera rejeteacutee par lrsquoeacutediteur de liens Drsquoune maniegravere geacuteneacuterale il

peut ecirctre judicieux de combiner les deux possibiliteacutes crsquoest-agrave-dire drsquoeffectuer une deacuteclaration

priveacutee sans deacutefinition Dans ce cas les tentatives de recopie par lrsquoutilisateur resteront deacutetec-

teacutees en compilation (avec un message explicite) et seules les recopies par une fonction mem-

bre se limiteront agrave une erreur drsquoeacutedition de liens (et ce point ne concerne que le concepteur de

la classe pas son utilisateur )

Remarques

1 Notez bien que C++ impose au constructeur par recopie que son unique argument soit

transmis par reacutefeacuterence (ce qui est logique puisque sinon lappel du constructeur de reco-

pie impliquerait une initialisation par recopie de largument donc un appel du construc-

teur de recopie qui lui-mecircme etc)

Quoi quil en soit la forme suivante serait rejeteacutee en compilation

point (point) incorrect

2 Les deux formes preacuteceacutedentes (point (point amp) et point (const point amp)) pourraient exis-

ter au sein dune mecircme classe Dans ce cas la premiegravere serait utiliseacutee en cas dinitialisa-

tion dun objet par un objet quelconque tandis que la seconde serait utiliseacutee en cas

dinitialisation par un objet constant En geacuteneacuteral comme un tel constructeur de recopie

na logiquement aucune raison de vouloir modifier lrsquoobjet reccedilu en argument il est con-

seilleacute de ne deacutefinir que la seconde forme qui restera ainsi applicable aux deux situa-

tions eacutevoqueacutees (une fonction preacutevue pour un objet constant peut toujours sappliquer agrave

un objet variable la reacuteciproque eacutetant naturellement fausse)

3 Nous avons deacutejagrave rencontreacute des situations de recopie dans le cas de laffectation Mais

alors les deux objets concerneacutes existaient deacutejagrave laffectation nest donc pas une situation

dinitialisation par recopie telle que nous venons de la deacutefinir Bien que les deux opeacutera-

tions possegravedent un traitement par deacutefaut semblable (copie superficielle) la prise en

compte dune copie profonde passe par des meacutecanismes diffeacuterents deacutefinition dun

constructeur de recopie pour lrsquoinitialisation surdeacutefinition de lopeacuterateur = pour laffec-

tation (ce que nous apprendrons agrave faire dans le chapitre consacreacute agrave la surdeacutefinition des

opeacuterateurs)

3 - Le constructeur de recopie121

4 Nous verrons que si une classe est destineacutee agrave donner naissance agrave des objets susceptibles

drsquoecirctre introduits dans des conteneurs il ne sera plus possible drsquoen deacutesactiver la reco-

pie (pas plus que lrsquoaffectation)

En Java

Les objets sont manipuleacutes non par valeur mais par reacutefeacuterence La notion de constructeur

de recopie nrsquoexiste pas En cas de besoin il reste possible de creacuteer explicitement une

copie profonde drsquoun objet nommeacutee clone

32 Exemple 1 objet transmis par valeurNous vous proposons de comparer les deux situations que nous venons deacutevoquer constructeur

de recopie par deacutefaut constructeur de recopie deacutefini dans la classe Pour ce faire nous allons

utiliser une classe vect permettant de geacuterer des tableaux dentiers de taille variable (on devrait

plutocirct dire de taille deacutefinissable lors de lexeacutecution car une fois deacutefinie cette taille ne changera

plus) Nous souhaitons que lutilisateur de cette classe deacuteclare un tableau sous la forme

vect t (dim)

dim eacutetant une expression entiegravere repreacutesentant sa taille

Il paraicirct alors naturel de preacutevoir pour vect

bull comme membres donneacutees la taille du tableau et un pointeur sur ses eacuteleacutements lesquels ver-

ront leurs emplacements alloueacutes dynamiquement

bull un constructeur recevant un argument entier chargeacute de cette allocation dynamique

bull un destructeur libeacuterant lemplacement alloueacute par le constructeur

Cela nous conduit agrave une premiegravere eacutebauche

class vect int nelem double adr public vect (int n) ~vect ( )

321 Emploi du constructeur de recopie par deacutefaut

Voici un exemple dutilisation de la classe vect preacuteceacutedente (nous avons ajouteacute des affichages

de messages pour suivre agrave la trace les constructions et destructions dobjets) Ici nous nous

contentons de transmettre par valeur un objet de type vect agrave une fonction ordinaire nommeacutee

fct qui ne fait rien dautre que dafficher un message indiquant son appel

include ltiostreamgtusing namespace std

Construction destruction et initialisation des objetsCHAPITRE 7

122

class vect

int nelem nombre deacuteleacutements

double adr pointeur sur ces eacuteleacutements

public

vect (int n) constructeur usuel

adr = new double [nelem = n]

cout ltlt + const usuel - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

~vect () destructeur

cout ltlt - Destr objet - adr objet

ltlt this ltlt - adr vecteur ltlt adr ltlt n

delete adr

void fct (vect b)

cout ltlt appel de fct n

main()

vect a(5)

fct (a)

+ const usuel - adr objet 006AFDE4 - adr vecteur 007D0320

appel de fct

- Destr objet - adr objet 006AFD90 - adr vecteur 007D0320

- Destr objet - adr objet 006AFDE4 - adr vecteur 007D0320

Lorsquaucun constructeur de recopie na eacuteteacute deacutefini

Comme vous pouvez le constater lappel

fct (a)

a creacuteeacute un nouvel objet dans lequel on a recopieacute les valeurs des membres nelem et adr de a

La situation peut ecirctre scheacutematiseacutee ainsi (b est le nouvel objet ainsi creacuteeacute)

a

b

5

5

3 - Le constructeur de recopie123

A la fin de lexeacutecution de la fonction fct le destructeur ~point est appeleacute pour b ce qui libegravere

lemplacement pointeacute par adr agrave la fin de lrsquoeacutexeacutecution de la fonction main le destructeur est

appeleacute pour a ce qui libegravere le mecircme emplacement Cette tentative constitue une erreur

dexeacutecution dont les conseacutequences varient avec lrsquoimpleacutementation

322 Deacutefinition dun constructeur de recopie

On peut eacuteviter ce problegraveme en faisant en sorte que lappel

fct (a)

conduise agrave creacuteer inteacutegralement un nouvel objet de type vect avec ses membres donneacutees

nelem et adr mais aussi son propre emplacement de stockage des valeurs du tableau Autre-

ment dit nous souhaitons aboutir agrave cette situation

Pour ce faire nous deacutefinissons au sein de la classe vect un constructeur par recopie de la

forme

vect (const vect amp) ou a la rigueur vect (vect amp)

dont nous savons quil sera appeleacute dans toute situation dinitialisation donc en particulier

lors de lappel de fct

Ce constructeur (appeleacute apregraves la creacuteation dun nouvel objet1) doit

bull creacuteer dynamiquement un nouvel emplacement dans lequel il recopie les valeurs correspon-

dant agrave lrsquoobjet reccedilu en argument

bull renseigner convenablement les membres donneacutees du nouvel objet (nelem = valeur du mem-

bre nelem de lrsquoobjet reccedilu en argument adr = adresse du nouvel emplacement)

1 Notez bien que le constructeur na pas agrave creacuteer lrsquoobjet lui-mecircme cest-agrave-dire ici les membres int et adr mais

simplement les parties soumises agrave la gestion dynamique

a

b

5

5

Construction destruction et initialisation des objetsCHAPITRE 7

124

Introduisons ce constructeur de recopie dans lrsquoexemple preacuteceacutedent

include ltiostreamgt

using namespace std

class vect

int nelem nombre deacuteleacutements

double adr pointeur sur ces eacuteleacutements

public

vect (int n) constructeur usuel

adr = new double [nelem = n]

cout ltlt + const usuel - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

vect (const vect amp v) constructeur de recopie

adr = new double [nelem = vnelem] creacuteation nouvel objet

int i for (i=0 iltnelem i++) adr[i]=vadr[i] recopie de lancien

cout ltlt + const recopie - adr objet ltlt this

ltlt - adr vecteur ltlt adr ltlt n

~vect () destructeur

cout ltlt - Destr objet - adr objet

ltlt this ltlt - adr vecteur ltlt adr ltlt n

delete adr

void fct (vect b)

cout ltlt appel de fct n

main()

vect a(5) fct (a)

+ const usuel - adr objet 006AFDE4 - adr vecteur 007D0320

+ const recopie - adr objet 006AFD88 - adr vecteur 007D0100

appel de fct

- Destr objet - adr objet 006AFD88 - adr vecteur 007D0100

- Destr objet - adr objet 006AFDE4 - adr vecteur 007D0320

Deacutefinition et utilisation dun constructeur de recopie

Vous constatez cette fois que chaque objet posseacutedant son propre emplacement meacutemoire les

destructions successives se deacuteroulent sans problegraveme

3 - Le constructeur de recopie125

Remarques

1 Si nous avons reacutegleacute le problegraveme de lrsquoinitialisation dun objet de type vect par un autre

objet du mecircme type nous navons pas pour autant reacutegleacute celui qui se poserait en cas

drsquoaffectation entre objets de type vect Comme nous lavons deacutejagrave signaleacute agrave plusieurs repri-

ses ce dernier point ne peut se reacutesoudre que par la surdeacutefinition de lopeacuterateur =

2 Nous avons choisi pour notre constructeur par recopie la deacutemarche la plus naturelle

consistant agrave effectuer une copie profonde en dupliquant la partie dynamique du vecteur

Dans certains cas on pourra chercher agrave eacuteviter cette duplication en la dotant drsquoun comp-

teur de reacutefeacuterences comme lrsquoexplique lrsquoAnnexe E

3 Si notre constructeur de recopie eacutetait deacuteclareacute priveacute lrsquoappel fct(a) entraicircnerait une erreur

de compilation preacutecisant qursquoun constructeur de recopie nrsquoest pas disponible Si le but

est de deacutefinir une classe dans laquelle la recopie est interdite il suffit alors de ne fournir

aucune deacutefinition On notera cependant qursquoil reste neacutecessaire de srsquoassurer qursquoaucune

fonction membre nrsquoaura besoin de ce constructeur ce qui serait par exemple le cas si

notre fonction membre f de la classe vect se preacutesentait ainsi

void f()

void fct (vect) deacuteclaration de la fonction ordinaire fct

vect v1(5)

fct (v1) appel de fct --gt appel contsructeur de recopie

vect v2 = v1 initialisation par appel constructeur de recopie

33 Exemple 2 objet en valeur de retour dune fonctionLorsque la transmission dun argument ou dune valeur de retour dune fonction a lieu par

valeur elle met en œuvre une recopie Lorsqursquoelle concerne un objet cette recopie est

comme nous lavons dit reacutealiseacutee soit par le constructeur de recopie par deacutefaut soit par le

constructeur de recopie preacutevu pour lobjet

Si un objet comporte une partie dynamique lemploi de la recopie par deacutefaut conduit agrave une

copie superficielle ne concernant que les membres de lobjet Les risques de double libeacutera-

tion dun emplacement meacutemoire sont alors les mecircmes que ceux eacutevoqueacutes au paragraphe 32

Mais pour la partie dynamique de lrsquoobjet on perd en outre le beacuteneacutefice de la protection contre

des modifications quoffre la transmission par valeur En effet dans ce cas la fonction con-

cerneacutee reccediloit bien une copie de ladresse de lemplacement mais par le biais de ce pointeur

elle peut tout agrave fait modifier le contenu de lemplacement lui-mecircme (revoyez le scheacutema du

paragraphe 321 dans lequel a jouait le rocircle dun argument et b celui de sa recopie)

Voici un exemple de programme faisant appel agrave une classe point doteacutee dune fonction mem-

bre nommeacutee symetrique fournissant en retour un point symeacutetrique de celui layant appeleacute

Notez bien quici contrairement agrave lexemple preacuteceacutedent le constructeur de recopie nest pas

Construction destruction et initialisation des objetsCHAPITRE 7

126

indispensable au bon fonctionnement de notre classe (qui ne comporte aucune partie

dynamique) il ne sert quagrave illustrer le meacutecanisme de son appel

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur usuel

x=abs y=ord

cout ltlt ++ Appel Const usuel ltlt this ltlt ltlt x ltlt ltlt y ltlt n

point (const point amp p) constructeur de recopie

x=px y=py

cout ltlt ++ Appel Const recopie ltlt this ltlt ltlt x ltlt ltlt y ltlt n

~point ()

cout ltlt -- Appel Destr ltlt this ltlt ltlt x ltlt ltlt y ltlt n

point symetrique ()

point pointsymetrique ()

point res resx = -x resy = -y return res

main()

point a(13) b

cout ltlt avant appel de symetriquen

b = asymetrique ()

cout ltlt apres appel de symetriquen

++ Appel Const usuel 006AFDE4 1 3

++ Appel Const usuel 006AFDDC 0 0

avant appel de symetrique

++ Appel Const usuel 006AFD60 0 0

++ Appel Const recopie 006AFDD4 -1 -3

-- Appel Destr 006AFD60 -1 -3

-- Appel Destr 006AFDD4 -1 -3

apres appel de symetrique

-- Appel Destr 006AFDDC -1 -3

-- Appel Destr 006AFDE4 1 3

Appel du constructeur de recopie en cas de transmission par valeur

4 - Initialisation dun objet lors de sa deacuteclaration127

4 Initialisation dun objet lors de sa deacuteclarationNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

En langage C on peut initialiser une variable au moment de sa deacuteclaration comme dans

int n = 12

En theacuteorie C++ permet de faire de mecircme avec les objets en ajoutant un initialiseur lors de

leur deacuteclaration Mais si le rocircle dun tel initialiseur va de soi dans le cas de variables classi-

ques (il ne sagit que den fournir la ou les valeurs) il nen va plus de mecircme dans le cas dun

objet en effet il ne sagit plus de se contenter dinitialiser simplement ses membres mais

plutocirct de fournir sous une forme peu naturelle des arguments pour un constructeur De plus

C++ nimpose aucune restriction sur le type de linitialiseur qui pourra donc ecirctre du mecircme

type que lrsquoobjet initialiseacute le constructeur utiliseacute sera alors le constructeur de recopie preacute-

senteacute preacuteceacutedemment

Consideacuterons dabord cette classe (munie dun constructeur usuel)

class point

int x y

public

point (int abs) x = abs y = 0

Nous avons deacutejagrave vu quel serait le rocircle dune deacuteclaration telle que

point a(3)

C++ nous autorise eacutegalement agrave eacutecrire

point a = 3

Cette deacuteclaration entraicircne

bull la creacuteation dun objet a

bull lappel du constructeur auquel on transmet en argument la valeur de linitialiseur ici 3

En deacutefinitive les deux deacuteclarations

point a(3)

point a = 3

sont eacutequivalentes

Dune maniegravere geacuteneacuterale lorsque lon deacuteclare un objet avec un initialiseur ce dernier peut

ecirctre une expression dun type quelconque agrave condition quil existe un constructeur agrave un seul

argument de ce type

Cela sapplique donc aussi agrave une situation telle que

point a

point b = a on initialise b avec lrsquoobjet a de mecircme type

Manifestement on aurait obtenu le mecircme reacutesultat en deacuteclarant

point b(a) on creacutee lobjet b en utilisant le constructeur par recopie

de la classe point auquel on transmet lobjet a

Construction destruction et initialisation des objetsCHAPITRE 7

128

Quoi quil en soit ces deux deacuteclarations (point b=a et point b(a)) entraicircnent effectivement la

creacuteation dun objet de type point suivie de lappel du constructeur par recopie de point (celui

par deacutefaut ou le cas eacutecheacuteant celui quon y a deacutefini) auquel on transmet en argument

lobjet a

Remarques

1 Il ne faut pas confondre linitialiseur dune classe avec celui employeacute en C pour donner

des valeurs initiales agrave un tableau

int t[5] = 3 5 11 2 0

ou agrave une structure Celui-ci est toujours utilisable en C++ y compris pour les structures

comportant des fonctions membres Il est mecircme applicable agrave des classes ne disposant

pas de constructeur et dans lesquelles tous les membres sont publics en pratique cette

possibiliteacute ne preacutesente guegravere dinteacuterecirct

2 Supposons quune classe point soit munie dun constructeur agrave deux arguments entiers et

consideacuterons la deacuteclaration

point a = point (1 5)

Il sagit bien dune deacuteclaration comportant un initialiseur constitueacute dune expression de

type point On pourrait logiquement penser quelle entraicircne lappel dun constructeur de

recopie (par deacutefaut ou effectif) en vue dinitialiser lobjet a nouvellement creacuteeacute avec

lrsquoexpression temporaire point (15)

En fait dans ce cas preacutecis dinitialisation dun objet par appel explicite du constructeur

C++ a preacutevu de traiter cette deacuteclaration comme

point a(1 5)

Autrement dit il y a creacuteation dun seul objet a et appel du constructeur (usuel) pour

cet objet Aucun constructeur de recopie nest appeleacute

Cette deacutemarche est assez naturelle et simplificatrice Elle nen demeure pas moins une

exception par opposition agrave celle qui sera mise en œuvre dans

point a = b

ou dans

point a = b + point (1 5)

lorsque nous aurons appris agrave donner un sens agrave une expression telle que b + point (1 5)

(qui suppose la surdeacutefinition de lopeacuterateur + pour la classe point)

5 - Objets membres129

5 Objets membres

51 IntroductionIl est tout agrave fait possible quune classe possegravede un membre donneacutee lui-mecircme de type classe

Par exemple ayant deacutefini

class point

int x y

public

int init (int int)

void affiche ( )

nous pouvons deacutefinir

class cercle

point centre

int rayon

public

void affrayon ( )

Si nous deacuteclarons alors

cercle c

lobjet c possegravede un membre donneacutee priveacute centre de type point Lobjet c peut acceacuteder classi-

quement agrave la meacutethode affrayon par caffrayon En revanche il ne pourra pas acceacuteder agrave la

meacutethode init du membre centre car centre est priveacute Si centre eacutetait public on pourrait acceacuteder

aux meacutethodes de centre par ccentreinit () ou ccentreaffiche ()

Dune maniegravere geacuteneacuterale la situation dobjets membres correspond agrave une relation entre classes

du type relation de possession (on dit aussi relation a ndash du verbe avoir) Effectivement on

peut bien dire ici quun cercle possegravede (a) un centre (de type point) Ce type de relation

soppose agrave la relation qui sera induite par lrsquoheacuteritage de type relation est (du verbe ecirctre)

Voyons maintenant comment sont mis en œuvre les constructeurs des diffeacuterents objets

lorsquils existent

52 Mise en œuvre des constructeurs et des destructeursSupposons cette fois que notre classe point ait eacuteteacute deacutefinie avec un constructeur

class point

int x y

public

point (int int)

Construction destruction et initialisation des objetsCHAPITRE 7

130

Nous ne pouvons plus deacutefinir la classe cercle preacuteceacutedente sans constructeur En effet si nous

le faisions son membre centre se verrait certes attribuer un emplacement (lors dune creacuteation

dun objet de type cercle) mais son constructeur ne pourrait ecirctre appeleacute (quelles valeurs

pourrait-on lui transmettre )

Il faut donc

bull dune part deacutefinir un constructeur pour cercle

bull dautre part speacutecifier les arguments agrave fournir au constructeur de point ceux-ci doivent ecirctre

choisis obligatoirement parmi ceux fournis agrave cercle

Voici ce que pourrait ecirctre la deacutefinition de cercle et de son constructeur

class cercle point centre int rayon public cercle (int int int) cerclecercle (int abs int ord int ray) centre (abs ord)

Vous voyez que len-tecircte de cercle speacutecifie apregraves les deux-points la liste des arguments qui

seront transmis agrave point

Les constructeurs seront appeleacutes dans lordre suivant point cercle Sil existe des destruc-

teurs ils seront appeleacutes dans lordre inverse

Voici un exemple complet

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord cout ltlt Constr point ltlt x ltlt ltlt y ltlt n class cercle point centre int rayon public cercle (int int int) cerclecercle (int abs int ord int ray) centre(abs ord) rayon = ray cout ltlt Constr cercle ltlt rayon ltlt n main() cercle a (139)

5 - Objets membres131

Constr point 1 3Constr cercle 9

Appel des diffeacuterents constructeurs dans le cas dobjets membres

Remarques

1 Si point dispose dun constructeur sans argument le constructeur de cercle peut ne pas

speacutecifier dargument agrave destination du constructeur de centre qui sera appeleacute automatique-

ment

2 On pourrait eacutecrire ainsi le constructeur de cercle

cerclecercle (int abs int ord int ray) rayon = ray centre = point (abs ord) cout ltlt Constr cercle ltlt rayon ltlt n

Mais dans ce cas on creacuteerait un objet temporaire de type point suppleacutementaire comme

le montre lrsquoexeacutecution du mecircme programme ainsi modifieacute

Constr point 0 0Constr point 1 3Constr cercle 9

3 Dans le cas dobjets comportant plusieurs objets membres la seacutelection des arguments

destineacutes aux diffeacuterents constructeurs se fait en seacuteparant chaque liste par une virgule En

voici un exemple

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(xq) a2(r)

Ici pour simplifier leacutecriture nous avons supposeacute que le constructeur de C eacutetait en

ligne Parmi les arguments n p x q et r quil reccediloit p sera transmis au constructeur A

de a1 x et q au constructeur B de b puis r au constructeur A de a2 Notez bien que

lordre dans lequel ces trois constructeurs sont exeacutecuteacutes est en theacuteorie celui de leur

Construction destruction et initialisation des objetsCHAPITRE 7

132

deacuteclaration dans la classe et non pas celui des initialiseurs En pratique on eacutevitera des

situtations ougrave cet ordre pourrait avoir de lrsquoimportance

En revanche comme on peut srsquoy attendre le constructeur C ne sera exeacutecuteacute quapregraves les

trois autres (lordre des imbrications est toujours respecteacute)

53 Le constructeur de recopieNous avons vu que pour toute classe il est preacutevu un constructeur de recopie par deacutefaut qui

est appeleacute en labsence de constructeur de recopie effectif Son rocircle est simple dans le cas

dobjets ne comportant pas dobjets membres puisquil sagit alors de recopier les valeurs des

diffeacuterents membres donneacutees

Lorsque lobjet comporte des objets membres la recopie (par deacutefaut) se fait membre par

membre1 autrement dit si lun des membres est lui-mecircme un objet on le recopiera en appe-

lant son propre constructeur de recopie (qui pourra ecirctre soit un constructeur par deacutefaut

soit un constructeur deacutefini dans la classe correspondante)

Cela signifie que la construction par recopie (par deacutefaut) dun objet sera satisfaisante degraves lors

quil ne contient pas de pointeurs sur des parties dynamiques mecircme si certains de ses objets

membres en comportent (agrave condition quils soient quant agrave eux munis des constructeurs par

recopie approprieacutes)

En revanche si lobjet contient des pointeurs il faudra le munir dun constructeur de recopie

approprieacute Ce dernier devra alors prendre en charge linteacutegraliteacute de la recopie de lobjet

Cependant on pourra pour cela transmettre les informations neacutecessaire aux constructeurs par

recopie (par deacutefaut ou non) de certains de ses membres en utilisant la technique deacutecrite au

paragraphe 52

6 Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur

La syntaxe que nous avons deacutecrite au paragraphe 52 pour transmettre des arguments agrave un

constructeur dun objet membre peut en fait sappliquer agrave nimporte quel membre mecircme sil

ne sagit pas dun objet Par exemple

class point int x y public point (int abs=0 int ord=0) x(abs) y(ord)

1 En anglais on parle de memberwise copy Avant la version 20 de C++ la copie se faisait bit agrave bit (bitwise copy)

ce qui neacutetait pas toujours satisfaisant

7 - Les tableaux drsquoobjets133

Lappel du constructeur point provoquera lrsquoinitialisation des membres x et y avec respective-

ment les valeurs abs et ord Son corps est vide ici puisquil ny a rien de plus agrave faire pour

remplacer notre constructeur classique

point (int abs=0 int ord=0) x=abs y=ord

Cette possibiliteacute peut devenir indispensable en cas

bull drsquoinitialisation dun membre donneacutee constant Par exemple avec cette classe

class truc const int n public truc ()

il nrsquoest pas possible de proceacuteder ainsi pour initialiser n dans le constructeur de truc

tructruc() n = 12 interdit n est constant

En revanche on pourra proceacuteder ainsi

tructruc() n(12)

bull drsquoinitialisation dun membre donneacutee qui est une reacutefeacuterence En effet on ne peut quinitialiser

une telle reacutefeacuterence jamais lui affecter une nouvelle valeur (revoyez eacuteventuellement le para-

graphe 35 du chapitre 4)

7 Les tableaux drsquoobjetsNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

En C++ un tableau peut posseacuteder des eacuteleacutements de nimporte quel type y compris de type

classe ce qui conduit alors agrave des tableaux dobjets Ce concept ne preacutesente pas de difficulteacutes

particuliegraveres au niveau des notations que nous allons nous contenter de rappeler agrave partir drsquoun

exemple En revanche il nous faudra preacuteciser certains points relatifs agrave lappel des construc-

teurs et aux initialiseurs

71 NotationsSoit une classe point sans constructeur deacutefinie par

class point int x y public void init (int int) void affiche ( )

Construction destruction et initialisation des objetsCHAPITRE 7

134

Nous pouvons deacuteclarer un tableau courbe de vingt objets de type point par

point courbe [20]

Si i est un entier la notation courbe[i] deacutesignera un objet de type point Linstruction

courbe[i]affiche ()

appellera le membre init pour le point courbe[i] (les prioriteacutes relatives des opeacuterateurs et []

permettent de saffranchir de parenthegraveses) De mecircme on pourra afficher tous les points par

for (i = 0 i lt 20 i++) courbe[i]affiche()

Remarque

Un tableau dobjets nest pas un objet Dans lesprit de la POO pure ce concept

nexiste pas puisquon ne manipule que des objets En revanche il reste toujours possible

de deacutefinir une classe dont un des membres est un tableau dobjets Ainsi nous pourrions

deacutefinir un type courbe par

class courbe point p[20]

Notez que la classe vector de la bibliothegraveque standard permettra de deacutefinir des tableaux

dynamiques (dont la taille pourra varier au fil de lrsquoexeacutecution) qui seront de vrais objets

En Java

Non seulement un tableau drsquoobjet est un objet mais mecircme un simple tableau drsquoeacuteleacutements

drsquoun type de base est aussi un objet

72 Constructeurs et initialiseursNous venons de voir la signification de la deacuteclaration

point courbe[20]

dans le cas ougrave point est une classe sans constructeur

Si la classe comporte un constructeur sans argument celui-ci sera appeleacute successivement

pour chacun des eacuteleacutements (de type point) du tableau courbe En revanche si aucun des cons-

tructeurs de point nest un constructeur sans argument la deacuteclaration preacuteceacutedente conduira agrave

une erreur de compilation Dans ce cas en effet C++ nest plus en mesure de garantir le pas-

sage par un constructeur degraves lors que la classe concerneacutee (point) en comporte au moins un

Il est cependant possible de compleacuteter une telle deacuteclaration par un initialiseur comportant une

liste de valeurs chaque valeur sera transmise agrave un constructeur approprieacute (les valeurs peu-

vent donc ecirctre de types quelconques eacuteventuellement diffeacuterents les uns des autres dans la

mesure ougrave il existe le constructeur correspondant) Pour les tableaux de classe automatique

les valeurs de linitialiseur peuvent ecirctre une expression quelconque (pour peu quelle soit cal-

7 - Les tableaux drsquoobjets135

culable au moment ougrave on en a besoin) En outre linitialiseur peut comporter moins de

valeurs que le tableau na deacuteleacutements1 Dans ce cas il y a appel du constructeur sans argument

(qui doit donc exister) pour les eacuteleacutements auxquels ne correspond aucune valeur

Voici un exemple illustrant ces possibiliteacutes (nous avons choisi un constructeur disposant

drsquoarguments par deacutefaut il remplace trois constructeurs agrave zeacutero un et deux arguments)

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur (0 1 ou 2 arguments) x=abs y =ord cout ltlt ++ Constr point ltlt x ltlt ltlt y ltlt n ~point () cout ltlt -- Destr point ltlt x ltlt ltlt y ltlt n main() int n = 3 point courbe[5] = 7 n 2n+5 cout ltlt fin programme n

++ Constr point 7 0++ Constr point 3 0++ Constr point 11 0++ Constr point 0 0++ Constr point 0 0 fin programme -- Destr point 0 0-- Destr point 0 0-- Destr point 11 0-- Destr point 3 0-- Destr point 7 0

Construction et initialisation dun tableau dobjets (version 20)

73 Cas des tableaux dynamiques dobjetsSi lon dispose dune classe point on peut creacuteer dynamiquement un tableau de points en fai-

sant appel agrave lopeacuterateur new Par exemple

point adcourbe = new point[20]

1 Mais pour linstant les eacuteleacutements manquants doivent obligatoirement ecirctre les derniers

Construction destruction et initialisation des objetsCHAPITRE 7

136

alloue lemplacement meacutemoire neacutecessaire agrave vingt objets (conseacutecutifs) de type point et place

ladresse du premier de ces objets dans adcourbe

Lagrave encore si la classe point comporte un constructeur sans argument ce dernier sera appeleacute

pour chacun des vingt objets En revanche si aucun des constructeurs de point nest un cons-

tructeur sans argument linstruction preacuteceacutedente conduira agrave une erreur de compilation Bien

entendu aucun problegraveme particulier ne se posera si la classe point ne comporte aucun cons-

tructeur

Par contre il nexiste ici aucune possibiliteacute de fournir un initialiseur alors que cela est possi-

ble dans le cas de tableaux automatiques ou statiques (voir paragraphe 62)

Pour deacutetruire notre tableau dobjets il suffira de linstruction (notez la preacutesence des crochets

[] qui preacutecisent que lon a affaire agrave un tableau dobjets)

delete [] adcourbe

Celle-ci provoquera lappel du destructeur de point et la libeacuteration de lespace correspondant

pour chacun des eacuteleacutements du tableau

8 Les objets temporairesNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Lorsquune classe dispose dun constructeur ce dernier peut ecirctre appeleacute explicitement (avec

la liste drsquoarguments neacutecessaires) Il y a alors creacuteation dun objet temporaire Par exemple si

nous supposons quune classe point possegravede le constructeur

point (int int)

nous pouvons si a est un objet de type point eacutecrire une affectation telle que

a = point (1 2)

Dans une telle instruction leacutevaluation de lexpression

point (1 2)

conduit agrave

bull la creacuteation dun objet temporaire de type point (il a une adresse preacutecise mais il nest pas ac-

cessible au programme)1

bull lappel du constructeur point pour cet objet temporaire avec transmission des arguments

speacutecifieacutes (ici 1 et 2)

bull la recopie de cet objet temporaire dans a (affectation dun objet agrave un autre de mecircme type)

Quant agrave lobjet temporaire ainsi creacuteeacute il na plus drsquointeacuterecirct degraves que linstruction daffectation est

exeacutecuteacutee La norme preacutevoit qursquoil soit deacutetruit degraves que possible

1 En fait il en va de mecircme lorsque lon reacutealise une affectation telle que y = a x + b Il y a bien creacuteation dun

emplacement temporaire destineacute agrave recueillir le reacutesultat de leacutevaluation de lexpression a x + b

8 - Les objets temporaires137

Voici un exemple de programme montrant lemploi dobjets temporaires Remarquez quici

nous avons preacutevu dans le constructeur et le destructeur de notre classe point dafficher non

seulement les valeurs de lobjet mais eacutegalement son adresse

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) constructeur (inline) x = abs y = ord cout ltlt ++ Constr point ltlt x ltlt ltlt y ltlt a ladresse ltlt this ltlt n ~point () destructeur (inline) cout ltlt -- Destr point ltlt x ltlt ltlt y ltlt a ladresse ltlt this ltlt n

main() point a(00) un objet automatique de classe point a = point (1 2) un objet temporaire a = point (3 5) un autre objet temporaire cout ltlt Fin main n

+ Constr point 0 0 a ladresse 006AFDE4+ Constr point 1 2 a ladresse 006AFDDC- Destr point 1 2 a ladresse 006AFDDC+ Constr point 3 5 a ladresse 006AFDD4- Destr point 3 5 a ladresse 006AFDD4 Fin main - Destr point 3 5 a ladresse 006AFDE4

Exemple de creacuteation dobjets temporaires

On voit clairement que les deux affectations de la fonction main entraicircnent la creacuteation dun

objet temporaire distinct de a qui se trouve deacutetruit tout de suite apregraves La derniegravere destruc-

tion reacutealiseacutee apregraves la fin de lrsquoexeacutecution concerne lrsquoobjet automatique a

Remarques

1 Reacutepeacutetons que dans une affectation telle que

a = point (1 2)

lobjet a existe deacutejagrave Il na donc pas agrave ecirctre creacuteeacute et il ny a pas dappel de constructeur agrave ce

niveau pour a

Construction destruction et initialisation des objetsCHAPITRE 7

138

2 Les remarques sur les risques que preacutesente une affectation entre objets notamment srsquoils

comportent des parties dynamiques1 restent valables ici On pourra utiliser la mecircme

solution agrave savoir la surdeacutefinition de lopeacuterateur daffectation

3 Il existe dautres circonstances dans lesquelles sont creacuteeacutes des objets temporaires agrave

savoir

ndash transmission de la valeur dun objet en argument dune fonction il y a creacuteation dun

objet temporaire au sein de la fonction concerneacutee

ndash transmission dun objet en valeur de retour dune fonction il y a creacuteation dun objet

temporaire au sein de la fonction appelante

Dans les deux cas lobjet temporaire est initialiseacute par appel du constructeur de recopie

4 La preacutesence dobjets temporaires (dont le moment de destruction nest pas parfaitement

imposeacute par la norme) peut rendre difficile le deacutenombrement exact dobjets dune classe

donneacutee

5 La norme ANSI autorise les compilateurs agrave supprimer certaines creacuteations drsquoobjets tem-

poraires notamment dans des situations telles que

f (point(12) appel drsquoune fonction attendant un point avec un argument qui est un objet temporaire lrsquoimpleacutementation peut ne pas creacuteer point(12) dans la fonction appelantereturn point(35) renvoi de la valeur drsquoun point lrsquoimpleacutementation peut ne pas creacuteer point(35) dans la fonction

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1 Comme le suggegravere la remarque du paragraphe 13 eacutecrivez une fonction main qui bien

que ne contenant que des deacuteclarations (voire une seule deacuteclaration) nen effectue pas

moins un certain traitement (par exemple affichage)

2 Expeacuterimentez le programme du paragraphe 2 pour voir comment sont traiteacutes les objets

temporaires dans votre impleacutementation

3 Cherchez agrave mettre en eacutevidence les problegravemes poseacutes par laffectation dobjets du type

vect tel quil est deacutefini dans lexemple du paragraphe 322

4 Ecrivez un programme permettant de mettre en eacutevidence lordre dappel des construc-

teurs et des destructeurs dans la situation du paragraphe 52 (objets membres) ainsi

que dans celle de la seconde remarque (objet comportant plusieurs objets membres)

Expeacuterimentez eacutegalement la situation dobjets membres dobjets membres

1 Nous incluons dans ce cas les objets dont un membre (lui-mecircme objet) comporte une partie dynamique

8 - Les objets temporaires139

5 (C) Ecrivez une classe nommeacutee pile_entier permettant de geacuterer une pile dentiers Ces der-

niers seront conserveacutes dans un tableau dentiers alloueacutes dynamiquement La classe

comportera les fonctions membres suivantes

bull pile_entier (int n) constructeur allouant dynamiquement un emplacement de n en-

tiers

bull pile_entier ( ) constructeur sans argument allouant par deacutefaut un emplacement de

vingt entiers

bull ~pile_entier ( ) destructeur

bull void empile (int p) ajoute lentier p sur la pile

bull int depile ( ) fournit la valeur de lentier situeacute en haut de la pile en le supprimant

de la pile

bull int pleine ( ) fournit 1 si la pile est pleine 0 sinon

bull int vide ( ) fournit 1 si la pile est vide 0 sinon

6 (C) Ecrivez une fonction main utilisant des objets automatiques et dynamiques du type

pile_entier deacutefini preacuteceacutedemment

7 Mettez en eacutevidence les problegravemes poseacutes par des deacuteclarations de la forme

pile_entier a(10) pile_entier b = a

8 (C) Ajoutez agrave la classe pile_entier le constructeur de recopie permettant de reacutegler les pro-

blegravemes preacuteceacutedents

8

Les fonctions amies

La POO pure impose lrsquoencapsulation des donneacutees Nous avons vu comment la mettre en

œuvre en C++ les membres priveacutes (donneacutees ou fonctions) ne sont accessibles quaux fonc-

tions membres (publiques ou priveacutees1) et seuls les membres publics sont accessibles de

lexteacuterieur

Nous avons aussi vu quen C++ luniteacute de protection est la classe cest-agrave-dire quune mecircme

fonction membre peut acceacuteder agrave tous les objets de sa classe Crsquoest ce qui se produisait dans la

fonction coincide (examen de la coiumlncidence de deux objets de type point) preacutesenteacutee au para-

graphe 4 du chapitre 6

En revanche ce mecircme principe dencapsulation interdit agrave une fonction membre dune classe

dacceacuteder agrave des donneacutees priveacutees dune autre classe Or cette contrainte savegravere gecircnante dans

certaines circonstances Supposez par exemple que vous ayez deacutefini une classe vecteur (de

taille fixe ou variable peu importe ) et une classe matrice Il est probable que vous souhaite-

rez alors deacutefinir une fonction permettant de calculer le produit dune matrice par un vecteur

Or avec ce que nous connaissons actuellement de C++ nous ne pourrions deacutefinir cette fonc-

tion ni comme fonction membre de la classe vecteur ni comme fonction membre de la classe

matrice et encore moins comme fonction indeacutependante (cest-agrave-dire membre daucune

classe)

Bien entendu vous pourriez toujours rendre publiques les donneacutees de vos deux classes mais

vous perdriez alors le beacuteneacutefice de leur protection Vous pourriez eacutegalement introduire dans

1 Le statut proteacutegeacute (protected) nrsquointervient qursquoen cas drsquoheacuteritage nous en parlerons au chapitre 13 Pour lrsquoinstant

vous pouvez consideacuterer que les membres proteacutegeacutes sont traiteacutes comme les membres priveacutes

Les fonctions amiesCHAPITRE 8

142

les deux classes des fonctions publiques permettant dacceacuteder aux donneacutees mais vous seriez

alors peacutenaliseacute en temps dexeacutecution

En fait la notion de fonction amie1 propose une solution inteacuteressante sous la forme dun

compromis entre encapsulation formelle des donneacutees priveacutees et des donneacutees publiques Lors

de la deacutefinition dune classe il est en effet possible de deacuteclarer quune ou plusieurs fonctions

(exteacuterieures agrave la classe) sont des amies une telle deacuteclaration damitieacute les autorise alors agrave

acceacuteder aux donneacutees priveacutees au mecircme titre que nimporte quelle fonction membre

Lavantage de cette meacutethode est de permettre le controcircle des accegraves au niveau de la classe

concerneacutee on ne peut pas simposer comme fonction amie dune classe si cela na pas eacuteteacute

preacutevu dans la classe Nous verrons toutefois quen pratique la protection est un peu moins

efficace quil ny paraicirct dans la mesure ougrave une fonction peut parfois se faire passer pour une

autre

Il existe plusieurs situations damitieacutes

bull fonction indeacutependante amie dune classe

bull fonction membre dune classe amie dune autre classe

bull fonction amie de plusieurs classes

bull toutes les fonctions membres dune classe amies dune autre classe

La premiegravere nous servira agrave preacutesenter les principes geacuteneacuteraux de deacuteclaration deacutefinition et utili-

sation dune fonction amie Nous examinerons ensuite en deacutetail chacune de ces situations

damitieacute Enfin nous verrons lincidence de lexistence de fonctions amies sur lexploitation

dune classe

1 Exemple de fonction indeacutependante amie drsquoune classe

Au paragraphe 4 du chapitre 6 nous avons introduit une fonction coincide examinant la

coiumlncidence de deux objets de type point pour ce faire nous en avons fait une fonction

membre de la classe point Nous vous proposons ici de reacutesoudre le mecircme problegraveme en fai-

sant cette fois de la fonction coincide une fonction indeacutependante amie de la classe point

Tout dabord il nous faut introduire dans la classe point la deacuteclaration damitieacute approprieacutee agrave

savoir

friend int coincide (point point)

Il sagit preacuteciseacutement du prototype de la fonction coincide preacuteceacutedeacute du mot cleacute friend Naturel-

lement nous avons preacutevu que coincide recevrait deux arguments de type point (cette fois il

1 Friend en anglais

1 - Exemple de fonction indeacutependante amie drsquoune classe143

ne sagit plus dune fonction membre elle ne recevra donc pas dargument implicite this cor-

respondant agrave lobjet layant appeleacute)

Leacutecriture de la fonction coincide ne pose aucun problegraveme particulier

Voici un exemple de programme

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) un constructeur (inline) x=abs y=ord deacuteclaration fonction amie (indeacutependante) nommeacutee coincide friend int coincide (point point) int coincide (point p point q) deacutefinition de coincide if ((px == qx) ampamp (py == qy)) return 1 else return 0 main() programme dessai point a(10) b(1) c if (coincide (ab)) cout ltlt a coincide avec b n else cout ltlt a et b sont differents n if (coincide (ac)) cout ltlt a coincide avec c n else cout ltlt a et c sont differents n

a coincide avec b a et c sont differents

Exemple de fonction indeacutependante (coincide) amie de la classe point

Remarques

1 Lemplacement de la deacuteclaration damitieacute au sein de la classe point est absolument indiffeacute-

rent

2 Il nest pas neacutecessaire de deacuteclarer la fonction amie dans la fonction ou dans le fichier

source ougrave on lutilise car elle est deacutejagrave obligatoirement deacuteclareacutee dans la classe concer-

neacutee Cela reste valable dans le cas (usuel) ougrave la classe a eacuteteacute compileacutee seacutepareacutement

puisquil faudra alors en introduire la deacuteclaration (geacuteneacuteralement par include) Neacutean-

moins une deacuteclaration superflue de la fonction amie ne constituerait pas une erreur

3 Comme nous lavons deacutejagrave fait remarquer nous navons plus ici dargument implicite

(this) Ainsi contrairement agrave ce qui se produisait au paragraphe 4 du chapitre 6 notre

fonction coincide est maintenant parfaitement symeacutetrique Nous retrouverons le mecircme

Les fonctions amiesCHAPITRE 8

144

pheacutenomegravene lorsque pour surdeacutefinir un opeacuterateur binaire nous pourrons choisir entre

une fonction membre (dissymeacutetrique) ou une fonction amie (symeacutetrique)

4 Ici les deux arguments de coincide sont transmis par valeur Ils pourraient lecirctre par

reacutefeacuterence notez que dans le cas dune fonction membre lobjet appelant la fonction

est doffice transmis par reacutefeacuterence (sous la forme de this)

5 Geacuteneacuteralement une fonction amie dune classe posseacutedera un ou plusieurs arguments ou

une valeur de retour du type de cette classe (cest ce qui justifiera son besoin daccegraves

aux membres priveacutes des objets correspondants) Ce nest toutefois pas une obligation1

on pourrait imaginer une fonction ayant besoin dacceacuteder aux membres priveacutes dobjets

locaux agrave cette fonction

6 Lorsquune fonction amie dune classe fournit une valeur de retour du type de cette

classe il est freacutequent que cette valeur soit celle dun objet local agrave la fonction Il est alors

impeacuteratif que sa transmission ait lieu par valeur dans le cas dune transmission par

reacutefeacuterence (ou par adresse) la fonction appelante recevrait ladresse dun emplacement

meacutemoire qui aurait eacuteteacute libeacutereacute agrave la sortie de la fonction Ce pheacutenomegravene a deacutejagrave eacuteteacute eacutevoqueacute

au paragraphe 6 du chapitre 6

2 Les diffeacuterentes situations drsquoamitieacuteNous venons dexaminer le cas dune fonction indeacutependante amie dune classe Celle-ci peut

ecirctre reacutesumeacutee par le scheacutema suivant

class point

int coincide (point point )

partie priveacutee on a accegraves ici aux membres pri-

veacutes de tout objet de type point

partie publique

friend int coincide (point point)

Fonction indeacutependante (coincide) amie drsquoune classe (point)

Bien que nous layons placeacutee ici dans la partie publique de point nous vous rappelons que la

deacuteclaration damitieacute peut figurer nimporte ougrave dans la classe

Dautres situations damitieacute sont possibles fondeacutees sur le mecircme principe elles peuvent con-

duire agrave des deacuteclarations damitieacute tregraves leacutegegraverement diffeacuterentes Nous allons maintenant les pas-

ser en revue

1 Mais ce sera obligatoire dans le cas des opeacuterateurs surdeacutefinis

2 - Les diffeacuterentes situations drsquoamitieacute145

21 Fonction membre dune classe amie dune autre classeIl sagit un peu dun cas particulier de la situation preacuteceacutedente En fait il suffit simplement de

preacuteciser dans la deacuteclaration damitieacute la classe agrave laquelle appartient la fonction concerneacutee agrave

laide de lopeacuterateur de reacutesolution de porteacutee ()

Par exemple supposons que nous ayons agrave deacutefinir deux classes nommeacutees A et B et que nous

ayons besoin dans B dune fonction membre f de prototype

int f(char A)

Si comme il est probable f doit pouvoir acceacuteder aux membres priveacutes de A elle sera deacuteclareacutee

amie au sein de la classe par

friend int Bf(char A)

Voici un scheacutema reacutecapitulatif de la situation

class A class B partie priveacutee int f (char A)

partie publique friend int Bf (char A) int Bf (char A )

on a accegraves ici aux membres priveacutes de tout objet de type A

Fonction (f) drsquoune classe (B) amie drsquoune autre classe (A)

Remarques

1 Pour compiler convenablement les deacuteclarations dune classe A contenant une deacuteclaration

damitieacute telle que

friend int Bf(char A)

le compilateur a besoin de connaicirctre les caracteacuteristiques de B cela signifie que la

deacuteclaration de B (mais pas neacutecessairement la deacutefinition de ses fonctions membres)

devra avoir eacuteteacute compileacutee avant celle de A

En revanche pour compiler convenablement la deacuteclaration

int f(char A)

figurant au sein de la classe B le compilateur na pas besoin de connaicirctre preacuteciseacutement

les caracteacuteristiques de A Il lui suffit de savoir quil sagit dune classe Comme dapregraves

ce qui vient drsquoecirctre dit la deacuteclaration de B na pu apparaicirctre avant on fournira linforma-

tion voulue au compilateur en faisant preacuteceacuteder la deacuteclaration de A de

class A

Les fonctions amiesCHAPITRE 8

146

Bien entendu la compilation de la deacutefinition de la fonction f neacutecessite (en geacuteneacuteral1) la

connaissance des caracteacuteristiques des classes A et B leurs deacuteclarations devront donc

apparaicirctre avant

A titre indicatif voici une faccedilon de compiler nos deux classes A et B et la fonction f

class A class B int f(char A) class A friend int Bf(char A) int Bf(char A)

2 Si lon a besoin de deacuteclarations damitieacutes croiseacutees entre fonctions de deux classes dif-

feacuterentes la seule faccedilon dy parvenir consiste agrave deacuteclarer au moins une des classes amie

de lautre (comme nous apprendrons agrave le faire au paragraphe 23)

22 Fonction amie de plusieurs classesRien nempecircche quune mecircme fonction (quelle soit indeacutependante ou fonction membre) fasse

lobjet de deacuteclarations damitieacute dans diffeacuterentes classes Voici un exemple dune fonction

amie de deux classes A et B

class A class B

partie priveacutee partie priveacutee

partie publique partie publique

friend void f(A B) friend void f(A B)

void f(A B)

on a accegraves ici aux membres priveacutes

de nrsquoimporte quel objet de type A ou B

Fonction indeacutependante (f) amie de deux classes (A et B)

1 Une exception aurait lieu pour B si f nacceacutedait agrave aucun de ses membres (ce qui serait surprenant) Il en irait de

mecircme pour A si aucun argument de ce type napparaissait dans f et si cette derniegravere nacceacutedait agrave aucun membre de A

(ce qui serait tout aussi surprenant)

3 - Exemple147

Remarque

Ici la deacuteclaration de A peut ecirctre compileacutee sans celle de B en la faisant preacuteceacuteder de la

deacuteclaration

class B

De mecircme la deacuteclaration de B peut ecirctre compileacutee sans celle de A en la faisant preacuteceacuteder

de la deacuteclaration

class A

Si lon compile en mecircme temps les deux deacuteclarations de A et B il faudra utiliser lune

des deux deacuteclarations citeacutees (class A si B figure avant A class B sinon)

Bien entendu la compilation de la deacutefinition de f neacutecessitera geacuteneacuteralement les deacuteclara-

tions de A et de B

23 Toutes les fonctions dune classe amies dune autre classeCest une geacuteneacuteralisation du cas eacutevoqueacute au paragraphe 21 On pourrait dailleurs effectuer

autant de deacuteclarations damitieacute quil y a de fonctions concerneacutees Mais il est plus simple

deffectuer une deacuteclaration globale Ainsi pour dire que toutes les fonctions membres de la

classe B sont amies de la classe A on placera dans la classe A la deacuteclaration

friend class B

Remarques

1 Cette fois pour compiler la deacuteclaration de la classe A il suffira de la faire preacuteceacuteder de

class B

2 Ce type de deacuteclaration damitieacute eacutevite de fournir les en-tecirctes des fonctions concerneacutees

3 ExempleNous vous proposons ici de reacutesoudre le problegraveme eacutevoqueacute en introduction agrave savoir reacutealiser

une fonction permettant de deacuteterminer le produit dun vecteur (objet de classe vect) par une

matrice (objet de classe matrice) Par souci de simpliciteacute nous avons limiteacute les fonctions

membres agrave

bull un constructeur pour vect et pour matrice

bull une fonction daffichage (affiche) pour matrice

Nous vous fournissons deux solutions fondeacutees sur lemploi dune fonction amie nommeacutee

prod

bull prod est indeacutependante et amie des deux classes vect et matrice

bull prod est membre de matrice et amie de la classe vect

Les fonctions amiesCHAPITRE 8

148

31 Fonction amie indeacutependante

include ltiostreamgtusing namespace std class matrice pour pouvoir compiler la deacuteclaration de vect La classe vect class vect double v[3] vecteur agrave 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 indeacutependante void affiche () int i for (i=0 ilt3 i++) cout ltlt v[i] ltlt cout ltlt n La classe matrice class matrice double mat[3] [3] matrice 3 X 3 public matrice (double t[3][3]) constructeur agrave partir dun tableau 3 x 3 int i int j for (i=0 ilt3 i++) for (j=0 jlt3 j++) mat[i] [j] = t[i] [j] friend vect prod (matrice vect) prod = fonction amie indeacutependante La fonction prod vect prod (matrice m vect x) int i j double som vect res pour le reacutesultat du produit for (i=0 ilt3 i++) for (j=0 som=0 jlt3 j++) som += mmat[i] [j] xv[j] resv[i] = som return res Un petit programme de test main() vect w (123) vect res double tb [3][3] = 1 2 3 4 5 6 7 8 9 matrice a = tb res = prod(a w) resaffiche ()

3 - Exemple149

14 32 50

Produit dune matrice par un vecteur agrave laide dune fonction indeacutependante amie des deux classes

32 Fonction amie membre dune classe

include ltiostreamgtusing namespace std Deacuteclaration de la classe matrice class vect pour pouvoir compiler correctementclass matrice double mat[3] [3] matrice 3 X 3 public matrice (double t[3][3]) constructeur agrave partir dun tableau 3 x 3 int i int j for (i=0 ilt3 i++) for (j=0 jlt3 j++) mat[i] [j] = t[i] [j] vect prod (vect) prod = fonction membre (cette fois) Deacuteclaration de la classe vect class vect double v[3] vecteur agrave 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 matriceprod (vect) prod = fonction amie void affiche () int i for (i=0 ilt3 i++) cout ltlt v[i] ltlt cout ltlt n Deacutefinition de la fonction prod vect matriceprod (vect x) int i j double som vect res pour le reacutesultat du produit for (i=0 ilt3 i++) for (j=0 som=0 jlt3 j++) som += mat[i] [j] xv[j] resv[i] = som return res

Les fonctions amiesCHAPITRE 8

150

Un petit programme de test main() vect w (123) vect res double tb [3][3] = 1 2 3 4 5 6 7 8 9 matrice a = tb res = aprod (w) resaffiche ()

14 32 50

Produit dune matrice par un vecteur agrave laide dune fonction membre amie dune autre classe

4 Exploitation de classes disposant de fonctions amies

Comme nous lavons deacutejagrave mentionneacute au chapitre 5 les classes seront geacuteneacuteralement compileacutees

seacutepareacutement Leur utilisation se fera agrave partir dun module objet contenant leurs fonctions

membres et dun fichier en-tecircte contenant leur deacuteclaration Bien entendu il est toujours possi-

ble de regrouper plusieurs classes dans un mecircme module objet et eacuteventuellement dans un

mecircme fichier en-tecircte

Dans tous les cas cette compilation seacutepareacutee des classes permet den assurer la reacuteutilisabiliteacute

le client (qui peut eacuteventuellement ecirctre le concepteur de la classe) ne peut pas intervenir sur

le contenu des objets de cette classe

Que deviennent ces possibiliteacutes lorsque lon utilise des fonctions amies En fait sil sagit de

fonctions amies membres dune classe rien nest changeacute (en dehors des eacuteventuelles deacuteclara-

tions de classes neacutecessaires agrave son emploi) En revanche sil sagit dune fonction indeacutepen-

dante il faudra bien voir que si lon souhaite en faire un module objet seacutepareacute on court le

risque de voir lutilisateur de la classe violer le principe dencapsulation

En effet dans ce cas lutilisateur dune classe disposant dune fonction amie peut toujours ne

pas incorporer la fonction amie agrave leacutedition de liens et fournir lui-mecircme une autre fonction de

mecircme en-tecircte puis acceacuteder comme il lentend aux donneacutees priveacutees

Ce risque drsquoeffet cameacuteleacuteon doit ecirctre nuanceacute par le fait quil sagit dune action deacutelibeacutereacutee

(demandant un certain travail) et non pas dune simple eacutetourderie

9

La surdeacutefinition drsquoopeacuterateurs

Nous avons vu au chapitre 4 que C++ autorise la surdeacutefinition de fonctions quil sagisse de

fonctions membres ou de fonctions indeacutependantes Rappelons que cette technique consiste agrave

attribuer le mecircme nom agrave des fonctions diffeacuterentes lors dun appel le choix de la bonne

fonction est effectueacute par le compilateur suivant le nombre et le type des arguments

Mais C++ permet eacutegalement dans certaines conditions de surdeacutefinir des opeacuterateurs En fait

le langage C comme beaucoup dautres reacutealise deacutejagrave la surdeacutefinition de certains opeacuterateurs

Par exemple dans une expression telle que

a + b

le symbole + peut deacutesigner suivant le type de a et b

bull laddition de deux entiers

bull lrsquoaddition de deux reacuteels (float)

bull lrsquoaddition de deux reacuteels double preacutecision (double)

bull etc

De la mecircme maniegravere le symbole peut suivant le contexte repreacutesenter la multiplication

dentiers ou de reacuteels ou une indirection (comme dans a = adr)

En C++ vous pourrez surdeacutefinir nimporte quel opeacuterateur existant (unaire ou binaire) pour

peu qursquoil porte sur au moins un objet1 Il sagit lagrave dune technique fort puissante puisquelle va

1 Cette restriction signifie simplement quil ne sera pas possible de surdeacutefinir les opeacuterateurs portant sur les diffeacuterents

types de base

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

152

vous permettre de creacuteer par le biais des classes des types agrave part entiegravere cest-agrave-dire munis

comme les types de base dopeacuterateurs parfaitement inteacutegreacutes La notation opeacuteratoire qui en

deacutecoulera aura lavantage drsquoecirctre beaucoup plus concise et (du moins si lon sy prend

intelligemment ) lisible qursquoune notation fonctionnelle (par appel de fonction)

Par exemple si vous deacutefinissez une classe complexe destineacutee agrave repreacutesenter des nombres com-

plexes il vous sera possible de donner une signification agrave des expressions telles que

a + b a - b a b ab

a et b eacutetant des objets de type complexe1 Pour cela vous surdeacutefinirez les opeacuterateurs + - et

en speacutecifiant le rocircle exact que vous souhaitez leur attribuer Cette deacutefinition se deacuteroulera

comme celle dune fonction agrave laquelle il suffira simplement dattribuer un nom speacutecial per-

mettant de speacutecifier quil sagit en fait dun opeacuterateur Autrement dit la surdeacutefinition dopeacutera-

teurs en C++ consistera simplement en leacutecriture de nouvelles fonctions surdeacutefinies

Apregraves vous avoir preacutesenteacute la surdeacutefinition dopeacuterateurs ses possibiliteacutes et ses limites nous

lrsquoappliquerons aux opeacuterateurs = et [] Certes il ne sagira que dexemples mais ils montreront

quagrave partir du moment ougrave lon souhaite donner agrave ces opeacuterateurs une signification naturelle et

acceptable dans un contexte de classe un certain nombre de preacutecautions doivent ecirctre prises

En particulier nous verrons comment la surdeacutefinition de laffectation permet de reacutegler le pro-

blegraveme deacutejagrave rencontreacute agrave savoir celui des objets comportant des pointeurs sur des emplace-

ments dynamiques

Enfin nous examinerons comment prendre en charge la gestion de la meacutemoire en surdeacutefinis-

sant les opeacuterateurs new et delete

1 Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs

Consideacuterons une classe point

class point int x y

et supposons que nous souhaitions deacutefinir lopeacuterateur + afin de donner une signification agrave une

expression telle que a + b lorsque a et b sont de type point Ici nous conviendrons que la

somme de deux points est un point dont les coordonneacutees sont la somme de leurs coordon-

neacutees2

1 Une notation fonctionnelle conduirait agrave des choses telles que somme (ab) ou asomme(b) suivant que lon utilise

une fonction amie ou une fonction membre

2 Nous aurions pu tout aussi bien prendre lexemple de la classe complexe eacutevoqueacutee en introduction Nous preacutefeacuterons

cependant choisir un exemple dans lequel la signification de lopeacuterateur na pas un caractegravere aussi eacutevident En effet

noubliez pas que nimporte quel symbole opeacuterateur peut se voir attribuer nimporte quelle signification

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs153

La convention adopteacutee par C++ pour surdeacutefinir cet opeacuterateur + consiste agrave deacutefinir une fonc-

tion de nom

operator +

Le mot cleacute operator est suivi de lopeacuterateur concerneacute (dans le cas preacutesent il ne serait pas obli-

gatoire de preacutevoir un espace car en C + sert de seacuteparateur)

Ici notre fonction operator + doit disposer de deux arguments de type point et fournir une

valeur de retour du mecircme type En ce qui concerne sa nature cette fonction peut agrave notre greacute

ecirctre une fonction membre de la classe concerneacutee ou une fonction indeacutependante dans ce der-

nier cas il sagira geacuteneacuteralement dune fonction amie car elle devra pouvoir acceacuteder aux

membres priveacutes de la classe

Examinons ici les deux solutions en commenccedilant par celle qui est la plus naturelle agrave

savoir la fonction amie

11 Surdeacutefinition dopeacuterateur avec une fonction amieLe prototype de notre fonction operator + sera

point operator + (point point)

Ses deux arguments correspondront aux opeacuterandes de lopeacuterateur + lorsquil sera appliqueacute agrave

des valeurs de type point

Le reste du travail est classique

bull deacuteclaration damitieacute au sein de la classe point

bull deacutefinition de la fonction

Voici un exemple de programme montrant la deacutefinition et lutilisation de notre opeacuterateur

daddition de points

include ltiostreamgtusing namespace std

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 ltlt coordonnees ltlt x ltlt ltlt y ltlt n

point operator + (point a point b) point p px = ax + bx py = ay + by return p

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

154

main() point a(12) aaffiche()

point b(25) baffiche()

point c c = a+b caffiche()

c = a+b+c caffiche()

coordonnees 1 2

coordonnees 2 5

coordonnees 3 7coordonnees 6 14

Surdeacutefinition de lopeacuterateur + pour des objets de type point en employant une fonction amie

Remarques

1 Une expression telle que a + b est en fait interpreacuteteacutee par le compilateur comme lappel

operator + (a b)

Bien que cela ne preacutesente guegravere dinteacuterecirct nous pourrions eacutecrire

c = operator + (a b)

au lieu de c = a + b

2 Une expression telle que a + b + c est eacutevalueacutee en tenant compte des regravegles de prioriteacute

et dassociativiteacute habituelles de lopeacuterateur + Nous reviendrons plus loin sur ce point

Pour linstant notez simplement que cette expression est eacutevalueacutee comme

(a + b) + c

cest-agrave-dire en utilisant la notation fonctionnelle

operator + (operator + (a b) c)

12 Surdeacutefinition dopeacuterateur avec une fonction membreCette fois le premier opeacuterande de notre opeacuterateur correspondant au premier argument de la

fonction operator + preacuteceacutedente va se trouver transmis implicitement ce sera lobjet ayant

appeleacute la fonction membre Par exemple une expression telle que a + b sera alors interpreacuteteacutee

par le compilateur comme

aoperator + (b)

Le prototype de notre fonction membre operator + sera donc

point operator + (point)

Voici comment lrsquoexemple preacuteceacutedent pourrait ecirctre adapteacute

1 - Le meacutecanisme de la surdeacutefinition drsquoopeacuterateurs155

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord constructeur point operator + (point) void affiche () cout ltlt coordonnees ltlt x ltlt ltlt y ltlt n point pointoperator + (point a) point p px = x + ax py = y + ay return p main() point a(12) aaffiche() point b(25) baffiche() point c c = a+b caffiche() c = a+b+c caffiche()

coordonnees 1 2coordonnees 2 5coordonnees 3 7coordonnees 6 14

Surdeacutefinition de lopeacuterateur + pour des objets de type point en employant une fonction membre

Remarques

1 Cette fois la deacutefinition de la fonction operator + fait apparaicirctre une dissymeacutetrie entre les

deux opeacuterandes Par exemple le membre x est noteacute x pour le premier opeacuterande (argument

implicite) et ax pour le second Cette dissymeacutetrie peut parfois inciter lutilisateur agrave choisir

une fonction amie plutocirct quune fonction membre Il faut toutefois se garder de deacutecider

trop vite dans ce domaine Nous y reviendrons un peu plus loin

2 Ici laffectation

c = a + b

est interpreacuteteacutee comme

c = aoperator + (b)

Quant agrave laffectation

c = a + b + c

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

156

le langage C++ ne preacutecise pas exactement son interpreacutetation Certains compilateurs

creacuteeront un objet temporaire t

t = aoperator + (b) c = toperator + (c)

Dautres proceacutederont ainsi en transmettant comme adresse de lobjet appelant operator

+ celle de lobjet renvoyeacute par lappel preacuteceacutedent

c = (aoperator + (b))operator + (c)

On peut deacutetecter le choix fait par un compilateur en affichant toutes les creacuteations

dobjets (en noubliant pas dintroduire un constructeur de recopie prenant la place du

constructeur par deacutefaut)

13 Opeacuterateurs et transmission par reacutefeacuterenceDans les deux exemples preacuteceacutedents la transmission des arguments (deux pour une fonction

amie un pour une fonction membre) et de la valeur de retour de operator + se faisait par

valeur1

Bien entendu on peut envisager de faire appel au transfert par reacutefeacuterence en particulier dans

le cas dobjets de grande taille Par exemple le prototype de la fonction amie operator +

pourrait ecirctre

point operator + (point amp a point amp b)

En revanche la transmission par reacutefeacuterence poserait un problegraveme si on cherchait agrave lappliquer

agrave la valeur de retour En effet le point p est creacuteeacute localement dans la fonction il sera donc

deacutetruit degraves la fin de son exeacutecution Dans ces conditions employer la transmission par reacutefeacute-

rence reviendrait agrave transmettre ladresse dun emplacement de meacutemoire libeacutereacute

Certes nous utilisons ici immeacutediatement la valeur de p degraves le retour dans la fonction main

(ce qui est geacuteneacuteralement le cas avec un opeacuterateur) Neacuteanmoins nous ne pouvons faire aucune

hypothegravese sur la maniegravere dont une impleacutementation donneacutee libegravere un emplacement meacutemoire

elle peut simplement se contenter de noter quil est disponible auquel cas son contenu reste

valable pendant un certain temps elle peut au contraire le mettre agrave zeacutero La premiegravere

situation est certainement la pire puisquelle peut donner lillusion que cela marche

Pour eacuteviter la recopie de cette valeur de retour on pourrait songer agrave allouer dynamiquement

lemplacement de p Geacuteneacuteralement cela prendra plus de temps que sa recopie ulteacuterieure et de

plus compliquera quelque peu le programme (il faudra libeacuterer convenablement lemplace-

ment en question et on ne pourra le faire quen dehors de la fonction )

Si lon cherche agrave proteacuteger contre deacuteventuelles modifications un argument transmis par reacutefeacute-

rence on pourra toujours faire appel au mot cleacute const par exemple len-tecircte de operator +

pourrait ecirctre2

point operator + (const pointamp a const pointamp b)

1 Rappelons que la transmission de lobjet appelant une fonction membre se fait par reacutefeacuterence

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral157

Naturellement si lon utilise const dans le cas dobjets comportant des pointeurs sur des par-

ties dynamiques seuls ces pointeurs seront proteacutegeacutes les parties dynamiques resteront

modifiables

2 La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteralNous venons de voir un exemple de surdeacutefinition de lopeacuterateur binaire + lorsquil reccediloit deux

opeacuterandes de type point et ce de deux faccedilons comme fonction amie comme fonction mem-

bre Examinons maintenant ce quil est possible de faire dune maniegravere geacuteneacuterale

21 Se limiter aux opeacuterateurs existantsLe symbole suivant le mot cleacute operator doit obligatoirement ecirctre un opeacuterateur deacutejagrave deacutefini

pour les types de base Il nest donc pas possible de creacuteer de nouveaux symboles Nous ver-

rons dailleurs que certains opeacuterateurs ne peuvent pas ecirctre redeacutefinis du tout (cest le cas de )

et que dautres imposent quelques contraintes suppleacutementaires

Il faut conserver la pluraliteacute (unaire binaire) de lopeacuterateur initial Ainsi vous pourrez surdeacute-

finir un opeacuterateur + unaire ou un opeacuterateur + binaire mais vous ne pourrez pas deacutefinir de =

unaire ou de ++ binaire

Lorsque plusieurs opeacuterateurs sont combineacutes au sein dune mecircme expression (quils soient sur-

deacutefinis ou non) ils conservent leur prioriteacute relative et leur associativiteacute Par exemple si vous

surdeacutefinissez les opeacuterateurs binaires + et pour le type complexe lexpression suivante (a b

et c eacutetant supposeacutes du type complexe)

a b + c

sera interpreacuteteacutee comme

(a b) + c

De telles regravegles peuvent vous paraicirctre restrictives En fait vous verrez agrave lusage quelles sont

encore tregraves larges et quil est facile de rendre un programme incompreacutehensible en abusant de

la surdeacutefinition dopeacuterateurs

Le tableau ci-apregraves preacutecise les opeacuterateurs surdeacutefinissables (en fait tous sauf et )

et rappelle leur prioriteacute relative et leur associativiteacute Notez la preacutesence

bull de lopeacuterateur de cast nous verrons au chapitre 10 quil peut sappliquer agrave la conversion

dune classe dans un type de base ou agrave la conversion dune classe dans une autre classe

bull des opeacuterateurs new et delete avant la version 20 ils ne pouvaient pas ecirctre surdeacutefinis pour

une classe particuliegravere on ne pouvait en modifier la signification que dune faccedilon globale

Depuis la version 20 ils sont surdeacutefinissables au mecircme titre que les autres Nous en parle-

rons au paragraphe 7

2 Cependant comme on le verra au chapitre 10 la preacutesence de cet attribut const pourra autoriser certaines

conversions de lrsquoargument

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

158

bull des opeacuterateurs -gt et introduits par la norme ils sont drsquoun usage restreint et ils srsquoappli-

quent aux pointeurs sur des membres Leur rocircle est deacutecrit en Annexe F

Les opeacuterateurs surdeacutefinissables en C++ (classeacutes par prioriteacute deacutecroissante)

(1) Srsquoil nrsquoest pas surdeacutefini il possegravede une signification par deacutefaut

(2) Depuis la version 20 seulement

(3) Doit ecirctre deacutefini comme fonction membre

(4) Soit agrave un niveau global (fonction indeacutependante) avant la version 20 Depuis la version 20 il peut en outre ecirctre

surdeacutefini pour une classe dans ce cas il doit lrsquoecirctre comme fonction membre

(5) Jusqursquoagrave la version 3 on ne pouvait pas distinguer entre les notations preacute et post Depuis la version 3 lorsqursquoils

sont deacutefinis de faccedilon unaire ces opeacuterateurs correspondent agrave la notation preacute mais il en existe une deacutefinition binaire

(avec deuxiegraveme opeacuterande fictif de type int) qui correspond agrave la notation post

(6) On distingue bien new de new[] et delete de delete[]

22 Se placer dans un contexte de classeOn ne peut surdeacutefinir un opeacuterateur que sil comporte au moins un argument (implicite ou

non) de type classe Autrement dit il doit sagir

Pluraliteacute Opeacuterateurs Associativiteacute

Binaire ()(3) [](3) -gt(1) (2) (3) -gt

Unaire + - ++(5) --(5) ~ amp(1)

new(1)(4)(6) new[](1)(4)(6) delete(1)(4)(6) delete[](1)(4)(6)

(cast)

lt-

Binaire -gt

Binaire -gt(1) (1) -gt

Binaire + - -gt

Binaire ltlt gtgt -gt

Binaire lt lt= gt gt= -gt

Binaire == = -gt

Binaire amp -gt

Binaire ^ -gt

Binaire || -gt

Binaire ampamp -gt

Binaire | -gt

Binaire =(1)(3) += -= = = =

amp= ^= |= ltlt= gtgt=

lt-

Binaire (2) -gt

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral159

bull Soit dune fonction membre dans ce cas elle comporte agrave coup sucircr un argument (implicite)

de type classe agrave savoir lobjet layant appeleacute Sil sagit dun opeacuterateur unaire elle ne com-

portera aucun argument explicite Sil sagit dun opeacuterateur binaire elle comportera un argu-

ment explicite auquel aucune contrainte de type nest imposeacutee (dans les exemples

preacuteceacutedents il sagissait du mecircme type que la classe elle-mecircme mais il pourrait sagir dun

autre type classe ou mecircme dun type de base)

bull Soit dune fonction indeacutependante ayant au moins un argument de type classe En geacuteneacuteral il

sagira dune fonction amie

Cette regravegle garantit limpossibiliteacute de surdeacutefinir un opeacuterateur portant sur des types de base

(imaginez ce que serait un programme dans lequel on pourrait changer la signification de

3 + 5 ou de adr ) Une exception a lieu cependant pour les seuls opeacuterateurs new et delete

dont la signification peut ecirctre modifieacutee de maniegravere globale (pour tous les objets et les types

de base) nous en reparlerons au paragraphe 7

De plus certains opeacuterateurs doivent obligatoirement ecirctre deacutefinis comme membres dune

classe Il sagit de [] ( ) -gt1 ainsi que de new et delete (dans le seul cas ougrave ils portent sur une

classe particuliegravere)

23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateurComme nous avons deacutejagrave eu loccasion de lindiquer vous ecirctes totalement libre dattribuer agrave un

opeacuterateur surdeacutefini la signification que vous deacutesirez Cette liberteacute nest limiteacutee que par le bon

sens qui doit vous inciter agrave donner agrave un symbole une signification relativement naturelle

par exemple + pour la somme de deux complexes plutocirct que - ou []

Cela dit vous ne retrouverez pas pour les opeacuterateurs surdeacutefinis les liens qui existent entre

certains opeacuterateurs de base Par exemple si a et b sont de type int

a += b

est eacutequivalent agrave

a = a + b

Autrement dit le rocircle de lopeacuterateur de base += se deacuteduit du rocircle de lopeacuterateur + et de celui

de lopeacuterateur = En revanche si vous surdeacutefinissez lopeacuterateur + et lopeacuterateur = lorsque leurs

deux opeacuterandes sont de type complexe vous naurez pas pour autant deacutefini la signification de

+= lorsquil aura deux opeacuterandes de type complexe De plus vous pourrez tregraves bien surdeacutefinir

+= pour quil ait une signification diffeacuterente de celle attendue naturellement cela nest pas

conseilleacute

De mecircme et de faccedilon peut-ecirctre plus surprenante C++ ne fait aucune hypothegravese sur la com-

mutativiteacute eacuteventuelle dun opeacuterateur surdeacutefini (contrairement agrave ce qui se passe pour sa prio-

riteacute relative ou son associativiteacute) Cette remarque est lourde de conseacutequences Supposez par

1 Il nest surdeacutefinissable que depuis la version 20

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

160

exemple que vous ayez surdeacutefini lopeacuterateur + lorsquil a comme opeacuterandes un complexe et

un double (dans cet ordre) son prototype pourrait ecirctre

complexe operator + (complexe double)

Si ceci vous permet de donner un sens agrave une expression telle que (a eacutetant complexe)

a + 35

cela ne permet pas pour autant dinterpreacuteter

35 + a

Pour ce faire il aurait fallu surdeacutefinir lopeacuterateur + lorsquil a comme opeacuterandes un double et

un complexe avec par exemple1 comme prototype

complexe operator + (double complexe)

Nous verrons cependant au chapitre 10 que les possibiliteacutes de conversions deacutefinies par lutili-

sateur permettront de simplifier quelque peu les choses Par exemple il suffira dans ce cas

preacutecis de deacutefinir lopeacuterateur + lorsquil porte sur deux complexes ainsi que la conversion de

double en complexe pour que les expressions de lune de ces formes aient un sens

double + complexecomplexe + doublefloat + complexecomplexe + float

24 Cas des opeacuterateurs ++ et --Jusquagrave la version 20 de C++ on ne pouvait pas distinguer lopeacuterateur ++ en notation preacute-

fixeacutee (comme dans ++a) de ce mecircme opeacuterateur en notation postfixeacutee (comme dans a++)

Autrement dit pour un type classe donneacute on ne pouvait deacutefinir quun seul opeacuterateur ++ (ope-

rator ++) qui eacutetait utiliseacute dans les deux cas

Depuis la version 3 on peut deacutefinir agrave la fois un opeacuterateur ++ utilisable en notation preacutefixeacutee et

un autre utilisable en notation postfixeacutee Pour ce faire on utilise une convention qui consiste

agrave ajouter un argument fictif suppleacutementaire agrave la version postfixeacutee Par exemple si T deacutesigne

un type classe et que ++ est deacutefini sous la forme drsquoune fonction membre

bull lopeacuterateur (usuel) den-tecircte T operator ++ () est utiliseacute en cas de notation preacutefixeacutee

bull lopeacuterateur den-tecircte T operator ++ (int) est utiliseacute en cas de notation postfixeacutee Notez bien

la preacutesence dun second opeacuterande de type int Celui-ci est totalement fictif en ce sens quil

permet au compilateur de choisir lopeacuterateur agrave utiliser mais quaucune valeur ne sera reacuteelle-

ment transmise lors de lappel

De mecircme si ++ est deacutefini sous forme de fonction amie

bull lrsquoopeacuterateur (usuel) drsquoen-tecircte T operator (T) est utiliseacute en cas de notation preacutefixeacutee

bull lrsquoopeacuterateur drsquoen-tecircte T operator (T int) est utiliseacute en cas de notation postfixeacutee

1 Nous verrons dailleurs un peu plus loin que dans ce cas on ne pourra pas surdeacutefinir cet opeacuterateur comme une

fonction membre (puisque son premier opeacuterande nest plus de type classe)

2 - La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral161

Les mecircmes consideacuterations sappliquent agrave lopeacuterateur --

Voici un exemple dans lequel nous avons deacutefini ++ pour quil increacutemente dune uniteacute les deux

coordonneacutees dun point et fournisse comme valeur soit celle du point avant increacutementation

dans le cas de la notation postfixeacutee soit celle du point apregraves increacutementation dans le cas de la

notation preacutefixeacutee

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord point operator ++ () notation preacutefixeacutee x++ y++ return this point operator ++ (int n) notation postfixeacutee point p = this x++ y++ return p void affiche () cout ltlt x ltlt ltlt y ltlt n

main() point a1 (2 5) a2(2 5) b b = ++a1 cout ltlt a1 a1affiche () affiche a1 3 6 cout ltlt b baffiche () affiche b 3 6 b = a2++ cout ltlt a2 a2affiche () affiche a2 3 6 cout ltlt b baffiche () affiche b 2 5

Exemple de surdeacutefinition de ++ en notation preacutefixeacutee et postfixeacutee

Remarque

Theacuteoriquement depuis la version 3 et donc depuis la norme ANSI il nrsquoest plus possible

de ne deacutefinir quun seul opeacuterateur ++ quon utiliserait agrave la fois en notation preacutefixeacutee et post-

fixeacutee En fait la plupart des compilateurs acceptent que lrsquoon ne fournisse que la version

preacutefixeacutee qui se trouve alors utiliseacutee dans les deux cas

25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinieDans notre exemple drsquointroduction nous avions surdeacutefini lrsquoopeacuterateur + pour des opeacuterandes

de type point Comme on srsquoen doute en lrsquoabsence drsquoune telle surdeacutefinition lrsquoopeacuterateur

nrsquoaurait aucun sens dans ce contexte et son utilisation conduirait agrave une erreur de compilation

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

162

Il en va ainsi pour la plupart des opeacuterateurs qui nrsquoont donc pas de signification preacutedeacutefinie

pour un type classe Il existe toutefois quelques exceptions qui vont geacuteneacuteralement de soi (par

exemple on srsquoattend bien agrave ce que amp repreacutesente lrsquoadresse drsquoun objet )

Lrsquoopeacuterateur = fait lui aussi exception Nous avons deacutejagrave eu lrsquooccasion de lrsquoemployer avec

deux opeacuterandes du mecircme type classe et nous nrsquoavions pas eu besoin de le surdeacutefinir Effecti-

vement en lrsquoabsence de surdeacutefinition explicite cet opeacuterateur correspond agrave la recopie des

valeurs de son second opeacuterande dans le premier Nous avons drsquoailleurs constateacute que cette

simple recopie pouvait srsquoaveacuterer insatisfaisante degraves lors que les objets concerneacutes comportaient

des pointeurs sur des emplacements dynamiques Il srsquoagit lagrave typiquement drsquoune situation qui

neacutecessite la surdeacutefinition de lrsquoopeacuterateur = dont nous donnerons un exemple dans le paragra-

phe suivant

On notera la grande analogie existant entre

bull le constructeur de recopie srsquoil nrsquoen existe pas drsquoexplicite il y a appel drsquoun constructeur de

recopie par deacutefaut

bull lrsquoopeacuterateur drsquoaffectation srsquoil nrsquoen existe pas drsquoexplicite il y a emploi drsquoun opeacuterateur drsquoaf-

fectation par deacutefaut

Constructeur de recopie par deacutefaut et opeacuterateur drsquoaffectation par deacutefaut effectuent le mecircme

travail la recopie des valeurs de lrsquoobjet Au chapitre 7 nous avons signaleacute que dans le cas

drsquoobjets dont certains membres sont eux-mecircmes des objets le constructeur de recopie par

deacutefaut travaillait membre par membre La mecircme remarque srsquoapplique agrave lrsquoopeacuterateur drsquoaffecta-

tion par deacutefaut il opegravere membre par membre1 ce qui laisse la possibiliteacute drsquoappeler un opeacutera-

teur drsquoaffectation explicite dans le cas ougrave lrsquoun des membres en posseacutederait un Cela peut

eacuteviter drsquoavoir agrave eacutecrire explicitement un opeacuterateur drsquoaffectation pour des objets sans pointeurs

(apparents) mais dont un ou plusieurs membres possegravedent quant agrave eux des parties dynami-

ques

26 Les conversionsC et C++ autorisent freacutequemment les conversions entre types de base de faccedilon explicite ou

implicite Ces possibiliteacutes seacutetendent aux objets Par exemple comme nous lavons deacutejagrave eacutevo-

queacute si a est de type complexe et si lopeacuterateur + a eacuteteacute surdeacutefini pour deux complexes une

expression telle que a + 35 pourra prendre un sens

bull soit si lon a surdeacutefini lopeacuterateur + lorsquil a un opeacuterande de type complexe et un opeacuterande

de type double

bull soit si lon a deacutefini une conversion de type double en complexe

Nous avons toutefois preacutefeacutereacute regrouper au chapitre 10 tout ce qui concerne les problegravemes de

conversion cest lagrave que nous parlerons de la surdeacutefinition dun opeacuterateur de cast

1 Lagrave encore depuis la version 20 de C++ Auparavant il opeacuterait de faccedilon globale (memberwise copy)

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =163

27 Choix entre fonction membre et fonction amieC++ vous laisse libre de surdeacutefinir un opeacuterateur agrave laide dune fonction membre ou dune

fonction indeacutependante (en geacuteneacuteral amie) Vous pouvez donc parfois vous demander sur quels

critegraveres effectuer le choix Certes il semble qursquoon puisse eacutennoncer la regravegle suivante si un

opeacuterateur doit absolument recevoir un type de base en premier argument il ne peut pas

ecirctre deacutefini comme fonction membre (puisque celle-ci reccediloit implicitement un premier argu-ment du type de sa classe)

Mais il faudra tenir compte des possibliteacutes exposeacutees au prochain chapitre de conversion en unobjet drsquoun opeacuterande drsquoun type de base Par exemple lrsquoaddition dun double (type de base) etdun complexe (type classe) dans cet ordre1 semble correspondre agrave la situation eacutevoqueacutee (pre-mier opeacuterande drsquoun type de base) et donc imposer le recours agrave une fonction amie de la classecomplexe En fait nous verrons qursquoil peut aussi se traiter par surdeacutefinition drsquoune fonctionmembre de la classe complexe effectuant laddition de deux complexes compleacuteteacutee par ladeacutefinition de la conversion double -gt complexe

3 Exemple de surdeacutefinition de lrsquoopeacuterateur =

31 Rappels concernant le constructeur par recopie Nous avons deacutejagrave eu loccasion dutiliser une classe vect correspondant agrave des vecteurs dyna-miques (voir au paragraphe 3 du chapitre 7)

class vect int nelem nombre deacuteleacutements int adr adresse public vect (int n) constructeur

Si fct eacutetait une fonction agrave un argument de type vect les instructions suivantes vect a(5) fct (a)

1 Il ne suffira pas davoir surdeacutefini laddition dun complexe et dun double (qui peut se faire par une fonction

membre) En effet comme nous lavons dit aucune hypothegravese nest faite par C++ sur lopeacuterateur surdeacutefini en

particulier sur sa commutativiteacute

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

164

posaient problegraveme lappel de fct conduisait agrave la creacuteation par recopie de a dun nouvel objetb Nous eacutetions alors en preacutesence de deux objets a et b comportant un pointeur (adr) vers lemecircme emplacement

En particulier si la classe vect posseacutedait (comme cest souhaitable ) un destructeur chargeacute delibeacuterer lemplacement dynamique associeacute on risquait daboutir agrave deux demandes de libeacuterationdu mecircme emplacement meacutemoire

Une solution consistait agrave deacutefinir un constructeur de recopie chargeacute deffectuer non seulementla recopie de lobjet lui-mecircme mais aussi celle de sa partie dynamique dans un nouvel empla-cement (ou agrave interdire la recopie)

32 Cas de lrsquoaffectationLaffectation dobjets de type vect pose les mecircmes problegravemes Ainsi avec cette deacuteclaration

vect a(5) b(3)

qui correspond au scheacutema

a

b

5

5

a

b

5

3

x

y

z

t

u

f

g

h

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =165

Laffectation b = a

conduit agrave

Le problegraveme est effectivement voisin de celui de la construction par recopie Voisin maisnon identique car quelques difffeacuterences apparaissent

bull On peut se trouver en preacutesence dune affectation dun objet agrave lui-mecircme

bull Avant affectation il existe ici deux objets complets (cest-agrave-dire avec leur partie dynami-que) Dans le cas de la construction par recopie il nexistait quun seul emplacement dyna-mique le second eacutetant agrave creacuteer On va donc se retrouver ici avec lancien emplacementdynamique de b Or srsquoil nest plus reacutefeacuterenceacute par b est-on sucircr quil nest pas reacutefeacuterenceacute parailleurs

33 Algorithme proposeacuteNous pouvons reacutegler les diffeacuterents points en surdeacutefinissant lopeacuterateur daffectation demaniegravere que chaque objet de type vect comporte son propre emplacement dynamique Dansce cas on est sucircr quil nest reacutefeacuterenceacute quune seule fois et son eacuteventuelle libeacuteration peut sefaire sans problegraveme Notez cependant que cette deacutemarche ne convient totalement que si elleest associeacutee agrave la deacutefinition conjointe du constructeur de recopie

Voici donc comment nous pourrions traiter une affectation telle que b = a lorsque a est dif-feacuterent de b

bull libeacuteration de lemplacement pointeacute par b

bull creacuteation dynamique dun nouvel emplacement dans lequel on recopie les valeurs de lempla-cement pointeacute par a

bull mise en place des valeurs des membres donneacutees de b

a

b

5

3

x

y

z

t

u

f

g

h

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

166

Voici un scheacutema illustrant la situation agrave laquelle on aboutit

Il reste agrave reacutegler le cas ougrave a et b correspondent au mecircme objet

Si la transmission de a agrave lrsquoopeacuterateur drsquoaffectation a lieu par valeur et si le constructeur parrecopie a eacuteteacute redeacutefini de faccedilon approprieacutee (par creacuteation drsquoun nouvel emplacement dynami-que) lrsquoalgorithme proposeacute fonctionnera sans problegraveme

En revanche si la transmission de a a lieu par reacutefeacuterence on abordera lrsquoalgorithme avec cettesituation

Lrsquoemplacement dynamique associeacute agrave b (donc aussi agrave a) sera libeacutereacute avant qursquoon tente de lrsquouti-liser pour le recopier dans un nouvel emplacement La situation sera alors catastrophique1

a

b

5

5

x

y

z

t

u

x

y

z

t

u

5z

t

ua et b

y

1 Dans beaucoup drsquoenvironnements les valeurs drsquoun emplacement libeacutereacute ne sont pas modifieacutees Lrsquoalgorithme peut

alors donner lrsquoillusion qursquoil fonctionne

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =167

34 Valeur de retourEnfin il faut deacutecider de la valeur de retour fournie par lrsquoopeacuterateur Agrave ce niveau tout deacutependde lrsquousage que nous souhaitons en faire

bull Si nous nous contentons drsquoaffectations simples (b=a) nous nrsquoavons besoin drsquoaucune va-leur de retour (void)

bull En revanche si nous souhaitons pouvoir traiter une affectation multiple ou plus geacuteneacuterale-ment faire en sorte que (comme on peut srsquoy attendre ) lrsquoexpression b=a ait une valeur(probablement celle de b ) il est neacutecessaire que lrsquoopeacuterateur fournisse une valeur de retour

Nous choisissons ici la seconde possibiliteacute qui a le meacuterite drsquoecirctre plus geacuteneacuterale1

35 En deacutefinitiveVoici finalement ce que pourrait ecirctre la deacutefinition de lrsquoopeacuterateur = (C++ impose de le deacutefinircomme une fonction membre) b devient le premier opeacuterande ndash ici this ndash et a devient lesecond opeacuterande ndash ici v De plus nous preacutevoyons de transmettre le second opeacuterande parreacutefeacuterence

vect vectoperator = (const vect amp v) notez const if (this = ampv) delete adr adr = new int [nelem = vnelem] for (int i=0 iltnelem i++) adr[i] = vadr[i] return this

Comme lrsquoargument de la fonction membre operator= est transmis par reacutefeacuterence il est neacuteces-saire de lui associer le qualificatif const si lrsquoon souhaite pouvoir affecter un vecteur constantagrave un vecteur quelconque2

36 Exemple de programme completNous vous proposons dinteacutegrer cette deacutefinition dans un programme complet servant agrave illus-trer le fonctionnement de lopeacuterateur Pour ce faire nous ajoutons comme dhabitude un cer-tain nombre dinstructions daffichage (en particulier nous suivons les adresses des objets etdes emplacements dynamiques qui leur sont associeacutes) Mais pour que le programme ne soitpas trop long nous avons reacuteduit la classe vect au strict minimum en particulier nousnrsquoavons pas preacutevu de constructeur de recopie or celui-ci deviendrait naturellement

indispensable dans une application reacuteelle

1 Bien entendu C++ vous laisse libre de faire ce que vous voulez y compris de renvoyer une valeur autre que celle

de b (avec tous les risques de manque de lisibiliteacute que cela suppose )

2 Cependant comme on le verra au chapitre 10 la preacutesence de cet attribut const pourra autoriser certaines

conversions de lrsquoargument

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

168

En outre bien qursquoici notre fonction main se limite agrave lemploi de lopeacuterateur = nous avons ducircpreacutevoir une transmission par reacutefeacuterence pour largument et la valeur de retour de operator=En effet si nous ne lavions pas fait lappel de cet opeacuterateur ndash traiteacute comme une fonction ndashaurait entraicircneacute un appel de constructeur de recopie (a = b est eacutequivalent ici agrave aoperator =

(b)) il se serait alors agi du constructeur de recopie par deacutefaut ce qui aurait entraicircneacute les pro-

blegravemes deacutejagrave eacutevoqueacutes de double libeacuteration dun emplacement1

include ltiostreamgtusing namespace std class vect int nelem nombre deacuteleacutements int adr pointeur sur ces eacuteleacutements public vect (int n) constructeur adr = new int [nelem = n] for (int i=0 iltnelem i++) adr[i] = 0 cout ltlt ++ obj taille ltlt nelem ltlt en ltlt this ltlt - v dyn en ltlt adr ltlt n ~vect () destructeur cout ltlt -- obj taille ltlt nelem ltlt en ltlt this ltlt - v dyn en ltlt adr ltlt n delete adr vect amp operator = (const vect amp) surdeacutefinition opeacuterateur = vect amp vectoperator = (const vect amp v) cout ltlt == appel operateur = avec adresses ltlt this ltlt ltlt ampv ltlt n if (this = ampv) cout ltlt effacement vecteur dynamique en ltlt adr ltlt n delete adr adr = new int [nelem = vnelem] cout ltlt nouveau vecteur dynamique en ltlt adr ltlt n for (int i=0 iltnelem i++) adr[i] = vadr[i] else cout ltlt on ne fait rien n return this main() vect a(5) b(3) c(4) cout ltlt affectation a=b n a = b cout ltlt affectation c=c n c = c cout ltlt affectation a=b=c n a = b = c

1 Un des exercices de ce chapitre vous propose de le veacuterifier

3 - Exemple de surdeacutefinition de lrsquoopeacuterateur =169

++ obj taille 5 en 006AFDE4 - v dyn en 007D0340

++ obj taille 3 en 006AFDDC - v dyn en 007D00D0

++ obj taille 4 en 006AFDD4 - v dyn en 007D0090

affectation a=b

== appel operateur = avec adresses 006AFDE4 006AFDDC

effacement vecteur dynamique en 007D0340

nouveau vecteur dynamique en 007D0340

affectation c=c

== appel operateur = avec adresses 006AFDD4 006AFDD4

on ne fait rien

affectation a=b=c

== appel operateur = avec adresses 006AFDDC 006AFDD4

effacement vecteur dynamique en 007D00D0

nouveau vecteur dynamique en 007D00D0

== appel operateur = avec adresses 006AFDE4 006AFDDC

effacement vecteur dynamique en 007D0340

nouveau vecteur dynamique en 007D0340

-- obj taille 4 en 006AFDD4 - v dyn en 007D0090

-- obj taille 4 en 006AFDDC - v dyn en 007D00D0

-- obj taille 4 en 006AFDE4 - v dyn en 007D0340

Exemple dutilisation dune classe vect avec un opeacuterateur daffectation surdeacutefini

37 Lorsqursquoon souhaite interdire lrsquoaffectationNous avons deacutejagrave vu (paragraphe 313 du chapitre 7) que dans certains cas on pouvait avoir

inteacuterecirct agrave interdire la recopie dobjets Les mecircmes consideacuterations sappliquent agrave laffectation

Ainsi une redeacutefinition de laffectation sous forme priveacutee en interdit lemploi par des fonc-

tions autres que les fonctions membres de la classe concerneacutee On peut eacutegalement exploiter la

possibiliteacute quoffre C++ de deacuteclarer une fonction sans en fournir de deacutefinition dans ce cas

toute tentative daffectation (mecircme au sein dune fonction membre) sera rejeteacutee par leacutediteur

de liens Dune maniegravere geacuteneacuterale il peut ecirctre judicieux de combiner les deux possibiliteacutes

cest-agrave-dire deffecteur une deacuteclaration priveacutee sans deacutefinition dans ces cas les tentatives

daffectation de la part de lutilisateur seront deacutetecteacutees en compilation et seules les tentatives

daffectation par une fonction membre produiront une erreur de leacutedition de liens (et ce point

ne concerne que le concepteur de la classe et non son utilisateur)

Remarques

1 Comme dans le cas de la deacutefinition du constructeur de recopie nous avons utiliseacute la

deacutemarche la plus naturelle consistant agrave effectuer une copie profonde en dupliquant la par-

tie dynamique de lobjet Dans certains cas on pourra chercher agrave eacuteviter cette duplication

en la dotant dun compteur de reacutefeacuterences comme lexplique lAnnexe E

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

170

2 Nous verrons plus tard que si une classe est destineacutee agrave donner naissance agrave des objets

susceptibles drsquoecirctre introduits dans des conteneurs il nrsquoest plus possible de deacutesactiver

lrsquoaffectation (pas plus que la recopie)

En Java

Java ne permet pas la surdeacutefinition dopeacuterateur On ne peut donc pas modifier la seacutemanti-

que de laffectation qui rappelons-le est tregraves diffeacuterente de celle agrave laquelle on est habitueacute

en C++ (les objets eacutetant manipuleacutes par reacutefeacuterence on aboutit apregraves affectation agrave deux reacutefeacute-

rences eacutegales agrave un unique objet)

4 La forme canonique dune classeDegraves lors quune classe dispose de pointeurs sur des parties dynamiques la copie dobjets de la

classe (aussi bien par le constructeur de recopie par deacutefaut que par lopeacuterateur daffectation

par deacutefaut) nest pas satisfaisante Dans ces conditions si lon souhaite que cette recopie fonc-

tionne convenablement il est neacutecessaire de munir la classe des quatre fonctions membres

suivantes au moins

bull constructeur (il sera geacuteneacuteralement chargeacute de lallocation de certaines parties de lobjet)

bull destructeur (il devra libeacuterer correctement tous les emplacements dynamiques creacuteeacutes par lobjet)

bull constructeur de recopie

bull opeacuterateur daffectation

Voici un canevas reacutecapitulatif correspondant agrave ce minimum quon nomme souvent classe

canonique

class T public

T () constructeurs autres que par recopie

T (const T amp) constructeur de recopie (forme conseilleacutee)

(deacuteclaration priveacutee pour lrsquointerdire) ~T () destructeur

T amp operator = (const T amp) affectation (forme conseilleacutee)

(deacuteclaration priveacutee pour lrsquointerdire)

La forme canonique dune classe

Bien que ce ne soit pas obligatoire nous vous conseillons

bull demployer le qualificatif const pour largument du constructeur de recopie et celui de laffec-

tation dans la mesure ougrave ces fonctions membres nont aucune raison de modifier les valeurs

5 - Exemple de surdeacutefinition de lopeacuterateur [ ]171

des objets correspondants On verra toutefois au chapitre 10 que cette faccedilon de proceacuteder peut

autoriser lintroduction de certaines conversions de lopeacuterande de droite de laffectation

bull de preacutevoir (agrave moins davoir de bonnes raisons de faire le contraire) une valeur de retour agrave

lopeacuterateur daffectation seul moyen de geacuterer correctement les affectations multiples

En revanche largument de lopeacuterateur daffectation et sa valeur de retour peuvent ecirctre indif-

feacuteremment transmis par reacutefeacuterence ou par valeur Cependant on ne perdra pas de vue que les

transmissions par valeur entraicircnent lappel du constructeur de recopie Dautre part degraves lors

que les objets sont de taille respectable la transmission par reacutefeacuterence savegravere plus efficace

Si vous creacuteez une classe comportant des pointeurs sans la doter de ce minimum vital et sans

prendre de preacutecautions particuliegraveres lutilisateur ne se verra nullement interdire la recopie ou

laffectation dobjets

Il peut arriver de creacuteer une classe qui nrsquoa pas besoin de disposer de ces possibiliteacutes de recopie

et drsquoaffectation par exemple parce qursquoelles nrsquoont pas de sens (cas drsquoune classe fenecirctre drsquoun

systegraveme graphique) Il se peut aussi que vous souhaitiez tout simplement ne pas offrir ces

possibliteacutes agrave lrsquoutilisateur de la classe Dans ce cas plutocirct que de compter sur la bonne

volonteacute de lrsquoutilisateur il est preacutefeacuterable drsquoutiliser quand mecircme la forme canonique en

srsquoarrangeant pour interdire ces actions Nous vous avons fourni des pistes dans ce sens au

paragraphe 37 ainsi qursquoau paragraphe 313 du chapitre 7 et nous avons vu qursquoune solution

simple agrave mettre en place consistait agrave fournir des deacuteclarations priveacutees de ces deux meacutethodes

sans en fournir de deacutefinition

Remarque

Ce scheacutema sera compleacuteteacute au chapitre 13 afin de prendre en compte la situation dheacuteritage

5 Exemple de surdeacutefinition de lopeacuterateur [ ] Consideacuterons agrave nouveau notre classe vect

class vect int nelem int adr

Cherchons agrave la munir doutils permettant dacceacuteder agrave un eacuteleacutement de lemplacement pointeacute par

adr agrave partir de sa position que lon repeacuterera par un entier compris entre 0 et nelem-1

Nous pourrions bien sucircr eacutecrire des fonctions membres comme

void range (int valeur int position)

pour introduire une valeur agrave une position donneacutee et

int trouve (int position)

pour fournir la valeur situeacutee agrave une position donneacutee

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

172

La manipulation de nos vecteurs ne serait alors guegravere aiseacutee Elle ressemblerait agrave ceci

vect a(5) arange (15 0) place 15 en position 0 de aarange (25 1) 25 en position 1for (int i = 2 i lt 5 i++) arange (0 i) et O ailleursfor i = 0 i lt 5 i++) pour afficher les valeurs de a cout ltlt atrouve (i)

En fait nous pouvons chercher agrave surdeacutefinir lopeacuterateur [] de maniegravere que a[i] deacutesigne leacuteleacute-

ment demplacement i de a La seule preacutecaution agrave prendre consiste agrave faire en sorte que cette

notation puisse ecirctre utiliseacutee non seulement dans une expression (cas qui ne preacutesente aucune

difficulteacute) mais eacutegalement agrave gauche dune affectation cest-agrave-dire comme lvalue Notez que

le problegraveme ne se posait pas dans lexemple ci-dessus puisque chaque cas eacutetait traiteacute par une

fonction membre diffeacuterente

Pour que a[i] soit une lvalue il est donc neacutecessaire que la valeur de retour fournie par lopeacute-

rateur [] soit transmise par reacutefeacuterence

Par ailleurs C++ impose de surdeacutefinir cet opeacuterateur sous la forme dune fonction membre ce

qui implique que son premier opeacuterande (le premier opeacuterande de a[i] est a) soit de type classe

(ce qui semble raisonnable ) Son prototype sera donc

int amp operator [] (int)

Si nous nous contentons de renvoyer leacuteleacutement chercheacute sans effectuer de controcircle sur la vali-

diteacute de la position le corps de la fonction operator[] peut se reacuteduire agrave

return adr[i]

Voici un exemple simple dutilisation dune classe vect reacuteduite agrave son strict minimum cons-

tructeur destructeur et opeacuterateur [] Bien entendu en pratique il faudrait au moins lui ajouter

un constructeur de recopie et un opeacuterateur daffectation

include ltiostreamgtusing namespace std class vect int nelem int adr public vect (int n) adr = new int [nelem=n] ~vect () delete adr int amp operator [] (int) int amp vectoperator [] (int i) return adr[i] main() int i vect a(3) b(3) c(3) for (i=0 ilt3 i++) a[i] = i b[i] = 2i for (i=0 ilt3 i++) c[i] = a[i]+b[i] for (i=0 ilt3 i++) cout ltlt c[i] ltlt

6 - Surdeacutefinition de lopeacuterateur ()173

0 3 6

Exemple de surdeacutefinition de lopeacuterateur[]

Remarques

1 Nous pourrions bien sucircr transmettre le second opeacuterande par reacutefeacuterence mais cela ne preacute-

senterait guegravere dinteacuterecirct compte tenu de la petite taille des variables du type int

2 C++ interdit de deacutefinir lopeacuterateur [] sous la forme dune fonction amie il en allait deacutejagrave

de mecircme pour lopeacuterateur = De toute faccedilon nous verrons au prochain chapitre quil

nest pas conseilleacute de deacutefinir par une fonction amie un opeacuterateur susceptible de modifier

un objet compte tenu des conversions implicites pouvant apparaicirctre

3 Seules les fonctions membres doteacutees du qualificatif const peuvent ecirctre appliqueacutees agrave un

objet constant Tel que nous lavons conccedilu lopeacuterateur [] ne permet donc pas dacceacuteder

agrave un objet constant mecircme sil ne sagit que drsquoutiliser la valeur de ses eacutelements sans la

modifier Certes on pourrait ajouter ce qualificatif const agrave lrsquoopeacuterateur [] mais il la

modification des valeurs drsquoun objet constant deviendrait alors possible ce qui nest

guegravere souhaitable En geacuteneacuteral on preacutefeacuterera deacutefinir un second opeacuterateur destineacute unique-

ment aux objets constants en faisant en sorte quil puisse consulter lobjet en question

mais non le modifier Dans notre cas voici ce que pourrait ecirctre ce second opeacuterateur

int vectoperator [] (int i) const return adr[i]

Une affectation telle que v[i] = v eacutetant un vecteur constant sera bien rejeteacutee en com-

pilation puisque notre opeacuterateur transmet son reacutesultat par valeur et non plus par reacutefeacute-

rence

4 Lopeacuterateur [] eacutetait ici dicteacute par le bon sens mais nullement imposeacute par C++ Nous

aurions pu tout aussi bien utiliser

ndash lopeacuterateur () la notation a(i) aurait encore eacuteteacute compreacutehensible

ndash lopeacuterateur lt que penser alors de la notation a lt i

ndash lopeacuterateur notation a i

ndash etc

6 Surdeacutefinition de lopeacuterateur ()Lorsquune classe surdeacutefinit lopeacuterateur () on dit que les objets auxquels elle donne naissance

sont des objets fonctions car ils peuvent ecirctre utiliseacutes de la mecircme maniegravere quune fonction

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

174

ordinaire En voici un exemple simple dans lequel nous surdeacutefinissons lopeacuterateur () pour

quil corresponde agrave une fonction agrave deux arguments de type int et renvoyant un int

class cl_fct public cl_fct(float x) constructeur int operator() (int n int p ) opeacuterateur ()

Dans ces conditions une deacuteclaration telle que

cl_fct obj_fct1(25)

construit bien sucircr un objet nommeacute obj_fct1 de type cl_fct en transmettant le paramegravetre 25 agrave

son constructeur En revanche la notation suivante reacutealise lappel de lopeacuterateur ( ) de lobjet

obj_fct1 en lui transmettant les valeurs 3 et 5

obj_fct1(3 5)

Ces possibiliteacutes peuvent servir lorsquil est neacutecessaire deffectuer certaines opeacuterations dini-

tialisation dune fonction ou de parameacutetrer son travail (par le biais des arguments passeacutes agrave son

constructeur) Mais elles saveacutereront encore plus inteacuteressantes dans le cas des fonctions dites

de rappel crsquoest-agrave-dire transmises en argument agrave une autre fonction

7 Surdeacutefinition des opeacuterateurs new et deleteNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Tout drsquoabord il faut bien noter que les opeacuterateurs new et delete peuvent srsquoappliquer agrave des

types de base agrave des structures usuelles ou agrave des objets Par ailleurs il existe drsquoautres opeacutera-

teurs new[] et delete[] srsquoappliquant agrave des tableaux (drsquoeacuteleacutements de type de base structure ou

objet) Cette remarque a des conseacutequences au niveau de leur redeacutefinition

bull Vous pourrez redeacutefinir new et delete seacutelectivement pour une classe donneacutee bien entendu

vous pourrez toujours redeacutefinir ces opeacuterateurs dans autant de classes que vous le

souhaiterez dans ce cas les opeacuterateurs preacutedeacutefinis (on parle aussi drsquoopeacuterateurs globaux)

continueront drsquoecirctre utiliseacutes pour les classes ougrave aucune surdeacutefinition nrsquoaura eacuteteacute preacutevue

bull Vous pourrez eacutegalement redeacutefinir ces opeacuterateurs de faccedilon globale il seront alors utiliseacutes

pour les types de base pour les structures usuelles et pour les types classe nrsquoayant opeacutereacute

aucune surdeacutefinition

bull Enfin il ne faudra pas perdre de vue que les surdeacutefinitions de new drsquoune part et de new[]

drsquoautre part sont deux choses diffeacuterentes lrsquoune nrsquoentraicircnant pas automatiquement lrsquoautre

la mecircme remarque srsquoapplique agrave delete et delete[]

Voyons cela plus en deacutetail en commenccedilant par la situation la plus usuelle agrave savoir la surdeacute-

finition de new et delete au sein drsquoune classe

7 - Surdeacutefinition des opeacuterateurs new et delete175

71 Surdeacutefinition de new et delete pour une classe donneacuteeLa surdeacutefinition de new se fait obligatoirement par une fonction membre qui doit

bull Posseacuteder un argument de type size_t correspondant agrave la taille en octets de lrsquoobjet agrave allouer

Bien qursquoil figure dans la deacutefinition de new il nrsquoa pas agrave ecirctre speacutecifieacute lors de son appel car

crsquoest le compilateur qui le geacuteneacuterera automatiquement en fonction de la taille de lrsquoobjet con-

cerneacute (Rappelons que size_t est un synonyme drsquoun type entier deacutefini dans le fichier en-

tecircte cstddef)

bull Fournir en retour une valeur de type void correspondant agrave lrsquoadresse de lrsquoemplacement al-

loueacute pour lrsquoobjet

Quant agrave la deacutefinition de la fonction membre correspondant agrave lrsquoopeacuterateur delete elle doit

bull Recevoir un argument du type pointeur sur la classe correspondante il repreacutesente lrsquoadresse

de lrsquoemplacement alloueacute agrave lrsquoobjet agrave deacutetruire

bull Ne fournir aucune valeur de retour (void)

Remarques

1 Mecircme lorsque lrsquoopeacuterateur new a eacuteteacute surdeacutefini pour une classe il reste possible de faire

appel agrave lrsquoopeacuterateur preacutedeacutefini en utilisant lrsquoopeacuterateur de reacutesolution de porteacutee il en va de

mecircme pour delete

2 Les opeacuterateurs new et delete sont des fonctions membres statiques de leur classe (voir

le paragraphe 8 du chapitre 6) En tant que tels ils nrsquoont donc accegraves qursquoaux membres

statiques de la classe ougrave ils sont deacutefinis et ne reccediloivent pas drsquoargument implicite (this)

72 ExempleVoici un programme dans lequel la classe point surdeacutefinit les opeacuterateurs new et delete dans

le seul but drsquoen comptabiliser les appels1 Ils font drsquoailleurs appel aux opeacuterateurs preacutedeacutefinis

(par emploi de ) pour ce qui concerne la gestion de la meacutemoire

include ltiostreamgtinclude ltcstddefgt pour size_tusing namespace std

class point static int npt nombre total de points static int npt_dyn nombre de points dynamiques int x y

1 Bien entendu dans un programme reacuteel lrsquoopeacuterateur new accomplira en geacuteneacuteral une tacircche plus eacutelaboreacutee

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

176

public point (int abs=0 int ord=0) constructeur x=abs y=ord npt++ cout ltlt ++ nombre total de points ltlt npt ltlt n ~point () destructeur npt-- cout ltlt -- nombre total de points ltlt npt ltlt n void operator new (size_t sz) new surdeacutefini npt_dyn++ cout ltlt il y a ltlt npt_dyn ltlt points dynamiques sur un n return new char[sz] void operator delete (void dp) npt_dyn-- cout ltlt il y a ltlt npt_dyn ltlt points dynamiques sur un n delete (dp) int pointnpt = 0 initialisation membre statique nptint pointnpt_dyn = 0 initialisation membre statique npt_dynmain() point ad1 ad2 point a(35) ad1 = new point (13) point b ad2 = new point (20) delete ad1 point c(2) 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

Exemple de surdeacutefinition de lrsquoopeacuterateur new pour la classe point

7 - Surdeacutefinition des opeacuterateurs new et delete177

Remarques

1 Comme le montre cet exemple et comme on peut srsquoy attendre la surdeacutefinition des opeacutera-

teurs new et delete nrsquoa drsquoincidence que sur les objets alloueacutes dynamiquement Les objets

statiques (alloueacutes agrave la compilation) et les objets dynamiques (alloueacutes lors de lrsquoexeacutecution

mais sur la pile) ne sont toujours pas concerneacutes

2 Que new soit surdeacutefini ou preacutedeacutefini son appel est toujours (heureusement) suivi de

celui du constructeur (lorsqursquoil existe) De mecircme que delete soit surdeacutefini ou preacutedeacutefini

son appel est toujours preacuteceacutedeacute de celui du destructeur (lorsqursquoil existe)

3 Nrsquooubliez pas qursquoil est neacutecessaire de distinguer new de new[] delete de delete[] Ainsi

dans lrsquoexemple de programme preacuteceacutedent une instruction telle que

point ad = new point [50]

ferait appel agrave lrsquoopeacuterateur new preacutedeacutefini (et 50 fois agrave lrsquoappel du constructeur sans argu-

ment) En geacuteneacuteral on surdeacutefinira eacutegalement new[] et delete[] comme nous allons le

voir ci-apregraves

73 Drsquoune maniegravere geacuteneacuteralePour surdeacutefinir new[] au sein drsquoune classe il suffit de proceacuteder comme pour new le nom

mecircme de lrsquoopeacuterateur (new[] au lieu de new) servant agrave effectuer la distinction Par exemple

dans notre classe point de lrsquoexemple preacuteceacutedent nous pourrons ajouter

void operator new [](size_t sz)

return new char[sz]

La valeur fournie en argument correspondra bien agrave la taille totale agrave allouer pour le tableau (et

non agrave la taille drsquoun seul eacuteleacutement) Cette fois dans notre preacuteceacutedent exemple de programme

lrsquoinstruction

point adp = new point[50]

effectuera bien un appel de lrsquoopeacuterateur new[] ainsi surdeacutefini (et toujours les 50 appels du

constructeur sans arguments de point)

De mecircme on surdeacutefinira delete[] de cette faccedilon

void operator delete (void dp) dp adresse de lrsquoemplacement agrave libeacuterer

Enfin pour surdeacutefinir les opeacuterateurs new et delete de maniegravere globale il suffit de deacutefinir

lrsquoopeacuterateur correspondant sous la forme drsquoune fonction indeacutependante comme dans cet

exemple

void operator new (size_t sz)

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

178

Notez bien qursquoalors

bull Cet opeacuterateur sera appeleacute pour tous les types pour lesquels aucun opeacuterateur new nrsquoa eacuteteacute sur-

deacutefini y compris pour les types de base Crsquoest le cas de la deacuteclaration suivante

int adi = new int

bull Dans la surdeacutefinition de cet opeacuterateur il nrsquoest plus possible de faire appel agrave lrsquoopeacuterateur new

preacutedeacutefini Toute tentative drsquoappel de new ou mecircme de new fera entrer dans un processus

reacutecursif

Ce dernier point limite lrsquointeacuterecirct de la surdeacutefinition globale de new de delete puisque le pro-

grammeur doit prendre complegravetement agrave sa charge la gestion dynamique de meacutemoire (par

exemple en reacutealisant les appels au systegraveme neacutecessaires)

ExercicesNB Les exercices marqueacutes (C) sont corrigeacutes en fin de volume

1) Dans les deux exemples de programme des paragraphes 11 et 12 mettez en eacutevidence

les appels dun constructeur de recopie Pour ce faire introduisez un constructeur sup-

pleacutementaire de la forme point (pointamp) dans la classe point Voyez ce qui se produit

lorsque vous employez la transmission par reacutefeacuterence pour le ou les arguments de ope-

rator+

2) Dans lexemple du paragraphe 3 introduisez un constructeur de recopie pour la classe

vect Constatez que le remplacement de la transmission par reacutefeacuterence par une trans-

mission par valeur entraicircne la creacuteation de nombreux objets suppleacutementaires

3 (C) Dans une classe point de la forme

class point

int x y

public

point (int abs = 0 int ord = 0)

introduisez un opeacuterateur == tel que si a et b sont deux points a==b fournisse la

valeur 1 lorsque a et b ont les mecircmes coordonneacutees et la valeur 0 dans le cas contraire

On preacutevoira les deux situations

a) fonction membre

b) fonction amie

7 - Surdeacutefinition des opeacuterateurs new et delete179

4 (C) Dans une classe pile_entier de la forme1

class pile_entier int dim nombre maxi deacuteleacutements de la pile int adr adresse du tableau repreacutesentant la pile int nelem nombre deacuteleacutements courant de la pile public pile_entier (int n) ~pile_entier ()

introduisez les opeacuterateurs gt et lt tels que si p est un objet de type pile_entier et n une

variable entiegravere

p lt n ajoute la valeur de n sur la pile p (en ne renvoyant aucune valeur)

p gt n supprime la valeur du haut de la pile et la place dans n

On preacutevoira les deux situations

a) fonctions membres

b) fonctions amies

5 Veacuterifiez si votre impleacutementation accepte qursquoon ne deacutefinisse que la version preacute de

lrsquoopeacuterateur ++ en vous inspirant de lrsquoexemple du paragraphe 24

6 (C) En langage C il nexiste pas de veacuteritable type chaicircne mais simplement une conven-

tion de repreacutesentation des chaicircnes (suite de caractegraveres termineacutee par un caractegravere de

code nul) Un certain nombre de fonctions utilisant cette convention permettent les

manipulations classiques (copie concateacutenation)

Cet exercice vous demande de deacutefinir une classe nommeacutee chaine offrant des possibili-

teacutes plus proches dun veacuteritable type chaicircne (tel que celui du Basic ou du Pascal) Pour

ce faire on preacutevoira comme membres donneacutees

bull la longueur courante de la chaicircne

bull ladresse dune zone alloueacutee dynamiquement destineacutee agrave recevoir la suite de carac-

tegraveres (il ne sera pas neacutecessaire dy ranger le caractegravere nul de fin puisque la longueur

de la chaicircne est deacutefinie par ailleurs)

Le contenu dun objet de type chaine pourra donc eacutevoluer par un simple jeu de gestion

dynamique

On munira la classe chaine des constructeurs suivants

bull chaine() initialise une chaicircne vide

bull chaine (char) initialise la chaicircne avec la chaicircne (au sens du C) dont on fournit

ladresse en argument

bull chaine (chaineamp) constructeur de recopie

1 Revoyez eacuteventuellement lexercice 5 du chapitre 7

On deacutefinira les opeacuterateurs

bull = pour laffectation entre objets de type chaine (penser agrave laffectation multiple)

bull == pour examiner leacutegaliteacute de deux chaicircnes

bull + pour reacutealiser la concateacutenation de deux chaicircnes Si a et b sont de type chaine a + b

sera une (nouvelle) chaicircne formeacutee de la concateacutenation de a et b (les chaicircnes a et b

devront ecirctre inchangeacutees)

bull [] pour acceacuteder agrave un caractegravere de rang donneacute dune chaicircne (les affectations de la for-

me a[i] = x devront pouvoir fonctionner

On pourra ajouter une fonction daffichage On ne preacutevoira pas demployer de comp-

teur par reacutefeacuterence ce qui signifie quon acceptera de dupliquer les chaicircnes identiques

NB On trouvera dans la bibliothegraveque standard preacutevue par la norme une classe string

offrant entre autres les fonctionnaliteacutes eacutevoqueacutees ici Pour conserver son inteacuterecirct agrave

lrsquoexercice il ne faut pas lrsquoutiliser ici

La surdeacutefinition drsquoopeacuterateursCHAPITRE 9

180

10

Les conversions de typedeacutefinies par lrsquoutilisateur

En matiegravere de conversion dun type de base en un autre type de base C++ offre naturellement

les mecircmes possibiliteacutes que le langage C qui rappelons-le fait intervenir des conversions

explicites et des conversions implicites

Les conversions sont explicites lorsque lon fait appel agrave un opeacuterateur de cast comme dans

int n double z

z = double(n) conversion de int en double

ou dans

n = int(z) conversion de double en int

Les conversions implicites ne sont pas mentionneacutees par lutilisateur1 mais elles sont mises

en place par le compilateur en fonction du contexte elles se rencontrent agrave diffeacuterents

niveaux

bull dans les affectations il y a alors conversion forceacutee dans le type de la variable reacuteceptrice

bull dans les appels de fonction comme le prototype est obligatoire en C++ il y a eacutegalement

conversion forceacutee dun argument dans le type deacuteclareacute dans le prototype

1 Cest-agrave-dire en fait lauteur du programme Nous avons toutefois conserveacute le terme reacutepandu dutilisateur qui

soppose ici agrave compilateur

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

182

bull dans les expressions pour chaque opeacuterateur il y a conversion eacuteventuelle de lun des opeacute-

randes dans le type de lautre suivant des regravegles preacutecises1 qui font intervenir

ndash des conversions systeacutematiques char et short en int

ndash des conversions dajustement de type par exemple int en long pour une addition de

deux valeurs de type long

Mais C++ permet aussi de deacutefinir des conversions faisant intervenir des types classe creacuteeacutes

par lutilisateur Par exemple pour un type complexe on pourra en eacutecrivant des fonctions

approprieacutees donner une signification aux conversions

complexe -gt doubledouble -gt complexe

Qui plus est nous verrons que lexistence de telles conversions permettra de donner un sens agrave

laddition dun complexe et dun double ou mecircme celle dun complexe et dun int

Cependant sil paraicirct logique de disposer de conversions entre une classe complexe et les

types numeacuteriques il nen ira plus neacutecessairement de mecircme pour des classes nayant pas une

connotation matheacutematique aussi forte ce qui nempecircchera pas le compilateur de mettre en

place le mecircme genre de conversions

Ce chapitre fait le point sur ces diffeacuterentes possibiliteacutes Consideacutereacutees comme assez dangereu-

ses il est bon de ne les employer qursquoen toute connaissance de cause Pour vous eacuteviter une

conclusion hacirctive nous avons volontairement utiliseacute des exemples de conversions tantocirct

signifiantes (agrave connotation matheacutematique) tantocirct non signifiantes

Au passage nous en profiterons pour insister sur le rocircle important du qualificatif const appli-

queacute agrave un argument muet transmis par reacutefeacuterence

1 Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur

Consideacuterons une classe point posseacutedant un constructeur agrave un argument comme

point (int abs) x = abs y = 0

On peut dire que ce constructeur reacutealise une conversion dun int en un objet de type point

Nous avons dailleurs deacutejagrave vu comment appeler explicitement ce constructeur par exemple

point a a = point(3)

Comme nous le verrons agrave moins de linterdire au moment de la deacutefinition de la classe ce

constructeur peut ecirctre appeleacute implicitement dans des affectations des appels de fonction ou

1 Ces regravegles sont deacutetailleacutees dans La reacutefeacuterence du C norme ANSIISO du mecircme auteur

1 - Les diffeacuterentes sortes de conversions deacutefinies par lrsquoutilisateur183

des calculs dexpression au mecircme titre quune conversion usuelle (on parle aussi de con-

version standard)

Plus geacuteneacuteralement si lon considegravere deux classes nommeacutees point et complexe on peut dire

qursquoun constructeur de la classe complexe agrave un argument de type point

complexe (point)

permet de convertir un point en complexe Nous verrons que cette conversion pourra elle

aussi ecirctre utiliseacutee implicitement dans les diffeacuterentes situations eacutevoqueacutees (agrave moins quon lait

interdit explicitement)

En revanche un constructeur (qui fournit un objet du type de sa classe) ne peut en aucun cas

permettre de reacutealiser une conversion dun objet en une valeur dun type simple (type de base

ou pointeur) par exemple un point en int ou un complexe en double Comme nous le verrons

ce type de conversion pourra ecirctre traiteacute en deacutefinissant au sein de la classe concerneacutee un opeacute-

rateur de cast approprieacute par exemple pour les deux cas citeacutes

operator int()

au sein de la classe point

operator double()

au sein de la classe complexe

Cette derniegravere deacutemarche de deacutefinition dun opeacuterateur de cast pourra aussi ecirctre employeacutee pour

deacutefinir une conversion dun type classe en un autre type classe Par exemple avec

operator complexe()

au sein de la classe point on deacutefinira la conversion dun point en complexe au mecircme titre

quavec le constructeur

complexe (point)

situeacute cette fois dans la classe complexe

Voici un scheacutema reacutecapitulant les diffeacuterentes possibiliteacutes que nous venons deacutevoquer A et B

deacutesignent deux classes b un type de base quelconque

Les quatre sortes de conversions deacutefinies par lrsquoutilisateur

Constructeur agrave un argument

A(b)

Opeacuterateur de cast dans A

operator (b)

Constructeur de D agrave un argument

D(C)

Opeacuterateur de cast dans C

operator D()

b A

C D

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

184

Parmi les diffeacuterentes possibiliteacutes de conversion que nous venons deacutevoquer seul lopeacuterateur

de cast appliqueacute agrave une classe apparaicirct comme nouveau Nous allons donc le preacutesenter mais

aussi expliquer quand et comment les diffeacuterentes conversions implicites sont mises en œuvre

et examiner les cas rejeteacutes par le compilateur

2 Lopeacuterateur de cast pour la conversion type classe ndashgt type de base

21 Deacutefinition de lopeacuterateur de castConsideacuterons une classe point

class point int x y

Supposez que nous souhaitions la munir dun opeacuterateur de cast permettant la conversion de

point en int Nous le noterons simplement

operator int()

Il sagit lagrave du meacutecanisme habituel de surdeacutefinition dopeacuterateur eacutetudieacute au chapitre preacuteceacutedent

lopeacuterateur se nomme ici int il est unaire (un seul argument) et comme il sagit dune fonc-

tion membre aucun argument napparaicirct dans son en-tecircte ou son prototype Reste la valeur de

retour en principe cet opeacuterateur fournit un int de sorte quon aurait pu penser agrave len-tecircte

int operator int()

En fait en C++ un opeacuterateur de cast doit toujours ecirctre deacutefini comme une fonction mem-

bre et le type de la valeur de retour (qui est alors celui deacutefini par le nom de lopeacuterateur) ne

doit pas ecirctre mentionneacute

En deacutefinitive voici comment nous pourrions deacutefinir notre opeacuterateur de cast (ici en ligne) en

supposant que le reacutesultat souhaiteacute pour la conversion en int soit labscisse du point

operator int() return x

Bien entendu pour ecirctre utilisable agrave lrsquoexteacuterieur de la classe cet opeacuterateur devra ecirctre public

22 Exemple dutilisationVoici un premier exemple de programme montrant agrave la fois un appel explicite de lopeacuterateur

int que nous venons de deacutefinir et un appel implicite entraicircneacute par une affectation1 Comme agrave

1 Srsquoil nrsquoeacutetait pas deacuteclareacute public on obtiendrait une erreur de compilation dans les deux appels

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base185

laccoutumeacutee nous avons introduit une instruction daffichage dans lopeacuterateur lui-mecircme

pour obtenir une trace de son appel

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x main() point a(34) b(57) int n1 n2 n1 = int(a) ou n1 = (int) a appel explicite de int () on peut aussi eacutecrire n1 = (int) a ou n1 = static_castltintgt (a) cout ltlt n1 = ltlt n1 ltlt n n2 = b appel implicite de int() cout ltlt n2 = ltlt n2 ltlt n

++ construction point 3 4++ construction point 5 7== appel int() pour le point 3 4n1 = 3== appel int() pour le point 5 7n2 = 5

Exemple dutilisation dun opeacuterateur de cast pour la conversion point -gt int

Nous voyons clairement que laffectation

n2 = b

a eacuteteacute traduite par le compilateur en

bull une conversion du point b en int

bull une affectation (classique) de la valeur obtenue agrave n2

23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonctionDeacutefinissons une fonction fct recevant un argument de type entier que nous appelons

bull une premiegravere fois avec un argument entier (6)

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

186

bull une deuxiegraveme fois avec un argument de type point (a)

En outre nous introduisons (artificiellement) dans la classe point un constructeur de recopie

afin de montrer quici il nest pas appeleacute

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n point (const point amp p) constructeur de recopie cout ltlt appel constructeur de recopie n x = px y = py operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x void fct (int n) fonction cout ltlt appel fct avec argument ltlt n ltlt n

main() void fct (int) point a(34) fct (6) appel normal de fct 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

Appel de lopeacuterateur de cast lors dun appel de fonction

On voit que lappel

fct(a)

a eacuteteacute traduit par le compilateur en

bull une conversion de a en int

bull un appel de fct agrave laquelle on fournit en argument la valeur ainsi obtenue

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base187

Comme on pouvait sy attendre la conversion est bien reacutealiseacutee avant lappel de la fonction et

il ny a pas de creacuteation par recopie dun objet de type point

24 Appel implicite de lopeacuterateur de cast dans leacutevaluation dune expression

Les reacutesultats de ce programme illustrent la maniegravere dont sont eacutevalueacutees des expressions telles

que a + 3 ou a + b lorsque a et b sont de type point

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x main() point a(34) b(57) int n1 n2 n1 = a + 3 cout ltlt n1 = ltlt n1 ltlt n n2 = a + b cout ltlt n2 = ltlt n2 ltlt n

double z1 z2 z1 = a + 3 cout ltlt z1 = ltlt z1 ltlt n z2 = a + b cout ltlt z2 = ltlt z2 ltlt n

++ construction point 3 4++ construction point 5 7== appel int() pour le point 3 4n1 = 6== appel int() pour le point 3 4== appel int() pour le point 5 7n2 = 8== appel int() pour le point 3 4z1 = 6== appel int() pour le point 3 4== appel int() pour le point 5 7z2 = 8

Utilisation de lopeacuterateur de cast dans leacutevaluation dune expression

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

188

Lorsquil rencontre une expression comme a + 3 avec un opeacuterateur portant sur un eacuteleacutement de

type point et un entier le compilateur recherche tout dabord sil existe un opeacuterateur + surdeacute-

fini correspondant agrave ces types dopeacuterandes Ici il nen trouve pas Il cherche alors agrave mettre en

place des conversions des opeacuterandes permettant daboutir agrave une opeacuteration existante Dans

notre cas il preacutevoit la conversion de a en int de maniegravere agrave se ramener agrave la somme de deux

entiers suivant le scheacutema

point int | | int | |___ + ___| | int

Certes une telle deacutemarche peut choquer Quelques remarques srsquoimposent

bull Ici aucune autre conversion nest envisageable Il nen irait pas de mecircme sil existait un opeacute-

rateur (surdeacutefini) daddition de deux points

bull La deacutemarche paraicirct moins choquante si lon ne cherche pas agrave donner une veacuteritable significa-

tion agrave lopeacuteration a + 3

bull Nous cherchons agrave preacutesenter les diffeacuterentes situations que lon risque de rencontrer non pas

pour vous encourager agrave les employer toutes mais plutocirct pour vous mettre en garde

Quant agrave leacutevaluation de a + b elle se fait suivant le scheacutema suivant

point point | | int int |___ + ___| | int

Pour chacune des deux expressions nous avons preacutevu deux sortes drsquoaffectation

bull agrave une variable entiegravere

bull agrave une variable de type double dans ce cas il y a conversion forceacutee du reacutesultat de lexpres-

sion en double

Notez bien que le type de la variable reacuteceptrice nagit aucunement sur la maniegravere dont

lexpression est eacutevalueacutee pas plus que sur son type final

25 Conversions en chaicircneConsideacuterez cet exemple

include ltiostreamgtusing namespace std

2 - Lopeacuterateur de cast pour la conversion type classe ndashgt type de base189

class point int x y public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n operator int() cast point --gt int cout ltlt == appel int() pour le point ltlt x ltlt ltlt y ltlt n return x void fct (double v) cout ltlt appel fct avec argument ltlt v ltlt n

main() point a(34) int n1 double z1 z2 n1 = a + 385 cout ltlt n1 = ltlt n1 ltlt n z1 = a + 385 cout ltlt z1 = ltlt z1 ltlt n z2 = a cout ltlt z2 = ltlt z2 ltlt n fct (a)

++ construction point 3 4== appel int() pour le point 3 4n1 = 6== appel int() pour le point 3 4z1 = 685== appel int() pour le point 3 4z2 = 3== appel int() pour le point 3 4 appel fct avec argument 3

Conversions en chaicircne

Cette fois nous avons agrave eacutevaluer agrave deux reprises la valeur de lexpression

a + 385

La diffeacuterence avec les situations preacuteceacutedentes est que la constante 385 est de type double et

non plus de type int Par analogie avec ce qui preacutecegravede on pourrait supposer que le compila-

teur preacutevoie la conversion de 385 en int Or il sagirait dune conversion dun type de base

double en un autre type de base int qui risquerait drsquoecirctre deacutegradante et qui comme dhabi-

tude nest jamais mise en œuvre de maniegravere implicite dans un calcul dexpression1

1 Elle pourrait lecirctre dans une affectation ou un appel de fonction en tant que conversion forceacutee

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

190

En fait leacutevaluation se fera suivant le scheacutema

point double | | int | | | double | |___ + ___| | double

La valeur afficheacutee pour z1 confirme le type double de lexpression

La valeur de ai a donc eacuteteacute soumise agrave deux conversions successives avant drsquoecirctre transmise agrave

un opeacuterateur Ceci est indeacutependant de lusage qui doit ecirctre fait ulteacuterieurement de la valeur de

lexpression agrave savoir

bull conversion en int pour affectation agrave n1 dans le premier cas

bull affectation agrave z2 dans le second cas

Quant agrave laffectation z2 = a elle entraicircne une double conversion de point en int puis de int en

double

Il en va de mecircme pour lappel

fct (a)

Dune maniegravere geacuteneacuterale

Remarque

Nous avons deacutejagrave rencontreacute ce meacutecanisme dans le cas des fonctions surdeacutefinies Ici il

sagit dun meacutecanisme comparable appliqueacute agrave un opeacuterateur preacutedeacutefini et non plus agrave une

fonction deacutefinie par lutilisateur Nous retrouverons des situations semblables par la

suite relatives cette fois agrave un opeacuterateur deacutefini par lutilisateur (donc agrave une fonction)

les regravegles appliqueacutees seront alors bien celles que nous avons eacutevoqueacutees dans la recher-

che de la bonne fonction surdeacutefinie

26 En cas dambiguiumlteacuteA partir du moment ougrave le compilateur accepte de mettre en place une chaicircne de conversions

certaines ambiguiumlteacutes peuvent apparaicirctre Reprenons lexemple de la classe point en suppo-

sant cette fois que nous lavons munie de deux opeacuterateurs de cast

En cas de besoin C++ peut ainsi mettre en œuvre une chaicircne de conver-sions agrave condition toutefois que celle-ci ne fasse intervenir qursquoune seule CDU (Conversion Deacutefinie par lrsquoUtilisateur) Plus preacuteciseacutement cette chaicircne peut ecirctre formeacutee drsquoau maximum trois conversions agrave savoir une conversion standard suivie drsquoune CDU suivie drsquoune conversion standard

3 - Le constructeur pour la conversion type de base -gt type classe191

operator int()operator double()

Supposons que nous utilisions de nouveau une expression telle que (a eacutetant de type point)

a + 385

Dans ce cas le compilateur se trouve en preacutesence de deux scheacutemas possibles de conversion

point double point double | | | | double | int | |____+____| | | | double | double |___ + ___| | double

Ici il refuse lexpression en fournissant un diagnostic dambiguiumlteacute

Cette ambiguiumlteacute reacuteside dans le fait que deux chaicircnes de conversions permettent de passer du

type point au type double Sil sagissait dune ambiguiumlteacute concernant le choix de lopeacuterateur agrave

appliquer (ce qui neacutetait pas le cas ici) le compilateur appliquerait alors les regravegles habituelles

de choix dune fonction surdeacutefinie1

3 Le constructeur pour la conversion type de base -gt type classe

31 ExempleNous avons deacutejagrave vu comment appeler explicitement un constructeur Par exemple avec la

classe point preacuteceacutedente si a est de type point nous pouvons eacutecrire

a = point (12)

Cette instruction provoque

bull la creacuteation dun objet temporaire de type point

bull lrsquoaffectation de cet objet agrave a

On peut donc dire que lexpression

point (12)

exprime la conversion de lentier 12 en un point

Dune maniegravere geacuteneacuterale tout constructeur agrave un seul argument dun type de base2 reacutealise une

conversion de ce type de base dans le type de sa classe

1 En toute rigueur il faudrait consideacuterer que les opeacuterateurs sur les types de base correspondent eux aussi agrave des

fonctions de la forme operator +

2 Ou eacuteventuellement comme cest le cas ici agrave plusieurs arguments ayant des valeurs par deacutefaut agrave partir du moment

ougrave il peut ecirctre appeleacute avec un seul argument

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

192

Or tout comme lopeacuterateur de cast ce constructeur peut eacutegalement ecirctre appeleacute implicitement

Ainsi laffectation

a = 12

provoque exactement le mecircme reacutesultat que

a = point (12)

A sa rencontre en effet le compilateur cherche sil existe une conversion (voire une chaicircne de con-

versions) unique permettant de passer du type int au type point Ici le constructeur fait laffaire

De la mecircme faccedilon si fct a pour prototype

void fct (point)

un appel tel que

fct (4)

entraicircne une conversion de lentier 4 en un point temporaire qui est alors transmis agrave fct

Voici un petit programme illustrant ces premiegraveres possibiliteacutes de conversion par un constructeur

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments

x = abs y = ord

cout ltlt ++ construction point ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

point (const point amp p) constructeur de recopie

x = px y = py

cout ltlt constr recopie de ltlt ampp ltlt en ltlt this ltlt n

void fct (point p) fonction simple

cout ltlt appel fct ltlt n

main()

void fct (point)

point a(34)

a = point (12) appel explicite constructeur

a = 12 appel implicite

fct(4)

++ construction point 3 4 en 006AFDF0

++ construction point 12 0 en 006AFDE8

++ construction point 12 0 en 006AFDE0

3 - Le constructeur pour la conversion type de base -gt type classe193

++ construction point 4 0 en 006AFD88

appel fct

Utilisation dun constructeur pour reacutealiser des conversions int ndashgt point

Remarques

1 Bien entendu si fct est surdeacutefinie le choix de la bonne fonction se fera suivant les regravegles

deacutejagrave rencontreacutees au chapitre 4 Cette fonction devra ecirctre unique de mecircme que les chaicircnes

de conversions mises en œuvre pour chaque argument

2 Si nous avions deacuteclareacute fct sous la forme void fct (point amp) lrsquoappel fct(4) serait rejeteacute

En revanche avec la deacuteclaration void fct (const point amp) ce mecircme appel serait

accepteacute il conduirait agrave la creacuteation drsquoun point temporaire obtenu par conversion de 4 en

point et agrave la transmission de sa reacutefeacuterence agrave la fonction fct Lrsquoexeacutecution se preacutesenterait

exactement comme ci-dessus

32 Le constructeur dans une chaicircne de conversionsSupposons que nous disposions dune classe complexe

class complexe

double reel imag

public

complexe (double r = 0 double i = 0)

Son constructeur permet des conversions double -gt complexe Mais compte tenu des possibi-

liteacutes de conversion implicite int -gt double ce constructeur peut intervenir dans une chaicircne de

conversions

int -gt double -gt complexe

Ce sera le cas dans une affectation telle que (c eacutetant de type complexe)

c = 3

Cette possibiliteacute de chaicircne de conversions rejoint ici les regravegles concernant les conversions

habituelles agrave propos des fonctions (surdeacutefinies ou non) En effet on peut consideacuterer ici que

lentier 3 est converti en double compte tenu du prototype de complexe Cette double inter-

preacutetation dune mecircme possibiliteacute nest pas gecircnante dans la mesure ougrave elle conduit dans les

deux cas agrave la mecircme conclusion concernant la faisabiliteacute de la conversion

33 Choix entre constructeur ou opeacuterateur daffectationDans lexemple daffectation

a = 12

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

194

du paragraphe 31 il nexistait pas dopeacuterateur drsquoaffectation dun int agrave un point Si tel est le

cas on peut penser que le compilateur doit alors choisir entre

bull utiliser la conversion int -gt point offerte par le constructeur suivie drsquoune affectation point -

gt point

bull sup2utiliser lopeacuterateur daffectation int -gt point

En fait une regravegle permet de trancher

Cest donc la seconde solution qui sera choisie ici par le compilateur comme le montre le

programme suivant Nous avons surdeacutefini lopeacuterateur drsquoaffectation non seulement dans le cas

intndashgt point mais aussi dans le cas point -gt point afin de bien montrer que cette derniegravere ver-

sion nest pas employeacutee dans laffectation a = 12

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments

x = abs y = ord

cout ltlt ++ construction point ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

point amp operator = (const point amp p) surdeacutef affectation point -gt point

x = px y = py

cout ltlt == affectation point --gt point de ltlt ampp ltlt en ltlt this

return this

point amp operator = (const int n) surdeacutef affectation int -gt point

x = n y = 0

cout ltlt == affectation int --gt point de ltlt x ltlt ltlt y

ltlt en ltlt this ltlt n

return this

main()

point a(34)

a = 12

++ construction point 3 4 en 006AFDF0

== affectation int --gt point de 12 0 en 006AFDF0

Les conversions deacutefinies par lutilisateur ne sont mises en œuvre que si neacutecessaire

Les conversions deacutefinies par lrsquoutilisateur (cast ou constructeur) ne sont mises en œuvre que lorsque cela est neacutecessaire

3 - Le constructeur pour la conversion type de base -gt type classe195

34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur

Consideacuterons une classe point munie dun constructeur agrave un argument entier et dun opeacuterateur

daddition fourni sous la forme dune fonction amie (nous verrons un peu plus loin ce qui se

passerait dans le cas dune fonction membre)

class point int x y public point (int) friend point operator + (point point)

Dans ces conditions si a est de type point une expression telle que

a + 3

a une signification En effet dans ce cas le compilateur met en œuvre

bull une conversion de lentier 3 en point (par appel du constructeur)

bull laddition de la valeur obtenue avec celle de a (par appel de operator +)

Le reacutesultat sera du type point Le scheacutema suivant reacutecapitule la situation

point int | | | point |___ + ___| | point

On peut dire eacutegalement que notre expression a + 3 est eacutequivalente agrave

operator + (a point (3))

Le mecircme meacutecanisme sapplique agrave une expression telle que

5 + a

qui sera donc eacutequivalente agrave

operator + (5 a)

Toutefois dans ce dernier cas il nen serait pas alleacute de mecircme si notre opeacuterateur + avait eacuteteacute

deacutefini par une fonction membre En effet son premier opeacuterande aurait alors ducirc ecirctre de type

point aucune conversion implicite naurait pu ecirctre mise en place1

Voici un petit programme illustrant les possibiliteacutes que nous venons deacutevoquer

include ltiostreamgtusing namespace std class point int x y

1 Des appels tels que 5operator + (a) ou noperator + (a) (n eacutetant de type int) seront rejeteacutes

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

196

public point (int abs=0 int ord=0) constructeur 0 1 ou 2 arguments x = abs y = ord cout ltlt ++ construction point ltlt x ltlt ltlt y ltlt n friend point operator + (point point) point + point --gt point void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n point operator+ (point a point b) point r rx = ax + bx ry = ay + by return r

main() point a b(94) a = b + 5 aaffiche() a = 2 + b baffiche()

++ construction point 0 0++ construction point 9 4++ construction point 5 0++ construction point 0 0Coordonneacutees 14 4++ construction point 2 0++ construction point 0 0Coordonneacutees 9 4

Elargissement de la signification de lopeacuterateur +

Remarques

1 On peut envisager de transmettre par reacutefeacuterence les arguments de operator Dans ce cas il

est neacutecessaire de preacutevoir le qualificatif const pour autoriser la conversion de 5 en un point

temporaire dans lrsquoaffectation a = b + 5 ou de 2 en un point temporaire dans a = 2 + b

2 Lrsquoutilisation du constructeur dans une chaicircne de conversions peut rendre de grands ser-

vices dans une situation reacuteelle puisquelle permet de donner un sens agrave des expressions

mixtes Lexemple le plus caracteacuteristique est celui dune classe de nombres complexes

(supposeacutes constitueacutes ici de deux valeurs de type double) Il suffit en effet de deacutefinir la

somme de deux complexes et un constructeur agrave un argument de type double

3 - Le constructeur pour la conversion type de base -gt type classe197

class complexe double reel imag public complexe (double v) reel = v imag = 0 friend complexe operator + (complexe complexe)

Les expressions de la forme

ndash complexe + double

ndash double + complexe

auront alors une signification (et ici ce sera bien celle que lon souhaite)

Compte tenu des possibiliteacutes de conversions il en ira de mecircme de nimporte quelle

addition dun complexe et dun float dun long dun short ou dun char

Ici encore ces conversions ne seront plus possibles si les opeacuterandes sont transmis par

reacutefeacuterence Elles le redeviendront avec des reacutefeacuterences agrave des constantes

3 Si nous avions deacutefini

class complexe float reel imag public complexe (float v) friend complexe operator + (complexe complexe)

laddition dun complexe et dun double ne serait pas possible Elle le deviendrait en

remplaccedilant le constructeur par

complexe (double v)

(ce qui ne signifie pas pour autant que le reacutesultat de la conversion forceacutee de double en

float qui y figurera sera acceptable )

35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit

La norme ANSI de C++ preacutevoit quon puisse interdire lutilisation du constructeur dans des

conversions implicites (simples ou en chaicircne) en utilisant le mot cleacute explicit lors de sa deacutecla-

ration Par exemple avec

class point public explicit point (int) friend operator + (point point)

les instructions suivantes seraient rejeteacutees (a et b eacutetant de type point)

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

198

a = 12 illeacutegal car le constructeur possegravede le qualificatif explicita = b + 5 idem

En revanche la conversion pourrait toujours se faire par un appel explicite comme dans

a = point (3) OK conversion explicite par le constructeura = b + point (5) idem

4 Les conversions drsquoun type classe en un autre type classe

Les possibiliteacutes de conversions dun type de base en un type classe que nous venons drsquoeacutetudier

se geacuteneacuteralisent ainsi

bull Au sein dune classe A on peut deacutefinir un opeacuterateur de cast reacutealisant la conversion dans le

type A dun autre type de classe B

bull Un constructeur de la classe A recevant un argument de type B reacutealise une conversion de B

en A

41 Exemple simple dopeacuterateur de castLe programme suivant illustre la premiegravere situation lopeacuterateur complexe de la classe point

permet des conversions dun objet de type point en un objet de type complexe

include ltiostreamgtusing namespace std class complexe

class point int x y public point (int abs=0 int ord=0) x=abs y=ord operator complexe () conversion point --gt complexe

class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i friend pointoperator complexe () void affiche () cout ltlt reel ltlt + ltlt imag ltltin pointoperator complexe () complexe r rreel=x rimag=y cout ltlt cast ltltxltlt ltltyltlt en ltltrreelltlt + ltltrimagltltin return r

4 - Les conversions drsquoun type classe en un autre type classe199

main() point a(25) complexe c c = (complexe) a caffiche () conversion explicite point b (912) c = b caffiche () conversion implicite

cast 2 5 en 2 + 5i2 + 5icast 9 12 en 9 + 12i9 + 12i

Exemple dutilisation dun opeacuterateur de cast pour des conversions point -gt complexe

Remarque

La conversion point ndashgt complexe eacutequivalente ici agrave la conversion de deux entiers en reacuteel

est assez naturelle et de toute faccedilon non deacutegradante Mais bien entendu C++ vous laisse

seul juge de la qualiteacute des conversions que vous pouvez deacutefinir de cette maniegravere

42 Exemple de conversion par un constructeurLe programme suivant illustre la seconde situation le constructeur complexe (point) repreacute-

sente une autre faccedilon de reacutealiser des conversions dun objet de type point en un objet de type

complexe

include ltiostreamgtusing namespace std class point class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i complexe (point) void affiche () cout ltlt reel ltlt + ltlt imag ltlt in class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend complexecomplexe (point) complexecomplexe (point p) reel = px imag = py

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

200

main()

point a(35)

complexe c (a) caffiche ()

3 + 5i

Exemple dutilisation dun constructeur pour des conversions point ndashgt complexe

Remarques

1 La remarque faite preacuteceacutedemment agrave propos de la qualiteacute des conversions sapplique tout

aussi bien ici Par exemple nous aurions pu introduire dans la classe point un construc-

teur de la forme point (complexe)

2 En ce qui concerne les conversions dun type de base en une classe la seule possibiliteacute

qui nous eacutetait offerte consistait agrave preacutevoir un constructeur approprieacute au sein de la classe

En revanche pour les conversions A ndashgt B (ougrave A et B sont deux classes) nous avons le

choix entre placer dans B un constructeur B(A) ou placer dans A un opeacuterateur de cast

B()

3 Il nest pas possible de deacutefinir simultaneacutement la mecircme conversion A ndashgt B en preacutevoyant

agrave la fois un constructeur B(A) dans B et un cast B() dans A En effet cela conduirait le

compilateur agrave deacuteceler une ambiguiumlteacute degraves quune conversion de A en B serait neacutecessaire

Il faut signaler cependant quune telle anomalie peut rester cacheacutee tant que le besoin

dune telle conversion ne se fait pas sentir (en particulier les classes A et B seront com-

pileacutees sans problegraveme y compris si elles figurent dans le mecircme fichier source)

43 Pour donner une signification agrave un opeacuterateur deacutefini dans une autre classe

Consideacuterons une classe complexe pour laquelle lopeacuterateur + a eacuteteacute surdeacutefini par une fonction

amie1 ainsi quune classe point munie dun opeacuterateur de cast complexe() Supposons a de

type point x de type complexe et consideacuterons lexpression

x + a

Compte tenu des regravegles habituelles relatives aux fonctions surdeacutefinies (mise en œuvre dune

chaicircne unique de conversions ne contenant pas plus dune CDU) le compilateur est conduit

agrave eacutevaluer cette expression suivant le scheacutema

1 Nous verrons que ce point est important on nobtiendrait pas les mecircmes possibiliteacutes avec une fonction membre

4 - Les conversions drsquoun type classe en un autre type classe201

complexe point | | | complexe |___ + ___| | complexe

Celui-ci fait intervenir lopeacuterateur + surdeacutefini par la fonction indeacutependante operator+ On

peut dire que lrsquoexpression x + a est en fait eacutequivalente agrave

operator + (x a)

Le mecircme raisonnement sapplique agrave lexpression a + x Quant agrave lexpression

a + b

ougrave a et b sont de type point elle est eacutequivalente agrave

operator + (a b)

et eacutevalueacutee suivant le scheacutema

point point | | complexe complexe |____ + ____| | complexe

Voici un exemple complet de programme illustrant ces possibiliteacutes

include ltiostreamgtusing namespace std class complexe class point int x y public point (int abs=0 int ord=0) x=abs y=ord operator complexe () void affiche () cout ltlt point ltlt x ltlt ltlt y ltlt n class complexe double reel imag public complexe (double r=0 double i=0) reel=r imag=i void affiche () cout ltlt reel ltlt + ltlt imag ltlt i n friend pointoperator complexe () friend complexe operator + (complexe complexe) pointoperator complexe () complexe r rreel = x rimag = y return r complexe operator + (complexe a complexe b) complexe r rreel = areel + breel rimag = aimag + bimag return r

Les conversions de type deacutefinies par lrsquoutilisateurCHAPITRE 10

202

main() point a(34) b(79) c complexe x(3528) y y = x + a yaffiche () marcherait encore si + eacutetait fct membre y = a + x yaffiche () ne marcherait pas si + eacutetait fonction membre y = a + b yaffiche () ne marcherait pas si + eacutetait fonction membre (voir remarque) NB c = a + b naurait pas de sens ici

65 + 68i 65 + 68i 10 + 13i

Elargissement de la signification de lopeacuterateur + de la classe complexe

Remarques

1 Sil est effectivement possible ici deacutecrire

y = a + b

il nest pas possible deacutecrire

c = a + b

car il nexiste pas de conversion de complexe (type de lexpression a + b) en point

Pour que cela soit possible il suffirait par exemple dintroduire dans la classe point un

constructeur de la forme point (complexe) Bien entendu cela ne preacutejuge nullement de

la signification dune telle opeacuteration et en particulier de son aspect deacutegradant

2 Si lopeacuterateur + de la classe complexe avait eacuteteacute deacutefini par une fonction membre de

prototype

complexe complexeoperator + (complexe)

lexpression a + x naurait pas eu de sens pas plus que a + b En effet dans le premier

cas lappel de operator + naurait pu ecirctre que

aoperator + (x)

Cela naurait pas eacuteteacute permis En revanche lexpression x + a aurait pu correctement ecirctre

eacutevalueacutee comme

xoperator + (a)

3 Il nest pas toujours aussi avantageux que dans cet exemple de deacutefinir un opeacuterateur sous

la forme dune fonction amie En particulier si un opeacuterateur modifie son premier opeacute-

rande (supposeacute ecirctre un objet) il est preacutefeacuterable den faire une fonction membre Dans le

cas contraire en effet on risque de voir cet opeacuterateur agir non pas sur lobjet concerneacute

mais sur un objet (ou une variable) temporaire dun autre type creacuteeacute par une conversion

5 - Quelques conseils203

implicite1 Crsquoest dailleurs pour cette raison que C++ impose que les opeacuterateurs = [] ()

et -gt soient toujours surdeacutefinis par des fonctions membres

4 On peut envisager de transmettre les arguments de operator+ par reacutefeacuterence Dans ce

cas si lrsquoon nrsquoa pas preacutevu le qualificatif const dans leur deacuteclaration dans lrsquoen-tecircte les

trois expressions x+a a+x et a+b conduisent agrave une erreur de compilation

5 Quelques conseilsLes possibiliteacutes de conversions implicites ne sont certes pas infinies puisquelles sont limi-

teacutees agrave une chaicircne dau maximum trois conversions (standard CDU standard) et que la

CDU nest mise en œuvre que si elle est utile

Elles nen restent pas moins tregraves (trop ) riches Une telle richesse peut laisser craindre que

certaines conversions soient mises en place sans que le concepteur des classes concerneacutees ne

lait souhaiteacute

En fait il faut bien voir que

bull lopeacuterateur de cast doit ecirctre introduit deacutelibeacutereacutement par le concepteur de la classe

bull le concepteur dune classe peut interdire lusage implicite du constructeur dans une conver-

sion en faisant appel au mot cleacute explicit

Il est donc possible de se proteacuteger totalement contre lusage des conversions implicites relati-

ves aux classes il suffira de qualifier tous les constructeurs avec explicit et de ne pas intro-

duire dopeacuterateur de cast

Dune maniegravere geacuteneacuterale on aura inteacuterecirct agrave reacuteserver ces possibiliteacutes de conversions implicites agrave

des classes ayant une forte connotation matheacutematique dans lesquelles on aura probable-

ment surdeacutefini un certain nombre dopeacuterateurs (+ - etc)

Lexemple le plus classique est certainement celui de la classe complexe (que nous avons ren-

contreacutee dans ce chapitre) Dans ce cas il paraicirct naturel de disposer de conversions de com-

plexe en float de float en complexe de int en complexe (par le biais de float) etc

De mecircme il paraicirct naturel de pouvoir reacutealiser aussi bien la somme dun complexe et dun float

que celle de deux complexes et donc de profiter des possibiliteacutes de conversions implicites

pour ne deacutefinir quun seul opeacuterateur daddition (celle de deux complexes)

1 Aucune conversion implicite ne peut avoir lieu sur lobjet appelant une fonction membre

11

Les patrons de fonctions

Nous avons deacutejagrave vu que la surdeacutefinition de fonctions permettait de donner un nom unique agrave

plusieurs fonctions reacutealisant un travail diffeacuterent La notion de patron de fonction (on parle

aussi de fonction geacuteneacuterique ou de modegravele de fonction) introduite par la version 3 est agrave la

fois plus puissante et plus restrictive plus puissante car il suffit deacutecrire une seule fois la

deacutefinition dune fonction pour que le compilateur puisse automatiquement ladapter agrave

nimporte quel type plus restrictive puisque toutes les fonctions ainsi fabriqueacutees par le com-

pilateur doivent correspondre agrave la mecircme deacutefinition donc au mecircme algorithme

Nous commencerons par vous preacutesenter cette nouvelle notion agrave partir drsquoun exemple simple

ne faisant intervenir quun seul paramegravetre de type Nous verrons ensuite quelle se geacuteneacutera-

lise agrave un nombre quelconque de paramegravetres et quon peut eacutegalement faire intervenir des

paramegravetres expressions Puis nous montrerons comment un patron de fonctions peut agrave son

tour ecirctre surdeacutefini Enfin nous verrons que toutes ces possibiliteacutes peuvent encore ecirctre affi-

neacutees en speacutecialisant une ou plusieurs des fonctions dun patron

NB On rencontre souvent le terme anglais template au lieu de celui de patron On parle alors

de fonctions template ou de classes template mais dans ce cas il est difficile de distin-

guer comme nous serons ameneacutes agrave le faire un patron de fonctions drsquoune fonction patron ou

un patron de classes drsquoune classe patron

Les patrons de fonctionsCHAPITRE 11

206

1 Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions

11 Creacuteation dun patron de fonctionsSupposons que nous ayons besoin deacutecrire une fonction fournissant le minimum de deux valeurs

de mecircme type reccedilues en arguments Nous pourrions eacutecrire une deacutefinition pour le type int

int min (int a int b) if (a lt b) return a ou return a lt b a b else return b

Bien entendu il nous faudrait probablement eacutecrire une autre deacutefinition pour le type float

cest-agrave-dire (en supposant que nous lui donnions le mecircme nom min ce que nous avons tout

inteacuterecirct agrave faire)

float min (float a float b) if (a lt b) return a ou return a lt b a b else return b

Nous aurions ainsi agrave eacutecrire de nombreuses deacutefinitions tregraves proches les unes des autres En

effet seul le type concerneacute serait ameneacute agrave ecirctre modifieacute

En fait nous pouvons simplifier consideacuterablement les choses en deacutefinissant un seul patron

de fonctions de la maniegravere suivante

creacuteation dun patron de fonctionstemplate ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

Creacuteation dun patron de fonctions

Comme vous le constatez seul len-tecircte de notre fonction a changeacute (il nen ira pas toujours

ainsi)

template ltclass Tgt T min (T a T b)

La mention template ltclass Tgt preacutecise que lon a affaire agrave un patron (template) dans lequel

apparaicirct un paramegravetre1 de type nommeacute T Notez que C++ a deacutecideacute demployer le mot cleacute

1 Ou argument ici nous avons convenu demployer le terme paramegravetre pour les patrons et le terme argument pour

les fonctions mais il ne sagit aucunement dune convention universelle

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions207

class pour preacuteciser que T est un paramegravetre de type (on aurait preacutefeacutereacute le mot cleacute type ) Autre-

ment dit dans la deacutefinition de notre fonction T repreacutesente un type quelconque

Le reste de len-tecircte

T min (T a T b)

preacutecise que min est une fonction recevant deux arguments de type T et fournissant un reacutesultat

du mecircme type

Remarque

Dans la deacutefinition drsquoun patron on utilise le mot cleacute class pour indiquer en fait un type

quelconque classe ou non La norme a introduit le mot cleacute typename qui peut se subtituer

agrave class dans la deacutefinition

template lttypename Tgt T min (T a T b) idem template ltclass Tgt

Cependant son arriveacutee tardive fait que la plupart des programmes continuent drsquoutiliser

le mot cleacute class dans ce cas

12 Premiegraveres utilisations du patron de fonctionsPour utiliser le patron min que nous venons de creacuteer il suffit dutiliser la fonction min dans

des conditions approprieacutees (cest-agrave-dire ici deux arguments de mecircme type) Ainsi si dans un

programme dans lequel n et p sont de type int nous faisons intervenir lexpression min (n p)

le compilateur fabriquera (on dit aussi instanciera) automatiquement la fonction min (dite

fonction patron1) correspondant agrave des arguments de type int Si nous appelons min avec

deux arguments de type float le compilateur fabriquera automatiquement une autre fonc-

tion patron min correspondant agrave des arguments de type float et ainsi de suite

Comme on peut sy attendre il est neacutecessaire que le compilateur dispose de la deacutefinition du

patron en question autrement dit que les instructions preacuteceacutedentes apparaissent avant une

quelconque utilisation de min Voici un exemple complet illustrant cela

include ltiostreamgtusing namespace std creacuteation dun patron de fonctionstemplate ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

1 Attention au vocabulaire patron de fonction pour la fonction geacuteneacuterique fonction patron pour une instance

donneacutee

Les patrons de fonctionsCHAPITRE 11

208

exemple dutilisation du patron de fonctions minmain() int n=4 p=12 float x=25 y=325 cout ltlt min (n p) = ltlt min (n p) ltlt n int min(int int) cout ltlt min (x y) = ltlt min (x y) ltlt n float min (float float)

min (n p) = 4min (x y) = 25

Deacutefinition et utilisation dun patron de fonctions

13 Autres utilisations du patron de fonctionsLe patron min peut ecirctre utiliseacute pour des arguments de nimporte quel type quil sagisse dun

type preacutedeacutefini (short char double int char int etc) ou dun type deacutefini par lutilisa-

teur (notamment structure ou classe)

Par exemple si n et p sont de type int un appel tel que min (ampn ampp) conduit le compilateur

agrave instancier une fonction int min (int int )

Examinons plus en deacutetail deux situations preacutecises

bull arguments de type char

bull arguments de type classe

131 Application au type char Voici un premier exemple dans lequel nous exploitons le patron min pour fabriquer une fonc-

tion portant sur des chaicircnes de caractegraveres

include ltiostreamgtusing namespace std template ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b main() char adr1 = monsieur adr2 = bonjour cout ltlt min (adr1 adr2) = ltlt min (adr1 adr2)

min (adr1 adr2) = monsieur

Application du patron min au type char

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de fonctions209

Le reacutesultat peut surprendre si vous vous attendiez agrave ce que min fournisse la chaicircne bon-

jour En fait agrave la rencontre de lexpression min (adr1 adr2) le compilateur a geacuteneacutereacute la fonc-

tion suivante

char min (char a char b)

if (a lt b) return a

else return b

La comparaison altb porte donc sur les valeurs des pointeurs reccedilus en argument (ici a eacutetait

infeacuterieur agrave b mais il peut en aller autrement dans dautres impleacutementations) En revanche

laffichage obtenu par lopeacuterateur ltlt porte non plus sur ces adresses mais sur les chaicircnes

situeacutees agrave ces adresses

132 Application agrave un type classe

Pour pouvoir appliquer le patron min agrave une classe il est bien sucircr neacutecessaire que lopeacuterateur lt

puisse sappliquer agrave deux opeacuterandes de ce type classe Voici un exemple dans lequel nous

appliquons min agrave deux objets de type vect classe munie drsquoun opeacuterateur lt fournissant un

reacutesultat baseacute sur le module des vecteurs

include ltiostreamgt

using namespace std

le patron de fonctions mintemplate ltclass Tgt T min (T a T b)

if (a lt 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 ltlt x ltlt ltlt y friend int operator lt (vect vect)

int operator lt (vect a vect b) return axax + ayay lt bxbx + byby

un exemple dutilisation de minmain()

vect u (3 2) v (4 1) w w = min (u v)

cout ltlt min (u v) = waffiche()

Les patrons de fonctionsCHAPITRE 11

210

min (u v) = 3 2

Utilisation du patron min pour la classe vect

Naturellement si nous cherchons agrave appliquer notre patron min agrave une classe pour laquelle

lopeacuterateur lt nest pas deacutefini le compilateur le signalera exactement de la mecircme maniegravere que

si nous avions eacutecrit nous-mecircme la fonction min pour ce type

Remarque

Un patron de fonctions pourra sappliquer agrave des classes patrons cest-agrave-dire agrave un type de

classe instancieacute par un patron de classe Nous en verrons des exemples dans le prochain

chapitre

14 Contraintes drsquoutilisation drsquoun patronLes instructions de deacutefinition dun patron ressemblent agrave des instructions exeacutecutables de deacutefi-

nition de fonction Neacuteanmoins le meacutecanisme mecircme des patrons fait que ces instructions sont

utiliseacutees par le compilateur pour fabriquer (instancier) chaque fois quil est neacutecessaire les ins-

tructions correspondant agrave la fonction requise en ce sens ce sont donc des deacuteclarations leur

preacutesence est toujours neacutecessaire et il nest pas possible de creacuteer un module objet correspon-

dant agrave un patron de fonctions

Tout se passe en fait comme si avec la notion de patron de fonctions apparaissaient deux

niveaux de deacuteclarations On retrouvera le mecircme pheacutenomegravene pour les patrons de classes Par

la suite nous continuerons agrave parler de deacutefinition dun patron

En pratique on placera les deacutefinitions de patron dans un fichier approprieacute dextension h

Remarque

Les consideacuterations preacuteceacutedentes doivent en fait ecirctre pondeacutereacutees par le fait que la norme a

introduit le mot cleacute export Appliqueacute agrave la deacutefinition drsquoun patron il preacutecise que celle-ci

sera accessible depuis un autre fichier source Par exemple en eacutecrivant ainsi notre patron

de fonctions min du paragraphe 11

export template ltclass Tgt T min (T a T b) if (a lt b) return a ou return a lt b a b else return b

on peut alors utiliser ce patron depuis un autre fichier source en se contentant de men-

tionner sa deacuteclaration (cette fois il srsquoagit bien drsquoune veacuteritable deacuteclaration et non plus

drsquoune deacutefinition)

2 - Les paramegravetres de type drsquoun patron de fonctions211

template ltclass Tgt T min (T a T b) deacuteclaration seule de min

min (x y)

En pratique on aura alors inteacuterecirct agrave preacutevoir deux fichiers en-tecirctes distincts un pour la

deacuteclaration un pour la deacutefinition On pourra agrave volonteacute inclure le premier dans la deacutefi-

nition du patron ou dans son utilisation

Ce meacutecanisme met en jeu une sorte de preacutecompilation des deacutefinitions de patrons

2 Les paramegravetres de type drsquoun patron de fonctions

Ce paragraphe fait le point sur la maniegravere dont les paramegravetres de type peuvent intervenir dans

un patron de fonctions sur lalgorithme qui permet au compilateur dinstancier la fonction

voulue et sur les problegravemes particuliers quil peut poser

Notez quun patron de fonctions peut eacutegalement comporter ce que lon nomme des paramegrave-

tres expressions qui correspondent en fait agrave la notion usuelle dargument dune fonction Ils

seront eacutetudieacutes au paragraphe suivant

21 Utilisation des paramegravetres de type dans la deacutefinition dun patron

Un patron de fonctions peut donc comporter un ou plusieurs paramegravetres de type chacun

devant ecirctre preacuteceacutedeacute du mot cleacute class par exemple

template ltclass T class Ugt fct (T a T b U c)

Ces paramegravetres peuvent intervenir agrave nimporte quel endroit de la deacutefinition dun patron1

bull dans len-tecircte (ceacutetait le cas des exemples preacuteceacutedents)

bull dans des deacuteclarations2 de variables locales (de lun des types des paramegravetres)

bull dans les instructions exeacutecutables3 (par exemple new sizeof ())

1 De la mecircme maniegravere quun nom de type peut intervenir dans la deacutefinition dune fonction

2 Il sagit alors de deacuteclarations au sein de la deacutefinition du patron cest-agrave-dire finalement de deacuteclarations au sein de

deacuteclarations

3 Nous parlons dinstructions exeacutecutables bien quil sagisse toujours de deacuteclarations (puisque la deacutefinition dun

patron est une deacuteclaration) En toute rigueur ces instructions donneront naissance agrave des instructions exeacutecutables agrave

chaque instanciation dune nouvelle fonction

Les patrons de fonctionsCHAPITRE 11

212

En voici un exemple

template ltclass T class Ugt 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 eacuteleacutements de type T

n = sizeof (T)

Dans tous les cas il est neacutecessaire que chaque paramegravetre de type apparaisse au moins une

fois dans len-tecircte du patron comme nous le verrons cette condition est parfaitement logi-

que puisque cest preacuteciseacutement gracircce agrave la nature de ces arguments que le compilateur est en

mesure dinstancier correctement la fonction neacutecessaire

22 Identification des paramegravetres de type dune fonction patronLes exemples preacuteceacutedents eacutetaient suffisamment simples pour que lon devine quelle eacutetait la

fonction instancieacutee pour un appel donneacute Mais reprenons le patron min

template ltclass Tgt T min (T a T b)

if (a lt b) return a else return b

avec ces deacuteclarations

int n char c

Que va faire le compilateur en preacutesence dun appel tel que min (nc) ou min(cn) En fait la

regravegle preacutevue par C++ dans ce cas est quil doit y avoir correspondance absolue des types

Cela signifie que nous ne pouvons utiliser le patron min que pour des appels dans lesquels les

deux arguments ont le mecircme type Manifestement ce nest pas le cas dans nos deux appels

qui aboutiront agrave une erreur de compilation On notera que dans cette correspondance abso-

lue les eacuteventuels qualifieurs const ou volatile interviennent

Voici quelques exemples dappels de min qui preacutecisent quelle sera la fonction instancieacutee lors-

que lappel est correct

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) erreurmin (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

2 - Les paramegravetres de type drsquoun patron de fonctions213

Il est cependant possible drsquointervenir sur ce meacutecanisme drsquoidentification de type En effet

C++ vous autorise agrave speacutecifier un ou plusieurs paramegravetres de type au moment de lrsquoappel du

patron Voici quelques exemples utilisant les deacuteclarations preacuteceacutedentes

minltintgt (c n) force lutilisation de minltintgt et donc la conversion

de c en int le reacutesultat sera de type int

minltchargt (q n) force lutilisation de minltchargt et donc la conversion de q et de n en char le reacutesultat sera de type char

Voici un autre exemple faisant intervenir plusieurs paramegravetres de type

template ltclass T class Ugt T fct (T x U y T z) return x + y + z

main () int n = 1 p = 2 q = 3

float x = 25 y = 50

cout ltlt fct (n x p) ltlt n affiche la valeur (int) 5 cout ltlt fct (x n y) ltlt n affiche la valeur (float) 85

cout ltlt fct (n p q) ltlt n affiche la valeur (int) 6

cout ltlt fct (n p x) ltlt n erreur pas de correspondance

Ici encore on peut forcer certains des paramegravetres de type comme dans ces exemples

fctltintfloatgt (n p x) force lutilisation de fctltintfloatgt et donc la conversion de p en float et de x en int

fctltfloatgt (n p x ) force lutilisation de float pour T U est deacutetermineacute par les regravegles habituelles

crsquoest-agrave-dire int (type de p)

n sera converti en float

Remarque

Le mode de transmission drsquoun paramegravetre (par valeur ou par reacutefeacuterence) ne joue aucun rocircle

dans lrsquoidentification des paramegravetres de type Cela va de soi puisque

bull drsquoune part ce mode ne peut pas ecirctre deacuteduit de la forme de lrsquoappel

bull drsquoautre part la notion de conversion nrsquoa aucune signfication ici elle ne peut donc pas in-

tervenir pour trancher entre une reacutefeacuterence et une reacutefeacuterence agrave une constante

23 Nouvelle syntaxe dinitialisation des variables des types standard

Dans un patron de fonctions un paramegravetre de type est susceptible de correspondre tantocirct agrave un

type standard tantocirct agrave un type classe Un problegraveme apparaicirct donc si lon doit deacuteclarer au sein

du patron un objet de ce type en transmettant un ou plusieurs arguments agrave son constructeur

Les patrons de fonctionsCHAPITRE 11

214

Consideacuterons cet exemple

template ltclass Tgt fct (T a)

T x (3) x est un objet local de type T quon construit

en transmettant la valeur 3 agrave son constructeur

Tant que lon utilise une fonction fct pour un type classe tout va bien En revanche si lon

cherche agrave lrsquoutiliser pour un type standard par exemple int le compilateur geacuteneacutere la fonction

suivante

fct (int a)

int x (3)

Pour que linstruction int x(3) ne pose pas de problegraveme C++ a preacutevu quelle soit simplement

interpreacuteteacutee comme une initialisation de x avec la valeur 3 cest-agrave-dire comme

int x = 3

En theacuteorie cette possibiliteacute est utilisable dans nimporte quelle instruction C++ de sorte que

vous pouvez tregraves bien eacutecrire

double x(35) au lieu de double x = 35

char c(e) au lieu de char c = e

En pratique cela sera rarement utiliseacute de cette faccedilon

24 Limitations des patrons de fonctionsLorsque lon deacutefinit un patron de classe agrave un paramegravetre de type peut theacuteoriquement corres-

pondre nimporte quel type effectif (standard ou classe) Il nexiste a priori aucun meacutecanisme

intrinsegraveque permettant dinterdire linstanciation pour certains types

Ainsi si un patron a un en-tecircte de la forme

template ltclass Tgt void fct (T)

on pourra appeler fct avec un argument de nimporte quel type int float int int t t ou

mecircme t (t deacutesignant un type classe quelconque)

Cependant un certain nombre deacuteleacutements peuvent intervenir indirectement pour faire

eacutechouer linstanciation

Tout dabord on peut imposer quun paramegravetre de type corresponde agrave un pointeur Ainsi avec

un patron den-tecircte

template ltclass Tgt void fct (T )

on ne pourra appeler fct quavec un pointeur sur un type quelconque int int t ou t

Dans les autres cas on aboutira agrave une erreur de compilation

Par ailleurs dans la deacutefinition dun patron peuvent apparaicirctre des instructions qui saveacutereront

incorrectes lors de la tentative dinstanciation pour certains types

3 - Les paramegravetres expressions drsquoun patron de fonctions215

Par exemple le patron min

template ltclass Tgt T min (T a T b) if (a lt b) return a else return b

ne pourra pas sappliquer si T correspond agrave un type classe dans lequel lopeacuterateur lt na pas eacuteteacute

surdeacutefini

De mecircme un patron comme

template ltclass Tgt void fct (T) T x (2 5) objet local de type T initialiseacute par un constructeur agrave 2 arguments

ne pourra pas sappliquer agrave un type classe pour lequel nexiste pas un constructeur agrave deux

arguments

En deacutefinitive bien quil nexiste pas de meacutecanisme formel de limitation les patrons de fonc-

tions peuvent neacuteanmoins comporter dans leur deacutefinition mecircme un certain nombre deacuteleacutements

qui en limiteront la porteacutee

3 Les paramegravetres expressions drsquoun patron de fonctions

Comme nous lavons deacutejagrave eacutevoqueacute un patron de fonctions peut comporter des paramegravetres

expressions1 crsquoest-agrave-dire des paramegravetres (muets) ordinaires analogues agrave ceux quon

trouve dans la deacutefinition dune fonction Consideacuterons cet exemple dans lequel nous deacutefinis-

sons un patron nommeacute compte permettant de fabriquer des fonctions comptabilisant le nom-

bre deacuteleacutements nuls dun tableau de type et de taille quelconques

include ltiostreamgtusing namespace std template ltclass Tgt int compte (T tab int n) int i nz=0 for (i=0 iltn i++) if (tab[i]) nz++ return nz

main () int t [5] = 5 2 0 2 0 char c[6] = 0 12 0 0 0 5 cout ltlt compte (t) = ltlt compte (t 5) ltlt n cout ltlt compte (c) = ltlt compte (c 6) ltlt n

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

Les patrons de fonctionsCHAPITRE 11

216

compte (t) = 2

compte (c) = 4

Exemple de patron de fonctions comportant un paramegravetre expression (n)

On peut dire que le patron compte deacutefinit une famille de fonctions compte dans laquelle le

type du premier argument est variable (et donc deacutefini par lappel) tandis que le second est de

type imposeacute (ici int) Comme on peut sy attendre dans un appel de compte seul le type du

premier argument intervient dans le code de la fonction instancieacutee

Dune maniegravere geacuteneacuterale un patron de fonctions peut disposer dun ou de plusieurs paramegravetres

expressions Lors de lappel leur type na plus besoin de correspondre exactement agrave celui

attendu il suffit quil soit acceptable par affectation comme dans nimporte quel appel dune

fonction ordinaire

4 Surdeacutefinition de patronsDe mecircme quil est possible de surdeacutefinir une fonction classique il est possible de surdeacutefinir

un patron de fonctions cest-agrave-dire de deacutefinir plusieurs patrons posseacutedant des arguments dif-

feacuterents On notera que cette situation conduit en fait agrave deacutefinir plusieurs familles de fonc-

tions (il y a bien plusieurs deacutefinitions de familles et non plus simplement plusieurs

deacutefinitions de fonctions) Elle ne doit pas ecirctre confondue avec la speacutecialisation dun patron de

fonctions qui consiste agrave surdeacutefinir une ou plusieurs des fonctions de la famille et que nous

eacutetudierons au paragraphe suivant

41 Exemples ne comportant que des paramegravetres de typeConsideacuterons cet exemple dans lequel nous avons surdeacutefini deux patrons de fonctions min de

faccedilon agrave disposer

bull dune premiegravere famille de fonctions agrave deux arguments de mecircme type quelconque (comme

dans les exemples preacuteceacutedents)

bull dune seconde famille de fonctions agrave trois arguments de mecircme type quelconque

include ltiostreamgt

using namespace std

patron numero I

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

4 - Surdeacutefinition de patrons217

patron numero IItemplate ltclass Tgt T min (T a T b T c) return min (min (a b) c) main() int n=12 p=15 q=2 float x=35 y=425 z=025 cout ltlt min (n p) ltlt n patron I int min (int int) cout ltlt min (n p q) ltlt n patron II int min (int int int) cout ltlt min (x y z) ltlt n patron II float min (float float float)

122025

Exemple de surdeacutefinition de patron de fonctions (1)

Dune maniegravere geacuteneacuterale on peut surdeacutefinir des patrons posseacutedant un nombre diffeacuterent de

paramegravetres de type (dans notre exemple il ny en avait quun dans chaque patron min) les

en-tecirctes des fonctions correspondantes peuvent donc ecirctre aussi varieacutes quon le deacutesire Mais il

est souhaitable quil ny ait aucun recoupement entre les diffeacuterentes familles de fonctions cor-

respondant agrave chaque patron Si tel nest pas le cas une ambiguiumlteacute risque dapparaicirctre avec cer-

tains appels

Voici un autre exemple dans lequel nous avons deacutefini plusieurs patrons de fonctions min agrave

deux arguments afin de traiter convenablement les trois situations suivantes

bull deux valeurs de mecircme type (comme dans les paragraphes preacuteceacutedents)

bull un pointeur sur une valeur dun type donneacute et une valeur de ce mecircme type

bull une valeur dun type donneacute et un pointeur sur une valeur de ce mecircme type

include ltiostreamgtusing namespace std

patron numeacutero Itemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

patron numeacutero IItemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

Les patrons de fonctionsCHAPITRE 11

218

patron numeacutero III

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

main()

int n=12 p=15

float x=25 y=52

cout ltlt min (n p) ltlt n patron numeacutero I int min (int int)

cout ltlt min (ampn p) ltlt n patron numeacutero II int min (int int)

cout ltlt min (x ampy) ltltn patron numeacutero III float min (float float )

cout ltlt min (ampn ampp) ltlt n patron numeacutero I int min (int int )

12

12

25

006AFDF0

Exemple de surdeacutefinition de patron de fonctions (2)

Les trois premiers appels ne posent pas de problegraveme En revanche un appel tel que min (ampn

ampp) conduit agrave instancier agrave laide du patron numeacutero I la fonction

int min (int int )

La valeur fournie alors par lappel est la plus petite des deux valeurs (de type int ) ampn et ampp

Il est probable que ce ne soit pas le reacutesultat attendu par lutilisateur (nous avons deacutejagrave rencon-

treacute ce genre de problegraveme dans le paragraphe 1 en appliquant min agrave des chaicircnes1)

Pour linstant notez quil ne faut pas espeacuterer ameacuteliorer la situation en deacutefinissant un patron

suppleacutementaire de la forme

template ltclass Tgt T min (T a T b)

if (a lt b) return a

else return b

En effet les quatre familles de fonctions ne seraient plus totalement indeacutependantes Plus preacute-

ciseacutement si les trois premiers appels fonctionnent toujours convenablement lappel min (ampn

ampp) conduit agrave une ambiguiumlteacute puisque deux patrons conviennent maintenant (celui que nous

venons dintroduire et le premier)

1 Mais ce problegraveme pourra se reacutegler convenablement avec la speacutecialisation de patron ce qui nest pas le cas du

problegraveme que nous exposons ici

4 - Surdeacutefinition de patrons219

Remarque

Nous avons deacutejagrave vu que le mode de transmission drsquoun paramegravetre de type (par valeur ou

par expression) ne jouait aucun rocircle dans lrsquoidentification des paramegravetres de type drsquoun

patron Il en va de mecircme pour le choix du bon patron en cas de surdeacutefinition La raison en

est la mecircme ce mode de transmission nrsquoest pas deacutefini par lrsquoappel de la fonction mais uni-

quement suivant la fonction choisie pour satisfaire agrave lrsquoappel Comme dans le cas des

patrons la correspondance de type doit ecirctre exacte il nrsquoest mecircme plus question de trou-

ver deux patrons lrsquoun correspondant agrave une transmission par valeur lrsquoautre agrave une trans-

mission par reacutefeacuterence1

template ltclass Tgt f(T a) template ltclass Tgt f(T amp a) main() int n f(n) ambiguiumlteacute f(T) avec T=int ou f(Tamp) avec T=int

Cela restait possible dans le cas des fonctions surdeacutefinies dans la mesure ougrave la reacutefeacute-

rence ne pouvait ecirctre employeacutee qursquoavec une correspondance exacte la transmission par

valeur autorisant des conversions (mais lrsquoambiguiumlteacute existait quand mecircme en cas de cor-

respondance exacte)

42 Exemples comportant des paramegravetres expressionsLa preacutesence de paramegravetres expressions donne agrave la surdeacutefinition de patron un caractegravere plus

geacuteneacuteral Dans lexemple suivant nous avons deacutefini deux familles de fonctions min

bull lune pour deacuteterminer le minimum de deux valeurs de mecircme type quelconque

bull lautre pour deacuteterminer le minimum des valeurs dun tableau de type quelconque et de taille

quelconque (fournie en argument sous la forme dun entier)include ltiostreamgt

using namespace std patron Itemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b patron IItemplate ltclass Tgt T min (T t int n) int i T min = t[0] for (i=1 iltn i++) if (t[i] lt min) min=t[i] return min

1 Nous reviendrons au paragraphe 5 sur la distinction entre f(Tamp) et f(const Tamp)

Les patrons de fonctionsCHAPITRE 11

220

main() long n=2 p=12

float t[6] = 25 32 15 38 11 28 cout ltlt min (n p) ltlt n patron I long min (long long)

cout ltlt min (t 6) ltlt n patron II float min (float int)

211

Exemple de surdeacutefinition de patrons comportant un paramegravetre expression

Notez que si plusieurs patrons sont susceptibles drsquoecirctre employeacutes et quils ne se distinguent

que par le type de leurs paramegravetres expressions ce sont alors les regravegles de choix dune fonc-

tion surdeacutefinie ordinaire qui sappliquent

5 Speacutecialisation de fonctions de patron

51 GeacuteneacuteraliteacutesUn patron de fonctions deacutefinit une famille de fonctions agrave partir dune seule deacutefinition Autre-

ment dit toutes les fonctions de la famille reacutealisent le mecircme algorithme Dans certains cas

cela peut saveacuterer peacutenalisant Nous lavons dailleurs deacutejagrave remarqueacute dans le cas du patron min

du paragraphe 1 le comportement obtenu lorsquon lappliquait au type char ne nous satis-

faisait pas

La notion de speacutecialisation offre une solution agrave ce problegraveme En effet C++ vous autorise agrave

fournir outre la deacutefinition dun patron la deacutefinition dune ou de plusieurs fonctions pour cer-

tains types darguments Voici par exemple comment ameacuteliorer notre patron min du paragra-

phe 1 en fournissant une version speacutecialiseacutee pour les chaicircnes

include ltiostreamgt

using namespace std include ltcstringgt pour strcmp (ancien stringh)

patron mintemplate ltclass Tgt T min (T a T b) if (a lt b) return a else return b

fonction min pour les chaineschar min (char cha char chb)

if (strcmp (cha chb) lt 0) return cha else return chb

5 - Speacutecialisation de fonctions de patron221

main() int n=12 p=15 char adr1 = monsieur adr2 = bonjour cout ltlt min (n p) ltlt n patron int min (int int) cout ltlt min (adr1 adr2) fonction char min (char char )

12bonjour

Exemple de speacutecialisation dune fonction dun patron

52 Les speacutecialisations partiellesIl est theacuteoriquement possible deffectuer ce que lon nomme des speacutecialisations partielles1

crsquoest-agrave-dire de deacutefinir des familles de fonctions certaines eacutetant plus geacuteneacuterales que dautres

comme dans

template ltclass T class Ugt void fct (T a U b) template ltclass Tgt void fct (T a T b)

Manifestement la seconde deacutefinition est plus speacutecialiseacutee que la premiegravere et devrait ecirctre utili-

seacutee dans des appels de fct dans lesquels les deux arguments sont de mecircme type

Ces possibiliteacutes de speacutecialisation partielle srsquoavegraverent tregraves utiles dans les situations suivantes

bull traitement particulier pour un pointeur en speacutecialisant partiellement T en T

template ltclass Tgt void f(T t) patron I template ltclass Tgt void f(T t) patron II int n int adc f(n) f(int) en utilisant patron I avec T = int f(adi) f(int ) en utilisant patron II avec T = int car il est plus speacutecialiseacute que patron I (avec T = int )

bull distinction entre pointeur ou reacutefeacuterence sur une variable de pointeur ou reacutefeacuterence sur une

constante

template ltclass Tgt void f(T amp t) patron I template ltclass Tgt void f(const T amp t) patron II int n const int cn=12 f(n) f(int amp) en utilisant patron I avec T = int f(cn) f(const int amp) en utilisant patron II avec T = int car il est plus speacutecialiseacute que patron I (avec T = const int)

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

Les patrons de fonctionsCHAPITRE 11

222

Drsquoune maniegravere geacuteneacuterale la norme deacutefinit une relation drsquoordre partiel permettant de dire

qursquoun patron est plus speacutecialiseacute qursquoun autre Comme on peut srsquoy attendre il existe des situa-

tions ambigueumls dans lesquelles aucun patron nrsquoest plus speacutecialiseacute qursquoun autre

6 Algorithme drsquoinstanciation drsquoune fonction patron

Nous avons donc vu qursquoon peut deacutefinir un ou plusieurs patrons de mecircme nom (surdeacutefinition)

chacun posseacutedant ses propres paramegravetres de type et eacuteventuellement des paramegravetres expres-

sions De plus il est possible de fournir des fonctions ordinaires portant le mecircme nom quun

patron (speacutecialisation dune fonction de patron)

Lorsque lrsquoon combine ces diffeacuterentes possibiliteacutes le choix de la fonction agrave instancier peut

srsquoaveacuterer moins eacutevident que dans nos preacuteceacutedents exemples Nous allons donc preacuteciser ici

lrsquoalgorithme utiliseacute par le compilateur dans linstanciation de la fonction correspondant agrave un

appel donneacute

Dans un premier temps on examine toutes les fonctions ordinaires ayant le nom voulu et on

sinteacuteresse aux correspondances exactes Si une seule convient le problegraveme est reacutesolu Sil en

existe plusieurs il y a ambiguiumlteacute une erreur de compilation est deacutetecteacutee et la recherche est

interrompue

Si aucune fonction ordinaire ne reacutealise de correspondance exacte on examine alors tous les

patrons ayant le nom voulu en ne consideacuterant que les paramegravetres de type Si une seule

correspondance exacte est trouveacutee on cherche agrave instancier la fonction correspondante1 agrave

condition que cela soit possible Cela signifie que si cette derniegravere dispose de paramegravetres

expressions il doit exister des conversions valides des arguments correspondants dans le type

voulu Si tel est le cas le problegraveme est reacutesolu

Si plusieurs patrons assurent une correspondance exacte de type on examine tout dabord si

lon est en preacutesence dune speacutecialisation partielle auquel cas on choisit le patron le plus speacute-

cialiseacute2 Si cela ne suffit pas agrave lever lrsquoambiguiumlteacute on examine les eacuteventuels paramegravetres expres-

sions qursquoon traite de la mecircme maniegravere que pour une surdeacutefinition usuelle Si plusieurs

fonctions restent utilisables on aboutit agrave une erreur de compilation et la recherche est inter-

rompue

En revanche si aucun patron de fonctions ne convient3 on examine agrave nouveau toutes les

fonctions ordinaires en les traitant cette fois comme de simples fonctions surdeacutefinies (promo-

tions numeacuteriques conversions standard4)

1 Du moins si elle na pas deacutejagrave eacuteteacute instancieacutee

2 Rappelons que la possibiliteacute de speacutecialisation partielle des patrons de fonctions nest pas correctement geacutereacutee par

toutes les impleacutementations

3 Y compris si un seul reacutealisait les correspondances exactes des paramegravetres de type sans qursquoil existe de conversions

leacutegales pour les eacuteventuels paramegravetres expressions

4 Voir au paragraphe 5 du chapitre 4

6 - Algorithme drsquoinstanciation drsquoune fonction patron223

Voici quelques exemples

Exemple 1template ltclass Tgt void f(T t int n) cout ltlt f(Tint)n template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n main() double y f(y 10) OK f(T int) avec T=double f(y 125) ambiguiumlteacute f(Tint) ou f(Tfloat) car 125 est de type double les conversions standard double--gtint et double--gtfloat conviennent f(y 125f) Ok f(T float) avec T=double

Exemple 2template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n template ltclass T class Ugt void f(T t U u) cout ltlt f(TU)n main() double y float x f(x y) OK f(TU) avec T=float U=double f(y x) ambiguiumlteacute f(TU) avec T=double U=float ou f(Tfloat) avec U=double

Exemple 3template ltclass Tgt void f(T t float x) cout ltlt f(Tfloat)n main() double y float x f(x y) OK avec T=double et conversion de y en float f(y x) OK avec T=float f(x hello) T=double convient mais char ne peut pas ecirctre converti en float

Les patrons de fonctionsCHAPITRE 11

224

Remarque

Il est tout agrave fait possible que la deacutefinition dun patron fasse intervenir agrave son tour une fonc-

tion patron (cest-agrave-dire une fonction susceptible decirctre instancieacutee agrave partir dun autre

patron)

12

Les patrons de classes

Le preacuteceacutedent chapitre a montreacute comment C++ permettait gracircce agrave la notion de patron de fonc-

tions de deacutefinir une famille de fonctions parameacutetreacutees par un ou plusieurs types et eacuteventuelle-

ment des expressions Dune maniegravere comparable C++ permet de deacutefinir des patrons de

classes Lagrave encore il suffira drsquoeacutecrire une seule fois la deacutefinition de la classe pour que le

compilateur puisse automatiquement ladapter agrave diffeacuterents types

Comme nous lavons fait pour les patrons de fonctions nous commencerons par vous preacutesen-

ter cette notion de patron de classes agrave partir drsquoun exemple simple ne faisant intervenir quun

paramegravetre de type Nous verrons ensuite quelle se geacuteneacuteralise agrave un nombre quelconque de

paramegravetres de type et de paramegravetres expressions Puis nous examinerons la possibiliteacute de speacute-

cialiser un patron de classes soit en speacutecialisant certaines de ses fonctions membres soit en

speacutecialisant toute une classe Nous ferons alors le point sur linstanciation de classes patrons

notamment en ce qui concerne lidentiteacute de deux classes Nous verrons ensuite comment se

geacuteneacuteralisent les deacuteclarations damitieacutes dans le cas de patrons de classes Nous terminerons par

un exemple dutilisation de classes patrons imbriqueacutees en vue de manipuler des tableaux

(dobjets) agrave deux indices

Signalons degraves maintenant que malgreacute leurs ressemblances les notions de patron de fonctions

et de patron de classes preacutesentent des diffeacuterences assez importantes Comme vous le consta-

terez ce chapitre nest nullement lextrapolation aux classes du preacuteceacutedent chapitre consacreacute

aux fonctions

Les patrons de classesCHAPITRE 12

226

1 Exemple de creacuteation et drsquoutilisation drsquoun patron de classes

11 Creacuteation dun patron de classesNous avons souvent eacuteteacute ameneacute agrave creacuteer une classe point de ce genre (nous ne fournissons pas

ici la deacutefinition des fonctions membres)

class point int x int y public point (int abs=0 int ord=0) void affiche ()

Lorsque nous proceacutedons ainsi nous imposons que les coordonneacutees dun point soient des

valeurs de type int Si nous souhaitons disposer de points agrave coordonneacutees dun autre type

(float double long unsigned int) nous devons deacutefinir une autre classe en remplaccedilant sim-

plement dans la classe preacuteceacutedente le mot cleacute int par le nom de type voulu

Ici encore nous pouvons simplifier consideacuterablement les choses en deacutefinissant un seul patron

de classe de cette faccedilon

template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) void affiche ()

Comme dans le cas des patrons de fonctions la mention template ltclass Tgt preacutecise que lon

a affaire agrave un patron (template) dans lequel apparaicirct un paramegravetre de type nommeacute T rappe-

lons que C++ a deacutecideacute demployer le mot cleacute class pour preacuteciser que T est un argument de

type (pas forceacutement classe)

Bien entendu la deacutefinition de notre patron de classes nest pas encore complegravete puisquil y

manque la deacutefinition des fonctions membres agrave savoir le constructeur point et la fonction affi-

che Pour ce faire la deacutemarche va leacutegegraverement diffeacuterer selon que la fonction concerneacutee est en

ligne ou non

Pour une fonction en ligne les choses restent naturelles il suffit simplement dutiliser le

paramegravetre T agrave bon escient Voici par exemple comment pourrait ecirctre deacutefini notre

constructeur

point (T abs=0 T ord=0) x = abs y = ord

En revanche lorsque la fonction est deacutefinie en dehors de la deacutefinition de la classe il est

neacutecessaire de rappeler au compilateur

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes227

bull que dans la deacutefinition de cette fonction vont apparaicirctre des paramegravetres de type pour ce

faire on fournira agrave nouveau la liste de paramegravetre sous la forme

template ltclass Tgt

bull le nom du patron concerneacute (de mecircme quavec une classe ordinaire il fallait preacutefixer le nom

de la fonction du nom de la classe) par exemple si nous deacutefinissons ainsi la fonction af-

fiche son nom sera

pointltTgtaffiche ()

En deacutefinitive voici comment se preacutesenterait len-tecircte de la fonction affiche si nous le deacutefinis-

sions ainsi en dehors de la classe

template ltclass Tgt void pointltTgtaffiche ()

En toute rigueur le rappel du paramegravetre T agrave la suite du nom de patron (point) est redondant1

puisqursquoil a deacutejagrave eacuteteacute speacutecifieacute dans la liste de paramegravetres suivant le mot cleacute template

Voici ce que pourrait ecirctre finalement la deacutefinition de notre patron point

include ltiostreamgtusing namespace std creacuteation dun patron de classetemplate ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () template ltclass Tgt void pointltTgtaffiche () cout ltlt Coordonneacutees ltlt x ltlt ltlt y ltlt n

Creacuteation dun patron de classes

Remarque

Comme on lrsquoa deacutejagrave fait remarquer agrave propos de la deacutefinition de patrons de fonctions

depuis la norme le mot cleacute class peut ecirctre remplaceacute par typename2

1 Stroustrup le concepteur du langage C++ se contente de mentionner cette redondance sans la justifier

2 En toute rigueur ce mot cleacute peut eacutegalement servir agrave lever une ambiguiumlteacute pour le compilateur en lrsquoajoutant en

preacutefixe agrave un identificateur afin qursquoil soit effectivement interpreacuteteacute comme un nom de type Par exemple avec cette

deacuteclaration

typename Atruc a eacutequivalent agrave Atruc a si aucune ambiguiteacute nrsquoexiste

on preacutecise que Atruc est bien un nom de type on deacuteclare donc a comme eacutetant de type Atruc

Il est rare que lrsquoon ait besoin de recourir agrave cette possibiliteacute

Les patrons de classesCHAPITRE 12

228

12 Utilisation dun patron de classes

Apregraves avoir creacuteeacute ce patron une deacuteclaration telle que

point ltintgt ai

conduit le compilateur agrave instancier la deacutefinition dune classe point dans laquelle le paramegravetre

T prend la valeur int Autrement dit tout se passe comme si nous avions fourni une deacutefinition

complegravete de cette classe

Si nous deacuteclarons

point ltdoublegt ad

le compilateur instancie la deacutefinition dune classe point dans laquelle le paramegravetre T prend la

valeur double exactement comme si nous avions fourni une autre deacutefinition complegravete de

cette classe

Si nous avons besoin de fournir des arguments au constructeur nous proceacutederons de faccedilon

classique comme dans

point ltintgt ai (3 5) point ltdoublegt ad (35 23)

13 Contraintes drsquoutilisation drsquoun patron de classes

Comme on peut sy attendre les instructions deacutefinissant un patron de classes sont des deacutecla-

rations au mecircme titre que les instructions deacutefinissant une classe (y compris les instructions de

deacutefinition de fonctions en ligne)

Mais il en va de mecircme pour les fonctions membres qui ne sont pas en ligne leurs instruc-

tions sont neacutecessaires au compilateur pour instancier chaque fois que neacutecessaire les instruc-

tions requises On retrouve ici la mecircme remarque que celle que nous avons formuleacutee pour les

patrons de fonctions (voir paragraphe 14 du chapitre 11)

Aussi nest-il pas possible de livrer agrave un utilisateur une classe patron toute compileacutee il faut

lui fournir les instructions source de toutes les fonctions membres (alors que pour une classe

ordinaire il suffit de lui fournir la deacuteclaration de la classe et un module objet correspondant

aux fonctions membres)

Tout se passe encore ici comme srsquoil existait deux niveaux de deacuteclarations Par la suite nous

continuerons cependant agrave parler de deacutefinition dun patron

En pratique on placera les deacutefinitions de patron dans un fichier approprieacute dextension h

1 - Exemple de creacuteation et drsquoutilisation drsquoun patron de classes229

Remarque

Ici encore les consideacuterations preacuteceacutedentes doivent en fait ecirctre pondeacutereacutees par le fait que la

norme a introduit le mot cleacute export Appliqueacute agrave la deacutefinition drsquoun patron de classes il preacute-

cise que celle-ci sera accessible depuis un autre fichier source Par exemple on pourra

deacutefinir un patron de classes point de cette faccedilon

export template ltclass Tgt class point

T x T y

public

point ()

void afiche ()

template ltclass Tgt pointltTgtpoint() deacutefinition constructeur

template ltclass Tgt void pointltTgtaffiche() deacutefinition affiche

On peut alors utiliser ce patron depuis un autre fichier source en se contentant de men-

tionner sa seule deacuteclaration (comme avec les patrons de fonctions on distingue alors

deacuteclaration et deacutefinition)

template ltclass Tgt pointltTgt deacuteclaration seule de pointltTgt

T x T y

point ()

void afiche ()

Ici encore on aura inteacuterecirct agrave preacutevoir deux fichiers en-tecirctes distincts un pour la deacuteclara-

tion un pour la deacutefinition Le premier sera inclus dans la deacutefinition du patron et dans

son utilisation

Rappelons que ce meacutecanisme met en jeu une sorte de preacutecompilation des deacutefinitions

de patrons

14 Exemple reacutecapitulatifVoici un programme complet comportant

bull la creacuteation dun patron de classes point doteacutee drsquoun constructeur en ligne et drsquoune fonction

membre (affiche) non en ligne

bull un exemple dutilisation (main)

include ltiostreamgt

using namespace std

Les patrons de classesCHAPITRE 12

230

creacuteation dun patron de classetemplate ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () template ltclass Tgt void pointltTgtaffiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

main () point ltintgt ai (3 5) aiaffiche () point ltchargt ac (d y) acaffiche () point ltdoublegt ad (35 23) adaffiche ()

coordonnees 3 5coordonnees d ycoordonnees 35 23

Creacuteation et utilisation dun patron de classes

Remarques

1 Le comportement de pointltchargt est satisfaisant si nous souhaitons effectivement dispo-

ser de points repeacutereacutes par de vrais caractegraveres En revanche si nous avons utiliseacute le type

char pour disposer de petits entiers le reacutesultat est moins satisfaisant En effet nous

pourrons toujours deacuteclarer un point de cette faccedilon

point ltchargt pc (4 9)

Mais le comportement de la fonction affiche ne nous conviendra plus (nous obtiendrons

les caractegraveres ayant pour code les coordonneacutees du point )

Nous verrons quil reste toujours possible de modifier cela en speacutecialisant notre

classe point pour le type char ou encore en speacutecialisant la fonction affiche pour la

classe pointltchargt

2 A priori on a plutocirct envie dappliquer notre patron point agrave des types T standard Toute-

fois rien ninterdit de lappliquer agrave un type classe T quelconque mecircme srsquoil peut alors

srsquoaveacuterer difficile dattribuer une signification agrave la classe patron ainsi obtenue Il faut

cependant quil existe une conversion de int en T utile pour convertir la valeur 0 dans le

2 - Les paramegravetres de type drsquoun patron de classes231

type T lors de linitialisation des arguments du constructeur de point (sinon on obtien-

dra une erreur de compilation) De plus il est neacutecessaire que la recopie et laffectation

dobjets de type T soient correctement prises en compte (dans le cas contraire aucun

diagnostic ne sera fourni agrave la compilation les conseacutequences nrsquoen seront perccedilues qursquoagrave

lrsquoexeacutecution)

2 Les paramegravetres de type drsquoun patron de classes

Tout comme les patrons de fonctions les patrons de classes peuvent comporter des paramegrave-

tres de type et des paramegravetres expressions Ce paragraphe eacutetudie les premiers les seconds

seront eacutetudieacutes au paragraphe suivant Une fois de plus notez bien que malgreacute leur ressem-

blance avec les patrons de fonctions les contraintes relatives agrave ces diffeacuterents types de para-

megravetres ne seront pas les mecircmes

21 Les paramegravetres de type dans la creacuteation dun patron de classes

Les paramegravetres de type peuvent ecirctre en nombre quelconque et utiliseacutes comme bon vous sem-

ble dans la deacutefinition du patron de classes En voici un exemple

template ltclass T class U class Vgt liste de trois param de nom (muet) T U et Vclass essai T x un membre x de type T U t[5] un tableau t de 5 eacuteleacutements de type U V fm1 (int U) deacuteclaration dune fonction membre recevant 2 arguments de type int et U et renvoyant un reacutesultat de type V

22 Instanciation dune classe patronRappelons que nous nommons classe patron une instance particuliegravere dun patron de clas-

ses

Une classe patron se deacuteclare simplement en fournissant agrave la suite du nom de patron un nom-

bre drsquoarguments effectifs (noms de types) eacutegal au nombre de paramegravetres figurant dans la liste

(template lt gt) du patron Voici des deacuteclarations de classes patron obtenues agrave partir du

patron essai preacuteceacutedent (il ne sagit que de simples exemples deacutecole auxquels il ne faut pas

chercher agrave attribuer une signification preacutecise)

essai ltint float intgt ce1 essai ltint int double gt ce2 essai ltchar int objgt ce3

Les patrons de classesCHAPITRE 12

232

La derniegravere suppose bien sucircr que le type obj a eacuteteacute preacutealablement deacutefini (il peut sagir dun

type classe)

Il est mecircme possible dutiliser comme paramegravetre de type effectif un type instancieacute agrave laide

dun patron de classes Par exemple si nous disposons du patron de classes nommeacute point tel

quil a eacuteteacute deacutefini dans le paragraphe preacuteceacutedent nous pouvons deacuteclarer

essai ltfloat pointltintgt doublegt ce4 essai ltpointltintgt pointltfloatgt char gt ce5

Remarques

1 Les problegravemes de correspondance exacte rencontreacutes avec les patrons de fonctions nexis-

tent plus pour les patrons de classes (du moins pour les paramegravetres de types eacutetudieacutes ici)

En effet dans le cas des patrons de fonctions linstanciation se fondait non pas sur la liste

des paramegravetres indiqueacutes agrave la suite du mot cleacute template mais sur la liste des paramegravetres de

len-tecircte de la fonction un mecircme nom (muet) pouvait apparaicirctre deux fois et il y avait

donc risque dabsence de correspondance

2 Il est tout agrave fait possible quun argument formel (figurant dans len-tecircte) dune fonction

patron soit une classe patron En voici un exemple dans lequel nous supposons deacutefini

le patron de classes nommeacute point (ce peut ecirctre le preacuteceacutedent)

template ltclass Tgt void fct (pointltTgt)

Lorsquil devra instancier une fonction fct pour un type T donneacute le compilateur instan-

ciera eacutegalement (si cela na pas encore eacuteteacute fait) la classe patron pointltTgt

3 Comme dans le cas des patrons de fonctions on peut rencontrer des difficulteacutes lorsque

lon doit initialiser (au sein de fonctions membres) des variables dont le type figure en

paramegravetre En effet il peut sagir dun type de base ou au contraire dun type classe Lagrave

encore la nouvelle syntaxe dinitialisation des types standard (preacutesenteacutee au paragraphe

23 du chapitre 11) permet de reacutesoudre le problegraveme

4 Un patron de classes peut comporter des membres (donneacutees ou fonctions) statiques

Dans ce cas il faut savoir que chaque instance de la classe dispose de son propre jeu de

membres statiques on est en quelque sorte statique au niveau de linstance et non au

niveau du patron Crsquoest logique puisque le patron de classes nest quun moule utiliseacute

pour instancier diffeacuterentes classes plus preacuteciseacutement un patron de classes peut toujours

ecirctre remplaceacute par autant de deacutefinitions diffeacuterentes de classes que de classes instancieacutees

3 - Les paramegravetres expressions drsquoun patron de classes233

3 Les paramegravetres expressions drsquoun patron de classes

Un patron de classes peut comporter des paramegravetres expressions Bien quil sagisse ici

encore dune notion voisine de celle preacutesenteacutee pour les patrons de fonctions certaines diffeacute-

rences importantes existent En particulier les valeurs effectives dun paramegravetre expression

devront obligatoirement ecirctre constantes dans le cas des classes

31 Exemple Supposez que nous souhaitions deacutefinir une classe tableau susceptible de manipuler des

tableaux dobjets dun type quelconque Lrsquoideacutee vient tout naturellement agrave lesprit den faire

une classe patron posseacutedant un paramegravetre de type On peut aussi preacutevoir un second paramegravetre

permettant de preacuteciser le nombre deacuteleacutements du tableau

Dans ce cas la creacuteation de la classe se preacutesentera ainsi

template ltclass T int ngt class tableau

T tab [n]

public

La liste de paramegravetres (template ltgt) comporte deux paramegravetres de nature totalement

diffeacuterente

bull un paramegravetre (deacutesormais classique) de type introduit par le mot cleacute class

bull un paramegravetre expression de type int on preacutecisera sa valeur lors de la deacuteclaration dune

instance particuliegravere de la classe tableau

Par exemple avec la deacuteclaration

tableau ltint 4gt ti

nous deacuteclarerons une classe nommeacutee ti correspondant finalement agrave la deacuteclaration suivante

class ti

int tab [4]

public

Voici un exemple complet de programme deacutefinissant un peu plus complegravetement une telle

classe patron nommeacutee tableau nous lavons simplement doteacutee de lopeacuterateur [] et dun cons-

tructeur (sans arguments) qui ne se justifie que par le fait quil affiche un message approprieacute

Nous avons instancieacute des tableaux dobjets de type point (ici point est agrave nouveau une classe

ordinaire et non une classe patron)

Les patrons de classesCHAPITRE 12

234

include ltiostreamgtusing namespace std template ltclass T int ngt class tableau T tab [n] public tableau () cout ltlt construction tableau n T amp operator [] (int i) return tab[i] class point int x y public point (int abs=1 int ord=1 ) ici init par deacutefaut agrave 1 x=abs y=ord cout ltlt constr point ltlt x ltlt ltlt y ltlt n void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n main() tableau ltint4gt ti int i for (i=0 ilt4 i++) ti[i] = i cout ltlt ti for (i=0 ilt4 i++) cout ltlt ti[i] ltlt cout ltlt n tableau ltpoint 3gt tp for (i=0 ilt3 i++) tp[i]affiche()

construction tableauti 0 1 2 3const point 1 1const point 1 1const point 1 1construction tableaucoordonneacutees 1 1coordonneacutees 1 1coordonneacutees 1 1

Exemple de classe patron comportant un paramegravetre expression

Remarque

La classe tableau telle quelle est preacutesenteacutee ici na pas veacuteritablement dinteacuterecirct pratique En

effet on obtiendrait le mecircme reacutesultat en deacuteclarant de simples tableaux dobjets par exem-

ple int ti[4] au lieu de tableau ltint4gt ti En fait il ne sagit que dun cadre initial quon

4 - Speacutecialisation drsquoun patron de classes235

peut compleacuteter agrave loisir Par exemple on pourrait facilement y ajouter un controcircle dindice

en adaptant la deacutefinition de lopeacuterateur [] on pourrait eacutegalement preacutevoir dinitialiser les

eacuteleacutements du tableau Cest dailleurs ce que nous aurons loccasion de faire au paragraphe

9 ougrave nous utiliserons le patron tableau pour manipuler des tableaux agrave plusieurs indices

32 Les proprieacuteteacutes des paramegravetres expressionsOn peut faire apparaicirctre autant de paramegravetres expressions quon le deacutesire dans une liste de

paramegravetres dun patron de classes Ces paramegravetres peuvent intervenir nimporte ougrave dans la

deacutefinition du patron au mecircme titre que nimporte quelle expression constante peut apparaicirctre

dans la deacutefinition dune classe

Lors de linstanciation dune classe comportant des paramegravetres expressions les paramegravetres

effectifs correspondants doivent obligatoirement ecirctre des expressions constantes1 dun type

rigoureusement identique agrave celui preacutevu dans la liste drsquoarguments (aux conversions triviales

pregraves) autrement dit aucune conversion nest possible

Contrairement agrave ce qui passait pour les patrons de fonctions il nest pas possible de surdeacutefinir

un patron de classes cest-agrave-dire de creacuteer plusieurs patrons de mecircme nom mais comportant

une liste de paramegravetres (de type ou expressions) diffeacuterents En conseacutequence les problegravemes

dambiguiumlteacute eacutevoqueacutes lors de linstanciation dune fonction patron ne peuvent plus se poser

dans le cas de linstanciation dune classe patron

Sur un plan meacutethodologique on pourra souvent heacutesiter entre lemploi de paramegravetres expres-

sions et la transmission drsquoarguments au constructeur Ainsi dans lrsquoexemple de classe tableau

nous aurions pu ne pas preacutevoir le paramegravetre expression n mais en revanche transmettre au

constructeur le nombre deacuteleacutements souhaiteacutes Une diffeacuterence importante serait alors apparue

au niveau de la gestion des emplacements meacutemoire correspondant aux diffeacuterents eacuteleacutements du

tableau

bull attribution demplacement agrave la compilation (statique ou automatique suivant la classe dal-

location de lobjet de type tableaultgt correspondant) dans le premier cas

bull allocation dynamique par le constructeur dans le second cas

4 Speacutecialisation drsquoun patron de classesNous avons vu quil eacutetait possible de speacutecialiser certaines fonctions dun patron de fonc-

tions Si la mecircme possibiliteacute existe pour les patrons de classes elle prend toutefois un aspect

leacutegegraverement diffeacuterent agrave la fois au niveau de sa syntaxe et de ses possibiliteacutes comme nous le

verrons apregraves un exemple dintroduction

1 Cette contrainte nexistait pas pour les paramegravetres expressions des patrons de fonctions mais leur rocircle neacutetait pas

le mecircme

Les patrons de classesCHAPITRE 12

236

41 Exemple de speacutecialisation dune fonction membreUn patron de classes deacutefinit une famille de classes dans laquelle chaque classe comporte agrave la

fois sa deacutefinition et la deacutefinition de ses fonctions membres Ainsi toutes les fonctions mem-

bres de nom donneacute reacutealisent le mecircme algorithme Si lon souhaite adapter une fonction mem-

bre agrave une situation particuliegravere il est possible den fournir une nouvelle

Voici un exemple qui reprend le patron de classes point deacutefini dans le premier paragraphe

Nous y avons speacutecialiseacute la fonction affiche dans le cas du type char afin quelle affiche non

plus des caractegraveres mais des nombres entiers

include ltiostreamgt

using namespace std

creacuteation dun patron de classe

template ltclass Tgt class point

T x T y

public

point (T abs=0 T ord=0)

x = abs y = ord

void affiche ()

deacutefinition de la fonction affiche

template ltclass Tgt void pointltTgtaffiche ()

cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

ajout dune fonction affiche speacutecialiseacutee pour les caractegraveres

void pointltchargtaffiche ()

cout ltlt Coordonnees ltlt (int)x ltlt ltlt (int)y ltlt n

main ()

point ltintgt ai (3 5) aiaffiche ()

point ltchargt ac (d y) acaffiche ()

point ltdoublegt ad (35 23) adaffiche ()

coordonneacutees 3 5

coordonneacutees 100 121

coordonneacutees 35 23

Exemple de speacutecialisation dune fonction membre dune classe patron

Notez quil nous a suffi deacutecrire len-tecircte de affiche sous la forme

void pointltchargtaffiche ()

pour preacuteciser au compilateur quil devait utiliser cette fonction agrave la place de la fonction affi-

che du patron point cest-agrave-dire agrave la place de linstance pointltchargt

4 - Speacutecialisation drsquoun patron de classes237

42 Les diffeacuterentes possibiliteacutes de speacutecialisation

421 On peut speacutecialiser une fonction membre pour tous les paramegravetres

Dans notre exemple la classe patron point ne comportait quun paramegravetre de type Il est pos-

sible de speacutecialiser une fonction membre en se basant sur plusieurs paramegravetres de type ainsi

que sur des valeurs preacutecises drsquoun ou plusieurs paramegravetres expressions (bien que cette der-

niegravere possibiliteacute nous paraisse dun inteacuterecirct limiteacute) Par exemple consideacuterons le patron tableau

deacutefini au paragraphe 31

template ltclass T int ngt class tableau T tab [n] public tableau () cout ltlt construction tableau n

Nous pouvons eacutecrire une version speacutecialiseacutee de son constructeur pour les tableaux de

10 eacuteleacutements de type point (il ne sagit vraiment que dun exemple deacutecole ) en proceacutedant

ainsi

tableaultpoint10gttableau ()

422 On peut speacutecialiser une fonction membre ou une classe

Dans les exemples preacuteceacutedents nous avons speacutecialiseacute une fonction membre dun patron En

fait on peut indiffeacuteremment

bull speacutecialiser une ou plusieurs fonctions membres sans modifier la deacutefinition de la classe elle-

mecircme (ce sera la situation la plus freacutequente)

bull speacutecialiser la classe elle-mecircme en en fournissant une nouvelle deacutefinition cette seconde

possibiliteacute peut saccompagner de la speacutecialisation de certaines fonctions membres

Par exemple apregraves avoir deacutefini le patron template ltclass Tgt class point (comme au paragra-

phe 41) nous pourrions deacutefinir une version speacutecialiseacutee de la classe point pour le type char

cest-agrave-dire une version approprieacutee de linstance pointltchargt en proceacutedant ainsi

class point ltchargt nouvelle deacutefinition

Nous pourrions aussi deacutefinir des versions speacutecialiseacutees de certaines des fonctions membre de

pointltchargt en proceacutedant comme preacuteceacutedemment ou ne pas en deacutefinir auquel cas on ferait

appel aux fonctions membres du patron

423 On peut preacutevoir des speacutecialisations partielles de patrons de classes

Nous avons deacutejagrave parleacute de speacutecialisation partielle dans le cas de patrons de fonctions (voir au

paragraphe 5 du chapitre 11) La norme ANSI autorise eacutegalement la speacutecialisation partielle

drsquoun patron de classes1 En voici un exemple

1 Cette possibiliteacute nrsquoexistait pas dans la version 3 Elle a eacuteteacute introduite par la norme ANSI et elle nrsquoest pas encore

reconnue de tous les compilateurs

Les patrons de classesCHAPITRE 12

238

template ltclass T class Ugt class A patron Itemplate ltclass Tgt class A ltT Tgt patron II

Une deacuteclaration telle que A ltint floatgt a1 utilisera le patron I tandis qursquoune deacuteclaration

telle que Altint int gt a2 utilisera le patron II plus speacutecialiseacute

5 Paramegravetres par deacutefautDans la deacutefinition dun patron de classes il est possible de speacutecifier des valeurs par deacutefaut

pour certains paramegravetres1 suivant un meacutecanisme semblable agrave celui utiliseacute pour les paramegrave-

tres de fonctions usuelles Voici quelques exemples

template ltclass T class U=floatgt class A template ltclass T int n=3gt class B Altintlonggt a1 instanciation usuelle Altintgt a2 eacutequivaut agrave Altint floatgt a2 Bltint 3gt b1 instanciation usuelle Bltintgt b2 eacutequivaut agrave Bltint 3gt b2

Remarque

La notion de paramegravetres par deacutefaut na pas de signification pour les patrons de fonctions

6 Patrons de fonctions membresLe meacutecanisme de deacutefinition de patrons de fonctions peut sappliquer agrave une fonction membre

dune classe ordinaire comme dans cet exemple

class A

template ltclass Tgt void fct (T a)

Cette possibiliteacute peut srsquoappliquer agrave une fonction membre dune classe patron comme dans cet

exemple2

template ltclass Tgt class A

template ltclass Ugt void fct (U x T y) ici le type T est utiliseacute mais

il pourrait ne pas lecirctre

Dans ce dernier cas linstanciation de la bonne fonction fct se fondera agrave la fois sur la classe agrave

laquelle elle appartient et sur la nature de son premier argument

1 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

2 Cette possibiliteacute a eacuteteacute introduite par la norme ANSI

7 - Identiteacute de classes patrons239

7 Identiteacute de classes patronsNous avons deacutejagrave vu que lopeacuterateur drsquoaffectation pouvait sappliquer agrave deux objets dun mecircme

type Lrsquoexpression mecircme type est parfaitement deacutefinie tant que lon nutilise pas dinstan-

ces de patron de classes deux objets sont de mecircme type sils sont deacuteclareacutes avec le mecircme

nom de classe Mais que devient cette deacutefinition dans le cas dobjets dont le type est une ins-

tance particuliegravere dun patron de classes

En fait deux classes patrons correspondront agrave un mecircme type si leurs paramegravetres de type cor-

respondent exactement au mecircme type et si leurs paramegravetres expressions ont la mecircme valeur

Ainsi en supposant que nous disposions du patron tableau deacutefini au paragraphe 31 avec ces

deacuteclarations

tableau ltint 12gt t1 tableau ltfloat 12gt t2

vous naurez pas le droit deacutecrire

t2 = t1 incorrect car valeurs diffeacuterentes du premier paramegravetre (float et int)

De mecircme avec ces deacuteclarations

tableau ltint 15gt ta

tableau ltint 20gt tb

vous naurez pas le droit deacutecrire

ta = tb incorrect car valeurs diffeacuterentes du second paramegravetre (15 et 20)

Ces regravegles apparemment restrictives ne servent en fait quagrave assurer un bon fonctionnement

de laffectation quil sagisse de laffectation par deacutefaut (membre agrave membre il faut donc bien

disposer exactement des mecircmes membres dans les deux objets) ou de laffectation surdeacutefinie

(pour que cela fonctionne toujours il faudrait que le concepteur du patron de classe preacutevoie

toutes les combinaisons possibles et de plus ecirctre sucircr quune eacuteventuelle speacutecialisation ne ris-

que pas de perturber les choses)

Certes dans le premier cas (t2=t1) une conversion int-gtfloat nous aurait peut-ecirctre convenu

Mais pour que le compilateur puisse la mettre en œuvre il faudrait quil sache quune classe

tableaultint 10gt ne comporte que des membres de type int quune classe tableaultfloat

10gt ne comporte que des membres de type float que les deux classes ont le mecircme nombre de

membres donneacutees

8 Classes patrons et deacuteclarations drsquoamitieacuteLexistence des patrons de classes introduit de nouvelles possibiliteacutes de deacuteclaration damitieacute

81 Deacuteclaration de classes ou fonctions ordinaires amiesLa deacutemarche reste celle que nous avons rencontreacutee dans le cas des classes ordinaires Par

exemple si A est une classe ordinaire et fct une fonction ordinaire

Les patrons de classesCHAPITRE 12

240

template ltclass Tgtclass 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

82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons

En fait cette possibiliteacute peut prendre deux aspects diffeacuterents selon que les paramegravetres utiliseacutes

pour deacutefinir linstance concerneacutee sont effectifs ou muets (deacutefinis dans la liste de paramegravetres

du patron de classe)

Supposons que point est une classe patron ainsi deacutefinie

template ltclass Tgt class point

et fct une fonction patron ainsi deacutefinie

template ltclass Tgt int fct (T x)

Voici un exemple illustrant le premier aspect

template ltclass T class Ugt

class essai1

int x

public

friend class pointltintgt la classe patron pointltintgt 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 exemple illustrant le second aspect

template ltclass T class Ugt

class essai2

int x

public

friend class pointltTgt

friend int fct (U)

Notez bien que dans le second cas on eacutetablit un couplage entre la classe patron geacuteneacutereacutee

par le patron essai2 et les deacuteclarations damitieacute correspondantes Par exemple pour lintance

essai2 ltint doublegt les deacuteclarations damitieacute porteront sur pointltintgt et int fct (double)

9 - Exemple de classe tableau agrave deux indices241

83 Deacuteclaration drsquoun autre patron de fonctions ou de classesVoici un exemple faisant appel aux mecircmes patrons point et fct que ci-dessus

template ltclass T class Ugt

class essai2

int x

public

template ltclass Xgt friend class point ltXgt

template ltclass Xgt friend class int fct (point ltXgt)

Cette fois toutes les instances du patron point sont amies de nrsquoimporte quelle instance du

patron essai2 De mecircme toutes les instances du patron de fonctions fct sont amies de

nrsquoimporte quelle instance du patron essai2

9 Exemple de classe tableau agrave deux indices Nous avons vu agrave plusieurs reprises comment surdeacutefinir lopeacuterateur [] au sein dune classe

tableau Neacuteanmoins nous nous sommes toujours limiteacute agrave des tableaux agrave un indice

Ici nous allons voir qursquoil est tregraves facile une fois qursquoon a deacutefini un patron de tableau agrave un

indice de lappliquer agrave un tableau agrave deux indices (ou plus) par le simple jeu de la composition

des patrons

Si nous consideacuterons pour linstant la classe tableau deacutefinie de cette faccedilon simplifieacutee

template ltclass T int ngt class tableau

T tab [n]

public

T amp operator [] (int i) opeacuterateur []

return tab[i]

nous pouvons tout agrave fait deacuteclarer

tableau lttableaultint2gt3gt t2d

En effet t2d est un tableau de 3 eacuteleacutements ayant chacun le type tableau ltint2gt autrement

dit chacun de ces 3 eacuteleacutements est lui-mecircme un tableau de 2 entiers

Une notation telle que t2d [1] [2] a un sens elle repreacutesente la reacutefeacuterence au troisiegraveme eacuteleacutement

de t2d [1] cest-agrave-dire au troisiegraveme eacuteleacutement du deuxiegraveme tableau de deux entiers de t2d

Voici un exemple complet (mais toujours simplifieacute) illustrant cela Nous avons simplement

ajouteacute artificiellement un constructeur afin dobtenir une trace des diffeacuterentes constructions

impleacutementation dun tableau agrave deux dimensions

include ltiostreamgt

using namespace std

Les patrons de classesCHAPITRE 12

242

template ltclass T int ngt class tableau

T tab [n]

public

tableau () constructeur

cout ltlt construction tableau a ltlt n ltlt elementsn

T amp operator [] (int i) opeacuterateur []

return tab[i]

main()

tableau lttableaultint2gt3gt t2d

t2d [1] [2] = 15

cout ltlt t2d [1] [2] = ltlt t2d [1] [2] ltlt n

cout ltlt t2d [0] [1] = ltlt t2d [0] [1] ltlt n

construction tableau a 2 elements

construction tableau a 2 elements

construction tableau a 2 elements

construction tableau a 3 elements

t2d [1] [2] = 15

t2d [0] [1] = -858993460

Utilisation du patron tableau pour manipuler des tableaux agrave deux indices (1)

On notera bien que notre patron tableau est a priori un tableau agrave un indice Seule la maniegravere

dont on lutilise permet de lappliquer agrave des tableaux agrave un nombre quelconque dindices

Manifestement cet exemple est trop simpliste dailleurs tel quel il napporte rien de plus

quun banal tableau Pour le rendre plus reacutealiste nous allons preacutevoir

bull de geacuterer les deacutebordements dindices ici nous nous contenterons dafficher un message et

de faire comme si lutilisateur avait fourni un indice nul1

bull dinitialiser tous les eacuteleacutements du tableau lors de sa construction nous utiliserons pour ce fai-

re la valeur 0 Mais encore faut-il que la chose soit possible cest-agrave-dire que quel que soit

le type T des eacuteleacutements du tableau on puisse leur affecter la valeur 0 Cela signifie quil doit

exister une conversion de T en int Il est facile de la reacutealiser avec un constructeur agrave un eacuteleacute-

ment de type int Du mecircme coup cela permettra de preacutevoir une valeur initiale lors de la deacute-

claration dun tableau (par seacutecuriteacute nous preacutevoirons la valeur 0 par deacutefaut)

Voici la classe ainsi modifieacutee et un exemple dutilisation

1 Il pourrait eacutegalement ecirctre judicieux de deacuteclencher une exception comme nous apprendrons agrave le faire sur ce

mecircme exemple au paragraphe 1 du chapitre 17

9 - Exemple de classe tableau agrave deux indices243

impleacutementation dun tableau 2d avec test deacutebordement dindicesinclude ltiostreamgtusing namespace std template ltclass T int ngt class tableau T tab [n] int limite nombre deacuteleacutements du tableau public tableau (int init=0) int i for (i=0 iltn i++) tab[i] = init il doit exister un constructeur agrave un argument pour le cas ougrave tab[i] est un objet limite = n-1 cout ltlt appel constructeur tableau de taille ltlt n ltlt init = ltlt init ltlt n T amp operator [] (int i) if (ilt0 || igtlimite) cout ltlt --debordement ltlt i ltlt n i=0 choix arbitraire return tab[i] main() tableau lttableaultint3gt2gt ti pas dinitialisation tableau lttableaultfloat4gt2gt td (10) initialisation agrave 10 ti [1] [6] = 15 ti [8] [-1] = 20 cout ltlt ti [1] [2] ltlt n eacuteleacutement initialiseacute agrave valeur par deacutefaut (0) cout ltlt td [1] [0] ltlt n eacuteleacutement initialiseacute explicitement

appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 3 init = 0appel constructeur tableau de taille 2 init = 0appel constructeur tableau de taille 4 init = 0appel constructeur tableau de taille 4 init = 0appel constructeur tableau de taille 4 init = 10appel constructeur tableau de taille 4 init = 10appel constructeur tableau de taille 2 init = 10--debordement 6--debordement 8--debordement -1010

Utilisation du patron tableau pour manipuler des tableaux agrave deux indices (2)

Les patrons de classesCHAPITRE 12

244

Remarque

Si vous examinez bien les messages de construction des diffeacuterents tableaux vous obser-

verez que lon obtient deux fois plus de messages que preacutevu pour les tableaux agrave un indice

Lexplication reacuteside dans linstruction tab[i] = init du constructeur tableau En effet lors-

que tab[i] deacutesigne un eacuteleacutement de type de base il y a simplement conversion de la valeur

entiegravere init dans ce type de base En revanche lorsque lon a affaire agrave un objet de type T

(ici T est de la forme tableaultgt) cette instruction provoque lappel du constructeur

tableau(int) pour creacuteer un objet temporaire de ce type Cela se voit tregraves clairement dans le

cas du tableau td pour lequel on trouve une construction dun tableau temporaire initialiseacute

avec la valeur 0 et une construction dun tableau initialiseacute avec la valeur 10

13

Lrsquoheacuteritage simple

On sait que le concept dheacuteritage (on parle eacutegalement de classes deacuteriveacutees) constitue lun des

fondements de la POO En particulier il est agrave la base des possibiliteacutes de reacuteutilisation de

composants logiciels (en loccurrence de classes) En effet il vous autorise agrave deacutefinir une nou-

velle classe dite deacuteriveacutee agrave partir dune classe existante dite de base La classe deacuteriveacutee

heacuteritera des potentialiteacutes de la classe de base tout en lui en ajoutant de nouvelles et cela

sans quil soit neacutecessaire de remettre en question la classe de base Il ne sera pas utile de la

recompiler ni mecircme de disposer du programme source correspondant (exception faite de sa

deacuteclaration)

Cette technique permet donc de deacutevelopper de nouveaux outils en se fondant sur un certain

acquis ce qui justifie le terme dheacuteritage Bien entendu plusieurs classes pourront ecirctre deacuteri-

veacutees dune mecircme classe de base En outre lrsquoheacuteritage nest pas limiteacute agrave un seul niveau une

classe deacuteriveacutee peut devenir agrave son tour classe de base pour une autre classe On voit ainsi

apparaicirctre la notion dheacuteritage comme outil de speacutecialisation croissante

Qui plus est nous verrons que C++ (depuis la version 20) autorise lrsquoheacuteritage multiple gracircce

auquel une classe peut ecirctre deacuteriveacutee de plusieurs classes de base

Nous commencerons par vous preacutesenter la mise en œuvre de lrsquoheacuteritage en C++ agrave partir drsquoun

exemple tregraves simple Nous examinerons ensuite comment agrave limage de ce qui se passait dans

le cas dobjets membres C++ offre un meacutecanisme inteacuteressant de transmission dinformations

entre constructeurs (de la classe deacuteriveacutee et de la classe de base) Puis nous verrons la sou-

plesse que preacutesente le C++ en matiegravere de controcircle des accegraves de la classe deacuteriveacutee aux membres

de la classe de base (aussi bien au niveau de la conception de la classe de base que de celle de

la classe deacuteriveacutee)

Lrsquoheacuteritage simpleCHAPITRE 13

246

Nous aborderons ensuite les problegravemes de compatibiliteacute entre une classe de base et une classe

deacuteriveacutee tant au niveau des objets eux-mecircmes que des pointeurs sur ces objets ou des reacutefeacuteren-

ces agrave ces objets Ces aspects deviendront fondamentaux dans la mise en œuvre du polymor-

phisme par le biais des meacutethodes virtuelles Nous examinerons alors ce quil advient du

constructeur de recopie de lopeacuterateur drsquoaffectation et des patrons de classes

Enfin apregraves avoir examineacute les situations de deacuterivations successives nous apprendrons agrave

exploiter concregravetement une classe deacuteriveacutee

Quant agrave lheacuteritage multiple il fera lobjet du chapitre suivant

1 La notion drsquoheacuteritageExposons tout drsquoabord les bases de la mise en œuvre de lrsquoheacuteritage en C++ agrave partir drsquoun exem-

ple simple ne faisant pas intervenir de constructeur ou de destructeur et ougrave le controcircle des

accegraves est limiteacute

Consideacuterons la premiegravere classe point deacutefinie au chapitre 5 dont nous rappelons la

deacuteclaration

------------ Deacuteclaration de la classe point ------------- class point deacuteclaration des membres priveacutes int x int y deacuteclaration des membres publics public void initialise (int int) void deplace (int int) void affiche ()

Deacuteclaration drsquoune classe de base (point)

Supposons que nous ayons besoin de deacutefinir un nouveau type classe nommeacute pointcol destineacute

agrave manipuler des points coloreacutes dun plan Une telle classe peut manifestement disposer des

mecircmes fonctionnaliteacutes que la classe point auxquelles on pourrait adjoindre par exemple

une meacutethode nommeacutee colore chargeacutee de deacutefinir la couleur Dans ces conditions nous pou-

vons ecirctre tenteacutes de deacutefinir pointcol comme une classe deacuteriveacutee de point Si nous preacutevoyons

(pour linstant) une fonction membre speacutecifique agrave pointcol nommeacutee colore et destineacutee agrave attri-

buer une couleur agrave un point coloreacute voici ce que pourrait ecirctre la deacuteclaration de pointcol (la

fonction colore est ici en ligne)

1 - La notion drsquoheacuteritage247

class pointcol public point pointcol deacuterive de point short couleur public void colore (short cl) couleur = cl

Une classe pointcol deacuteriveacutee de point

Notez la deacuteclaration

class pointcol public point

Elle speacutecifie que pointcol est une classe deacuteriveacutee de la classe de base point De plus le mot

public signifie que les membres publics de la classe de base (point) seront des membres

publics de la classe deacuteriveacutee (pointcol) cela correspond agrave lideacutee la plus freacutequente que lon

peut avoir de lrsquoheacuteritage sur le plan geacuteneacuteral de la POO Nous verrons plus loin dans le para-

graphe consacreacute au controcircle des accegraves agrave quoi conduirait lomission du mot public

La classe pointcol ainsi deacutefinie nous pouvons deacuteclarer des objets de type pointcol de maniegravere

usuelle

pointcol p q

Chaque objet de type pointcol peut alors faire appel

bull aux meacutethodes publiques de pointcol (ici colore)

bull aux meacutethodes publiques de la classe de base point (ici init deplace et affiche)

Voici un programme illustrant ces possibiliteacutes Vous nrsquoy trouverez pas la liste de la classe

point car nous nous sommes placeacute dans les conditions habituelles drsquoutilisation drsquoune classe

deacutejagrave au point Plus preacuteciseacutement nous supposons que nous disposons

bull drsquoun module objet relatif agrave la classe point qursquoil est neacutecessaire drsquoincorporer au moment de

lrsquoeacutedition de liens

bull drsquoun fichier nommeacute ici pointh contenant la deacuteclaration de la classe point

include ltiostreamgtinclude pointh incorporation des deacuteclarations de pointusing namespace std --- Deacuteclaration et deacutefinition de la classe pointcol ----- class pointcol public point pointcol deacuterive de point short couleur public void colore (short cl) couleur = cl main() pointcol p pinitialise (1020) pcolore (5) paffiche ()

Lrsquoheacuteritage simpleCHAPITRE 13

248

pdeplace (24) paffiche ()

Je suis en 10 20Je suis en 12 24

Exemple dutilisation dune classe pointcol deacuteriveacutee de point

2 Utilisation des membres de la classe de base dans une classe deacuteriveacutee

Lrsquoexemple preacuteceacutedent destineacute agrave montrer comment sexprime lrsquoheacuteritage en C++ ne cherchait

pas agrave en explorer toutes les possibiliteacutes notamment en matiegravere de controcircle des accegraves Pour

lrsquoinstant nous savons simplement que gracircce agrave lemploi du mot public les membres publics

de point sont eacutegalement membres publics de pointcol Cest ce qui nous a permis de les utili-

ser au sein de la fonction main par exemple dans linstruction pinitialise (10 20)

Or la classe pointcol telle que nous lavons deacutefinie preacutesente des lacunes Par exemple lorsque

nous appelons affiche pour un objet de type pointcol nous nobtenons aucune information sur

sa couleur Une premiegravere faccedilon dameacuteliorer cette situation consiste agrave eacutecrire une nouvelle

fonction membre publique de pointcol censeacutee afficher agrave la fois les coordonneacutees et la couleur

Appelons-la pour linstant affichec (nous verrons plus tard quil est possible de lappeler eacutega-

lement affiche)

A ce niveau vous pourriez penser deacutefinir affichec de la maniegravere suivante

void affichec ()

cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n cout ltlt et ma couleur est ltlt couleur ltlt n

Mais alors cela signifierait que la fonction affichec membre de pointcol aurait accegraves aux

membres priveacutes de point ce qui serait contraire au principe dencapsulation En effet il

deviendrait alors possible deacutecrire une fonction acceacutedant directement1 aux donneacutees priveacutees

dune classe simplement en creacuteant une classe deacuteriveacutee Dougrave la regravegle adopteacutee par C++

En revanche une meacutethode drsquoune classse deacuteriveacutee a accegraves aux membres publics de sa classe de

base Ainsi dans le cas qui nous preacuteoccupe si notre fonction membre affichec ne peut pas

1 Cest-agrave-dire sans passer par linterface obligatoire constitueacutee par les fonctions membres publiques

Une meacutethode drsquoune classe deacuteriveacutee nrsquoa pas accegraves aux membres priveacutes de sa classe de base

2 - Utilisation des membres de la classe de base dans une classe deacuteriveacutee249

acceacuteder directement aux donneacutees priveacutees x et y de la classe point elle peut neacuteanmoins faire

appel agrave la fonction affiche de cette mecircme classe Dougrave une deacutefinition possible de affichec

void pointcolaffichec () affiche () cout ltlt et ma couleur est ltlt couleur ltlt n

Une fonction daffichage pour un objet de type pointcol

Notez bien que au sein de affichec nous avons fait directement appel agrave affiche sans avoir agrave

speacutecifier agrave quel objet cette fonction devait ecirctre appliqueacutee par convention il sagit de

celui ayant appeleacute affichec Nous retrouvons la mecircme regravegle que pour les fonctions membres

dune mecircme classe En fait il faut deacutesormais consideacuterer que affiche est une fonction membre

de pointcol1

Dune maniegravere analogue nous pouvons deacutefinir dans pointcol une nouvelle fonction dinitiali-

sation nommeacutee initialisec chargeacutee dattribuer des valeurs aux donneacutees x y et couleur agrave partir

de trois valeurs reccedilues en argument

void pointcolinitialisec (int abs int ord short cl)

initialise (abs ord) couleur = cl

Une fonction dinitialisation pour un objet de type pointcol

Voici un exemple complet de programme reprenant la deacutefinition de la classe pointcol (nous

supposons que la deacutefinition de la classe point est fournie seacutepareacutement et que sa deacuteclaration

figure dans pointh

include ltiostreamgtinclude pointh deacuteclaration de la classe point (neacutecessaire pour compiler la deacutefinition de pointcol) using namespace std class pointcol public point short couleur

public void colore (short cl) couleur = cl void affichec ()

1 Mais ce ne serait pas le cas si affiche neacutetait pas une fonction publique de point

Lrsquoheacuteritage simpleCHAPITRE 13

250

void initialisec (int int short) void pointcolaffichec () affiche () cout ltlt et ma couleur est ltlt couleur ltlt n void pointcolinitialisec (int abs int ord short cl) initialise (abs ord) couleur = cl main() pointcol p pinitialisec (1020 5) paffichec () paffiche () pdeplace (24) paffichec () pcolore (2) paffichec ()

Je suis en 10 20 et ma couleur est 5Je suis en 10 20Je suis en 12 24 et ma couleur est 5Je suis en 12 24 et ma couleur est 2

Une nouvelle classe pointcol et son utilisation

En Java

La notion drsquoheacuteritage existe bien sucircr en Java Elle fait appel au mot cleacute extends agrave la place

de public On peut interdire agrave une classe de donner naissance agrave une classe deacuteriveacutee en la

qualifiant avec le mot cleacute final une telle possibiliteacute nrsquoexiste pas en C++

3 Redeacutefinition des membres drsquoune classe deacuteriveacutee

31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacuteeDans le dernier exemple de classe pointcol nous disposions agrave la fois

bull dans point dune fonction membre nommeacutee affiche

bull dans pointcol dune fonction membre nommeacutee affichec

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee251

Or ces deux meacutethodes font le mecircme travail agrave savoir afficher les valeurs des donneacutees de leur

classe Dans ces conditions on pourrait souhaiter leur donner le mecircme nom Ceci est effecti-

vement possible en C++ moyennant une petite preacutecaution En effet au sein de la fonction

affiche de pointcol on ne peut plus appeler la fonction affiche de point comme auparavant

cela provoquerait un appel reacutecursif de la fonction affiche de pointcol Il faut alors faire appel

agrave lopeacuterateur de reacutesolution de porteacutee () pour localiser convenablement la meacutethode voulue

(ici on appellera pointaffiche)

De maniegravere comparable si pour un objet p de type pointcol on appelle la fonction paffiche

il sagira de la fonction redeacutefinie dans pointcol Si lon tient absolument agrave utiliser la fonction

affiche de la classe point on appellera ppointaffiche

Voici comment nous pouvons transformer lrsquoexemple du paragraphe preacuteceacutedent en nommant

affiche et initialise les nouvelles fonctions membres de pointcol

include ltiostreamgtinclude pointhusing namespace std class pointcol public point short couleur public void colore (short cl) couleur = cl void affiche () redeacutefinition de affiche de point void initialise (int int short) redeacutefinition de initialise de point void pointcolaffiche () pointaffiche () appel de affiche de la classe point cout ltlt et ma couleur est ltlt couleur ltlt n void pointcolinitialise (int abs int ord short cl) pointinitialise (abs ord) appel de initialise de la classe point couleur = cl main() pointcol p pinitialise (1020 5) paffiche () ppointaffiche () pour forcer lappel de affiche de point pdeplace (24) paffiche () pcolore (2) paffiche ()

Je suis en 10 20 et ma couleur est 5Je suis en 10 20Je suis en 12 24 et ma couleur est 5Je suis en 12 24 et ma couleur est 2

Une classe pointcol dans laquelle les meacutethodes initialise et affiche sont redeacutefinies

Lrsquoheacuteritage simpleCHAPITRE 13

252

En Java

On a deacutejagrave dit que Java permettait drsquointerdire agrave une classe de donner naissance agrave des clas-

ses deacuteriveacutees Ce langage permet eacutegalement drsquointerdire la redeacutefinition drsquoune fonction

membre en la deacuteclarant avec le mot cleacute final dans la classe de base

32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacuteeBien que cela soit dun emploi moins courant ce que nous avons dit agrave propos de la redeacutefini-

tion des fonctions membres sapplique tout aussi bien aux membres donneacutees Plus preacuteciseacute-

ment si une classe A est deacutefinie ainsi

class A int a char b

une classe B deacuteriveacutee de A pourra par exemple deacutefinir un autre membre donneacutee nommeacute a

class B public A float a

Dans ce cas si lobjet b est de type B ba fera reacutefeacuterence au membre a de type float de b Il

sera toujours possible dacceacuteder au membre donneacutee a de type int (heacuteriteacute de A) par bAa1

Notez bien que le membre a deacutefini dans B sajoute au membre a heacuteriteacute de A il ne le rem-

place pas

33 Redeacutefinition et surdeacutefinitionIl va de soi que lorsqursquoune fonction est redeacutefinie dans une classe deacuteriveacutee elle masque une

fonction de mecircme signature de la classe de base En revanche comme on va le voir les cho-

ses sont moins naturelles en cas de surdeacutefinition ou mecircme de mixage entre ces deux possibi-

liteacutes Consideacuterez

class A public void f(int n) f est surdeacutefinie void f(char c) dans A class B public A public void f(float x) on ajoute une troisegraveme deacutefinition dans B

1 En supposant bien sucircr que les accegraves en question soient autoriseacutes

3 - Redeacutefinition des membres drsquoune classe deacuteriveacutee253

main()

int n char c A a B b

af(n) appelle Af(int) (regravegles habituelles)

af(c) appelle Af(char) (regravegles habituelles)

bf(n) appelle Bf(float) (alors que peut-ecirctre Af(int) conviendrait)

bf(c) appelle Bf(float) (alors que peut-ecirctre Af(char) conviendrait)

Ici on a ajouteacute dans B une troisiegraveme version de f pour le type float Pour reacutesoudre les appels

bf(n) et bf(c) le compilateur nrsquoa consideacutereacute que la fonction f de B qui srsquoest trouveacutee appeleacutee

dans les deux cas Si aucune fonction f nrsquoavait eacuteteacute deacutefinie dans B on aurait utiliseacute les fonc-

tions f(int) et (char) de A

Le mecircme pheacutenomegravene se produirait si lrsquoon effectuait dans B une redeacutefinition de lrsquoune des

fonctions f de A comme dans

class A

public

void f(int n) f est surdeacutefinie

void f(char c) dans A

class B public A

public

void f(int n) on redeacutefinit f(int) dans B

main()

int n char c B b

bf(n) appelle B(int)

bf(c) appelle Bf(int)

Dans ce dernier cas on voit qursquoune redeacutefinition drsquoune meacutethode dans une classe deacuteriveacutee cache

en quelque sorte les autres Voici un dernier exemple

class A

public

void f(int n)

void f(char c)

class B public A

public

void f(int int)

main()

int n char c B b

bf(n) erreur de compilation

bf(c) erreur de compilation

Ici pour les appels bf(n) et bf(c) le compilateur nrsquoa consideacutereacute que lrsquounique fonction

f(int int) de B laquelle ne convient manifestement pas

Lrsquoheacuteritage simpleCHAPITRE 13

254

En reacutesumeacute

On voit drsquoailleurs que cette particulariteacute peut ecirctre employeacutee pour interdire lrsquoemploi dans une

classe deacuteriveacutee drsquoune fonction membre drsquoune classe de base il suffit drsquoy deacutefinir une fonction

priveacutee de mecircme nom (peu importent ses arguments et sa valeur de retour)

Remarque

Il est possible drsquoimposer que la recherche drsquoune fonction surdeacutefinie se fassse dans plu-

sieurs classes en utilisant une directive using Par exemple si dans la classe A preacuteceacutedente

on introduit (agrave un niveau public) lrsquoinstruction

using Af on reacuteintroduit les fonctions f de A

lrsquoinstruction bf(c) conduira alors agrave lrsquoappel de Af(char) (le comportement des autres

appels restant ici le mecircme)

En Java on considegravere toujours lrsquoensemble des meacutethodes de nom donneacute agrave la fois dans la

classe concerneacutee et dans toutes ses ascendantes

4 Appel des constructeurs et des destructeurs

41 RappelsRappelons lessentiel des regravegles concernant lappel dun constructeur ou du destructeur dune

classe (dans le cas ougrave il ne sagit pas dune classe deacuteriveacutee)

bull Sil existe au moins un constructeur toute creacuteation dun objet (par deacuteclaration ou par new)

entraicircnera lappel dun constructeur choisi en fonction des informations fournies en argu-

ments Si aucun constructeur ne convient il y a erreur de compilation Il est donc impossible

dans ce cas de creacuteer un objet sans qursquoun constructeur ne soit appeleacute

bull Sil nexiste aucun constructeur il nest pas possible de preacuteciser des informations lors de la

creacuteation dun objet Cette fois il devient possible de creacuteer un objet sans qursquoun constructeur

ne soit appeleacute1 (crsquoest mecircme la seule faccedilon de le faire )

bull Sil existe un destructeur il sera appeleacute avant la destruction de lobjet

Lorsqursquoune fonction membre est deacutefinie dans une classe elle masque toutes les fonctions membres de mecircme nom de la classe de base (et des classes ascendan-tes) Autrement dit la recherche drsquoune fonction (surdeacutefinie ou non) se fait dans une seule porteacutee soit celle de la classe concerneacutee soit celle de la classe de base (ou drsquoune classe ascendante) mais jamais dans plusieurs classes agrave la fois

1 On dit aussi parfois qursquoil y a appel du constructeur par deacutefaut

4 - Appel des constructeurs et des destructeurs255

42 La hieacuterarchisation des appelsCes regravegles se geacuteneacuteralisent au cas des classes deacuteriveacutees en tenant compte de laspect hieacuterarchi-

que quelles introduisent Pour fixer les ideacutees supposons que chaque classe possegravede un cons-

tructeur et un destructeur

class A class B public A public public A () B () ~A () ~B ()

Pour creacuteer un objet de type B il faut tout dabord creacuteer un objet de type A donc faire appel au

constructeur de A puis le compleacuteter par ce qui est speacutecifique agrave B et faire appel au construc-

teur de B Ce meacutecanisme est pris en charge par C++ il ny aura pas agrave preacutevoir dans le cons-

tructeur de B lappel du constructeur de A

La mecircme deacutemarche sapplique aux destructeurs lors de la destruction dun objet de type B il

y aura automatiquement appel du destructeur de B puis appel de celui de A (les destructeurs

sont appeleacutes dans lordre inverse de lappel des constructeurs)

43 Transmission dinformations entre constructeursToutefois un problegraveme se pose lorsque le constructeur de A neacutecessite des arguments En

effet les informations fournies lors de la creacuteation dun objet de type B sont a priori destineacutes agrave

son constructeur En fait C++ a preacutevu la possibiliteacute de speacutecifier dans la deacutefinition dun

constructeur dune classe deacuteriveacutee les informations que lon souhaite transmettre agrave un cons-

tructeur de la classe de base Le meacutecanisme est le mecircme que celui que nous vous avons

exposeacute dans le cas des objets membres (au paragraphe 5 du chapitre 7) Par exemple si lon a

ceci

class point class pointcol public point public public point (int int) pointcol (int int char)

et que lon souhaite que pointcol retransmette agrave point les deux premiegraveres informations reccedilues

on eacutecrira son en-tecircte de cette maniegravere

pointcol (int abs int ord char cl) point (abs ord)

Le compilateur mettra en place la transmission au constructeur de point des informations abs

et ord correspondant (ici) aux deux premiers arguments de pointcol Ainsi la deacuteclaration

pointcol a (10 15 3)

entraicircnera

bull lappel de point qui recevra les arguments 10 et 15

bull lappel de pointcol qui recevra les arguments 10 15 et 3

Lrsquoheacuteritage simpleCHAPITRE 13

256

En revanche la deacuteclaration

pointcol q (5 2)

sera rejeteacutee par le compilateur puisquil nexiste aucun constructeur pointcol agrave deux argu-

ments

Bien entendu il reste toujours possible de mentionner des arguments par deacutefaut dans point-

col par exemple

pointcol (int abs = 0 int ord = 0 char cl = 1) point (abs ord)

Dans ces conditions la deacuteclaration

pointcol b (5)

entraicircnera

bull lappel de point avec les arguments 5 et 0

bull lappel de pointcol avec les arguments 5 0 et 1

Notez que la preacutesence eacuteventuelle darguments par deacutefaut dans point na aucune incidence ici

(mais on peut les avoir preacutevus pour les objets de type point)

En Java

La transmission drsquoinformations entre un constructeur drsquoune classe deacuteriveacutee et un construc-

teur drsquoune classe de base reste possible mais elle srsquoexprime de faccedilon diffeacuterente Dans un

constructeur drsquoune classe deacuteriveacutee il est neacutecessaire de preacutevoir lrsquoappel explicite drsquoun cons-

tructeur drsquoune classe de base on utilise alors le mot super pour deacutesigner la classe de

base

44 ExempleVoici un exemple complet de programme illustrant cette situation les classes point et point-

col ont eacuteteacute limiteacutees agrave leurs constructeurs et destructeurs (ce qui leur enlegraveverait bien sucircr tout

inteacuterecirct en pratique)

include ltiostreamgtsing namespace std classe point class point int x y public point (int abs=0 int ord=0) constructeur de point (inline) cout ltlt ++ constr point ltlt abs ltlt ltlt ord ltlt n x = abs y =ord ~point () destructeur de point (inline) cout ltlt -- destr point ltlt x ltlt ltlt y ltlt n

4 - Appel des constructeurs et des destructeurs257

classe pointcol class pointcol public point short couleur public pointcol (int int short) deacuteclaration constructeur pointcol ~pointcol () destructeur de pointcol (inline) cout ltlt -- dest pointcol - couleur ltlt couleur ltlt n pointcolpointcol (int abs=0 int ord=0 short cl=1) point (abs ord) cout ltlt ++ constr pointcol ltlt abs ltlt ltlt ord ltlt ltlt cl ltlt n couleur = cl programme dessai main() pointcol a(10153) objets pointcol b (23) automatiques pointcol c (12) pointcol adr adr = new pointcol (1225) 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 12 25++ constr pointcol 12 25 1-- dest pointcol - couleur 1-- destr point 12 25-- dest pointcol - couleur 1-- destr point 12 0-- dest pointcol - couleur 1-- destr point 2 3-- dest pointcol - couleur 3-- destr point 10 15

Appel des constructeurs et destructeurs de la classe de base et de la classe deacuteriveacutee

Remarque

Dans le message afficheacute par ~pointcol vous auriez peut ecirctre souhaiteacute voir apparaicirctre les

valeurs de x et de y Or cela nest pas possible du moins telle que la classe point a eacuteteacute con-

ccedilue En effet un membre dune classe deacuteriveacutee na pas accegraves aux membres priveacutes de la

classe de base Nous reviendrons sur cet aspect fondamental dans la conception de classes

reacuteutilisables

Lrsquoheacuteritage simpleCHAPITRE 13

258

45 CompleacutementsNous venons dexaminer la situation la plus usuelle la classe de base et la classe deacuteriveacutee

posseacutedaient au moins un constructeur

Si la classe de base ne possegravede pas de constructeur aucun problegraveme particulier ne se pose Il

en va de mecircme si elle ne possegravede pas de destructeur

En revanche si la classe deacuteriveacutee ne possegravede pas de constructeur alors que la classe de base

en comporte le problegraveme de la transmission des informations attendues par le constructeur

de la classe de base se pose de nouveau Comme celles-ci ne peuvent plus provenir du cons-

tructeur de la classe deacuteriveacutee on comprend que la seule situation acceptable soit celle ougrave la

classe de base dispose dun constructeur sans argument Dans les autres cas on aboutit agrave une

erreur de compilation

Par ailleurs lorsque lon mentionne les informations agrave transmettre agrave un constructeur de la

classe de base on nest pas obligeacute de se limiter comme nous lavons fait jusquici agrave des noms

darguments On peut employer nimporte quelle expression Par exemple bien que cela nait

guegravere de sens ici nous pourrions eacutecrire

pointcol (int abs int ord char cl) point (abs + ord abs - ord)

Remarque

Le cas du constructeur de recopie sera examineacute un peu plus loin car sa bonne mise en

œuvre neacutecessite la connaissance des possibiliteacutes de conversion implicite dune classe deacuteri-

veacutee en une classe de base

5 Controcircle des accegravesNous navons examineacute jusquici que la situation drsquoheacuteritage la plus naturelle cest-agrave-dire celle

dans laquelle

bull la classe deacuteriveacutee1 a accegraves aux membres publics de la classe de base

bull les utilisateurs2 de la classe deacuteriveacutee ont accegraves agrave ses membres publics ainsi quaux mem-

bres publics de sa classe de base

Comme nous allons le voir maintenant C++ permet dintervenir en partie sur ces deux sortes

dautorisation daccegraves et ce agrave deux niveaux

Lors de la conception de la classe de base en plus des statuts publics et priveacutes que nous

connaissons il existe un troisiegraveme statut dit proteacutegeacute (mot cleacute protected) Les membre pro-

1 Crsquoest-agrave-dire toute fonction membre dune classe deacuteriveacutee

2 Crsquoest-agrave-dire tout objet du type de la classe deacuteriveacutee

5 - Controcircle des accegraves259

teacutegeacutes se comportent comme des membres priveacutes pour lutilisateur de la classe deacuteriveacutee mais

comme des membres publics pour la classe deacuteriveacutee elle-mecircme

Lors de la conception de la classe deacuteriveacutee on peut restreindre les possibiliteacutes daccegraves aux

membres de la classe de base

51 Les membres proteacutegeacutesJusquici nous avons consideacutereacute quil nexistait que deux statuts possibles pour un membre

de classe

bull priveacute le membre nest accessible quaux fonctions membres (publiques ou priveacutees) et aux

fonctions amies de la classe

bull public le membre est accessible non seulement aux fonctions membres ou aux fonctions

amies mais eacutegalement agrave lutilisateur de la classe (cest-agrave-dire agrave nimporte quel objet du type

de cette classe)

Nous avons vu que lemploi des mots cleacutes public et private permettait de distinguer les mem-

bres priveacutes des membres publics

Le troisiegraveme statut ndash proteacutegeacute ndash est deacutefini par le mot cleacute protected qui semploie comme les

deux mots cleacutes preacuteceacutedents Par exemple la deacutefinition dune classe peut prendre lallure

suivante

class X private partie priveacutee protected partie proteacutegeacutee public partie publique

Les membres proteacutegeacutes restent inaccessibles agrave lutilisateur de la classe pour qui ils apparais-

sent comme des membres priveacutes Mais ils seront accessibles aux membres dune eacuteventuelle

classe deacuteriveacutee tout en restant dans tous les cas inaccessibles aux utilisateurs de cette classe

52 ExempleAu deacutebut du paragraphe 2 nous avons eacutevoqueacute limpossibiliteacute pour une fonction membre

dune classe pointcol deacuteriveacutee de point dacceacuteder aux membres priveacutes x et y de point Si nous

deacutefinissons ainsi notre classe point

class point protected int x y public point ( ) affiche ()

Lrsquoheacuteritage simpleCHAPITRE 13

260

il devient possible de deacutefinir dans pointcol une fonction membre affiche de la maniegravere

suivante

class pointcol public point short couleur public void affiche () cout ltlt Je suis en ltlt x ltlt ltlt y ltlt n cout ltlt et ma couleur est ltlt couleur ltlt n

53 Inteacuterecirct du statut proteacutegeacuteLes membres priveacutes dune classe sont deacutefinitivement inaccessibles depuis ce que nous

appellerons lexteacuterieur de la classe (objets de cette classe fonctions membres dune classe

deacuteriveacutee objets de cette classe deacuteriveacutee) Cela peut poser des problegravemes au concepteur dune

classe deacuteriveacutee notamment si ces membres sont des donneacutees dans la mesure ougrave il est con-

traint comme un banal utilisateur de passer par linterface obligatoire De plus cette

faccedilon de faire peut nuire agrave lefficaciteacute du code geacuteneacutereacute

Lintroduction du statut proteacutegeacute constitue donc un progregraves manifeste les membres proteacutegeacutes

se preacutesentent comme des membres priveacutes pour lutilisateur de la classe mais ils sont compa-

rables agrave des membres publics pour le concepteur dune classe deacuteriveacutee (tout en restant compa-

rables agrave des membres priveacutes pour lutilisateur de cette derniegravere) Neacuteanmoins il faut

reconnaicirctre qursquoon offre du mecircme coup les moyens de violer (consciemment) le principe

dencapsulation des donneacutees En effet rien nempecircche un utilisateur dune classe comportant

une partie proteacutegeacutee de creacuteer une classe deacuteriveacutee contenant les fonctions approprieacutees permet-

tant dacceacuteder aux donneacutees correspondantes Bien entendu il sagit dun viol conccedilu deacutelibeacutereacute-

ment par lutilisateur cela na plus rien agrave voir avec des risques de modifications

accidentelles des donneacutees

Remarques

1 Lorsquune classe deacuteriveacutee possegravede des fonctions amies ces derniegraveres disposent exacte-

ment des mecircmes autorisations daccegraves que les fonctions membres de la classe deacuteriveacutee En

particulier les fonctions amies dune classe deacuteriveacutee auront bien accegraves aux membres deacutecla-

reacutes proteacutegeacutes dans sa classe de base

2 En revanche les deacuteclarations damitieacute ne sheacuteritent pas Ainsi si f a eacuteteacute deacuteclareacutee amie

dune classe A et si B deacuterive de A f nest pas automatiquement amie de B (il est bien sucircr

possible de preacutevoir une deacuteclaration drsquoamitieacute approprieacutee dans B)

5 - Controcircle des accegraves261

En Java

Le statut proteacutegeacute existe aussi en Java mais avec une signification un peu difeacuterente les

membres proteacutegeacutes sont accessibles non seulement aux classes deacuteriveacutees mais aussi aux

classes appartenant au mecircme package (la notion de package nrsquoexiste pas en C++)

54 Deacuterivation publique et deacuterivation priveacutee

541 Rappels concernant la deacuterivation publiqueLes exemples preacuteceacutedents faisaient intervenir la forme la plus courante de deacuterivation dite

publique car introduite par le mot cleacute public dans la deacuteclaration de la classe deacuteriveacutee

comme dans

class pointcol public point

Rappelons que dans ce cas

bull Les membres publics de la classe de base sont accessibles agrave tout le monde cest-agrave-dire agrave

la fois aux fonctions membres et aux fonctions amies de la classe deacuteriveacutee ainsi quaux utili-

sateurs de la classe deacuteriveacutee

bull Les membres proteacutegeacutes de la classe de base sont accessibles aux fonctions membres et aux

fonctions amies de la classe deacuteriveacutee mais pas aux utilisateurs de cette classe deacuteriveacutee

bull Les membres priveacutes de la classe de base sont inaccessibles agrave la fois aux fonctions membres

ou amies de la classe deacuteriveacutee et aux utilisateurs de cette classe deacuteriveacutee

De plus tous les membres de la classe de base conservent dans la classe deacuteriveacutee le statut

quils avaient dans la classe de base Cette remarque nintervient quen cas de deacuterivation dune

nouvelle classe de la classe deacuteriveacutee

Voici un tableau reacutecapitulant la situation

La deacuterivation publique

Ces possibiliteacutes peuvent ecirctre restreintes en deacutefinissant ce que lon nomme des deacuterivations pri-

veacutees ou proteacutegeacutees

Statut dans la classe

de base

Accegraves aux fonctions

membres et amies de

la classe deacuteriveacutee

Accegraves agrave un utilisateur

de la classe deacuteriveacutee

Nouveau statut dans la

classe deacuteriveacutee en cas

de nouvelle deacuterivation

public oui oui public

proteacutegeacute oui non proteacutegeacute

priveacute non non priveacute

Lrsquoheacuteritage simpleCHAPITRE 13

262

542 Deacuterivation priveacuteeEn utilisant le mot cleacute private au lieu du mot cleacute public il est possible dinterdire agrave un utilisa-

teur dune classe deacuteriveacutee laccegraves aux membres publics de sa classe de base Par exemple avec

ces deacuteclarations

class point class pointcol private point public public point () pointcol () void affiche () void colore () void deplace ()

Si p est de type pointcol les appels suivants seront rejeteacutes par le compilateur1

paffiche () ou mecircme ppointaffiche () pdeplace () ou mecircme ppointdeplace ()

alors que naturellement celui-ci sera accepteacute

pcolore ()

On peut agrave juste titre penser que cette technique limite linteacuterecirct de lheacuteritage Plus preacuteciseacutement

le concepteur de la classe deacuteriveacutee peut quant agrave lui utiliser librement les membres publics de

la classe de base (comme un utilisateur ordinaire) en revanche il deacutecide de fermer totale-

ment cet accegraves agrave lutilisateur de la classe deacuteriveacutee On peut dire que lutilisateur connaicirctra tou-

tes les fonctionnaliteacutes de la classe en lisant sa deacuteclaration sans quil nait aucunement besoin

de lire celle de sa classe de base (il nen allait pas de mecircme dans la situation usuelle dans les

exemples des paragraphes preacuteceacutedents pour connaicirctre lexistence de la fonction membre

deplace pour la classe pointcol il fallait connaicirctre la deacuteclaration de point)

Cela montre que cette technique de fermeture des accegraves agrave la classe de base ne sera employeacutee

que dans des cas bien preacutecis par exemple

bull lorsque toutes les fonctions utiles de la classe de base sont redeacutefinies dans la classe deacuteriveacutee

et quil ny a aucune raison de laisser lutilisateur acceacuteder aux anciennes

bull lorsque lon souhaite adapter linterface dune classe de maniegravere agrave reacutepondre agrave certaines

exigences dans ce cas la classe deacuteriveacutee peut agrave la limite ne rien apporter de plus (pas de

nouvelles donneacutees pas de nouvelles fonctionnaliteacutes) elle agit comme la classe de base

seule son utilisation est diffeacuterente

1 A moins que lune des fonctions membres affiche ou deplace nrsquoait eacuteteacute redeacutefinie dans pointcol

5 - Controcircle des accegraves263

55 Les possibiliteacutes de deacuterivation proteacutegeacutee Depuis sa version 3 C++ dispose drsquoune possibiliteacute suppleacutementaire de deacuterivation dite deacuteriva-

tion proteacutegeacutee intermeacutediaire entre la deacuterivation publique et la deacuterivation priveacutee Dans ce cas

les membres publics de la classe de base seront consideacutereacutes comme proteacutegeacutes lors de deacuteriva-

tions ulteacuterieures

On prendra garde agrave ne pas confondre le mode de deacuterivation dune classe par rapport agrave sa

classe de base (publique proteacutegeacutee ou priveacutee) deacutefini par lun des mots public protected ou

private avec le statut des membres dune classe (public proteacutegeacute ou priveacute) deacutefini eacutegalement

par lun de ces trois mots

Remarques

1 Dans le cas dune deacuterivation priveacutee les membres proteacutegeacutes de la classe de base restent

accessibles aux fonctions membres et aux fonctions amies de la classe deacuteriveacutee En revan-

che ils seront consideacutereacutes comme priveacutes pour une deacuterivation future

2 Les expressions deacuterivation publique et deacuterivation priveacutee seront ambigueumls dans le cas

dheacuteritage multiple Plus preacuteciseacutement il faudra alors dire pour chaque classe de base

quel est le type de deacuterivation (publique ou priveacutee)

3 En toute rigueur il est possible dans une deacuterivation priveacutee ou proteacutegeacutee de laisser

public un membre de la classe de base en le redeacuteclarant explicitement comme dans cet

exemple

class pointcol private point deacuterivation priveacutee public pointaffiche() la meacutethode affiche de la classe de base point sera publique dans pointcol

Depuis la norme cette deacuteclaration peut eacutegalement se faire agrave lrsquoaide du mot cleacute using1

class pointcol private point deacuterivation priveacutee public using pointaffiche() la meacutethode affiche de la classe de base point sera publique dans pointcol

1 Dont la vocation premiegravere reste cependant lrsquoutilisation de symboles deacuteclareacutes dans des espaces de noms comme

nous le verrons au chapitre 24

Lrsquoheacuteritage simpleCHAPITRE 13

264

56 ReacutecapitulationVoici un tableau reacutecapitulant les proprieacuteteacutes des diffeacuterentes sortes de deacuterivation (la mention

Accegraves FMA signifie accegraves aux fonctions membres ou amies de la classe la mention

nouveau statut signifie statut quaura ce membre dans une eacuteventuelle classe deacuteriveacutee)

Les diffeacuterentes sortes de deacuterivation

Remarque

On voit clairement quune deacuterivation proteacutegeacutee ne se distingue dune deacuterivation priveacutee que

lorsque lon est ameneacute agrave deacuteriver de nouvelles classes de la classe deacuteriveacutee en question

En Java

Alors que Java dispose des trois statuts public proteacutegeacute (avec une signification plus large

qursquoen C++) et priveacute il ne dispose que drsquoun seul mode de deacuterivation correspondant agrave la

deacuterivation publique du C++

6 Compatibiliteacute entre classe de base et classe deacuteriveacutee

Dune maniegravere geacuteneacuterale en POO on considegravere quun objet dune classe deacuteriveacutee peut rem-

placer un objet dune classe de base ou encore que lagrave ougrave un objet de classe A est attendu tout

objet dune classe deacuteriveacutee de A peut faire laffaire

Cette ideacutee repose sur le fait que tout ce que lon trouve dans une classe de base (fonctions ou

donneacutees) se trouve eacutegalement dans la classe deacuteriveacutee De mecircme toute action reacutealisable sur

une classe de base peut toujours ecirctre reacutealiseacutee sur une classe deacuteriveacutee (ce qui ne veut pas dire

pour autant que le reacutesultat sera aussi satisfaisant dans le cas de la classe deacuteriveacutee que dans

celui de la classe de base ndash on affirme seulement quune telle action est possible ) Par exem-

ple un point coloreacute peut toujours ecirctre traiteacute comme un point il possegravede des coordonneacutees on

peut les afficher en proceacutedant comme pour celles dun point

Bien entendu les reacuteciproques de ces deux propositions sont fausses par exemple on ne peut

pas colorer un point ou sinteacuteresser agrave sa couleur

Classe de base Deacuteriveacutee publique Deacuteriveacutee proteacutegeacutee Deacuteriveacutee priveacutee

Statut initial

Accegraves FMA

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

Nouveau statut

Accegraves utilisateur

public

proteacutegeacute

priveacute

O

O

O

O

N

N

public

proteacutegeacute

priveacute

O

N

N

proteacutegeacute

proteacuteg

priveacute

N

N

N

priveacute

priveacute

priveacute

N

N

N

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee265

On traduit souvent ces proprieacuteteacutes en disant que lrsquoheacuteritage reacutealise une relation est entre la

classe deacuteriveacutee et la classe de base1 tout objet de type pointcol est un point mais tout objet de

type point nrsquoest pas un pointcol

Cette compatibiliteacute entre une classe deacuteriveacutee et sa classe de base2 se retrouve en C++ avec

une leacutegegravere nuance elle ne sapplique que dans le cas de deacuterivation publique3 Concregravetement

cette compatibiliteacute se reacutesume agrave lexistence de conversions implicites

bull dun objet dun type deacuteriveacute dans un objet dun type de base

bull dun pointeur (ou dune reacutefeacuterence) sur une classe deacuteriveacutee en un pointeur (ou une reacutefeacuterence)

sur une classe de base

Nous allons voir lincidence de ces conversions sur les affectations entre objets dabord entre

pointeurs ensuite La derniegravere situation au demeurant la plus reacutepandue nous permettra de

mettre en eacutevidence

bull le typage statique des objets qui en deacutecoule ce point constituera en fait une introduction agrave

la notion de meacutethode virtuelle permettant le typage dynamique sur lequel repose le polymor-

phisme (qui fera lobjet du chapitre 15)

bull les risques de violation du principe dencapsulation qui en deacutecoulent

61 Conversion dun type deacuteriveacute en un type de baseSoit nos deux classes habituelles

class point class pointcol public point

Avec les deacuteclarations

point a pointcol b

laffectation

a = b

est leacutegale Elle entraicircne une conversion de b dans le type point4 et laffectation du reacutesultat agrave a

Cette affectation se fait suivant les cas

bull par appel de lopeacuterateur daffectation (de la classe point) si celui-ci a eacuteteacute surdeacutefini

bull par emploi de laffectation par deacutefaut dans le cas contraire

En revanche laffectation suivante serait rejeteacutee

b = a

1 Lrsquoappartenance drsquoun objet agrave un autre objet sous forme drsquoobjets membres reacutealisait une relation de type a (du verbe

avoir)

2 Ou lune de ses classes de base dans le cas de lrsquoheacuteritage multiple que nous aborderons au chapitre suivant

3 Ce qui se justifie par le fait que dans le cas contraire il suffirait de convertir un objet dune classe deacuteriveacutee dans le

type de sa classe de base pour passer outre la privatisation des membres publics du type de base

4 Cette conversion revient agrave ne conserver de b que ce qui est du type point Geacuteneacuteralement elle nrsquoentraicircne pas la

creacuteation drsquoun nouvel objet

Lrsquoheacuteritage simpleCHAPITRE 13

266

62 Conversion de pointeursConsideacuterons agrave nouveau une classe point et une classe pointcol deacuteriveacutee de point chacune

comportant une fonction membre affiche

class point class pointcol public point int x y short couleur public public void affiche () void affiche ()

Soit ces deacuteclarations

point adp pointcol adpc

Lagrave encore C++ autorise laffectation

adp = adpc

qui correspond agrave une conversion du type pointcol dans le type point

Laffectation inverse

adpc = adp

serait naturellement rejeteacutee Elle est cependant reacutealisable en faisant appel agrave lopeacuterateur de

cast Ainsi bien que sa signification soit discutable1 il vous sera toujours possible deacutecrire

linstruction

adpc = (pointcol ) adp

Remarque

Sil est possible de convertir explicitement un pointeur de type point en un pointeur de

type pointcol il est impossible de convertir un objet de type point en un objet de type

pointcol La diffeacuterence vient de ce que lon a affaire agrave une conversion preacutedeacutefinie dans le

premier cas2 alors que dans le second le compilateur ne peut imaginer ce que vous sou-

haitez faire

63 Limitations lieacutees au typage statique des objetsConsideacuterons les deacuteclarations du paragraphe preacuteceacutedent accompagneacutees de3

point p (3 5) pointcol pc (8 6 2) adp = amp p adpc = amp pc

1 Et mecircme dangereuse comme nous le verrons au paragraphe 64

2 Laquelle se borne en fait agrave un changement de type (sur le plan syntaxique) accompagneacute eacuteventuellement dun

alignement dadresse (attention rien ne garantit que lapplication successive des deux conversions reacuteciproques

(point ndashgt pointcol puis pointcol ndashgt point ) fournisse exactement ladresse initiale )

3 En supposant quil existe des constructeurs approprieacutes

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee267

La situation est alors celle-ci

A ce niveau linstruction

adp -gt affiche ()

appellera la meacutethode pointaffiche tandis que linstruction

adpc -gt affiche ()

appellera la meacutethode pointcolaffiche

Nous aurions obtenu les mecircmes reacutesultats avec

paffiche ()

pcaffiche ()

Si nous exeacutecutons alors laffectation

adp = adpc

nous aboutissons agrave cette situation

A ce niveau que va faire une instruction telle que

adp -gt affiche ()

Y aura-t-il appel de pointaffiche ou de pointcolaffiche

En effet adp est du type point mais lobjet pointeacute par adp est du type pointcol En fait le

choix de la meacutethode appeleacutee est reacutealiseacute par le compilateur ce qui signifie qursquoelle est deacutefinie

une fois pour toutes et ne pourra eacutevoluer au fil des changements eacuteventuels de type de lobjet

pointeacute Bien entendu dans ces conditions on comprend que le compilateur ne peut que deacuteci-

der de mettre en place lappel de la meacutethode correspondant au type deacutefini par le pointeur Ici

il sagira donc de pointaffiche puisque adp est du type point

adp

3

5

8

6

2

adpc

adp

3

5

8

6

2

adpc

Lrsquoheacuteritage simpleCHAPITRE 13

268

Notez bien que si pointcol dispose dune meacutethode colore (nexistant pas dans point) un appel

tel que

adp -gt colore (8)

sera rejeteacute par le compilateur

On peut donc dire pour linstant que le type des objets pointeacutes par adp et adpc est deacutecideacute et

figeacute au moment de la compilation On peut alors consideacuterer comme un leurre le fait que C++

tolegravere certaines conversions de pointeurs Drsquoailleurs il tolegravere celles qui au bout du compte

ne poseront pas de problegraveme vis-agrave-vis du choix fait au moment de la compilation (comme

nous lavons dit on pourra toujours afficher un pointcol comme sil sagissait dun point) En

effet nous pouvons deacutesigner agrave laide dun mecircme pointeur des objets de type diffeacuterent mais

nous navons pour linstant aucun moyen de tenir reacuteellement compte du type de lobjet pointeacute

(par exemple affiche traite un pointcol comme un point mais ne peut pas savoir sil sagit

dun point ou dun pointcol)

En reacutealiteacute nous verrons que C++ permet deffectuer cette identification dun objet au moment

de lexeacutecution (et non plus arbitrairement agrave la compilation) et de reacutealiser ce que lon nomme

le polymorphisme ou le typage dynamique (alors que jusquici nous navions affaire quagrave

du typage statique) Cela neacutecessitera lemploi de fonctions virtuelles que nous aborderons

au chapitre 15

Voici un exemple de programme illustrant les limitations que nous venons deacutevoquer Remar-

quez que dans la meacutethode affiche de pointcol nous navons pas fait appel agrave la meacutethode affi-

che de point pour quelle puisse acceacuteder aux membres x et y de point nous avons preacutevu de

leur donner le statut proteacutegeacute

include ltiostreamgtusing namespace std class point protected pour que x et y soient accessibles agrave pointcol int x y public point (int abs=0 int ord=0) x=abs y=ord void affiche () cout ltlt Je suis un point n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y cout ltlt et ma couleur est ltlt couleur ltlt n

6 - Compatibiliteacute entre classe de base et classe deacuteriveacutee269

main() point p(35) point adp = ampp pointcol pc (862) pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche () cout ltlt -----------------n adp = adpc adpc = adp serait rejeteacute adp-gtaffiche () adpc-gtaffiche ()

Je suis un point mes coordonnees sont 3 5Je suis un point colore mes coordonnees sont 8 6 et ma couleur est 2-----------------Je suis un point mes coordonnees sont 8 6Je suis un point colore mes coordonnees sont 8 6 et ma couleur est 2

Les limitations lieacutees au typage statique des objets

En Java

En Java comme en C++ il y a bien compatibiliteacute entre classe de base et classe deacuteriveacutee en

ce qui concerne lrsquoaffectation drsquoobjets (les pointeurs nrsquoexistent pas en Java) Mais il ne

faut pas oublier qursquoil srsquoagit drsquoaffectation de reacutefeacuterences (et non de copie effective) Par

ailleurs les problegravemes eacutevoqueacutes agrave propos du typage statique nrsquoexistent pas en Java la liga-

ture eacutetant toujours dynamique tout se passe en fait comme si tout objet posseacutedait des

fonctions virtuelles

64 Les risques de violation des protections de la classe de baseNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Nous avons vu quil eacutetait possible dans une classe deacuteriveacutee de rendre priveacutes les membres

publics heacuteriteacutes de la classe de base en recourrant agrave une deacuterivation priveacutee En voici un

exemple

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 lobjet a aura accegraves aux membres z et fa de A On pourra eacutecrire par exemple

Lrsquoheacuteritage simpleCHAPITRE 13

270

az = 525 afa ()

Par contre lobjet b naura pas accegraves agrave ces membres compte tenu du mot private figurant

dans la deacuteclaration de la classe B Dans ces conditions les instructions

bz = 83 bfa ()

seront rejeteacutees par le compilateur (agrave moins bien sucircr que les membres z et fa ne soient redeacutefi-

nis dans la classe B)

Neacuteanmoins lutilisateur de la classe B peut passer outre cette protection mise en place par le

concepteur de la classe en proceacutedant ainsi

A ada B adb adb = ampb ada = (A ) adb

ou encore plus briegravevement

A ada = (A ) amp b

Dans ces conditions ada contient effectivement ladresse de b (nous avons ducirc employer le

cast car noubliez pas que sinon la conversion deacuteriveacutee -gt base serait rejeteacutee) mais ada a

toujours le type A On peut donc maintenant acceacuteder aux membres publics de la classe A

alors qursquoils sont priveacutes pour la classe B Ces instructions seront accepteacutees

ada -gt z = 83 ada -gt fa ()

7 Le constructeur de recopie et lrsquoheacuteritageQuil sagisse de celui par deacutefaut ou de celui fourni explicitement nous savons que le cons-

tructeur de recopie est appeleacute en cas

bull dinitialisation dun objet par un objet de mecircme type

bull de transmission de la valeur dun objet en argument ou en retour dune fonction

Les regravegles que nous avons eacutenonceacutees au paragraphe 4 srsquoappliquent agrave tous les constructeurs

donc au constructeur de recopie Toutefois il faut aussi tenir compte de lexistence dun cons-

tructeur de recopie par deacutefaut Examinons les diverses situations possibles en supposant que

lon ait affaire aux instructions suivantes (B deacuterive de A)

class A class B public A void fct (B) fct est une fonction recevant un argument de type B B b1 () arguments eacuteventuels pour un constructeur usuelfct (b1) appel de fct agrave qui on doit transmettre b1 par valeur ce qui implique lappel dun constructeur de recopie de la classe B

Bien entendu tout ce que nous allons dire sappliquerait eacutegalement aux autres situations dini-

tialisation par recopie cest-agrave-dire au cas ougrave une fonction renverrait par valeur un reacutesultat de

type B ou encore agrave celui ougrave lon initialiserait un objet de type B avec un autre objet de type B

7 - Le constructeur de recopie et lrsquoheacuteritage271

comme dans B b2 = b1 ou encore B b2 (b1) (voir eacuteventuellement au paragraphe 3 du chapitre

7 et au paragraphe 4 du chapitre 7)

71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopieIl y a donc appel du constructeur de recopie par deacutefaut de B Rappelons que la recopie se fait

membre par membre Nous avons vu ce que cela signifiait dans le cas des objets membres

Ici cela signifie que la partie de b1 appartenant agrave la classe A sera traiteacutee comme un mem-

bre de type A On cherchera donc agrave appeler le constructeur de recopie de A pour les membres

donneacutees correspondants Rappelons que

bull si A a deacutefini un tel constructeur sous forme publique il sera appeleacute

bull srsquoil nrsquoexiste aucune deacuteclaration et aucune deacutefinition drsquoun tel constructeur on fera appel agrave la

construction par deacutefaut

Drsquoautre part il existe des situations intermeacutediaires (revoyez eacuteventuellement le paragraphe

313 du chapitre 7) Notamment si A deacuteclare un constructeur priveacute sans le deacutefinir en vue

drsquointerdire la recopie drsquoobjets de type A dans ce cas la recopie drsquoobjets de type B srsquoen trou-

vera eacutegalement interdite

Remarque

Cette geacuteneacuteralisation de la recopie membre par membre aux classes deacuteriveacutees pourrait lais-

ser supposer qursquoil en ira de mecircme pour lrsquoopeacuterateur drsquoaffectation (dont nous avons vu qursquoil

fonctionnait de faccedilon semblable agrave la recopie) En fait ce ne sera pas le cas nous y

reviendrons au paragraphe 8

72 La classe deacuteriveacutee deacutefinit un constructeur de recopieLe constructeur de recopie de B est alors naturellement appeleacute Mais la question qui se pose

est de savoir srsquoil y a appel drsquoun constructeur de A En fait C++ a deacutecideacute de ne preacutevoir aucun

appel automatique de constructeur de la classe de base dans ce cas (mecircme srsquoil existe un cons-

tructeur de recopie dans A ) Cela signifie que

Mais il reste possible drsquoutiliser le meacutecanisme de transmission drsquoinformations entre construc-

teurs (eacutetudieacutee au paragraphe 43) Ainsi si le constructeur de B preacutevoit des informations pour

un constructeur de A avec un en-tecircte de la forme

B (B amp x) A ()

il y aura appel du constructeur correspondant de A

Le constructeur de recopie de la classe deacuteriveacutee doit prendre en charge lrsquointeacutegra-liteacute de la recopie de lrsquoobjet et non seulement de sa partie heacuteriteacutee

Lrsquoheacuteritage simpleCHAPITRE 13

272

En geacuteneacuteral on souhaitera que le constructeur de A appeleacute agrave ce niveau soit le constructeur de

recopie de A1 Dans ces conditions on voit que ce constructeur doit recevoir en argument

non pas lrsquoobjet x tout entier mais seulement ce qui dans x est de type A Crsquoest lagrave qursquointer-

vient la possibiliteacute de conversion implicite drsquoune classe deacuteriveacutee dans une classe de base (eacutetu-

dieacutee au paragraphe 6) Il nous suffira de deacutefinir ainsi notre constructeur pour aboutir agrave une

recopie satisfaisante

B (B amp x) A (x) x de type B est converti dans le type A pour ecirctre

transmis au constructeur de recopie de A

recopie de la partie de x speacutecifique agrave B (non heacuteriteacutee de A)

Voici un programme illustrant cette possibiliteacute Nous deacutefinissons simplement nos deux clas-

ses habituelles point et pointcol en les munissant toutes les deux dun constructeur de reco-

pie2 et nous provoquons lappel de celui de pointcol en appelant une fonction fct agrave un

argument de type pointcol transmis par valeur

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0) constructeur usuel

x = abs y = ord

cout ltlt ++ point ltlt x ltlt ltlt y ltlt n

point (point amp p) constructeur de recopie

x = px y = py

cout ltlt CR point ltlt x ltlt ltlt y ltlt n

class pointcol public point

char coul

public

pointcol (int abs=0 int ord=0 int cl=1) point (abs ord) constr usuel

coul = cl

cout ltlt ++ pointcol ltlt int(coul) ltlt n

1 Bien entendu en theacuteorie il reste possible au constructeur par recopie de la classe deacuteriveacutee B drsquoappeler nrsquoimporte

quel constructeur de A autre que son constructeur par recopie Il faut alors ecirctre en mesure de reporter convenable-

ment dans lrsquoobjet les valeurs de la partie de x qui est un A Dans certains cas on pourra encore y parvenir par le

meacutecanisme de transmission drsquoinformations entre constructeurs Sinon il faudra effectuer le travail au sein du cons-

tructeur de recopie de B ce qui peut srsquoaveacuterer deacutelicat compte tenu drsquoeacuteventuels problegravemes de droits drsquoaccegraves

2 Ce qui dans ce cas preacutecis de classe ne comportant pas de pointeurs nest pas utile la recopie par deacutefaut deacutecrite

preacuteceacutedemment saveacuterant suffisante dans tous les cas Mais ici lobjectif est simplement dillustrer le meacutecanisme de

transmission drsquoinformations entre constructeurs

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage273

pointcol (pointcol amp p) point (p) constructeur de recopie

il y aura conversion implicite

de p dans le type point

coul = pcoul

cout ltlt CR pointcol ltlt int(coul) ltlt n

void fct (pointcol pc)

cout ltlt entree dans fct n

main()

void fct (pointcol)

pointcol a (234)

fct (a) appel de fct agrave qui on transmet a par valeur

++ point 2 3

++ pointcol 4

CR point 2 3

CR pointcol 4

entree dans fct

Pour forcer lappel dun constructeur de recopie de la classe de base

8 Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritageNous avons expliqueacute comment C++ deacutefinit laffectation par deacutefaut entre deux objets de

mecircme type Dautre part nous avons montreacute qursquoil eacutetait possible de surdeacutefinir cet opeacuterateur

drsquoaffectation (obligatoirement sous la forme dune fonction membre)

Voyons ce que deviennent ces possibiliteacutes en cas dheacuteritage Supposons que la classe B heacuterite

(publiquement) de A et consideacuterons comme nous lavons fait pour le constructeur de recopie

(paragraphe 7) les diffeacuterentes situations possibles

81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur =Lrsquoaffectation de deux objets de type B se deacuteroule membre agrave membre en consideacuterant que la

partie heacuteriteacutee de A constitue un membre Ainsi les membres propres agrave B sont traiteacutes par

lrsquoaffectation preacutevue pour leur type (par deacutefaut ou surdeacutefinie) La partie heacuteriteacutee de A est traiteacutee

par lrsquoaffectation preacutevue dans la classe A crsquoest-agrave-dire

bull par lrsquoopeacuterateur = surdeacutefini dans A srsquoil existe et qursquoil est public

bull par lrsquoaffectation par deacutefaut de A si lrsquoopeacuterateur = nrsquoa pas eacuteteacute redeacutefini du tout

Lrsquoheacuteritage simpleCHAPITRE 13

274

On notera bien que si lrsquoopeacuterateur = a eacuteteacute surdeacutefini sous forme priveacutee dans A son appel ne

pourra pas se faire pour un objet de type B (en dehors des fonctions membres de B) Lrsquointer-

diction de lrsquoaffectation dans A entraicircne donc drsquooffice celle de lrsquoaffectation dans B

On retrouve un comportement tout agrave fait analogue agrave celui deacutecrit dans le cas du constructeur

de recopie

82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur =Laffectation de deux objets de type B fera alors neacutecessairement appel agrave lopeacuterateur = deacutefini

dans B Celui de A ne sera pas appeleacute mecircme sil a eacuteteacute surdeacutefini Il faudra donc que lopeacutera-

teur = de B prenne en charge tout ce qui concerne laffectation dobjets de type B y

compris pour ce qui est des membres heacuteriteacutes de A

Voici un premier exemple de programme illustrant cela la classe pointcol deacuterive de point

Les deux classes ont surdeacutefini lopeacuterateur =

include ltiostreamgtusing namespace std class point protected int x y public point (int abs=0 int ord=0) x=abs y=ord point amp operator = (point amp a) x = ax y = ay cout ltlt operateur = 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 amp operator = (pointcol amp b) coul = bcoul cout ltlt operateur = de pointcoln return this void affiche () cout ltlt pointcol ltlt x ltlt ltlt y ltlt ltlt coul ltlt n main() pointcol p(1 3 10) q(4 9 20) cout ltlt p = paffiche () cout ltlt q avant = qaffiche () q = p cout ltlt q apres = qaffiche ()

8 - Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage275

p = pointcol 1 3 10

q avant = pointcol 4 9 20

operateur = de pointcol

q apres = pointcol 4 9 10

Quand la classe de base et la classe deacuteriveacutee surdeacutefinissent lopeacuterateur =

On voit clairement que lopeacuterateur = deacutefini dans la classe point na pas eacuteteacute appeleacute lors dune

affectation entre objets de type pointcol

Le problegraveme est voisin de celui rencontreacute agrave propos du constructeur de recopie avec cette dif-

feacuterence quon ne dispose plus ici du meacutecanisme de transfert drsquoarguments qui en permettait un

appel (presque) implicite Si lon veut pouvoir profiter de lopeacuterateur = deacutefini dans A il fau-

dra lappeler explicitement Le plus simple pour ce faire est dutiliser les possibiliteacutes de con-

versions de pointeurs examineacutees au paragraphe preacuteceacutedent

Voici comment nous pourrions modifier en ce sens lopeacuterateur = de pointcol

pointcol amp operator = (pointcol amp b)

point ad1 ad2

cout ltlt opeacuterateur = de pointcoln

ad1 = this conversion pointeur sur pointcol en pointeur sur point

ad2 = amp b idem

ad1 = ad2 affectation de la partie point de b

coul = bcoul affectation de la partie propre agrave pointcol

return this

Nous convertissons les pointeurs (this et ampb) sur des objets de pointcol en des pointeurs sur

des objets de type point Il suffit ensuite de reacutealiser une affectation entre les nouveaux objets

pointeacutes ( ad1 et ad2) pour entraicircner lappel de lopeacuterateur = de la classe point Voici le nou-

veau programme complet ainsi modifieacute Cette fois les reacutesultats montrent que laffectation

entre objets de type pointcol est satisfaisante

include ltiostreamgt

using namespace std

class point

protected

int x y

public

point (int abs=0 int ord=0) x=abs y=ord

point amp operator = (point amp a)

x = ax y = ay

cout ltlt operateur = de point n

return this

Lrsquoheacuteritage simpleCHAPITRE 13

276

class pointcol public point

protected

int coul

public

pointcol (int abs=0 int ord=0 int cl=1) point (abs ord) coul=cl

pointcol amp operator = (pointcol amp b)

point ad1 ad2

cout ltlt operateur = de pointcoln

ad1 = this conversion pointeur sur pointcol en pointeur sur point

ad2 = amp b idem

ad1 = ad2 affectation de la partie point de b

coul = bcoul affectation de la partie propre agrave pointcol

return this

void affiche ()

cout ltlt pointcol ltlt x ltlt ltlt y ltlt ltlt coul ltlt n

main()

pointcol p(1 3 10) q(4 9 20)

cout ltlt p = paffiche ()

cout ltlt q avant = qaffiche ()

q = p

cout ltlt q apres = qaffiche ()

p = pointcol 1 3 10

q avant = pointcol 4 9 20

operateur = de pointcol

operateur = de point

q apres = pointcol 1 3 10

Comment forcer dans une classe deacuteriveacutee lutilisation de lopeacuterateur = surdeacutefini dans la classe de base

Remarque

On dit souvent quen C++ lopeacuterateur drsquoaffectation nest pas heacuteriteacute Une telle affirmation

est en fait source de confusions En effet on peut consideacuterer quelle est exacte car lorsque

B na pas deacutefini lopeacuterateur = on ne se contente pas de faire appel agrave celui deacutefini (eacuteventuel-

lement) dans A (ce qui reviendrait agrave reacutealiser une affectation partielle ne concernant que la

partie heacuteriteacutee de A ) En revanche on peut consideacuterer que cette affirmation est fausse

puisque lorsque B ne surdeacutefinit pas lopeacuterateur = cette classe peut quand mecircme profi-

ter (automatiquement) de lopeacuterateur deacutefini dans A

9 - Heacuteritage et forme canonique dune classe277

9 Heacuteritage et forme canonique dune classeAu paragraphe 4 du chapitre 9 nous avons deacutefini ce que lon nomme la forme canonique

dune classe cest-agrave-dire le canevas selon lequel devrait ecirctre construite toute classe disposant

de pointeurs

En tenant compte de ce qui a eacuteteacute preacutesenteacute aux paragraphes 7 et 8 de ce chapitre voici com-

ment ce scheacutema pourrait ecirctre geacuteneacuteraliseacute dans le cadre de lrsquoheacuteritage (par souci de briegraveveteacute

certaines fonctions ont eacuteteacute placeacutees en ligne) On trouve

bull une classe de base nommeacutee T respectant la forme canonique deacutejagrave preacutesenteacutee

bull une classe deacuteriveacutee nommeacutee U respectant elle aussi la forme canonique mais sappuyant sur

certaines des fonctionnaliteacutes de sa classe de base (constructeur par recopie et opeacuterateur drsquoaf-

fectation)

class T public T () constructeurs de T autres que par recopie T (const T amp) constructeur de recopie de T (forme conseilleacutee) ~T () destructeur T amp Toperator = (const T amp) opeacuterateur daffectation (forme conseilleacutee)

class U public T public U () constructeurs autres que recopie U (const U amp x) T (x) constructeur recopie de U utilise celui de T preacutevoir ici la copie de la partie de x speacutecifique agrave T (qui nest pas un T) ~U () U amp Uoperator = (const U amp x) opeacuterateur daffectation (forme conseilleacutee) T ad1 = this ad2 = ampx ad1 = ad2 affectation (agrave lobjet courant) de la partie de x heacuteriteacutee de T preacutevoir ici laffectation (agrave lobjet courant) de la partie de x speacutecifique agrave U (non heacuteriteacutee de T)

Forme canonique dune classe deacuteriveacutee

Remarque

Rappelons que si T deacutefinit un constructeur de recopie priveacute la recopie drsquoobjets de type U

sera eacutegalement interdite agrave moins bien sucircr de deacutefinir dans U un constructeur par recopie

public prenant en charge lrsquointeacutegraliteacute de lrsquoobjet (il pourra eacuteventuellement srsquoappuyer sur

Lrsquoheacuteritage simpleCHAPITRE 13

278

un constructeur par recopie priveacute de T agrave condition qursquoil nrsquoait pas eacuteteacute preacutevu de corps

vide )

De mecircme si T deacutefinit un opeacuterateur drsquoaffectation priveacute lrsquoaffectation drsquoobjets de type U

sera eacutegalement interdite si lrsquoon ne redeacutefinit pas un opeacuterateur drsquoaffectation public dans

U

Ainsi drsquoune maniegravere geacuteneacuterale proteacuteger une classe contre les recopies et les affectations

protegravege du mecircme coup ses classes deacuteriveacutees

10 Lrsquoheacuteritage et ses limitesNous avons vu comment une classe deacuteriveacutee peut tirer parti des possibiliteacutes dune classe de

base Si lrsquoon dit parfois quelle heacuterite de ses fonctionnaliteacutes lrsquoexpression peut precircter agrave con-

fusion en laissant croire que lrsquoheacuteritage est plus geacuteneacuteral quil ne lest en reacutealiteacute

Prenons lexemple dune classe point qui a surdeacutefini lopeacuterateur + (point + point -gt point) et

dune classe pointcol qui heacuterite publiquement de point (et qui ne redeacutefinit pas +) Pourra-t-

elle utiliser cette fonctionnaliteacute de la classe point quest lopeacuterateur + En fait un certain

nombre de choses sont floues La somme de deux points coloreacutes sera-t-elle un point coloreacute

Si oui quelle pourrait bien ecirctre sa couleur Sera-t-elle simplement un point Dans ce cas on

ne peut pas vraiment dire que pointcol a heacuteriteacute des possibiliteacutes daddition de point

Prenons maintenant un autre exemple celui de la classe point munie dune fonction (mem-

bre ou amie) coincide telle que nous lavions consideacutereacutee au paragraphe 1 du chapitre 8 et une

classe pointcol heacuteritant de point Cette fonction coincide pourra-t-elle (telle quelle est) ecirctre

utiliseacutee pour tester la coiumlncidence de deux points coloreacutes

Nous vous proposons dapporter des eacuteleacutements de reacuteponse agrave ces diffeacuterentes questions Pour ce

faire nous allons preacuteciser ce quest lrsquoheacuteritage ce qui nous permettra de montrer que les situa-

tions deacutecrites ci-dessus ne relegravevent pas (uniquement) de cette notion Nous verrons ensuite

comment la conjugaison de lrsquoheacuteritage et des regravegles de compatibiliteacute entre objets deacuteriveacutes (dont

nous avons parleacute ci-dessus) permet de donner un sens agrave certaines des situations eacutevoqueacutees les

autres neacutecessiteront le recours agrave des moyens suppleacutementaires (conversions par exemple)

101La situation dheacuteritageConsideacuterons ce canevas (t deacutesignant un type quelconque)

class A class B public A

public

t f()

10 - Lrsquoheacuteritage et ses limites279

La classe A possegravede une fonction membre f (dont nous ne preacutecisons pas ici les arguments)

fournissant un reacutesultat de type t (type de base ou deacutefini par lutilisateur) La classe B heacuterite

des membres publics de A donc de f Soient deux objets a et b

A a B b

Bien entendu lappel

af ()

a un sens et fournit un reacutesultat de type t

Le fait que B heacuterite publiquement de A permet alors daffirmer que lappel

bf ()

a lui aussi un sens autrement dit que f agira sur b (ou avec b) comme sil eacutetait du type A Son

reacutesultat sera toujours de type t et ses arguments auront toujours le type imposeacute par son proto-

type

Tout lheacuteritage est contenu dans cette affirmation agrave laquelle il faut absolument se tenir Expli-

quons-nous

1011 Le type du reacutesultat de lappelGeacuteneacuteralement tant que t est un type usuel laffirmation ci-dessus semble eacutevidente Mais des

doutes apparaissent degraves que t est un type objet surtout sil sagit du type de la classe dont f est

membre Ainsi avec le prototype

A f()

le reacutesultat de lappel bf() sera bien de type A (et non de type B comme on pourrait parfois

le souhaiter)

Cette limitation se trouvera toutefois leacutegegraverement atteacutenueacutee dans le cas de fonctions renvoyant

des pointeurs ou des reacutefeacuterences comme on le verra au paragraphe 43 du chapitre 15 On y

apprendra en effet que les fonctions virtuelles pourront alors disposer de valeurs de retours

covariantes crsquoest-agrave-dire susceptibles de deacutependre du type de lrsquoobjet concerneacute

1012 Le type des arguments de fLa remarque faite agrave propos de la valeur de retour sapplique aux arguments de f Par exemple

supposons que f ait pour prototype

t f(A)

et que nous ayons deacuteclareacute

A a1 a2 B b1 b2

Lheacuteritage (public) donne effectivement une signification agrave

b1f(a1)

Quant agrave lappel

b1f(b2)

sil a un sens cest gracircce agrave lexistence de conversions implicites

bull de lobjet b1 de type B en un objet du type A si f reccediloit son argument par valeur noubliez

pas qualors il y aura appel dun constructeur de recopie (par deacutefaut ou surdeacutefini)

bull dune reacutefeacuterence agrave b1 de type B en une reacutefeacuterence agrave un objet de type A si f reccediloit ses arguments

par reacutefeacuterence

Lrsquoheacuteritage simpleCHAPITRE 13

280

102ExemplesRevenons maintenant aux exemples eacutevoqueacutes en introduction de ce paragraphe

1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point

En fait que lopeacuterateur + soit deacutefini sous la forme dune fonction membre ou dune fonction

amie la somme de deux objets a et b de type pointcol sera de type point En effet dans le

premier cas lexpression

a + b

sera eacutevalueacutee comme

aoperator+ (b)

Il y aura appel de la fonction membre operator+1 pour lobjet a (dont on ne consideacuterera que

ce qui est du type point) agrave laquelle on transmettra en argument le reacutesultat de la conversion de

b en un point2 Son reacutesultat sera de type point

Dans le second cas lexpression sera eacutevalueacutee comme

operator+ (a b)

Il y aura appel de la fonction amie3 operator+ agrave laquelle on transmettra le reacutesultat de la con-

version de a et b dans le type point Le reacutesultat sera toujours de type point

Dans ces conditions vous voyez que si c est de type pointcol une banale affectation telle

que

c = a + b

sera rejeteacutee faute de disposer de la conversion de point en pointcol On peut dailleurs logi-

quement se demander quelle couleur une telle conversion pourrait attribuer agrave son reacutesultat Si

maintenant on souhaite deacutefinir la somme de deux points coloreacutes il faudra redeacutefinir lopeacutera-

teur + au sein de pointcol quitte agrave ce quil fasse appel agrave celui deacutefini dans point pour la somme

des coordonneacutees

1022 Heacuteritage dans pointcol de la fonction coincide de point

Cette fois il est facile de voir quaucun problegraveme particulier ne se pose4 agrave partir du moment

ougrave lon considegravere que la coiumlncidence de deux points coloreacutes correspond agrave leacutegaliteacute de leurs

seules coordonneacutees (la couleur nintervenant pas)

A titre indicatif voici un exemple de programme complet dans lequel coincide est deacutefini

comme une fonction membre de point

1 Fonction membre de pointcol mais heacuteriteacutee de point

2 Selon les cas il y aura conversion dobjets ou conversion de reacutefeacuterences

3 Amie de point et de pointcol par heacuteritage mais ici cest seulement la relation damitieacute avec point qui est

employeacutee

4 Mais ici le reacutesultat fourni par coincide nest pas dun type classe

11 - Exemple de classe deacuteriveacutee281

include ltiostreamgtusing namespace std class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend int coincide (point amp point amp) int coincide (point amp p point amp q) if ((px == qx) ampamp (py == qy)) return 1 else return 0 class pointcol public point short couleur public pointcol (int abs=0 int ord=0 short cl=1) point (abs ord) couleur = cl main() programme dessai pointcol a(253) b(259) c if (coincide (ab)) cout ltlt a coincide avec b n else cout ltlt a et b sont diffeacuterents n if (coincide (ac)) cout ltlt a coincide avec c n else cout ltlt a et c sont differents n

a coincide avec b a et c sont differents

Heacuteritage dans pointcol de la fonction coincide de point

11 Exemple de classe deacuteriveacuteeSupposons que nous disposions de la classe vect telle que nous lavons deacutefinie au paragraphe

5 du chapitre 9 Cette classe est munie dun constructeur dun destructeur et dun opeacuterateur

dindiccedilage [] (notez bien que pour ecirctre exploitable cette classe qui contient des parties dyna-

miques devrait comporter eacutegalement un constructeur par recopie et la surdeacutefinition de lopeacute-

rateur daffectation)

class vect int nelem int adr public vect (int n) adr = new int [nelem=n] ~vect () delete adr int amp operator [] (int) int amp vectoperator [] (int i) return adr[i]

Lrsquoheacuteritage simpleCHAPITRE 13

282

Supposons maintenant que nous ayons besoin de vecteurs dans lesquels on puisse fixer non

seulement le nombre deacuteleacutements mais les bornes (minimum et maximum) des indices (sup-

poseacutes ecirctre toujours de type entier) Par exemple nous pourrions deacuteclarer (si vect1 est le nom

de la nouvelle classe)

vect1 t (15 24)

ce qui signifierait que t est un tableau de dix entiers dindices variant de 15 agrave 24

Il semble alors naturel dessayer de deacuteriver une classe de vect Il faut preacutevoir deux membres

suppleacutementaires pour conserver les bornes de lindice dougrave le deacutebut de la deacuteclaration de notre

nouvelle classe

class vect1 public vect int debut fin

Manifestement vect1 neacutecessite un constructeur agrave deux arguments entiers correspondant aux

bornes de lindice Son en-tecircte sera de la forme

vect1 (int d int f)

Mais lappel de ce constructeur entraicircnera automatiquement celui du constructeur de vect Il

nest donc pas question de faire dans vect1 lallocation dynamique de notre vecteur Au con-

traire nous reacuteutilisons le travail effectueacute par vect il nous suffit de lui transmettre le nombre

deacuteleacutements souhaiteacutes dougrave len-tecircte complet de vect1

vect1 (int d int f) vect (f-d+1)

Quant agrave la tacircche speacutecifique de vect1 elle se limite agrave renseigner les valeurs de debut et fin

A priori la classe vect1 na pas besoin de destructeur puisqursquoelle nalloue aucun emplace-

ment dynamique autre que celui deacutejagrave alloueacute par vect

Nous pourrions aussi penser que vect1 na pas besoin de surdeacutefinir lopeacuterateur [] dans la

mesure ougrave elle heacuterite de celui de vect Quen est-il exactement Dans vect la fonction

membre operator[] reccediloit un argument implicite et un argument de type int elle fournit une

valeur de type int Sur ce plan lrsquoheacuteritage fonctionnera donc correctement et C++ acceptera

quon fasse appel agrave operator[] pour un objet de type deacuteriveacute vect1 Ainsi avec

vect1 t (15 24)

la notation

t[i]

qui signifiera

toperator[] (i)

aura bien une signification

Le seul ennui est que cette notation deacutesignera toujours le iegraveme eacuteleacutement du tableau dynamique

de lobjet t Et ce nest plus ce que nous voulons Il nous faut donc surdeacutefinir lopeacuterateur []

pour la classe vect1

A ce niveau deux solutions au moins soffrent agrave nous

bull utiliser lopeacuterateur existant dans vect ce qui nous conduit agrave

int amp operator[] (int i) return vectoperator[] (i-debut)

11 - Exemple de classe deacuteriveacutee283

bull ne pas utiliser lopeacuterateur existant dans vect ce qui nous conduirait agrave

int amp operator [] (int i)

return adr [i-debut]

(agrave condition que adr soit accessible agrave la fonction operator [] donc deacuteclareacute public ou plus

raisonnablement priveacute)

Cette derniegravere solution paraicirct peut-ecirctre plus seacuteduisante1

Voici un exemple complet faisant appel agrave la premiegravere solution Nous avons fait figurer la

classe vect elle-mecircme pour faciliter son examen et introduit comme agrave lrsquoaccoutumeacutee quel-

ques affichages dinformation au sein de certaines fonctions membres de vect et de vect1

include ltiostreamgt

using namespace std la classe vect

class vect int nelem nombre deacuteleacutements int adr pointeur sur ces eacuteleacutements

public vect (int n) constructeur vect

adr = new int [nelem = n] cout ltlt + Constr vect de taille ltlt n ltlt n

~vect () destructeur vect

cout ltlt - Destr vect delete adr

int amp operator [] (int)

int amp vectoperator [] (int i) return adr[i]

la classe deacuteriveacutee vect1

class vect1 public vect int debut fin

public vect1 (int d int f) vect (f - d + 1) constructeur vect1

cout ltlt ++ Constr vect1 - bornes ltlt d ltlt ltlt f ltlt n debut = d fin = f

int amp operator [] (int)

int amp vect1operator [] (int i) return vectoperator [] (i-debut)

1 Du moins ici car le travail agrave effectuer eacutetait simple En pratique on cherchera plutocirct agrave reacutecupeacuterer le travail deacutejagrave

effectueacute en se contentant de le compleacuteter si neacutecessaire

Lrsquoheacuteritage simpleCHAPITRE 13

284

un programme dessai

main()

const int MIN=15 MAX = 24

vect1 t(MIN MAX)

int i

for (i=MIN ilt=MAX i++) t[i] = i

for (i=MIN ilt=MAX i++) cout ltlt t[i] ltlt

cout ltlt n

+ Constr vect de taille 10

++ Constr vect1 - bornes 15 24

15 16 17 18 19 20 21 22 23 24

- Destr vect

Remarque

Bien entendu lagrave encore pour ecirctre exploitable la classe vect1 devrait deacutefinir un construc-

teur par recopie et lopeacuterateur daffectation A ce propos on peut noter quil reste possible

de deacutefinir ces deux fonctions dans vect1 mecircme si elles nont pas eacuteteacute deacutefinies correctement

dans vect

12 Patrons de classes et heacuteritageIl est tregraves facile de combiner la notion dheacuteritage avec celle de patron de classes Cette combi-

naison peut revecirctir plusieurs aspects

bull Classe ordinaire deacuteriveacutee dune classe patron (cest-agrave-dire dune instance particuliegravere

dun patron de classes) Par exemple si A est une classe patron deacutefinie par template ltclass

Tgt A

class B public A ltintgt B deacuterive de la classe patron Altintgt

on obtient une seule classe nommeacutee B

bull Patron de classes deacuteriveacute dune classe ordinaire Par exemple A eacutetant une classe

ordinaire

template ltclass Tgt class B public A

on obtient une famille de classes (de paramegravetre de type T) Laspect patron a eacuteteacute introduit

ici au moment de la deacuterivation

12 - Patrons de classes et heacuteritage285

bull Patron de classes deacuteriveacute dun patron de classes Cette possibiliteacute peut revecirctir deux aspects

selon que lon introduit ou non de nouveaux paramegravetres lors de la deacuterivation Par exemple

si A est une classe patron deacutefinie par template ltclass Tgt A on peut

ndash deacutefinir une nouvelle famille de fonctions deacuteriveacutees par

template ltclass Tgt class B public A ltTgt

Dans ce cas il existe autant de classes deacuteriveacutees possibles que de classes de base possi-

bles

ndash deacutefinir une nouvelle famille de fonctions deacuteriveacutees par

template ltclass T class Ugt class B public A ltTgt

Dans ce cas on peut dire que chaque classe de base possible peut engendrer une famille

de classes deacuteriveacutees (de paramegravetre de type U)

Dune maniegravere geacuteneacuterale vous pouvez jouer agrave votre greacute avec les paramegravetres crsquoest-agrave-dire en

introduire ou en supprimer agrave volonteacute

Voici trois exemples correspondant agrave certaines des situations que nous venons deacutevoquer

121Classe ordinaire deacuterivant dune classe patronIci nous avons deacuteriveacute de la classe patron pointltintgt une classe ordinaire nommeacutee

point_int

include ltiostreamgtusing namespace std template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

class pointcol_int public point ltintgt int coul public pointcol_int (int abs=0 int ord=0 int cl=1) point ltintgt (abs ord) coul = cl void affiche ()

pointltintgtaffiche () cout ltlt couleur ltlt coul ltlt n main () point ltfloatgt pf (35 28) pfaffiche () instanciation classe patron pointcol_int p (3 5 9) paffiche () emploi (classique) de la classe pointcol_int

Lrsquoheacuteritage simpleCHAPITRE 13

286

Coordonnees 35 28Coordonnees 3 5 couleur 9

122Deacuterivation de patrons avec les mecircmes paramegravetresA partir du patron template ltclass Tgt class point nous deacuterivons un patron nommeacute pointcol

dans lequel le nouveau membre introduit est du mecircme type T que les coordonneacutees du point

include ltiostreamgtusing namespace std

template ltclass Tgt class point T x T y public point (T abs=0 T ord=0) x = abs y = ord void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

template ltclass Tgt class pointcol public point ltTgt T coul public pointcol (T abs=0 T ord=0 T cl=1) point ltTgt (abs ord) coul = cl void affiche () pointltTgtaffiche () cout ltlt couleur ltlt coul

main () point ltlonggt p (34 45) paffiche () pointcol ltshortgt q (12 45 5) qaffiche ()

Coordonnees 34 45Coordonnees 12 45couleur 5

123Deacuterivation de patrons avec introduction drsquoun nouveau paramegravetre

A partir du patron template ltclass Tgt class point nous deacuterivons un patron nommeacute pointcol

dans lequel le nouveau membre introduit est dun type U diffeacuterent de celui des coordonneacutees

du point

include ltiostreamgtusing namespace std

13 - Lrsquoheacuteritage en pratique287

template ltclass Tgt class point

T x T y public

point (T abs=0 T ord=0) x = abs y = ord

void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

template ltclass T class Ugt class pointcol public point ltTgt U coul

public

pointcol (T abs=0 T ord=0 U cl=1) point ltTgt (abs ord) coul = cl

void affiche ()

pointltTgtaffiche () cout ltlt couleur ltlt coul ltlt n

main ()

un point agrave coordonneacutees de type float et couleur de type int pointcol ltfloat intgt p (35 28 12) paffiche ()

un point agrave coordonneacutees de type unsigned long et couleur de type short

pointcol ltunsigned long shortgt q (295467 345789 8) qaffiche ()

Coordonnees 35 28

couleur 12Coordonnees 295467 345789

couleur 8

13 Lrsquoheacuteritage en pratiqueCe paragraphe examine quelques points qui interviennent dans la mise en application de

lrsquoheacuteritage Tout drsquoabord nous montrerons que la technique peut ecirctre iteacutereacutee autant de fois

qursquoon le souhaite en utilisant des deacuterivations successives Puis nous verrons que lrsquoheacuteritage

peut ecirctre utiliseacute dans des buts relativement diffeacuterents Enfin nous examinerons la maniegravere de

mettre en oeuvre les diffeacuterentes compilations et eacuteditions de liens rendues geacuteneacuteralement

neacutecessaires dans le cadre de lrsquoheacuteritage

131Deacuterivations successivesNous venons drsquoexposer les principes de base de lrsquoheacuteritage en nous limitant agrave des situations ne

faisant intervenir que deux classes agrave la fois une classe de base et une classe deacuteriveacutee

En fait ces notions de classe de base et de classe deacuteriveacutee sont relatives puisque

bull drsquoune mecircme classe peuvent ecirctre deacuteriveacutees plusieurs classes diffeacuterentes (eacuteventuellement uti-

liseacutees au sein dun mecircme programme)

bull une classe deacuteriveacutee peut agrave son tour servir de classe de base pour une autre classe deacuteriveacutee

Lrsquoheacuteritage simpleCHAPITRE 13

288

Autrement dit les diffeacuterentes classes deacuteriveacutees dune mecircme classe de base peuvent ecirctre repreacute-

senteacutees par une arborescence telle que

Ici D est deacuteriveacutee de B elle-mecircme deacuteriveacutee de A (on dit aussi que D heacuterite de B qui elle-

mecircme heacuterite de A) Pour traduire la relation existant entre A et D on dira que D est une des-

cendante de A ou encore que A est une ascendante de D Naturellement D est aussi une des-

cendante de B lorsquon aura besoin drsquoecirctre plus preacutecis on dira que D est une descendante

directe de B

Par ailleurs depuis la version 2 C++ eacutelargit les possibiliteacutes dheacuteritage en introduisant ce que

lon nomme lrsquoheacuteritage multiple une classe donneacutee peut heacuteriter simultaneacutement de plusieurs

classes Dans ces conditions on na plus affaire agrave une arborescence de classes mais agrave un gra-

phe qui peut eacuteventuellement devenir complexe

En voici un exemple simple

Tout ce qui a eacuteteacute dit jusquagrave maintenant srsquoeacutetend sans aucun problegraveme agrave toutes les situations

dheacuteritage simple (syntaxe appel des constructeurs) Dune maniegravere geacuteneacuterale lorsque nous

parlerons dune classe deacuteriveacutee dune classe de base il pourra sagir dune descendante quel-

conque (directe ou non) De mecircme lorsque nous parlerons de deacuterivation publique il faudra

comprendre que la classe concerneacutee sobtient par une ou plusieurs deacuterivations successives

publiques de sa classe de base Notez quil suffit quune seule de ces deacuterivations soit priveacutee

pour quau bout du compte on parle globalement de deacuterivation priveacutee

A

B C

D E F G

13 - Lrsquoheacuteritage en pratique289

En ce qui concerne les situations drsquoheacuteritage multiple leur mise en œuvre neacutecessite quelques

connaissances suppleacutementaires Nous avons preacutefeacutereacute les regrouper au chapitre 14 notamment

parce que leur usage est peu reacutepandu

132Diffeacuterentes utilisations de lrsquoheacuteritageLrsquoheacuteritage peut ecirctre utiliseacute dans deux buts tregraves diffeacuterents

Par exemple face agrave un problegraveme donneacute il se peut qursquoon dispose deacutejagrave drsquoune classe qui le

reacutesolve partiellement On peut alors creacuteer une classe deacuteriveacutee qursquoon complegravete de faccedilon agrave

reacutepondre agrave lrsquoensemble du problegraveme On gagne alors du temps de programmation puisquon

reacuteutilise une partie de logiciel Mecircme si lon nexploite pas toutes les fonctions de la classe de

deacutepart on ne sera pas trop peacutenaliseacute dans la mesure ougrave les fonctions non utiliseacutees ne seront pas

incorporeacutees agrave leacutedition de liens Le seul risque encouru sera celui dune perte de temps drsquoexeacute-

cution dans des appels imbriqueacutes que lon aurait pu limiter en reacuteeacutecrivant totalement la classe

En revanche les membres donneacutees non utiliseacutes (sil y en a) occuperont de lespace dans tous

les objets du type

Dans cet esprit de reacuteutilisation on trouve aussi le cas ougrave disposant dune classe on souhaite

en modifier linterface utilisateur pour quelle reacuteponde agrave des critegraveres donneacutes On creacutee alors

une classe deacuteriveacutee qui agit comme la classe de base seule la faccedilon de lrsquoutiliser est diffeacuterente

Dans un tout autre esprit on peut en ne partant de rien chercher agrave reacutesoudre un problegraveme en

lexprimant sous forme dun graphe de classes1 On peut mecircme creacuteer ce que lon nomme des

classes abstraites cest-agrave-dire dont la vocation nest pas de donner naissance agrave des objets

mais simplement drsquoecirctre utiliseacutees comme classes de base pour dautres classes deacuteriveacutees

133 Exploitation drsquoune classe deacuteriveacuteeEn ce qui concerne lutilisation (compilation eacutedition de liens) dune classe deacuteriveacutee au sein

dun programme les choses sont tregraves simples si la classe de base et la classe deacuteriveacutee sont

creacuteeacutees dans le programme lui-mecircme (un seul fichier source un module objet) Mais il en va

rarement ainsi Au paragraphe 2 nous avons deacutejagrave vu comment proceacuteder lorsqursquoon utilise une

classe de base deacutefinie dans un fichier seacutepareacute Vous trouverez ci-dapregraves un scheacutema geacuteneacuteral

montrant les opeacuterations mises en jeu lorsqursquoon compile successivement et seacutepareacutement

bull une classe de base

bull une classe deacuteriveacutee

bull un programme utilisant cette classe deacuteriveacutee

La plupart des environnements de programmation permettent de tenir compte des deacutependan-

ces entre ces diffeacuterents fichiers et de faire en sorte que les compilations correspondantes

nrsquoaient lieu que si neacutecessaire On retrouve ce meacutecanisme dans la notion de projet (dans bon

nombre drsquoenvironnements PC) ou de fichier make (dans les environnements UNIX ou

LINUX)

1 Ou dun arbre si lon ne dispose pas de lrsquoheacuteritage multiple

Lrsquoheacuteritage simpleCHAPITRE 13

290

Deacuteclaration

classe de

base

Deacutefinition

classe de

base

Deacuteclaration

classe

deacuteriveacutee

Deacutefinition

classe

deacuteriveacutee

Programme

utilisant la

classe deacuteriveacutee

Module objet

classe de

base

Compilation

Module objet

classe

deacuteriveacutee

Module objet

programme

utilisateur

Edtion

de

liens

Programme

exeacutecutable

Compilation

Compilation

Exploitation drsquoune classe deacuteriveacutee

14

Lheacuteritage multiple

Comme nous lavons signaleacute au chapitre preacuteceacutedent C++ dispose de possibiliteacutes dheacuteritage

multiple Il sagit lagrave dune geacuteneacuteralisation conseacutequente dans la mesure ougrave elle permet de

saffranchir de la contrainte hieacuterarchique imposeacutee par lrsquoheacuteritage simple

Malgreacute tout son usage reste assez peu reacutepandu La principale raison reacuteside certainement dans

les difficulteacutes quil implique au niveau de la conception des logiciels Il est en effet plus

facile de structurer un ensemble de classes selon un ou plusieurs arbres (cas de lrsquoheacuteritage

simple) que selon un simple graphe orienteacute sans circuit (cas de lrsquoheacuteritage multiple)

Bien entendu la plupart des choses que nous avons dites agrave propos de lrsquoheacuteritage simple srsquoeacuteten-

dent agrave lrsquoheacuteritage multiple Neacuteanmoins un certain nombre dinformations suppleacutementaires

doivent ecirctre introduites pour reacutepondre aux questions suivantes

bull Comment exprimer cette deacutependance multiple au sein dune classe deacuteriveacutee

bull Comment sont appeleacutes les constructeurs et destructeurs concerneacutes ordre transmission din-

formations etc

bull Comment reacutegler les conflits qui risquent dapparaicirctre dans des situations telles que celle-ci

ougrave D heacuterite de B et C qui heacuteritent toutes deux de A

Lheacuteritage multipleCHAPITRE 14

292

1 Mise en œuvre de lheacuteritage multipleConsideacuterons une situation simple celle ougrave une classe que nous nommerons pointcoul heacuterite

de deux autres classes nommeacutees point et coul

Supposons pour fixer les ideacutees que les classes point et coul se preacutesentent ainsi (nous les

avons reacuteduites agrave ce qui eacutetait indispensable agrave la deacutemonstration)

class point class coul int x y short couleur public public point () coul () ~point () ~coul () affiche () affiche ()

Nous pouvons deacutefinir une classe pointcoul heacuteritant de ces deux classes en la deacuteclarant ainsi

(ici nous avons choisi public pour les deux classes mais nous pourrions employer private ou

protected1)

class pointcoul public point public coul

Notez que nous nous sommes contenteacute de remplacer la mention dune classe de base par une

liste de mentions de classes de base

A

B C

D

point coul

pointcoul

1 Depuis la version 3

1 - Mise en œuvre de lheacuteritage multiple293

Au sein de cette classe nous pouvons deacutefinir de nouveaux membres Ici nous nous limitons

agrave un constructeur un destructeur et une fonction daffichage

Dans le cas de lrsquoheacuteritage simple le constructeur devait pouvoir retransmettre des informa-

tions au constructeur de la classe de base Il en va de mecircme ici avec cette diffeacuterence quil y a

deux classes de base Len-tecircte du constructeur se preacutesente ainsi

pointcoul ( ) point () coul ()

| | |

arguments arguments arguments

de pointcoul agrave transmettre agrave transmettre

agrave point agrave coul

Lordre dappel des constructeurs est le suivant

bull constructeurs des classes de base dans lordre ougrave les classes de base sont deacuteclareacutees dans la

classe deacuteriveacutee (ici point puis coul)

bull constructeur de la classe deacuteriveacutee (ici pointcoul)

Les destructeurs eacuteventuels seront lagrave encore appeleacutes dans lordre inverse lors de la destruc-

tion dun objet de type pointcoul

Dans la fonction drsquoaffichage que nous nommerons elle aussi affiche nous vous proposons

drsquoemployer successivement les fonctions affiche de point et de coul Comme dans le cas de

lrsquoheacuteritage simple dans une fonction membre de la classe deacuteriveacutee on peut utiliser toute fonc-

tion membre publique (ou proteacutegeacutee) dune classe de base Lorsque plusieurs fonctions mem-

bres portent le mecircme nom dans diffeacuterentes classes on peut lever lambiguiumlteacute en employant

lopeacuterateur de reacutesolution de porteacutee Ainsi la fonction affiche de pointcoul sera

void affiche ()

pointaffiche () coulaffiche ()

Bien entendu si les fonctions drsquoaffichage de point et de coul se nommaient par exemple affp

et affc la fonction affiche aurait pu seacutecrire simplement

void affiche ()

affp () affc ()

Lutilisation de la classe pointcoul est classique Un objet de type pointcoul peut faire appel

aux fonctions membres de pointcoul ou eacuteventuellement aux fonctions membres des classes

de base point et coul (en se servant de lopeacuterateur de reacutesolution de porteacutee pour lever des ambi-

guiumlteacutes) Par exemple avec

pointcoul p(3 9 2)

paffiche () appellera la fonction affiche de pointcoul tandis que ppointaffiche () appellera

la fonction affiche de point

Naturellement si lune des classes point et coul eacutetait elle-mecircme deacuteriveacutee dune autre classe il

serait eacutegalement possible den utiliser lun des membres (en ayant eacuteventuellement plusieurs

fois recours agrave lopeacuterateur de reacutesolution de porteacutee)

Lheacuteritage multipleCHAPITRE 14

294

Voici un exemple complet de deacutefinition et dutilisation de la classe pointcoul dans laquelle

ont eacuteteacute introduits quelques affichages informatifs

include ltiostreamgtusing namespace std class point int x y public point (int abs int ord) cout ltlt ++ Constr point n x=abs y=ord ~point () cout ltlt -- Destr point n void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n

class coul short couleur public coul (int cl) cout ltlt ++ Constr coul n couleur = cl ~coul () cout ltlt -- Destr coul n void affiche () cout ltlt Couleur ltlt couleur ltlt n

class pointcoul public point public coul public pointcoul (int int int) ~pointcoul () cout ltlt ---- Destr pointcoul n void affiche () pointaffiche () coulaffiche ()

pointcoulpointcoul (int abs int ord int cl) point (abs ord) coul (cl) cout ltlt ++++ Constr pointcoul n

1 - Mise en œuvre de lheacuteritage multiple295

main() pointcoul p(392) cout ltlt ------------n paffiche () appel de affiche de pointcoul cout ltlt ------------n

ppointaffiche () on force lappel de affiche de point cout ltlt ------------n pcoulaffiche () on force lappel de affiche de coul cout ltlt ------------n

++ Constr point++ Constr coul++++ Constr pointcoul------------Coordonnees 3 9

Couleur 2------------Coordonnees 3 9------------Couleur 2------------

---- Destr pointcoul-- Destr coul-- Destr point

Un exemple dheacuteritage multiple pointcoul heacuterite de point et de coul

Remarque

Nous avons vu comment distinguer deux fonctions membres de mecircme nom appartenant agrave

deux classes diffeacuterentes (par exemple affiche) La mecircme deacutemarche sappliquerait agrave des

membres donneacutees (dans la mesure ougrave leur accegraves est autoriseacute) Par exemple avec

class A class B public public

int x int x class C public A public B

C posseacutedera deux membres nommeacutes x lun heacuteriteacute de A lautre de B Au sein des fonc-

tions membres de C on fera la distinction agrave laide de lopeacuterateur de reacutesolution de

porteacutee on parlera de Ax ou de Bx

Lheacuteritage multipleCHAPITRE 14

296

En Java

Java ne connaicirct pas lrsquoheacuteritage multiple En revanche il dispose de la notion drsquointerface

(inconnue de C++) qui permet en geacuteneacuteral de traiter plus eacuteleacutegamment les problegravemes Une

interface est simplement un ensemble de speacutecifications de meacutethodes (il nrsquoy a pas de don-

neacutees) Lorsqursquoune classe impleacutemente une interface elle doit fournir effectivement les

meacutethodes correspondantes Une classe peut impleacutementer autant drsquointerfaces qursquoelle le

souhaite indeacutependamment de la notion drsquoheacuteritage

2 Pour reacutegler les eacuteventuels conflits les classes virtuelles

Consideacuterons la situation suivante

correspondant agrave des deacuteclarations telles que

class A

int x y

class B public A

class C public A

class D public B public C

A

B C

D

2 - Pour reacutegler les eacuteventuels conflits les classes virtuelles297

En quelque sorte D heacuterite deux fois de A Dans ces conditions les membres de A (fonctions

ou donneacutees) apparaissent deux fois dans D En ce qui concerne les fonctions membres cela

est manifestement inutile (ce sont les mecircmes fonctions) mais sans importance puisqursquoelles

ne sont pas reacuteellement dupliqueacutees (il nen existe quune pour la classe de base) En revanche

les membres donneacutees (x et y) seront effectivement dupliqueacutes dans tous les objets de type D

Y a-t-il redondance En fait la reacuteponse deacutepend du problegraveme Si lon souhaite que D dispose

de deux jeux de donneacutees (de A) on ne fera rien de particulier et on se contentera de les distin-

guer agrave laide de lopeacuterateur de reacutesolution de porteacutee Par exemple on distinguera

ABx de ACx

ou eacuteventuellement si B et C ne possegravedent pas de membre x

Bx de Cx

En geacuteneacuteral cependant on ne souhaitera pas cette duplication des donneacutees Dans ces condi-

tions on peut toujours se deacutebrouiller pour travailler avec lun des deux jeux (toujours le

mecircme ) mais cela risque decirctre fastidieux et dangereux En fait vous pouvez demander agrave

C++ de nincorporer quune seule fois les membres de A dans la classe D Pour cela il vous

faut preacuteciser dans les deacuteclarations des classes B et C (attention pas dans celle de D ) que la

classe A est virtuelle (mot cleacute virtual)

class B public virtual A class C public virtual A class D public B public C

Notez bien que virtual apparaicirct ici dans B et C En effet deacutefinir A comme virtuelle dans la

deacuteclaration de B signifie que A ne devra ecirctre introduite quune seule fois dans les descendants

eacuteventuels de C Autrement dit cette deacuteclaration na guegravere deffet sur les classes B et C elles-

mecircmes (si ce nest une information cacheacutee mise en place par le compilateur pour marquer

A comme virtuelle au sein de B et C ) Avec ou sans le mot virtual les classes B et C se

comportent de la mecircme maniegravere tant quelles nont pas de descendants

Remarque

Le mot virtual peut ecirctre placeacute indiffeacuteremment avant ou apregraves le mot public (ou le mot pri-

vate)

Lheacuteritage multipleCHAPITRE 14

298

3 Appels des constructeurs et des destructeurs cas des classes virtuelles

Nous avons vu comment sont appeleacutes les constructeurs et les destructeurs dans des situations

telles que

De plus nous savons comment demander des transferts dinformations entre un constructeur

dune classe et les constructeurs de ses ascendants directs (C pour B B pour A F pour D et

E) En revanche nous ne pouvons pas demander agrave un constructeur de transfeacuterer des informa-

tions agrave un constructeur dun ascendant indirect (C pour A par exemple) et nous navons

dailleurs aucune raison de le vouloir (puisque chaque transfert dinformation dun niveau

vers le niveau supeacuterieur eacutetait speacutecifieacute dans len-tecircte du constructeur du niveau correspon-

dant) Mais consideacuterons maintenant la situation suivante

Si A nest pas deacuteclareacutee virtuelle dans B et C on peut consideacuterer que la classe A eacutetant dupli-

queacutee tout se passe comme si lon eacutetait en preacutesence de la situation suivante dans laquelle les

notations A1 et A2 symbolisent toutes les deux la classe A

D E

F

A

B

C

A

B C

D

3 - Appels des constructeurs et des destructeurs cas des classes virtuelles299

Si D a deacuteclareacute les classes B et C dans cet ordre les constructeurs seront appeleacutes dans lordre

suivant

A1 B A2 C D

En ce qui concerne les transferts dinformations on peut tregraves bien imaginer que B et C naient

pas preacutevu les mecircmes arguments en ce qui concerne A

Par exemple on peut avoir

B (int n int p double z) A (n p)C (int q float x) A (q)

Cela na aucune importance puisqursquoil y aura en deacutefinitive construction de deux objets dis-

tincts de type A

Mais si A a eacuteteacute deacuteclareacutee virtuelle dans B et C il en va tout autrement (le dernier scheacutema nest

plus valable) En effet dans ce cas on ne construira quun seul objet de type A Quels argu-

ments faut-il transmettre alors au constructeur Ceux preacutevus par B ou ceux preacutevus par C

En fait C++ reacutesout cette ambiguiumlteacute de la faccedilon suivante

Le choix des informations agrave fournir au constructeur de A a lieu non plus dans B ou C mais

dans D Pour ce faire C++ vous autorise (uniquement dans ce cas de deacuterivation virtuelle) agrave

speacutecifier dans le constructeur de D des informations destineacutees agrave A Ainsi nous pourrons

avoir

D (int n int p double z) B (n p z) A (n p)

Bien entendu il sera inutile (et interdit) de preacuteciser des informations pour A au niveau des

constructeurs B et C (comme nous lavions preacutevu preacuteceacutedemment alors que A navait pas eacuteteacute

deacuteclareacutee virtuelle dans B et C)

En outre il faudra absolument que A dispose drsquoun constructeur sans argument (ou

drsquoaucun constructeur) afin de permettre la creacuteation convenable drsquoobjets de type B ou C

(puisque cette fois il nrsquoexiste plus de meacutecanisme de transmission drsquoinformation drsquoun cons-

tructeur de B ou C vers un constructeur de A)

A1

B

A2

C

D

Lheacuteritage multipleCHAPITRE 14

300

En ce qui concerne lordre des appels le constructeur dune classe virtuelle est toujours

appeleacute avant les autres Ici cela nous conduit agrave lordre A B C et D auquel on peut tout

naturellement srsquoattendre Mais dans une situation telle que

cela conduit agrave lordre (moins eacutevident) F E G H I (ou F E H G I selon lordre dans lequel

figurent G et H dans la deacuteclaration de I)

4 Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle

Nous vous proposons un petit exemple illustrant agrave la fois lrsquoheacuteritage multiple les deacuterivations

virtuelles et les transmissions drsquoinformations entre constructeur Il srsquoagit drsquoune geacuteneacuteralisation

de lrsquoexemple du pargraphe 1 Nous y avions deacutefini une clase coul pour reacutepreacutesenter une cou-

leur et une classe pointcol deacuteriveacutee de point pour repreacutesenter des points coloreacutes Ici nous deacutefi-

nissons en outre une classe masse pour repreacutesenter une masse et une classe pointmasse pour

repreacutesenter des points doteacutes drsquoune masse Enfin nous creacuteons une classe pointcolmasse pour

repreacutesenter des points doteacutes agrave la fois drsquoune couleur et drsquoune masse Nous la faisons deacuteriver de

pointcol et de pointmasse ce qui nous conduit agrave ce scheacutema

F

I

G

(virtual F)

H

(virtual F)

E

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle301

Pour eacuteviter la duplication des membres de point dans cette classe on voit qursquoil est neacutecesaire

drsquoavoir preacutevu que les classes pointcol et pointmasse deacuterivent virtuellement de la classe point

qui doit alors disposser drsquoun constructeur sans argument

include ltiostreamgtclass point int x y public point (int abs int ord) cout ltlt ++ Constr point ltlt abs ltlt ltlt ord ltlt n x=abs y=ord point () constr par deacutefaut neacutecessaire pour deacuterivations virtuelles cout ltlt ++ Constr defaut point n x=0 y=0 void affiche () cout ltlt Coordonnees ltlt x ltlt ltlt y ltlt n class coul short couleur public coul (short cl) cout ltlt ++ Constr coul ltlt cl ltlt n couleur = cl void affiche () cout ltlt Couleur ltlt couleur ltlt n

point

pointcoul pointmasse

pointcolmasse

coul masse

Lheacuteritage multipleCHAPITRE 14

302

class masse int mas public masse (int m) cout ltlt ++ Constr masse ltlt m ltlt n mas = m void affiche () cout ltlt Masse ltlt mas ltlt n class pointcoul public virtual point public coul public pointcoul (int abs int ord int cl) coul (cl) pas dinfo pour point car deacuterivation virtuelle cout ltlt ++++ Constr pointcoul ltlt abs ltlt ltlt ord ltlt ltlt cl ltlt n void affiche () pointaffiche () coulaffiche ()

class pointmasse public virtual point public masse public pointmasse (int abs int ord int m) masse (m) pas dinfo pour point car deacuterivation virtuelle cout ltlt ++++ Constr pointmasse ltlt abs ltlt ltlt ord ltlt ltlt m ltlt n void affiche () pointaffiche () masseaffiche () class pointcolmasse public pointcoul public pointmasse public pointcolmasse (int abs int ord short c int m) point (abs ord) pointcoul (abs ord c) pointmasse (abs ord m) infos abs ord en fait inutiles pour pointcol et pointmasse cout ltlt ++++ Constr pointcolmasse ltlt abs + ltlt ord ltlt ltlt c ltlt ltlt m ltlt n void affiche () pointaffiche () coulaffiche() masseaffiche ()

4 - Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle303

main() pointcoul p(392) paffiche () appel de affiche de pointcoul pointmasse pm(12 25 100) pmaffiche () pointcolmasse pcm (2 5 10 20) pcmaffiche () int n cin gtgt n

++ Constr defaut point++ Constr coul 2++++ Constr pointcoul 3 9 2Coordonnees 0 0Couleur 2++ Constr defaut point++ Constr masse 100++++ Constr pointmasse 12 25 100Coordonnees 0 0Masse 100++ Constr point 2 5++ Constr coul 10++++ Constr pointcoul 2 5 10++ Constr masse 20++++ Constr pointmasse 2 5 20++++ Constr pointcolmasse 5 10 20Coordonnees 2 5Couleur 10Masse 20

Exemple drsquoutilisation de lrsquoheacuteritage multiple et des deacuterivations virtuelles

15

Les fonctions virtuelleset le polymorphisme

Nous avons vu quen C++ un pointeur sur un type dobjet pouvait recevoir lrsquoadresse de

nimporte quel objet descendant Toutefois comme nous lrsquoavons constateacute au paragraphe 63

du chapitre 13 agrave cet avantage srsquooppose une lacune importante lappel dune meacutethode pour

un objet pointeacute conduit systeacutematiquement agrave appeler la meacutethode correspondant au type du

pointeur et non pas au type effectif de lobjet pointeacute lui-mecircme

Cette lacune provient essentiellement de ce que dans les situations rencontreacutees jusquici

C++ reacutealise ce que lon nomme une ligature statique1 ou encore un typage statique Le type

dun objet (pointeacute) y est deacutetermineacute au moment de la compilation Dans ces conditions le

mieux que puisse faire le compilateur est effectivement de consideacuterer que lobjet pointeacute a le

type du pointeur

Pour pouvoir obtenir lappel de la meacutethode correspondant au type de lobjet pointeacute il est

neacutecessaire que le type de lobjet ne soit pris en compte quau moment de lexeacutecution (le type

de lobjet deacutesigneacute par un mecircme pointeur pourra varier au fil du deacuteroulement du programme)

On parle alors de ligature dynamique2 ou de typage dynamique ou mieux de polymor-

phisme

Comme nous allons le voir maintenant en C++ le polymorphisme peut ecirctre mis en œuvre en

faisant appel au meacutecanisme des fonctions virtuelles

1 En anglais early binding

2 En anglais late binding ou encore dynamic binding

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

306

1 Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire

Consideacuterons la situation suivante deacutejagrave rencontreacutee au 13

class point class pointcol public point

void affiche () void affiche ()

point p

pointcol pc

point adp = ampp

Linstruction

adp -gt affiche ()

appelle la meacutethode affiche du type point

Mais si nous exeacutecutons cette affectation (autoriseacutee)

adp = amp pc

le pointeur adp pointe maintenant sur un objet de type pointcol Neacuteanmoins linstruction

adp -gt affiche ()

fait toujours appel agrave la meacutethode affiche du type point alors que le type pointcol dispose

lui aussi dune meacutethode affiche

En effet le choix de la meacutethode agrave appeler a eacuteteacute reacutealiseacute lors de la compilation il a donc eacuteteacute

fait en fonction du type de la variable adp Cest la raison pour laquelle on parle de ligature

statique

2 Le meacutecanisme des fonctions virtuellesLe meacutecanisme des fonctions virtuelles proposeacute par C++ va nous permettre de faire en sorte

que linstruction

adp -gt affiche ()

appelle non plus systeacutematiquement la meacutethode affiche de point mais celle correspondant au

type de lobjet reacuteellement deacutesigneacute par adp (ici point ou pointcol)

Pour ce faire il suffit de deacuteclarer virtuelle (mot cleacute virtual) la meacutethode affiche de la classe

point

class point

virtual void affiche ()

2 - Le meacutecanisme des fonctions virtuelles307

Cete instruction indique au compilateur que les eacuteventuels appels de la fonction affiche doi-

vent utiliser une ligature dynamique et non plus une ligature statique Autrement dit lorsque

le compilateur rencontrera un appel tel que

adp -gt affiche ()

il ne deacutecidera pas de la proceacutedure agrave appeler Il se contentera de mettre en place un dispositif

permettant de neffectuer le choix de la fonction quau moment de lexeacutecution de cette instruc-

tion ce choix eacutetant baseacute sur le type exact de lobjet ayant effectueacute lappel (plusieurs exeacutecu-

tions de cette mecircme instruction pouvant appeler des fonctions diffeacuterentes)

Dans la classe pointcol on ne proceacutedera agrave aucune modification il nest pas neacutecessaire de

deacuteclarer virtuelle dans les classes deacuteriveacutees une fonction deacuteclareacutee virtuelle dans une classe de

base (cette information serait redondante)

A titre dexemple voici le programme correspondant agrave celui du paragraphe 63 du chapitre

13 dans lequel nous nous sommes contenteacute de rendre virtuelle la fonction affiche

include ltiostreamgtusing namespace std

class point protected pour que x et y soient accessibles agrave pointcol int x y public

point (int abs=0 int ord=0) x=abs y=ord virtual void affiche () cout ltlt Je suis un point n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore n cout ltlt mes coordonnees sont ltlt x ltlt ltlt y

cout ltlt et ma couleur est ltlt couleur ltlt n

main() point p(35) point adp = ampp pointcol pc (862) pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche ()

cout ltlt -----------------n adp = adpc adpc = adp serait rejeteacute adp-gtaffiche () adpc-gtaffiche ()

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

308

Je suis un point

mes coordonneacutees sont 3 5

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

-----------------

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

Je suis un point colore

mes coordonneacutees sont 8 6 et ma couleur est 2

Mise en œuvre drsquoune ligature dynamique (ici pour affiche) par la technique des fonctions virtuelles

Remarques

1 Par deacutefaut C++ met en place des ligatures statiques A laide du mot virtual on peut choi-

sir la ou les fonctions pour lesquelles on souhaite mettre en place une ligature dynamique

2 En C++ la ligature dynamique est limiteacutee agrave un ensemble de classes deacuteriveacutees les unes

des autres

En Java

En Java les objets sont manipuleacutes par reacutefeacuterence et la ligature des fonctions est toujours

dynamique La notion de fonction virtuelle nrsquoexiste pas tout se passe en fait comme si

toutes les fonctions membres eacutetaient virtuelles En outre comme toute classe est toujours

deacuteriveacutee de la classe Object deux classes diffeacuterentes appartiennent toujours agrave une mecircme

hieacuterarchie Le polymorphisme est donc toujours effectif en Java

3 Autre situation ougrave la ligature dynamique est indispensable

Dans lrsquoexemple preacuteceacutedent lors de la conception de la classe point nous avons preacutevu que cha-

cune de ses descendantes redeacutefinirait agrave sa guise la fonction affiche Cela conduit agrave preacutevoir

dans chaque fonction des instructions drsquoaffichage des coordonneacutees Pour eacuteviter cette redon-

dance1 nous pouvons deacutefinir la fonction affiche (de la classe point) de maniegravere quelle

bull affiche les coordonneacutees (action commune agrave toutes les classes)

1 Bien entendu lenjeu est tregraves limiteacute ici Mais il pourrait ecirctre important dans un cas reacuteel

3 - Autre situation ougrave la ligature dynamique est indispensable309

bull fasse appel agrave une autre fonction (nommeacutee par exemple identifie) ayant pour vocation daf-

ficher les informations speacutecifiques agrave chaque objet Bien entendu ce faisant nous supposons

que chaque descendante de point redeacutefinira identifie de faccedilon approprieacutee (mais elle naura

plus agrave prendre en charge laffichage des coordonneacutees)

Cette deacutemarche nous conduit agrave deacutefinir la classe point de la faccedilon suivante

class point

int x y public

point (int abs=0 int ord=0) x=abs y=ord void identifie ()

cout ltlt Je suis un point n

void affiche () identifie ()

cout ltlt Mes coordonnees sont ltlt x ltlt ltlt y ltlt n

Deacuterivons une classe pointcol en redeacutefinissant comme voulu la fonction identifie

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 ltlt Je suis un point colore de couleur ltlt couleur ltlt n

Si nous cherchons alors agrave utiliser pointcol de la faccedilon suivante

pointcol pc (8 6 2)

pcaffiche ()

nous obtenons le reacutesultat

Je suis un point

Mes coordonneacutees sont 8 6

ce qui nest pas ce que nous espeacuterions

Certes la compilation de lappel

pcaffiche ()

a conduit le compilateur agrave appeler la fonction affiche de la classe point (puisque cette fonc-

tion nest pas redeacutefinie dans pointcol) En revanche agrave ce moment-lagrave lappel

identifie ()

figurant dans cette fonction a deacutejagrave eacuteteacute compileacute en un appel didentifie de la classe point

Comme vous le constatez bien quici la fonction affiche ait eacuteteacute appeleacutee explicitement pour un

objet (et non comme preacuteceacutedemment agrave laide dun pointeur) nous nous trouvons agrave nouveau

en preacutesence dun problegraveme de ligature statique

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

310

Pour le reacutesoudre il suffit de deacuteclarer virtuelle la fonction identifie dans la classe point Cela

permet au compilateur de mettre en place les instructions assurant lappel de la fonction iden-

tifie correspondant au type de lobjet layant effectivement appeleacutee Ici vous noterez cepen-

dant que la situation est leacutegegraverement diffeacuterente de celle qui nous a servi agrave preacutesenter les

fonctions virtuelles (paragraphe 1) En effet lappel didentifie est reacutealiseacute non plus directe-

ment par lobjet lui-mecircme mais indirectement par la fonction affiche Nous verrons comment

le meacutecanisme des fonctions virtuelles est eacutegalement capable de prendre en charge cet aspect

Voici un programme complet reprenant les deacutefinitions des classes point et pointcol Il mon-

tre comment un appel tel que pcaffiche () entraicircne bien lappel de identifie du type pointcol

(ce qui constitue le but de ce paragraphe) A titre indicatif nous avons introduit quelques

appels par pointeur afin de montrer que lagrave aussi les choses se deacuteroulent convenablement

include ltiostreamgtusing namespace std

class point int x y public point (int abs=0 int ord=0) x=abs y=ord virtual void identifie () cout ltlt Je suis un point n void affiche () identifie () cout ltlt Mes coordonnees sont ltlt x ltlt ltlt y ltlt 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 ltlt Je suis un point colore de couleur ltlt couleur ltlt n main() point p(34) pointcol pc(595) paffiche () pcaffiche () cout ltlt ---------------n point adp = ampp pointcol adpc = amppc adp-gtaffiche () adpc-gtaffiche () cout ltlt ---------------n adp = adpc adp-gtaffiche () adpc-gtaffiche ()

Je suis un pointMes coordonnees sont 3 4Je suis un point colore de couleur 5Mes coordonnees sont 5 9---------------

4 - Les proprieacuteteacutes des fonctions virtuelles311

Je suis un point

Mes coordonnees sont 3 4

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

---------------

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

Je suis un point colore de couleur 5

Mes coordonnees sont 5 9

Mise en œuvre de ligature dynamique (ici pour identifie) par la technique des fonctions virtuelles

4 Les proprieacuteteacutes des fonctions virtuellesLes deux exemples preacuteceacutedents constituaient des cas particuliers dutilisation de meacutethodes vir-

tuelles Nous vous proposons ici de voir quelles en sont les possibiliteacutes et les limitations

41 Leurs limitations sont celles de lrsquoheacuteritageA partir du moment ougrave une fonction f a eacuteteacute deacuteclareacutee virtuelle dans une classe A elle sera sou-

mise agrave la ligature dynamique dans A et dans toutes les classes descendantes de A on nest

donc pas limiteacute aux descendantes directes Ainsi on peut imaginer une hieacuterarchie de formes

geacuteomeacutetriques

Si la fonction affiche est deacuteclareacutee virtuelle dans la classe point et redeacutefinie dans les autres

classes descendant de point elle sera bien soumise agrave la ligature dynamique Il est mecircme envi-

sageable que les six classes ci-dessus soient parfaitement deacutefinies et compileacutees et quon

vienne en ajouter de nouvelles sans remettre en cause les preacuteceacutedentes de quelque faccedilon que

ce soit Ce dernier point serait dailleurs encore plus flagrant si comme dans le second exem-

ple (paragraphe 3) la fonction affiche non virtuelle faisait elle-mecircme appel agrave une fonction

virtuelle identifie redeacutefinie dans chaque classe En effet dans ce cas on voit que la fonction

affiche aurait pu ecirctre reacutealiseacutee et compileacutee (au sein de point) sans que toutes les fonctions

identifie quelle eacutetait susceptible dappeler soient connues On trouve lagrave un aspect seacuteduisant

point

carreacute

rectangle

cercle

ellipse

vecteur

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

312

de reacuteutilisabiliteacute on a deacutefini dans affiche un sceacutenario dont certaines parties pourront ecirctre

preacuteciseacutees plus tard lors de la creacuteation de classes deacuteriveacutees

De mecircme supposons que lon ait deacutefini la structure suivante deacutejagrave preacutesenteacutee au paragraphe 4

du chapitre 14

Si dans point la fonction affiche a eacuteteacute deacuteclareacutee virtuelle il devient possible dutiliser la

classe liste-points pour geacuterer une liste dobjets heacuteteacuterogegravenes en deacuterivant les classes voulues

de point et en y redeacutefinissant affiche Vous trouverez un exemple au paragraphe suivant

42 La redeacutefinition dune fonction virtuelle nest pas obligatoireJusquici nous avons toujours redeacutefini dans les classes descendantes une meacutethode deacuteclareacutee

virtuelle dans une classe de base Cela nest pas plus indispensable que dans le cas des fonc-

tions membres ordinaires Ainsi consideacuterons de nouveau la preacuteceacutedente hieacuterarchie de figures

en supposant que affiche na eacuteteacute redeacutefinie que dans les classes que nous avons marqueacutees dune

eacutetoile (et deacutefinie bien sucircr comme virtuelle dans point)

Dans ces conditions lappel daffiche conduira pour chaque classe agrave lappel de la fonction

mentionneacutee agrave cocircteacute

vecteur vecteuraffiche

carre pointaffiche

rectangle pointaffiche

cercle pointaffiche

ellipse ellipseaffiche

liste point

liste_points

point

carreacute

rectangle

cercle

ellipse

vecteur

4 - Les proprieacuteteacutes des fonctions virtuelles313

Le mecircme meacutecanisme sappliquerait en cas dheacuteritage multiple agrave condition de le compleacuteter par

les regravegles concernant les ambiguiumlteacutes

43 Fonctions virtuelles et surdeacutefinitionOn peut surdeacutefinir1 une fonction virtuelle chaque fonction surdeacutefinie pouvant ecirctre deacuteclareacutee

virtuelle ou non

Par ailleurs si lon a deacutefini une fonction virtuelle dans une classe et quon la surdeacutefinit dans

une classe deacuteriveacutee avec des arguments diffeacuterents il sagira alors bel et bien dune autre fonc-

tion Si cette derniegravere nest pas deacuteclareacutee virtuelle elle sera soumise agrave une ligature statique

En fait on peut consideacuterer que le statut virtuelnon virtuel joue lui aussi un rocircle discrimina-

teur dans le choix dune fonction surdeacutefinie Par souci de simpliciteacute et de lisibiliteacute nous vous

conseillons deacuteviter dexploiter cette possibiliteacute si vous devez surdeacutefinir une fonction vir-

tuelle il est preacutefeacuterable que toutes les fonctions de mecircme nom restent virtuelles

44 Le type de retour drsquoune fonction virtuelle redeacutefinieDans la redeacutefinition drsquoune fonction membre usuelle (non virtuelle) on ne tient pas compte du

type de la valeur de retour ce qui est logique Mais dans le cas drsquoune fonction virtuelle des-

tineacutee agrave ecirctre deacutefinie ulteacuterieurement il nrsquoen va plus de mecircme Par exemple supposons que

dans la hieacuterarchie de classes du paragraphe preacuteceacutedent la fonction affiche soit deacutefinie ainsi

dans point

virtual void affiche ()

et ainsi dans ellipse

virtual int affiche ()

Il va alors de soi que le polymorphisme fonctionnerait mal Crsquoest pourquoi C++ refuse cette

possibiliteacute qui conduit agrave une erreur de compilation

La redeacutefinition drsquoune fonction virtuelle doit donc respecter exactement le type de la

valeur de retour Il existe toutefois une exception agrave cette regravegle qui concerne ce que lrsquoon

nomme parfois les valeurs de retour covariantes Il srsquoagit du cas ougrave la valeur de retour

drsquoune fonction virtuelle est un pointeur ou une reacutefeacuterence sur une classe C La redeacutefinition

de cette fonction virtuelle dans une classe deacuteriveacutee peut alors se faire avec un pointeur ou une

reacutefeacuterence sur une classe deacuteriveacutee de C En voici un exemple

class Y public X Y deacuterive de Xclass A public virtual X amp f (int) Af(int) renvoie un X

1 Ne confondez pas surdeacutefinition et redeacutefinition

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

314

class B public A public virtual Y amp f (int) Bf(int) renvoie un Y Bf(int) redeacutefinit bien Af(int)

Bien entendu qui peut le plus peut le moins Si X et Y correspondent agrave A et B on a

class A public virtual A amp f (int) Af(int) renvoie un A class B public A public virtual B amp f (int) Bf(int) renvoie un B Bf(int) redeacutefinit bien Af(int) et renvoie un B

On obtient ainsi une geacuteneacuteralisation du polymorphisme agrave la valeur de retour

45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe

Dans tous nos exemples nous avions deacuteclareacute virtuelle une fonction dune classe qui neacutetait

pas elle-mecircme deacuteriveacutee dune autre Cela nest pas obligatoire Ainsi dans les exemples de

hieacuterarchie de formes point pourrait elle-mecircme deacuteriver dune autre classe Cependant il faut

alors distinguer deux situations

bull La fonction affiche de la classe point na jamais eacuteteacute deacutefinie dans les classes ascendantes

aucun problegraveme particulier ne se pose

bull La fonction affiche a deacutejagrave eacuteteacute deacutefinie avec les mecircmes arguments dans une classe ascendan-

te Dans ce cas il faut consideacuterer la fonction virtuelle affiche comme une nouvelle fonction

(comme sil y avait eu surdeacutefinition le caractegravere virtuelnon virtuel servant agrave faire la dis-

tinction) Bien entendu toutes les nouvelles deacutefinitions daffiche dans les classes descendan-

tes seront soumises agrave la ligature dynamique sauf si lon effectue un appel explicite dune

fonction dune classe ascendante au moyen de lopeacuterateur de reacutesolution de porteacutee Rappelons

toutefois que nous vous deacuteconseillons fortement ce type de situation

46 Quelques restrictions et conseils

461 Seule une fonction membre peut ecirctre virtuelleCela se justifie par le meacutecanisme employeacute pour effectuer la ligature dynamique agrave savoir un

choix baseacute sur le type de lrsquoobjet ayant appeleacute la fonction Cela ne pourrait pas srsquoappliquer agrave

une fonction ordinaire (mecircme si elle eacutetait amie drsquoune classe)

4 - Les proprieacuteteacutes des fonctions virtuelles315

462 Un constructeur ne peut pas ecirctre virtuel

De par sa nature un construteur ne peut ecirctre appeleacute que pour un type classe parfaitement

deacutefini qui sert preacuteciseacutement agrave deacutefinir le type de lrsquoobjet agrave construire A priori donc un cons-

tructeur nrsquoa aucune raison drsquoecirctre soumis au polymorphisme Drsquoailleurs on peut penser qursquoon

nrsquoappelle jamais un constructeur par pointeur ou reacutefeacuterence Cependant il existe des situations

particuliegraveres lieacutees agrave lrsquoappel implicite drsquoun constructeur par recopie (qui constitue un cons-

tructeur comme un autre ) Voyez cet exemple

include ltiostreamgtusing namespace std class A public A (const A amp) cout ltlt Constructeur de recopie de An A () class B public A public B (const B amp b) A (b) cout ltlt CR copy Bn B() void g (A a) reccediloit une copievoid f (A ada) g(ada) main () B adb = new B A ada = adb f(ada) ada pointe sur un objet de type B

Constructeur de recopie de A

Appel implicite drsquoun constructeur par recopie

La fonction ordinaire f reccediloit lrsquoadresse drsquoun objet de type B par lrsquointermeacutediaire drsquoun poin-

teur de type A Elle appelle alors la fonction g en lui transmettant lrsquoobjet correspondant par

valeur ce qui entraicircne lrsquoappel du construteur par recopie de la classe A Pour qursquoil y ait appel

de celui de la classe B il aurait fallu qursquoil y ait polymorphisme donc que ce constructeur soit

virtuel ce qui nrsquoest pas possible

463 Un destructeur peut ecirctre virtuel

En revanche un destructeur peut ecirctre virtuel Il est toutefois conseilleacute de prendre quelques

preacutecautions agrave ce sujet En effet consideacuterons cette situation

class A public ~A() class B public A public ~B() la presence de virtual ici ne changerait rien

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

316

main()

A a B b

b = new B()

a = b

delete a a pointe sur un objet de type B mais on nrsquoappelle que ~A

Comme on peut srsquoy attendre lrsquoappel de delete sur lrsquoobjet de type B pointeacute par a ne conduira

qursquoagrave lrsquoappel du destructeur de A lequel opegravere quand mecircme sur un objet de type B Il est clair

que les conseacutequences peuvent ecirctre deacutesastreuses Deux deacutemarches permettent de pallier cette

difficulteacute

bull soit interdire la suppression drsquoobjets de type A il suffit alors de ne pas placer de destructeur

dans A ou encore de le rendre priveacute ou proteacutegeacute

bull soit placer dans A un constructeur virtuel (quitte agrave ce qursquoil soit vide)

class A public ~A()

class B public A

public ~B() la presence de virtual ici est facultative

main()

A a B b

b = new B()

a = b

delete a a pointe sur un objet de type B et on appelle bien ~B

Dans ces conditions les destructeurs des classes deacuteriveacutees seront bien virtuels (mecircme si le

mot-cleacute virtual nrsquoest pas rappeleacute et bien que leurs noms soient diffeacuterents drsquoune classe agrave sa

deacuteriveacutee) Ici on appellera donc bien le destructeur du type B

Drsquoune maniegravere geacuteneacuterale nous vous encourageons agrave respecter la regravegle suivante

464 Cas particulier de lrsquoopeacuterateur drsquoaffectation

En theacuteorie lrsquoopeacuterateur drsquoaffectation peut comme toute fonction membre ecirctre deacuteclareacute virtuel

Cependant il faut bien voir que cette fonction est particuliegravere dans la mesure ougrave la deacutefinition

de lrsquoaffectation drsquoune classe B deacuteriveacutee de A ne constitue pas une redeacutefinition de lrsquoopeacuterateur

drsquoaffectation de A On nrsquoest donc pas dans une situation de polymorphisme comme le mon-

tre cet exemple artificiel

Dans une classe de base (destineacutee agrave ecirctre deacuteriveacutee) preacutevoir

- soit aucun destructeur

- soit un destructeur priveacute ou proteacutegeacute

- soit un destructeur public et virtuel

5 - Les fonctions virtuelles pures pour la creacuteation de classes abstraites317

include ltiostreamgtusing namespace std

class A public virtual A amp operator = (const A amp) cout ltlt affectation fictive An

class B public A public virtual B amp operator = (const B amp) cout ltlt affectation fictive Bn

main () B adb1 = new B B adb2 = new B

adb1 = adb2 A ada1 = new A A ada2 = new A ada1 = adb1 ada2 = adb2

ada1 = ada2 appelle affectation de A - virtual ne sert a rien car on ne redeacutefinit pas la meme fonction

affectation fictive Baffectation fictive A

Le polymorphisme ne peut pas srsquoappliquer agrave lrsquoaffectation

5 Les fonctions virtuelles pures pour la creacuteation de classes abstraites

Nous avons deacutejagrave eu loccasion de dire quon pouvait deacutefinir des classes destineacutees non pas agrave

instancier des objets mais simplement agrave donner naissance agrave dautres classes par heacuteritage En

POO on dit quon a affaire agrave des classes abstraites

En C++ vous pouvez toujours deacutefinir de telles classes Mais vous devrez peut-ecirctre y intro-

duire certaines fonctions virtuelles dont vous ne pouvez encore donner aucune deacutefinition

Imaginez par exemple une classe abstraite forme_geo destineacutee agrave geacuterer le dessin sur un eacutecran

de diffeacuterentes formes geacuteomeacutetriques (carreacute cercle) Supposez que vous souhaitiez deacutejagrave y

faire figurer une fonction deplace destineacutee agrave deacuteplacer une figure Il est probable que celle-ci

fera alors appel agrave une fonction daffichage de la figure (nommeacutee par exemple dessine) La

fonction dessine sera deacuteclareacutee virtuelle dans la classe forme_geo et devra ecirctre redeacutefinie dans

ses descendants Mais quelle deacutefinition lui fournir dans forme_geo Avec ce que vous con-

naissez de C++ vous avez toujours la ressource de preacutevoir une deacutefinition vide1

1 Notez bien quil vous faut absolument deacutefinir dessine dans forme_geo puisquelle est appeleacutee par deplace

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

318

Toutefois deux lacunes apparaissent alors

bull Rien ninterdit agrave un utilisateur de deacuteclarer un objet de classe forme_geo alors que dans les-

prit du concepteur il sagissait dune classe abstraite Lappel de deplace pour un tel objet

conduira agrave un appel de dessine ne faisant rien mecircme si aucune erreur nen deacutecoule cela na

guegravere de sens

bull Rien noblige une classe descendant de forme_geo agrave redeacutefinir dessine Si elle ne le fait pas

on retrouve les problegravemes eacutevoqueacutes ci-dessus

C++ propose un outil facilitant la deacutefinition de classes abstraites les fonctions virtuelles

pures Ce sont des fonctions virtuelles dont la deacutefinition est nulle (0) et non plus seulement

vide Par exemple nous aurions pu faire de notre fonction dessine de la classe forme_geo une

fonction virtuelle pure en la deacuteclarant1 ainsi

virtual void dessine () = 0

Certes agrave ce niveau linteacuterecirct de cette convention napparaicirct pas encore Mais C++ adopte les

regravegles suivantes

bull Une classe comportant au moins une fonction virtuelle pure est consideacutereacutee comme abstraite

et il nest plus possible de deacuteclarer des objets de son type

bull Une fonction deacuteclareacutee virtuelle pure dans une classe de base doit obligatoirement ecirctre redeacute-

finie2 dans une classe deacuteriveacutee ou deacuteclareacutee agrave nouveau virtuelle pure3 dans ce dernier cas la

classe deacuteriveacutee est elle aussi abstraite

Comme vous le voyez lemploi de fonctions virtuelles pures regravegle les deux problegravemes soule-

veacutes par lemploi de deacutefinitions vides Dans le cas de notre classe forme_geo le fait davoir

rendu dessine virtuelle pure interdit

bull la deacuteclaration dobjets de type forme_geo

bull la deacutefinition de classes deacuteriveacutees de forme_geo dans lesquelles on omettrait la deacutefinition de

dessine

Remarque

La notion de fonction virtuelle pure deacutepasse celle de classe abstraite Si C++ seacutetait con-

tenteacute de deacuteclarer une classe comme abstraite cela naurait servi quagrave en interdire

lutilisation il aurait fallu une seconde convention pour preacuteciser les fonctions devant

obligatoirement ecirctre redeacutefinies

1 Ici on ne peut plus distinguer deacuteclaration et deacutefinition

2 Toujours avec les mecircmes arguments sinon il sagit dune autre fonction

3 Depuis la version 30 si une fonction virtuelle pure dune classe de base nest pas redeacutefinie dans une classe deacuteri-

veacutee elle reste une fonction virtuelle pure de cette classe deacuteriveacutee dans les versions anteacuterieures on obtenait une

erreur

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene319

En Java

On peut deacutefinir explicitement une classe abstraite en utilisant tout naturellement le mot

cleacute abstract1 On y preacutecise alors (toujours avec ce mecircme mot cleacute abstract) les meacutethodes

qui doivent obligatoirement ecirctre redeacutefinies dans les classes deacuteriveacutees

6 Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene

Nous allons creacuteer une classe permettant de geacuterer une liste chaicircneacutee drsquoobjets de types diffeacuterents

et disposant des fonctionnaliteacutes suivantes

bull ajout drsquoun nouvel eacuteleacutement

bull affichage des valeurs de tous les eacuteleacutements de la liste

bull meacutecanisme de parcours de la liste

Rappelons que dans une liste chaicircneacutee chaque eacuteleacutement comporte un pointeur sur lrsquoeacuteleacutement

suivant En outre un pointeur deacutesigne le premier eacuteleacutement de la liste Cela correspond agrave ce

scheacutema

Mais ici lrsquoon souhaite que les diffeacuterentes informations puissent ecirctre de types diffeacuterents Aussi

chercherons nous agrave isoler dans une classe (nommeacutee liste) toutes les fonctionnaliteacutes de gestion

de la liste elle-mecircme sans entrer dans les deacutetails speacutecifiques aux objets concerneacutes Nous

appliquerons alors ce scheacutema

1 Ce qui est manifestement plus logique et plus direct qursquoen C++

Informations

1

Informations

3

Informations

2

debut

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

320

La classe liste elle-mecircme se contentera donc de geacuterer des eacuteleacutements simples reacuteduits chacun agrave

bull un pointeur sur leacuteleacutement suivant

bull un pointeur sur linformation associeacutee (en fait ici un objet)

On voit donc que la classe va posseacuteder au moins

bull un membre donneacutee pointeur sur le premier eacuteleacutement (debut dans notre scheacutema)

bull une fonction membre destineacutee agrave inseacuterer dans la liste un objet dont on lui fournira lrsquoadresse

(nous choisirons lrsquoinsertion en deacutebut de liste par souci de simplification)

Lrsquoaffichage des eacuteleacutements de la liste se fera en appelant une meacutethode affiche speacutecifique agrave

lrsquoobjet concerneacute Cela implique la mise en oeuvre de la ligature dynamique par le biais des

fonctions virtuelles La fonction affiche sera deacutefinie dans un premier type drsquoobjet (nommeacute ici

mere) et redeacutefinie dans chacune de ses descendantes

En deacutefinitive on pourra geacuterer une liste dobjets de types diffeacuterents sous reacuteserve que les clas-

ses correspondantes soient toutes deacuteriveacutees dune mecircme classe de base Cela peut sembler

quelque peu restrictif En fait cette famille de classes peut toujours ecirctre obtenue par la

creacuteation dune classe abstraite (reacuteduite au minimum eacuteventuellement agrave une fonction affiche

vide ou virtuelle pure) destineacutee simplement agrave donner naissance aux classes concerneacutees Bien

entendu cela nest concevable que si les classes en question ne sont pas deacutejagrave figeacutees (car il faut

quelles heacuteritent de cette classe abstraite)

Dougrave une premiegravere eacutebauche de la classe liste

struct element structure dun eacuteleacutement de liste element suivant pointeur sur leacuteleacutement suivant

mere contenu pointeur sur un objet quelconque

Objet

1

Objet

3

Objet

2

debut

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene321

class liste element debut pointeur sur premier eacuteleacutement public liste () constructeur ~liste () destructeur void ajoute (mere ) ajoute un eacuteleacutement en deacutebut de liste void affiche ()

Pour mettre en oeuvre le parcours de la liste nous preacutevoyons des fonctions eacuteleacutementaires

pour

bull initialiser le parcours

bull avancer dun eacuteleacutement

Celles-ci neacutecessitent un pointeur sur un eacuteleacutement courant Il sera membre donneacutee de notre

classe liste nous le nommerons courant Par ailleurs les deux fonctions membres eacutevoqueacutees

doivent fournir en retour une information concernant lobjet courant A ce niveau on peut

choisir entre

bull lrsquoadresse de leacuteleacutement courant

bull lrsquoadresse de lobjet courant (crsquoest-agrave-dire lrsquoobjet pointeacute par lrsquoeacuteleacutement courant)

bull la valeur de leacuteleacutement courant

La deuxiegraveme solution semble la plus naturelle Il faut simplement fournir agrave lrsquoutilisateur un

moyen de deacutetecter la fin de liste Nous preacutevoirons donc une fonction suppleacutementaire permet-

tant de savoir si la fin de liste est atteinte (en toute rigueur nous aurions aussi pu fournir un

pointeur nul comme adresse de lobjet courant mais ce serait moins pratique car il faudrait

obligatoirement agir sur le pointeur de liste avant de savoir si lon est agrave la fin)

En deacutefinitive nous introduisons trois nouvelles fonctions membres

void premier () void prochain () int fini ()

Voici la liste complegravete des diffeacuterentes classes voulues Nous lui avons adjoint un petit pro-

gramme drsquoessai qui deacutefinit deux classes point et complexe (lesquelles nrsquoont pas besoin de

deacuteriver lrsquoune de lrsquoautre) deacuteriveacutees de la classe abstraite mere et doteacutees chacune drsquoune fonction

affiche approprieacutee

include ltiostreamgtinclude ltcstddefgt pour la deacutefinition de NULLusing namespace std classe mere class mere public virtual void affiche () = 0 fonction virtuelle pure

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

322

classe liste struct element structure dun eacuteleacutement de liste element suivant pointeur sur leacuteleacutement suivant mere contenu pointeur sur un objet quelconque class liste element debut pointeur sur premier eacuteleacutement element courant pointeur sur eacuteleacutement courant public liste () constructeur debut = NULL courant = debut ~liste () destructeur void ajoute (mere ) ajoute un eacuteleacutement void premier () positionne sur premier eacuteleacutement courant = debut

mere prochain () fournit lrsquoadresse de leacuteleacutement courant (0 si fin) et positionne sur prochain eacuteleacutement (rien si fin) mere adsuiv = NULL if (courant = NULL) adsuiv = courant -gt contenu courant = courant -gt suivant return adsuiv void affiche_liste () affiche tous les eacuteleacutements de la liste int fini () return (courant == NULL)

liste~liste () element suiv courant = debut while (courant = NULL ) suiv = courant-gtsuivant delete courant courant = suiv

void listeajoute (mere chose) element adel = new element adel-gtsuivant = debut adel-gtcontenu = chose debut = adel

void listeaffiche_liste () mere ptr premier() while ( fini() ) ptr = (mere ) prochain() ptr-gtaffiche ()

6 - Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene323

classe point

class point public mere

int x y

public

point (int abs=0 int ord=0) x=abs y=ord

void affiche ()

cout ltlt Point de coordonnees ltlt x ltlt ltlt y ltlt n

classe complexe

class complexe public mere

double reel imag

public

complexe (double r=0 double i=0) reel=r imag=i

void affiche ()

cout ltlt Complexe ltlt reel ltlt + ltlt imag ltlt in

programme drsquoessai

main()

liste l1

point a(23) b(59)

complexe x(4527) y(235486)

l1ajoute (ampa) l1ajoute (ampx) l1affiche_liste ()

cout ltlt --------n

l1ajoute (ampy) l1ajoute (ampb) l1affiche_liste ()

Complexe 45 + 27i

Point de coordonnees 2 3

--------

Point de coordonnees 5 9

Complexe 235 + 486i

Complexe 45 + 27i

Point de coordonnees 2 3

Deacuteclaration deacutefinition et utilisation drsquoune liste heacuteteacuterogegravene

Remarque

Par souci de simpliciteacute nous nrsquoavons pas redeacutefini dans la classe liste lrsquoopeacuterateur drsquoaffec-

tation et le constructeur de recopie Dans un programme reacuteel il faudrait le faire quite

drsquoailleurs agrave ce que ces fonctions se contentent drsquointerrompre lrsquoexeacutecution ou encore de

lever une exception (comme nous apprendrons agrave le faire plus tard)

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

324

7 Le meacutecanisme drsquoidentification dynamique des objetsNB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Nous avons vu que la technique des fonctions virtuelles permettait de mettre en œuvre la

ligature dynamique pour les fonctions concerneacutees Cependant pour linstant cette technique

peut vous apparaicirctre comme une simple recette La compreacutehension plus fine du meacutecanisme

et donc sa porteacutee veacuteritable passent par la connaissance de la maniegravere dont il est effective-

ment implanteacute Bien que cette impleacutementation ne soit pas explicitement imposeacutee par le lan-

gage nous vous proposons de deacutecrire ici la deacutemarche couramment adopteacutee par les diffeacuterents

compilateurs existants

Pour ce faire nous allons consideacuterer un exemple un peu plus geacuteneacuteral que le preacuteceacutedent agrave

savoir

bull une classe point comportant deux fonctions virtuelles

class point virtual void identifie () virtual void deplace ()

bull une classe pointcol deacuteriveacutee de point ne redeacutefinissant que identifie

class pointcol public point void identifie ()

Dune maniegravere geacuteneacuterale lorsquune classe comporte au moins une fonction virtuelle le com-

pilateur lui associe une table contenant les adresses de chacune des fonctions virtuelles cor-

respondantes Avec lexemple citeacute nous obtiendrons les deux tables suivantes

bull lors de la compilation de point

Table de point

amppointdeplace

amppointidentifie

7 - Le meacutecanisme drsquoidentification dynamique des objets325

bull lors de la compilation de pointcol

Table de pointcol

Notez quici la seconde adresse de la table de pointcol est la mecircme que pour la table de point

dans la mesure ougrave la fonction deplace na pas eacuteteacute redeacutefinie

Dautre part tout objet dune classe comportant au moins une fonction virtuelle se voit attri-

buer par le compilateur outre lemplacement meacutemoire neacutecessaire agrave ses membres donneacutee un

emplacement suppleacutementaire de type pointeur contenant ladresse de la table associeacutee agrave sa

classe Par exemple si nous deacuteclarons (en supposant que nous disposons des constructeurs

habituels)

point p (3 5) pointcol pc (8 6 2)

nous obtiendrons

On peut ainsi dire que ce pointeur introduit dans chaque objet repreacutesente linformation per-

mettant didentifier la classe de lobjet Cest effectivement cette information qui est exploiteacutee

pour mettre en œuvre la ligature dynamique Chaque appel dune fonction virtuelle est traduit

par le compilateur de la faccedilon suivante

bull preacutelegravevement dans lobjet de ladresse de la table correspondante (quelle que soit la maniegravere

dont une fonction est appeleacutee ndash directement ou par pointeur ndash elle reccediloit toujours ladresse

de lobjet en argument implicite)

bull branchement agrave ladresse figurant dans cette table agrave un rang donneacute Notez bien que ce rang

est parfaitement deacutefini agrave la compilation toutes les tables comporteront ladresse de depla-

ce1 par exemple en position 2 En revanche cest lors de lexeacutecution que sera effectueacute le

choix de la bonne table

amppointcolidentifie

amppointcoldeplace

3

vers table de point

vers table de pointcol

5

6

8

2

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

326

8 Identification de type agrave lexeacutecutionLa norme ANSI a introduit dans C++ un meacutecanisme permettant de connaicirctre (identifier et

comparer) lors de lexeacutecution du programme le type dune variable dune expression ou dun

objet1

Bien entendu cela ne preacutesente guegravere dinteacuterecirct si un tel type est deacutefini lors de la compilation

Ainsi avec

int n float x

il ne sera guegravere inteacuteressant de savoir que le type de n ou celui de x peuvent ecirctre connus ou

encore que n et x sont dun type diffeacuterent La mecircme remarque sappliquerait agrave des objets dun

type classe

En fait cette possibiliteacute a surtout eacuteteacute introduite pour ecirctre utiliseacutee dans les situations de poly-

morphisme que nous avons eacutevoqueacutees tout au long de ce chapitre

Plus preacuteciseacutement il est possible lors de lexeacutecution de connaicirctre le veacuteritable type dun

objet deacutesigneacute par un pointeur ou par une reacutefeacuterence

Pour ce faire il existe un opeacuterateur agrave un opeacuterande nommeacute typeid fournissant en reacutesultat un

objet de type preacutedeacutefini type_info Cette classe contient la fonction membre name() laquelle

fournit une chaicircne de caractegraveres2 repreacutesentant le nom du type Ce nom nest pas imposeacute par la

norme il peut donc deacutependre de limpleacutementation mais on est sucircr que deux types diffeacuterents

nauront jamais le mecircme nom

De plus la classe dispose de deux opeacuterateurs binaires == et = qui permettent de comparer

deux types

81 Utilisation du champ name de type_infoVoici un premier exemple inspireacute du programme utiliseacute au paragraphe 2 pour illustrer le

meacutecanisme des fonctions virtuelles il montre linteacuterecirct que preacutesente typeid lorsquon lappli-

que dans un contexte de polymorphisme

include ltiostreamgtinclude lttypeinfogt pour typeidusing namespace std

1 Eventuellement les tables de certaines classes pourront contenir plus dadresses si elles introduisent de nouvelles

fonctions virtuelles mais celles quelles partagent avec leurs ascendantes occuperont toujours la mecircme place et cest

lagrave lessentiel pour le bon deacuteroulement des opeacuterations

1 En anglais ce meacutecanisme est souvent nommeacute RTTI (Run Time Type Identification)

2 Il srsquoagit drsquoune chaicircne au sens du C (pointeur de type char ) et non drsquoun objet de type preacutedeacutefini string

8 - Identification de type agrave lexeacutecution327

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 = ampp cout ltlt type de adp ltlt typeid (adp)name() ltlt n cout ltlt type de adp ltlt typeid (adp)name() ltlt n

adp = amppc cout ltlt type de adp ltlt typeid (adp)name() ltlt n cout ltlt type de adp ltlt typeid (adp)name() ltlt n

type de adp point type de adp point

type de adp point type de adp pointcol

Exemple dutilisation de lopeacuterateur typeid

On notera bien que pour typeid le type du pointeur adp reste bien point En revanche le

type de lobjet pointeacute (adp) est bien deacutetermineacute par la nature exacte de lobjet pointeacute

Remarques

1 Rappelons que la norme nimpose pas le nom exact que doit fournir cet opeacuterateur on

nest donc pas assureacute que le nom de type sera toujours point point pointcol comme

ici

2 Ici les meacutethodes affiche ont eacuteteacute preacutevues vides elles ne servent en fait quagrave assurer le

polymorphisme En lrsquoabsence de meacutethode virtuelle lopeacuterateur typeid se contenterait de

fournir comme type dun objet pointeacute celui deacutefini par le type (statique) du pointeur

Notez que nous nrsquoavons pas utiliseacute une fonction virtuelle pure dans point car il nrsquoaurait

plus eacuteteacute possible drsquoinstancier un objet de type point

3 Le typage dynamique obtenu par les fonctions virtuelles permet drsquoobtenir drsquoun objet un

comportement adapteacute agrave son type sans qursquoil soit pour autant possible de connaicirctre expli-

citement ce type Ces possibiliteacutes srsquoavegraverent geacuteneacuteralement suffisantes Seules quelques

applications tregraves speacutecifiques (telles que des deacutebogueurs) auront besoin de recourir agrave

lrsquoidentification dynamique de type

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

328

82 Utilisation des opeacuterateurs de comparaison de type_infoVoici toujours inspireacute du programme utiliseacute au paragraphe 2 un exemple montrant lrsquoutilisa-

tion de lrsquoopeacuterateur ==

include ltiostreamgtinclude lttypeinfogt pour typeid

using namespace std 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 = ampp1 adp2 = ampp2 cout ltlt En A les objets pointes par adp1 et adp2 sont de if (typeid(adp1) == typeid (adp2)) cout ltlt meme typen else cout ltlt type differentn adp1 = ampp1 adp2 = amppc cout ltlt En B les objets pointes par adp1 et adp2 sont de if (typeid(adp1) == typeid (adp2)) cout ltlt meme typen else cout ltlt type differentn

En A les objets pointes par adp1 et adp2 sont de meme typeEn B les objets pointes par adp1 et adp2 sont de type different

Exemple de comparaison de types dynamiques avec lrsquoopeacuterateur == (1)

83 Exemple avec des reacutefeacuterencesVoici un dernier exemple ougrave lrsquoon applique lrsquoopeacuterateur == agrave des reacutefeacuterences On voit qursquoon dis-

pose ainsi drsquoun moyen de srsquoassurer dynamiquement (au moment de lrsquoexeacutecution) de lrsquoidentiteacute

de type de deux objets reccedilus en argument drsquoune fonction

include ltiostreamgtinclude lttypeinfogt pour typeidusing namespace std

9 - Les cast dynamiques329

class point public virtual void affiche () ici vide class pointcol public point public void affiche () ici vide void fct (point amp a point amp b) if (typeid(a) == typeid(b)) cout ltlt reference a des objets de meme type n else cout ltlt reference a des objets de type different n main() point p pointcol pc1 pc2 cout ltlt Appel A fct (p pc1) cout ltlt Appel B fct (pc1 pc2)

Appel A reference a des objets de meme typeAppel B reference a des objets de type different

Exemple de comparaison de types dynamiques avec lrsquoopeacuterateur == (2)

9 Les cast dynamiquesNous venons de voir comment les possibiliteacutes didentification des types agrave lexeacutecution complegrave-

tent le polymorphisme offert par les fonctions virtuelles en permettant didentifier le type des

objets pointeacutes ou reacutefeacuterenceacutes

Cependant une lacune subsiste on sait agir sur lobjet pointeacute en fonction de son type on

peut connaicirctre le type exact de cet objet mais le type proprement dit des pointeurs utiliseacutes

dans ce polymorphisme reste celui deacutefini agrave la compilation Par exemple si lon sait que adp

pointe sur un objet de type pointcol (deacuteriveacute de point) on pourrait souhaiter convertir sa

valeur en un pointeur de type pointcol

La norme de C++ a introduit cette possibiliteacute par le biais dopeacuterateurs dits cast dynamiques

Ainsi avec lhypothegravese preacuteceacutedente (on est sucircr que adp pointe reacuteellement sur un objet de type

pointcol) on pourra eacutecrire

pointcol adpc = dynamic_cast ltpointcol gt (adp)

Bien entendu en compilation la seule veacuterification qui sera faite est que cette conversion est

(peut-ecirctre) acceptable car lobjet pointeacute par adp est dun type point ou deacuteriveacute et pointcol est

lui-mecircme deacuteriveacute de point Mais ce nest quau moment de lexeacutecution quon saura si la conver-

Les fonctions virtuelles et le polymorphismeCHAPITRE 15

330

sion est reacutealisable ou non Par exemple si adp pointait sur un objet de type point la conver-

sion eacutechouerait

Drsquoune maniegravere geacuteneacuterale lopeacuterateur dynamic_cast aboutit si lobjet reacuteellement pointeacute est par

rapport au type darriveacutee demandeacute dun type identique ou dun type descendant (mais dans un

contexte de polymorphisme cest-agrave-dire quil doit exister au moins une fonction virtuelle)

Lorsque lopeacuterateur naboutit pas

bull il fournit le pointeur NULL sil sagit dune conversion de pointeur

bull il deacuteclenche une exception bad_cast sil sagit dune conversion de reacutefeacuterence

Voici un exemple faisant intervenir une hieacuterarchie de trois classes deacuteriveacutees les unes des

autres

include ltiostreamgtusing namespace std

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 = ampa ada de type A pointe sur un A sa conversion dynamique en B ne marche pas adb = dynamic_cast ltB gt (ada) cout ltlt dc ltBgt(ada) ltlt adb ltlt n ada = ampb ada de type A pointe sur un B sa conversion dynamique en B marche adb = dynamic_cast ltB gt (ada) cout ltlt dc ltBgt ada ltlt adb ltlt n sa conversion dynamique en A marche ada1 = dynamic_cast ltAgt (ada) cout ltlt dc ltAgt ada ltlt ada1 ltlt n mais sa conversion dynamique en C ne marche pas adc = dynamic_cast ltC gt (ada) cout ltlt dc ltCgt ada ltlt adc ltlt n adb = ampb adb de type B pointe sur un B sa conversion dynamique en A marche

9 - Les cast dynamiques331

ada1 = dynamic_cast ltA gt (adb) cout ltlt dc ltAgt adb ltlt ada1 ltlt n sa conversion dynamique en B marche adb1 = dynamic_cast ltB gt (adb) cout ltlt dc ltAgt adb1 ltlt adb1 ltlt n mais sa conversion dynamique en C ne marche pas adc = dynamic_cast ltC gt (adb) cout ltlt dc ltCgt adb1 ltlt adc ltlt n

dc ltBgt(ada) 0x00000000dc ltBgt ada 0x54820ffcdc ltAgt ada 0x54820ffcdc ltCgt ada 0x00000000dc ltAgt adb 0x54820ffcdc ltAgt adb1 0x54820ffcdc ltCgt adb1 0x00000000

Exemple dutilisation de lopeacuterateur dynamic_cast

16

Les flots

Au cours des preacuteceacutedents chapitres nous avons souvent eacuteteacute ameneacute agrave eacutecrire sur la sortie stan-

dard Pour ce faire nous utilisions des instructions telles que

cout ltlt n

Cette derniegravere fait appel agrave lopeacuterateur ltlt auquel elle fournit deux opeacuterandes correspondant

respectivement au flot de sortie concerneacute (ici cout) et agrave lexpression dont on souhaite eacutecrire

la valeur (ici n)

De mecircme nous avons eacuteteacute ameneacute agrave lire sur lrsquoentreacutee standard en utilisant des instructions telles

que

cin gtgt x

Celle-ci fait appel agrave lopeacuterateur gtgt auquel elle fournit deux opeacuterandes correspondant respec-

tivement au flot dentreacutee concerneacute (ici cin) et agrave la lvalue dans laquelle on souhaite lire une

information

Dune maniegravere geacuteneacuterale un flot peut ecirctre consideacutereacute comme un canal

bull recevant de linformation ndash flot de sortie

bull fournissant de linformation ndash flot dentreacutee

Les opeacuterateurs ltlt ou gtgt servent agrave assurer le transfert de linformation ainsi que son eacuteventuel

formatage

Un flot peut ecirctre connecteacute agrave un peacuteripheacuterique ou agrave un fichier Par convention le flot preacutedeacutefini

cout est connecteacute agrave ce que lon nomme la sortie standard correspondant au fichier preacutedeacutefini

stdout du langage C De mecircme le flot preacutedeacutefini cin est connecteacute agrave ce que lon nomme

lentreacutee standard correspondant au fichier preacutedeacutefini stdin du langage C Geacuteneacuteralement

Les flotsCHAPITRE 16

334

lentreacutee standard correspond par deacutefaut au clavier et la sortie standard agrave lrsquoeacutecran mais la plu-

part des impleacutementations vous permettent de rediriger lentreacutee standard ou la sortie standard

vers un fichier

En dehors de ces flots preacutedeacutefinis1 lutilisateur peut deacutefinir lui-mecircme dautres flots quil

pourra connecter agrave un fichier de son choix

On peut dire quun flot est un objet dune classe preacutedeacutefinie agrave savoir

bull ostream pour un flot de sortie

bull istream pour un flot dentreacutee

Chacune de ces deux classes surdeacutefinit les opeacuterateurs ltlt et gtgt pour les diffeacuterents types de

base Leur emploi neacutecessite lincorporation du fichier en-tecircte iostream

Jusquici nous nous sommes contenteacute dexploiter quelques-unes des possibiliteacutes des classes

istream et ostream en nous limitant aux flots preacutedeacutefinis cin et cout Ce chapitre va faire le

point sur lensemble des possibiliteacutes dentreacutees-sorties offertes par C++ telles quelles sont preacute-

vues par la norme ANSI

Nous adopterons la progression suivante

bull preacutesentation geacuteneacuterale des possibiliteacutes de la classe ostream types de base accepteacutes princi-

pales fonctions membres (put write) exemples de formatage de linformation

bull preacutesentation geacuteneacuterale des possibiliteacutes de la classe istream types de base accepteacutes principa-

les fonctions membres (get getline gcount read)

bull gestion du statut derreur dun flot

bull possibiliteacutes de surdeacutefinition des opeacuterateurs ltlt et gtgt pour des types (classes) deacutefinis par

lutilisateur

bull eacutetude deacutetailleacutee des possibiliteacutes de formatage des informations aussi bien en entreacutee quen

sortie

bull connexion dun flot agrave un fichier et possibiliteacutes daccegraves direct offertes dans ce cas

Drsquoune maniegravere geacuteneacuterale sachez que tout ce qui sera dit degraves le deacutebut de ce chapitre agrave propos

des flots sappliquera sans restriction agrave nrsquoimporte quel flot donc agrave un flot connecteacute agrave un

fichier

Informations compleacutementaires

La nouvelle bibliothegraveque drsquoentreacutees-sorties deacutefinie par la norme est une geacuteneacuteralisation de

celle qui existait auparavant (jusqursquoagrave la version 3 de C++) Elle est fondeacutee sur des patrons

de classes permettant de manipuler des flots geacuteneacuteraliseacutes crsquoest-agrave-dire recevant ou fournis-

1 Nous verrons quil en existe dailleurs deux autres cerr et clog

1 - Preacutesentation geacuteneacuterale de la classe ostream335

sant des suites de valeurs drsquoun type donneacute type qui apparaicirct comme paramegravetre despatrons Mais il existe des versions speacutecialiseacutees de ces patrons pour le type char1 qui por-tent le mecircme nom que les classes drsquoavant la norme et qui se comportent de la mecircmemaniegravere2 Ce sont de tregraves loin les plus utiliseacutees et ce sont celles que nous eacutetudierons iciLa geacuteneacuteralisation agrave drsquoautres types ne preacutesenterait de toute faccedilon pas de difficulteacutes

Dans certaines impleacutementations anciennes on risque de trouver encore les deux ver-sions de classes Dans ce cas il faut savoir que lrsquoen-tecircte ltiostreamhgt correspond agravelrsquoancienne version et que les identificateurs correspondants restent comme avant lanorme deacutefinis en dehors de tout espace de noms3 Autrement dit lrsquoinstruction using

namespace std nrsquoest pas requise dans ce cas (neacuteanmoins elle peut le devenir si lrsquoon faitappel agrave drsquoautres fichiers en-tecirctes)

1 Preacutesentation geacuteneacuterale de la classe ostreamApregraves avoir preacuteciseacute le rocircle de lopeacuterateur ltlt et rappeleacute les types de base pour lesquels lopeacutera-teur ltlt est surdeacutefini nous verrons le rocircle des deux fonctions membres put et write Nousexaminerons ensuite quelques exemples de formatage de linformation ce qui nous permettradintroduire la notion importante de manipulateur

11 Lopeacuterateur ltltDans la classe ostream lopeacuterateur ltlt est surdeacutefini pour les diffeacuterents types de base sous laforme

ostream amp operator ltlt (expression)

Il reccediloit deux opeacuterandes

bull la classe layant appeleacute (argument implicite this)

bull une expression dun type de base quelconque

Son rocircle consiste agrave transmettre la valeur de lexpression au flot concerneacute en la formatant4 defaccedilon approprieacutee Consideacuterons par exemple linstruction

cout ltlt n

Si n contient la valeur 1234 le travail de lopeacuterateur ltlt consiste agrave convertir la valeur (binaire)de n dans le systegraveme deacutecimal et agrave envoyer au flot cout les caractegraveres correspondant agrave chacun

1 Il existe eacutegalement des versions speacutecialiseacutees pour le type wchar Les classes correspondantes portent le mecircme nom

que pour le type char preacuteceacutedeacute de w par exemple wistream ou lieu de istream

2 Les diffeacuterences sont extrecircmement mineures Elles seront mentionneacutees le moment venu

3 Rappelons que les espaces de noms seront eacutetudieacutes en deacutetail au chapitre 24

4 Nous verrons quil est possible dintervenir sur la maniegravere dont est effectueacute ce formatage Dautre part dans cer-

tains cas il pourra ne pas y avoir de formatage cest ce qui se produira par exemple lorsque lon utilisera la fonc-

tion write

Les flotsCHAPITRE 16

336

des chiffres ainsi obtenus (ici les caractegraveres 1 2 3 et 4) Nous emploierons le mot eacutecri-ture pour qualifier le rocircle de cet opeacuterateur sachez toutefois que ce terme nest pas universel-lement reacutepandu notamment on rencontre parfois injection

Par ailleurs cet opeacuterateur ltlt fournit comme reacutesultat la reacutefeacuterence au flot concerneacute apregraves quila eacutecrit linformation voulue Cela permet de lappliquer facilement plusieurs fois de suitecomme dans

cout ltlt valeur ltlt na ltlt n

Voici un reacutecapitulatif concernant les types accepteacutes par cet opeacuterateur

Les types accepteacutes par lrsquoopeacuterateur ltlt

12 Les flots preacutedeacutefinisEn plus de cout il existe deux autres flots preacutedeacutefinis de classe ostream

bull cerr flot de sortie connecteacute agrave la sortie standard derreur (stderr en C) sans tampon1 in-termeacutediaire

bull clog flot de sortie connecteacute aussi agrave la sortie standard derreur mais en utilisant un tam-pon2 intermeacutediaire

Tous les types de base sont accepteacutes par lrsquoopeacuterateur ltlt

- soit par surdeacutefinition effective de lrsquoopeacuterateur types char (avec les variantes signed ou unsigned) int (avec sa variante unsigned) long (avec sa variante unsigned) float double et long double

- soit par le jeu des conversions implicites types bool short

Les types pointeurs sont accepteacutes

- char on obtient la chaicircne situeacutee agrave lrsquoadresse correspondante le type string sera accepteacute avec le mecircme comportement

- pointeur sur un type quelconque autre que char on obtient la valeur du pointeur correspondant Si lrsquoon souhaite afficher la valeur drsquoun pointeur de type char (et non plus la chaicircne qursquoil reacutefeacuterence) il suffit de le convertir explicitement en void

Les tableaux sont accepteacutes mais ils sont alors convertis dans le pointeur correspon-dant on nrsquoobtient donc geacuteneacuteralement une adresse et non les valeurs des eacuteleacutements du tableau sauf pour les tableaux de caractegraveres traiteacutes comme une chaicircne de style C (attention au problegraveme du zeacutero de fin )

Les types classes seront accepteacutes si lrsquoon y a deacutefini convenablement lrsquoopeacuterateur ltlt

1 En anglais buffer On parle parfois en franglais de sortie non bufferiseacutee

2 On parle parfois de sortie bufferiseacutee

1 - Preacutesentation geacuteneacuterale de la classe ostream337

13 La fonction putIl existe dans la classe ostream une fonction membre nommeacutee put qui transmet au flot cor-respondant le caractegravere reccedilu en argument Ainsi

coutput(c)

transmet au flot cout le caractegravere contenu dans c comme le ferait cout ltlt c

En fait la fonction put eacutetait surtout indispensable dans les versions anteacuterieures agrave la 20 pourpallier labsence de surdeacutefinition de lopeacuterateur pour le type char

La valeur de retour de put est le flot concerneacute apregraves quon y a eacutecrit le caractegravere correspon-dant Cela permet deacutecrire par exemple (c1 c2 et c3 eacutetant de type char)

coutput(c1)put(c2)put(c3)

ce qui est eacutequivalent agrave coutput(c1) coutput(c2) coutput(c3)

14 La fonction writeDans la classe ostream la fonction membre write permet de transmettre une suite drsquooctets auflot de sortie consideacutereacute

141 Cas des caractegraveres

Comme un caractegravere est toujours rangeacute dans un octet on peut utiliser write pour une chaicircnede longueur donneacutee Par exemple avec

char t[] = bonjour

lrsquoinstruction coutwrite (t 4)

envoie sur le flot cout 4 caractegraveres conseacutecutifs agrave partir de lrsquoadresse t crsquoest-agrave-dire les caractegrave-res b o n et j

Cette fonction peut ici sembler faire double emploi avec la transmission drsquoune chaicircne agravelrsquoaide de lrsquoopeacuterateur ltlt En fait son comportement nrsquoest pas le mecircme puisque write ne faitpas intervenir de caractegravere de fin de chaicircne (caractegravere nul) si un tel caractegravere apparaicirct dans lalongueur preacutevue il sera transmis comme les autres au flot de sortie De plus cette fonctionne reacutealise aucun formatage (alors que comme nous le verrons avec lrsquoopeacuterateur ltlt on peutagir sur le gabarit de lrsquoinformation effectivement eacutecrite sur le flot)

142 Autres cas

En fait cette fonction write srsquoaveacuterera indispensable lorsque lrsquoon souhaitera transmettre uneinformation sous une forme brute (on dit souvent binaire) sans qursquoelle subisse la moin-dre modification En geacuteneacuteral cela nrsquoa guegravere drsquointeacuterecirct dans le cas drsquoun eacutecran En revanche ce

Les flotsCHAPITRE 16

338

sera la seule faccedilon de creacuteer un fichier sous forme binaire (crsquoest-agrave-dire dans lequel les infor-mations ndash quel que soit leur type ndash sont enregistreacutees telles qursquoelles figurent en meacutemoire)

Comme put la fonction write fournit en retour le flot concerneacute apregraves qursquoon y a eacutecrit lrsquoinfor-mation correspondante

15 Quelques possibiliteacutes de formatage avec ltltNous eacutetudierons au paragraphe 5 lensemble des possibiliteacutes de formatage de la classeostream ainsi que celles de la classe istream Cependant nous vous preacutesentons degraves mainte-nant les exemples de formatage en sortie les plus courants ce qui nous permettra dintroduirela notion de manipulateur (parameacutetrique ou non)

151 Action sur la base de numeacuteration

Lorsque lon eacutecrit une valeur entiegravere sur un flot de sortie on peut choisir de lexprimer danslune des bases suivantes

bull 10 deacutecimal (il sagit de la valeur par deacutefaut)

bull 16 hexadeacutecimal

bull 8 octal

En outre depuis la norme on peut choisir drsquoexprimer une expression booleacuteenne (de typebool) soit sous la forme drsquoun entier (0 ou 1) soit sous la forme false true

Voici un exemple de programme dans lequel nous eacutecrivons

bull dans diffeacuterentes bases la valeur de la mecircme variable entiegravere n

bull de diffeacuterentes maniegraveres la valeur drsquoune variable ok de type bool

include ltiostreamgtusing namespace std main() int n = 12000 cout ltlt par defaut ltlt n ltlt n cout ltlt en hexadecimal ltlt hex ltlt n ltlt n cout ltlt en decimal ltlt dec ltlt n ltlt n cout ltlt en octal ltlt oct ltlt n ltlt n cout ltlt et ensuite ltlt n ltlt n bool ok = 1 ou ok = true cout ltlt par defaut ltlt ok ltlt n cout ltlt avec noboolalpha ltlt noboolalpha ltlt ok ltlt n cout ltlt avec boolalpha ltlt boolalpha ltlt ok ltlt n cout ltlt et ensuite ltlt ok ltlt n

par defaut 12000en hexadecimal 2ee0en decimal 12000

1 - Preacutesentation geacuteneacuterale de la classe ostream339

en octal 27340et ensuite 27340par defaut 1avec noboolalpha 1avec boolalpha trueet ensuite true

Action sur la base de numeacuteration des valeurs eacutecrites sur cout

Les symboles hex dec oct se nomment des manipulateurs Il sagit dopeacuterateurs preacutedeacutefinisagrave un seul opeacuterande de type flot fournissant en retour le mecircme flot apregraves quils ont opeacutereacute unecertaine action (manipulation) Ici cette action consiste agrave modifier la valeur de la base denumeacuteration (cette information eacutetant en fait meacutemoriseacutee dans la classe ostream1) Notez bienque la valeur de la base reste la mecircme tant quon ne la modifie pas (par un manipulateur) etcela quelles que soient les informations transmises au flot (entiers caractegraveres flottants)2

Le manipulateur boolalpha demande drsquoafficher les valeurs booleacuteennes sous la forme alpha-beacutetique crsquoest-agrave-dire true ou false Le manipulateur noboolalpha demande en revanche drsquouti-liser la forme numeacuterique 0 ou 1

Nous verrons au paragraphe 5 quil existe beaucoup dautres manipulateurs dont nous feronsune analyse complegravete

152 Action sur le gabarit de linformation eacutecrite

Consideacuterons cet exemple de programme qui montre comment agir sur la largeur (gabarit)selon laquelle linformation est eacutecrite

include ltiostreamgtinclude ltiomanipgtusing namespace std main() int n = 12345 int i for (i=0 ilt15 i++) cout ltlt setw(2) ltlt i ltlt ltlt setw(i) ltlt n ltlt n

0 12345 1 12345 2 12345 3 12345 4 12345 5 12345

1 En toute rigueur de la classe ios dont deacuterivent les classes ostream et istream

2 Attention tous les manipulateurs ne se comportent pas ainsi

Les flotsCHAPITRE 16

340

6 12345

7 12345 8 12345

9 12345

10 1234511 12345

12 12345

13 12345

14 12345

Action sur le gabarit de linformation eacutecrite sur cout

Ici encore nous faisons appel agrave un manipulateur (setw) Un peu plus complexe que les preacuteceacute-dents (hex oct ou dec) il comporte un paramegravetre repreacutesentant le gabarit souhaiteacute On parlealors de manipulateur parameacutetrique Nous verrons quil existe beaucoup dautres manipula-teurs parameacutetriques leur emploi neacutecessite absolument lincorporation du fichier en-tecircteltiomanipgt1

En ce qui concerne setw sachez que ce manipulateur deacutefinit uniquement le gabarit de la pro-

chaine information agrave eacutecrire Si lon ne fait pas agrave nouveau appel agrave setw pour les informationssuivantes celles-ci seront eacutecrites suivant les conventions habituelles agrave savoir en utilisantlemplacement minimal neacutecessaire pour les eacutecrire (2 caractegraveres pour la valeur 245 caractegraverespour la valeur -2345 7 caractegraveres pour la chaicircne bonjour) Dautre part si la valeur four-nie agrave setw est insuffisante pour leacutecriture de la valeur suivante cette derniegravere sera eacutecrite selonles conventions habituelles (elle ne sera donc pas tronqueacutee)

Agrave titre indicatif en remplaccedilant lrsquoinstruction drsquoaffichage du programme preacuteceacutedent par cout ltlt setw(2) ltlt i ltlt setw(i) ltlt ltlt n ltlt n

on obtiendrait ces reacutesultats 1 12345

2 12345

3 12345 4 12345

5 12345

6 12345

7 12345 8 12345

9 12345

10 12345

11 12345

Notez bien la position du premier caractegravere dans les reacutesultats afficheacutes En effet cette foissetw(i) ne srsquoapplique qursquoagrave la chaicircne constante ( ) afficheacutee ensuite la valeur de n restantafficheacutee suivant les conventions par deacutefaut

1 ltiomaniphgt si lrsquoon utilise encore ltiostreamhgt

1 - Preacutesentation geacuteneacuterale de la classe ostream341

153 Action sur la preacutecision de lrsquoinformation eacutecriteVoyez ce programme

include ltiomanipgtinclude ltiostreamgtusing namespace std main() float x = 20003 double pi = 3141926536 cout ltlt affichage de 20003 et de pi dans differentes precisions n cout ltlt par defaut ltlt x ltlt ltlt pi ltlt n for (int i=1 ilt8 i++) cout ltlt precision ltlt i ltlt ltlt setprecision (i) ltlt x ltlt ltlt pi ltlt n

affichage de 20003 et de pi dans differentes precisions par defaut 666667 314193precision 1 7e+02 3precision 2 67e+02 31precision 3 667 314precision 4 6667 3142precision 5 66667 31419precision 6 666667 314193precision 7 6666667 3141927

Action sur la preacutecision de lrsquoinformation eacutecrite sur cout

Par deacutefaut comme on le voit dans la premiegravere ligne afficheacutee pour les informations de typeflottant lrsquoopeacuterateur ltlt

bull choisit la notation la plus approprieacutee (flottante ou exponentielle avec un chiffre avant lepoint de la mantisse)

bull utilise 6 chiffres significatifs

Le manipulateur parameacutetrique setw (precision) permet de deacutefinir le nombre de chiffres signi-catifs voulus Cette fois lrsquoeffet de ce manipulateur est permanent (jusqursquoagrave modificationexplicite) comme le montre lrsquoaffichage de la seconde information On notera que si la preacuteci-sion demandeacutee nrsquoest pas suffisante pour afficher au moins la valeur entiegravere du nombre con-cerneacute elle est modifieacutee en conseacutequence ainsi drsquoailleurs que le choix de la notation En C++on ne voit jamais de reacutesultat totalement faux (il faut quand mecircme eacuteviter la preacutecision zeacutero )

154 Choix entre notation flottante ou exponentielleVoyez cet exemple qui montre lrsquoutilisation des manipulateurs fixed (notation flottante) etscientific (notation exponentielle avec un chiffre avant le point de la mantisse) coupleacute avecle choix de la preacutecision

include ltiostreamgtinclude ltiomanipgtusing namespace std

Les flotsCHAPITRE 16

342

main() float x = 2e53

double pi = 3141926536

cout ltlt fixed ltlt choix notation flottante n for (int i=1 ilt8 i++)

cout ltlt precision ltlt i ltlt setprecision (i) ltlt ltlt x ltlt

ltlt pi ltlt n cout ltlt scientific ltlt choix notation exponentielle n

for (int i=1 ilt8 i++) cout ltlt precision ltlt i ltlt setprecision (i) ltlt ltlt x ltlt

ltlt pi ltlt n

choix notation flottante precision 1 666667 31

precision 2 6666666 314precision 3 66666664 3142

precision 4 666666641 31419

precision 5 6666666406 314193precision 6 66666664062 3141927

precision 7 666666640625 31419265choix notation exponentielle

precision 1 67e+04 31e+00

precision 2 667e+04 314e+00precision 3 6667e+04 3142e+00

precision 4 66667e+04 31419e+00

precision 5 666667e+04 314193e+00precision 6 6666666e+04 3141927e+00

precision 7 66666664e+04 31419265e+00

Choix de la notation (flottante ou exponentielle)

On notera que cette fois la preacutecision correspond au nombre de chiffres apregraves le point deacuteci-mal quelle que soit la notation utiliseacutee On aura donc inteacuterecirct agrave eacuteviter drsquoutiliser le mode pardeacutefaut degraves lors qursquoon souhaite maicirctriser la preacutecision des affichages

Lagrave encore lrsquoeffet des modificateurs fixed ou scientific est permanent (jusqursquoagrave modificationexplicite) On notera qursquoune fois choisie lrsquoune de ces notations il nrsquoest plus possible de reve-nir au comportement par deacutefaut (choix automatique de la notation) avec un manipulateur Onpourra y parvenir en utilisant drsquoautres possibliteacutes deacutecrites au paragraphe 5 (il faudrait remet-tre agrave zeacutero les bits du champ floatfield du mot drsquoeacutetat de formatage par exemple avec la fonc-tion setf)

2 Preacutesentation geacuteneacuterale de la classe istreamComme nous avons fait pour la classe ostream nous commencerons par preacuteciser le rocircle delopeacuterateur gtgt Puis nous deacutefinirons le rocircle des diffeacuterentes fonctions membres de la classe

2 - Preacutesentation geacuteneacuterale de la classe istream343

istream (get getline gcount read) Nous terminerons sur un exemple de formatage delinformation

21 Lrsquoopeacuterateur gtgtDans la classe istream lopeacuterateur gtgt est surdeacutefini pour tous les types de base y comprischar 1 sous la forme

istream amp operator gtgt (type_de_base amp )

Il reccediloit deux opeacuterandes

bull la classe layant appeleacute (argument implicite this)

bull une lvalue dun type de base quelconque

Son rocircle consiste agrave extraire du flot concerneacute les caractegraveres neacutecessaires pour former une valeurdu type de base voulu en reacutealisant une opeacuteration inverse du formatage opeacutereacute par lopeacuterateurltlt

Il fournit comme reacutesultat la reacutefeacuterence au flot concerneacute apregraves quil en a extrait linformationvoulue Cela permet de lappliquer plusieurs fois de suite comme dans

cin gtgt n gtgt p gtgt x

Les espaces blancs2 jouent un rocircle important puisque drsquoune part ils servent de seacuteparateurs etque drsquoautre part toute lecture commence par sauter ces caractegraveres srsquoil en existe Rappelonsque lrsquoon range dans cette cateacutegorie les caractegraveres espace tabulation horizontale (t) tabula-tion verticale (v) fin de ligne (n) et changement de page (f)

211 Cas des caractegraveresUne des conseacutequences immeacutediates de ce meacutecanisme fait que (par deacutefaut) ces deacutelimiteurs nepeuvent pas ecirctre lus en tant que caractegraveres Par exemple la reacutepeacutetition de lrsquoinstruction (c eacutetantsupposeacute de type char)

cin gtgt c

appliqueacutee agrave un flot contenant ce texte b o

n j

our

conduira agrave ne prendre en compte que les 7 caractegraveres b o n j o u et r

En theacuteorie il existe un modificateur nommeacute noskipws (ne pas sauter les espaces blancs) per-met drsquoagir sur ce point mais son utilisation est peu aiseacutee dans la mesure ougrave il concerne alorstoutes les informations lues en particulier celles de type numeacuterique Nous verrons ci-dessousqursquoil existe des solutions plus agreacuteables pour acceacuteder aux deacutelimiteurs en utilisant lrsquoune desfonctions membres get ou getline

1 Mais pas a priori pour les types pointeurs

2 De white spaces en anglais

Les flotsCHAPITRE 16

344

212 Cas des chaicircnes de caractegraveresLorsqursquoon lit sur un flot une information agrave destination drsquoune chaicircne de caractegraveres (typechar ) lrsquoinformation rangeacutee en meacutemoire est compleacuteteacutee par un caractegravere nul de fin de chaicircne(0) Ainsi pour lire une chaicircne de n caractegraveres il faut preacutevoir un emplacement de n+1 carac-tegraveres De plus si lrsquoon veut eacuteviter des problegravemes drsquoeacutecrasement en meacutemoire il faut ecirctre capablede deacutefinir le nombre maximal de caractegraveres que lrsquoutilisateur risque de fournir ce qui nrsquoest pastoujours une chose aiseacutee (dans certains environnements les lignes au clavier peuventatteindre des longueurs importantes) On peut recourir au manipulateur parameacutetrique setw

qui limite le nombre de caractegraveres pris en compte lors de la prochaine lecture (et uniquementcelle-la) Par exemple avec

const int LGNOM = 10 char nom[LGNOM+1] cin gtgt setw(LGNOM) gtgt nom

on est certain de ne pas prendre en compte plus de 10 caractegraveres pour le tableau nom

En outre comme par deacutefaut les espaces blancs servent de deacutelimiteurs il nrsquoest pas possiblede lire en une seule fois une chaicircne contenant par exemple un espace telle que

bonjour mademoiselle

Notez que dans ce cas il ne sert agrave rien de la placer entre guillemets bonjour mademoiselle

En effet la premiegravere chaicircne lue serait alors bonjour

Lagrave encore nous verrons un peu plus loin que la fonction getline fournit une solution agreacuteableagrave ce problegraveme

213 Les types accepteacutes par gtgtVoici un reacutecapitulatif concernant les types accepteacutes par cet opeacuterateur

Les types accepteacutes par lrsquoopeacuterateur gtgt

Tous les types de base sont accepteacutes par lrsquoopeacuterateur gtgt bool char (et ses variantes signed et unsigned) short (et sa variante unsigned) int (et sa variante unsigned) long (et sa variante unsigned) float double et long double

Parmi les types pointeurs seul char est accepteacute dans ce cas on lit une chaicircne de caractegraveres

Les tableaux ne sont pas accepteacutes hormis les tableaux de caractegraveres (on y lit une chaicircne de caractegraveres termineacutee par un caractegravere nul)

Le type string (chaicircnes de type classe) sera accepteacute (il jouera un rocircle comparable aux chaicircnes de caractegraveres avec moins de risques)

Les autres types classes seront accepteacutes si lrsquoon y a surdeacutefini convenablement lrsquoopeacuterateur gtgt

2 - Preacutesentation geacuteneacuterale de la classe istream345

22 La fonction getLa fonction

istream amp get (char amp)

permet dextraire un caractegravere dun flot dentreacutee et de le ranger dans la variable (de type char)quon lui fournit en argument Tout comme put cette fonction fournit en retour la reacutefeacuterenceau flot concerneacute apregraves quon en a extrait le caractegravere voulu

Contrairement au comportement par deacutefaut de lopeacuterateur gtgt la fonction get peut lirenimporte quel caractegravere deacutelimiteurs compris Ainsi en lappliquant agrave un flot contenant cetexte

b on j

our

elle conduira agrave prendre en compte 16 caractegraveres b espace o n n espace espace espaceespace j n n o u r et n

Il existe une autre fonction get (il y a donc surdeacutefinition) de la forme int get ()

Celle-ci permet elle aussi dextraire un caractegravere dun flot dentreacutee mais elle le fournit commevaleur de retour sous la forme dun entier Elle est ainsi en mesure de fournir une valeur speacute-ciale EOF (en geacuteneacuteral -1) lorsque la fin de fichier a eacuteteacute rencontreacutee sur le flot correspondant1

Remarque

Nous verrons au paragraphe 3 consacreacute au statut derreur dun flot quil est possible deconsideacuterer un flot comme une valeur logique (vrai ou faux) et par suite deacutecrire desinstructions telles que

char c while ( cinget(c) ) recopie le flot cin coutput (c) sur le flot cout arrecirct quand eof car alors (cin) = 0

Celles-ci sont eacutequivalentes agrave

int c while ( ( c = cinget() ) = EOF ) coutput (c)

23 Les fonctions getline et gcountCes deux fonctions facilitent la lecture des chaicircnes de caractegraveres ou plus geacuteneacuteralement dunesuite de caractegraveres quelconques termineacutee par un caractegravere connu (et non preacutesent dans lachaicircne en question)

1 Cest ce qui justifie que sa valeur de retour soit de type int et non char

Les flotsCHAPITRE 16

346

Len-tecircte de la fonction getline se preacutesente sous la forme

istream amp getline (char ch int taille char delim = n )

Cette fonction lit des caractegraveres sur le flot layant appeleacutee et les place dans lemplacementdadresse ch Elle srsquointerrompt lorsquune des deux conditions suivantes est satisfaite

bull le caractegravere deacutelimiteur delim a eacuteteacute trouveacute dans ce cas ce caractegravere nest pas recopieacute enmeacutemoire

bull taille - 1 caractegraveres ont eacuteteacute lus

Dans tous les cas cette fonction ajoute un caractegravere nul de fin de chaicircne agrave la suite des carac-tegraveres lus

Notez que le caractegravere deacutelimiteur possegravede une valeur par deacutefaut (n) bien adapteacutee agrave la lecturede lignes de texte

Quant agrave la fonction gcount elle fournit le nombre de caractegraveres effectivement lus lors du der-nier appel de getline Ni le caractegravere deacutelimiteur ni celui placeacute agrave la fin de la chaicircne ne sontcompteacutes autrement dit gcount fournit la longueur effective de la chaicircne rangeacutee en meacutemoirepar getline

Voici agrave titre dexemple un programme qui affiche des lignes entreacutees au clavier et en preacutecisele nombre de caractegraveres

include ltiostreamgt

using namespace std

main()

const int LG_LIG = 120 longueur maxi dune ligne de texte

char ch [LG_LIG+1] pour lire une ligne

int lg longueur courante dune ligne

do

cingetline (ch LG_LIG)

lg = cingcount ()

cout ltlt ligne de ltlt lg-1 ltlt caracteres ltlt ch ltlt n

while (lg gt1)

bonjour

ligne de 7 caracteres bonjour

9 fois 5 font 45

ligne de 16 caracteres 9 fois 5 font 45

nimporte quoi ltampeacute(-egrave_ccedilagrave))=

ligne de 29 caracteres nimporte quoi ltampeacute(-egrave_ccedilagrave))=

ligne de 0 caracteres

Exemple drsquoutilisation de la fonction getline

2 - Preacutesentation geacuteneacuterale de la classe istream347

Remarques

1 Le programme preacuteceacutedent peut tout agrave fait servir agrave lister un fichier texte pour peu qursquoon aitredirigeacute vers lui lrsquoentreacutee standard

2 Il existe une autre fonction getline (indeacutependante cette fois) destineacutee agrave lire des caractegrave-res dans un objet de type string nous en parlerons au paragraphe 3 du chapitre 22 ougravenous proposerons une adaptation du preacuteceacutedent programme

24 La fonction readLa fonction read permet de lire une suite drsquooctets sur le flot drsquoentreacutee consideacutereacute

241 Cas des caractegraveresComme un octet peut toujours contenir un caractegravere on peut utiliser read pour une chaicircne decaractegraveres de longueur donneacutee Par exemple avec

char t[10]

lrsquoinstruction cinread (t 5)

lira sur cin 5 caractegraveres et les rangera agrave partir de lrsquoadresse t

Lagrave encore ette fonction peut sembler faire double emploi soit avec la lecture drsquoune chaicircneavec lrsquoopeacuterateur gtgt soit avec la fonction getline Toutefois read ne neacutecessite ni seacuteparateurni caractegravere deacutelimiteur particulier En outre aucun caractegravere de fin de chaicircne nrsquointervient nisur le flot ni en meacutemoire

242 Autres casEn fait cette fonction srsquoaveacuterera indispensable lorsque lrsquoon souhaitera acceacuteder agrave une informa-tion drsquoun fichier sous forme brute (binaire) sans qursquoelle ne subisse aucune transformationcrsquoest-agrave-dire en recopiant en meacutemoire les informations telles qursquoelles figurent dans le fichierLa fonction read jouera le rocircle symeacutetrique de la fonction write

25 Quelques autres fonctionsDans la classe istream il existe eacutegalement deux fonctions membres agrave caractegravere utilitaire

bull putback (char c) pour renvoyer dans le flot concerneacute un caractegravere donneacute

bull peek () qui fournit le prochain caractegravere disponible sur le flot concerneacute mais sans lextrairedu flot (il sera donc agrave nouveau obtenu lors dune prochaine lecture sur le flot)

Remarque

En toute rigueur il existe aussi une classe iostream heacuteritant agrave la fois de istream et deostream Celle-ci permet de reacutealiser des entreacutees-sorties bidirectionnelles

Les flotsCHAPITRE 16

348

3 Statut drsquoerreur drsquoun flotA chaque flot dentreacutee ou de sortie est associeacute un ensemble de bits dun entier formant ce quelon nomme le statut derreur du flot Il permet de rendre compte du bon ou du mauvaisdeacuteroulement des opeacuterations sur le flot Nous allons tout dabord voir quelle est la significationde ces diffeacuterents bits (au nombre de 4) Puis nous apprendrons comment en connaicirctre lavaleur et le cas eacutecheacuteant la modifier Enfin nous montrerons que la surdeacutefinition des opeacutera-teurs () et permet de simplifier lutilisation dun flot

31 Les bits derreurLa position des diffeacuterents bits derreur au sein dun entier est deacutefinie par des constantes deacutecla-reacutees dans la classe ios dont deacuterivent les deux classes istream et ostream Chacune de cesconstantes correspond agrave la valeur prise par lentier en question lorsque le bit correspondant ndashet lui seul ndash est activeacute (agrave 1) Il sagit de

bull eofbit ce bit est activeacute si la fin de fichier a eacuteteacute atteinte autrement dit si le flot correspondantna plus aucun caractegravere disponible

bull failbit ce bit est activeacute lorsque la prochaine opeacuteration dentreacutee-sortie ne peut aboutir

bull badbit ce bit est activeacute lorsque le flot est dans un eacutetat irreacutecupeacuterable

La diffeacuterence entre badbit et failbit nexiste que pour les flots dentreacutee Lorsque failbit estactiveacute aucune information na eacuteteacute reacuteellement perdue sur le flot il nen va plus de mecircme lors-que badbit est activeacute

De plus il existe une constante goodbit (valant en fait 0) qui correspond agrave la valeur que doitavoir le statut derreur lorsquaucun de ses bits nest activeacute

On peut dire quune opeacuteration dentreacutee-sortie a reacuteussi lorsque lun des bits goodbit ou eofbit

est activeacute De mecircme on peut dire que la prochaine opeacuteration dentreacutee-sortie ne pourra aboutirque si goodbit est activeacute (mais il nest pas encore certain quelle reacuteussisse)

Lorsquun flot est dans un eacutetat derreur aucune opeacuteration ne peut aboutir tant que

bull la condition derreur na pas eacuteteacute corrigeacutee (ce qui va de soi )

bull le bit derreur correspondant na pas eacuteteacute remis agrave zeacutero nous allons voir quil existe des fonc-tions permettant dagir sur ces bits derreur

32 Actions concernant les bits derreurIl existe deux cateacutegories de fonctions

bull celles qui permettent de connaicirctre le statut derreur dun flot cest-agrave-dire en fait la valeur deses diffeacuterents bits derreur

bull celles qui permettent de modifier la valeur de certains de ces bits derreur

3 - Statut drsquoerreur drsquoun flot349

321 Accegraves aux bits derreur

Dune part il existe 5 fonctions membres (de ios1)

bull eof () fournit la valeur vrai (1) si la fin de fichier a eacuteteacute rencontreacutee cest-agrave-dire si le bit eofbit

est activeacute

bull bad () fournit la valeur vrai (1) si le flot est alteacutereacute cest-agrave-dire si le bit badbit est activeacute

bull fail () fournit la valeur vrai (1) si le bit failbit est activeacute

bull good () fournit la valeur vrai (1) si aucune des trois fonctions preacuteceacutedentes na la valeur vraicest-agrave-dire si aucun des bits du statut derreur nest activeacute2

Dautre part la fonction membre3 rdstate () fournit en retour un entier correspondant agrave lavaleur du statut derreur

322 Modification du statut derreur

La fonction membre clear den-tecircte

void clear (int i=0)

active les bits derreur correspondant agrave la valeur fournie en argument En geacuteneacuteral on deacutefinitla valeur de cet argument en utilisant les constantes preacutedeacutefinies de la classe ios

Par exemple si fl deacutesigne un flot linstruction flclear (iosbadbit)

activera le bit badbit du statut derreur du flot fl et mettra tous les autres bits agrave zeacutero

Si lon souhaite activer ce bit sans modifier les autres il suffit de faire appel agrave rdstate en pro-ceacutedant ainsi

flclear (iosbadbit | flrdstate () )

Remarque

Lorsque vous surdeacutefinirez les opeacuterateurs ltlt et gtgt pour vos propres types (classes) il serapratique de pouvoir activer les bits derreur en guise de compte rendu du deacuteroulement delopeacuteration

33 Surdeacutefinition des opeacuterateurs () et Comme nous lavons deacutejagrave eacutevoqueacute dans la remarque du paragraphe 22 il est possible de tes-ter un flot en le consideacuterant comme une valeur logique (vrai ou faux) Pour ce faire on arecours agrave la surdeacutefinition dans la classe ios des opeacuterateurs () et

1 Donc de istream et de ostream par heacuteritage

2 Dans les preacuteceacutedentes versions de la bibliothegraveque drsquoentreacutees-sorties (ou si lrsquoon utilise ltiostreamhgt au lieu de

ltiostreamgt cette fonction fournit la valeur vrai mecircme si eofbit est activeacute

3 Deacutesormais nous ne preacuteciserons plus quil sagit dun membre de ios dont heacuteritent istream et ostream

Les flotsCHAPITRE 16

350

Plus preacuteciseacutement lopeacuterateur () est surdeacutefini de maniegravere que si fl deacutesigne un flot

( fl )

bull prenne une valeur non nulle1 (vrai) si aucun des bits derreur nest activeacute cest-agrave-dire si good

() a la valeur vrai

bull prenne une valeur nulle (faux) dans le cas contraire cest-agrave-dire si good () a la valeur faux

Ainsi if (fl)

peut remplacer if (flgood () )

De mecircme lopeacuterateur est surdeacutefini de maniegravere que si fl deacutesigne un flot

fl

bull prenne une valeur nulle (faux) si un des bits derreur est activeacute cest-agrave-dire si good() a la va-leur faux

bull prenne une valeur non nulle (vrai) si aucun des bits derreur nest activeacute cest-agrave-dire sigood() a la valeur vrai

Ainsi if ( flot )

peut remplacer if ( flotgood () )

34 ExemplesEn testant et en modifiant lrsquoeacutetat du flot cin nous pouvons geacuterer les situations dans lesquellesun caractegravere invalide venait bloquer les lectures ulteacuterieures Nous vous proposons une adap-tation dans ce sens du programme du paragraphe 353 du chapitre 3 Nous verrons qursquoilsouffre encore de lacunes de sorte que cet exemple devra surtout ecirctre consideacutereacute comme unexemple drsquoutilisation des outils de gestion de lrsquoeacutetat drsquoun flot

include ltiostreamgtusing namespace std main() int n char c do cout ltlt donnez un nombre entier if (cin gtgt n) cout ltlt voici son carre ltlt nn ltlt n else (cinclear()) cin gtgt c while (n)

1 Sa valeur exacte nest pas preacuteciseacutee et elle na donc pas de signification particuliegravere

3 - Statut drsquoerreur drsquoun flot351

donnez un nombre entier 12

voici son carre 144

donnez un nombre entier x25

donnez un nombre entier voici son carre 625

donnez un nombre entier ampamp2

donnez un nombre entier donnez un nombre entier voici son carre 4

donnez un nombre entier 0

voici son carre 0

Pour eacuteviter une boucle infinie en cas de caractegravere invalide

Lorsque le flot est bloqueacute nous lisons artificiellement un caractegravere (correspondant au carac-tegravere invalide responsable du blocage) nous deacutebloquons le flot par appel de clear et nousrelanccedilons la lecture Comme le montre lrsquoexemple drsquoexeacutecution la situation est deacutebloqueacuteemais le dialogue avec lrsquoutilisateur laisse agrave deacutesirer

Agrave titre indicatif voici agrave quoi conduirait une adaptation comparable du programme du para-graphe 352 du chapitre 3

include ltiostreamgt

using namespace std

main()

int n = 12 char c = rsquoarsquo char cc

bool ok = false

do cout ltlt donnez un entier et un caractere n

if (cin gtgt n gtgt c)

cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

ok = true

else

ok = false

cinclear()

cin gtgt cc pour lire au moins le caractere invalide

while ( ok)

donnez un entier et un caractere

12 y

merci pour 12 et y

donnez un entier et un caractere

amp2 y

donnez un entier et un caractere

merci pour 2 et y

Les flotsCHAPITRE 16

352

donnez un entier et un caractere xx12donnez un entier et un caractere donnez un entier et un caractere 12 xmerci pour 12 et 1

Gestion de lrsquoeacutetat drsquoun flot pour sauter un caractegravere invalide

Les exemples drsquoexeacutecution montrent que la situation est encore moins agreacuteable que preacuteceacutedem-ment

Drsquoune maniegravere geacuteneacuterale nous nrsquoavons reacutegleacute ici que le problegraveme de blocage sur le caractegravereinvalide mais pas celui de manque de synchronisme entre lecture et affichage Au paragra-phe 72 du chapitre 22 nous preacutesenterons des solutions plus satisafaisantes en deacutesynchroni-sant la lecture drsquoune ligne au clavier de son utilisation par le biais drsquoun formatage enmeacutemoire

4 Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur

Comme nous lavons deacutejagrave dit les opeacuterateurs ltlt et gtgt peuvent ecirctre redeacutefinis par lutilisateurpour des types classes quil a lui-mecircme creacuteeacutes Nous allons dabord examiner la meacutethode agrave sui-vre pour reacutealiser cette surdeacutefinition avant den preacutesenter un exemple dapplication

41 MeacutethodeLes deux opeacuterateurs ltlt et gtgt deacutejagrave surdeacutefinis au sein des classes istream et ostream pour les diffeacute-rents types de base peuvent ecirctre surdeacutefinis pour nimporte quel type classe creacuteeacute par lutilisateur

Pour ce faire il suffit de tenir compte des remarques suivantes

1 Ces opeacuterateurs doivent recevoir un flot en premier argument ce qui empecircche de les surdeacute-finir sous la forme drsquoune fonction membre de la classe concerneacutee (notez quon ne peut pluscomme dans le cas des types de base les surdeacutefinir sous la forme drsquoune fonction membrede la classe istream ou ostream car lutilisateur ne peut plus modifier ces classes qui luisont fournies avec C++)

Il sagira donc de fonctions indeacutependantes ou amies de la classe concerneacutee et ayant unprototype de la forme

ostream amp operator ltlt (ostream amp expression_de_type_classe)

ou

istream amp operator gtgt (ostream amp amp type_classe)

4 - Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur353

2 La valeur de retour sera obligatoirement la reacutefeacuterence au flot concerneacute (reccedilu en premier ar-gument)

On peut dire que toutes les surdeacutefinitions de ltlt suivront ce scheacutema

ostream amp operator ltlt (ostream amp sortie type_classe objet1) Envoi sur le flot sortie des membres de objet en utilisant les possibiliteacutes classiques de ltlt pour les types de base cest-agrave-dire des instructions de la forme sortie ltlt return sortie

De mecircme toutes les surdeacutefinitions de gtgt suivront ce scheacutema

istream amp operator gtgt (istream amp entree type_classe amp objet) Lecture des informations correspondant aux diffeacuterents membres de objet en utilisant les possibiliteacutes classiques de gtgt pour les types de base cest-agrave-dire des instructions de la forme entree gtgt return entree

Remarque

Dans le cas de la surdeacutefinition de gtgt (flot dentreacutee) il sera souvent utile de sassurer quelinformation lue reacutepond agrave certaines exigences et dagir en conseacutequence sur leacutetat du flotCrsquoest ce que montre lrsquoexemple suivant

42 ExempleVoici un programme dans lequel nous avons surdeacutefini les opeacuterateurs ltlt et gtgt pour le typepoint que nous avons souvent rencontreacute dans les preacuteceacutedents chapitres

class point int x y

Nous supposerons quune valeur de type point se preacutesente toujours (aussi bien en lecturequen eacutecriture) sous la forme

lt entier entier gt

avec eacuteventuellement des espaces blancs suppleacutementaires de part et dautre des valeurs entiegrave-res

1 Ici la transmission peut se faire par valeur ou par reacutefeacuterence

Les flotsCHAPITRE 16

354

include ltiostreamgt

using namespace std

class point

int x y

public

point (int abs=0 int ord=0)

x = abs y = ord

int abscisse () return x

friend ostream amp operator ltlt (ostream amp point)

friend istream amp operator gtgt (istream amp point amp)

ostream amp operator ltlt (ostream amp sortie point p)

sortie ltlt lt ltlt px ltlt ltlt py ltlt gt

return sortie

istream amp operator gtgt (istream amp entree point amp p)1

char c = 0

float x y

int ok = 1

entree gtgt c

if (c = lt) ok = 0

else

entree gtgt x gtgt c

if (c = ) ok = 0

else

entree gtgt y gtgt c

if (c = gt) ok = 0

if (ok) px = x py = y on naffecte agrave p que si tout est OK

else entreeclear (iosbadbit | entreerdstate () )

return entree

main()

char ligne [121]

point a(23) b

cout ltlt point a ltlt a ltlt point b ltlt b ltlt n

1 Certaines impleacutementations requiegraverent (agrave tort) qursquoon preacutefixe les noms operatorltlt et operatorgtgt par std en

eacutecrivant les en-tecirctes de cette faccedilon

istream amp stdoperator gtgt (istream amp entree point amp p)

istream amp stdoperator gtgt (istream amp entree point amp p)

5 - Gestion du formatage355

do cout ltlt donnez un point

if (cin gtgt a) cout ltlt merci pour le point ltlt a ltlt n

else cout ltlt information incorrecte n cinclear ()

cingetline (ligne 120 n)

while ( aabscisse () )

point a lt23gt point b lt00gt

donnez un point 29 information incorrecte

donnez un point lt2 9lt

information incorrectedonnez un point lt29gt

merci pour le point lt29gtdonnez un point lt 12 999gt

merci pour le point lt12999gt

donnez un point bof information incorrecte

donnez un point lt0 0gtmerci pour le point lt00gt

Press any key to continue

Surdeacutefinition de lopeacuterateur ltlt pour la classe point

Dans la surdeacutefinition de gtgt nous avons pris soin de lire tout dabord toutes les informationsrelatives agrave un point dans des variables locales Ce nest que lorsque tout sest bien deacuterouleacute quenous transfeacuterons les valeurs ainsi lues dans le point concerneacute Cela eacutevite par exemple en casdinformation incomplegravete de modifier lune des composantes du point sans modifier lautreou encore de modifier les deux composantes alors que le caractegravere gt de fin na pas eacuteteacute trouveacute

Si nous ne prenions pas soin dactiver le bit badbit lorsque lon ne trouve pas lun des caractegrave-res lt ou gt lutilisateur ne pourrait pas savoir que la lecture sest mal deacuterouleacutee

Notez que dans la fonction main en cas derreur sur cin nous commenccedilons par remettre agravezeacutero leacutetat du flot avant dutiliser getline pour sauter les informations qui risquent de ne pasavoir pu ecirctre exploiteacutees

5 Gestion du formatageNous avons preacutesenteacute quelques possibiliteacutes daction sur le formatage des informations aussibien pour un flot dentreacutee que pour un flot de sortie Nous allons ici eacutetudier en deacutetail ladeacutemarche suivie par C++ pour geacuterer ce formatage

Les flotsCHAPITRE 16

356

Chaque flot cest-agrave-dire chaque objet de classe istream ou ostream conserve en permanenceun ensemble dinformations1 (indicateurs) speacutecifiant quel est agrave un moment donneacute son statutde formatage Cette faccedilon de proceacuteder est tregraves diffeacuterente de celle employeacutee par les fonctionsC telles que printf ou scanf Dans ces derniegraveres en effet on fournissait pour chaque opeacuterationdentreacutee-sortie les indications de formatage approprieacutees (sous la forme dun format com-poseacute entre autres dune succession de codes de format)

Un des avantages de la meacutethode employeacutee par C++ est quelle permet agrave lutilisateur dignorertotalement cet aspect formatage tant quil se contente dun comportement par deacutefaut (ce quiest loin drsquoecirctre le cas en C ougrave la moindre entreacutee-sortie neacutecessite obligatoirement lemploi dunformat)

Un autre avantage de la meacutethode est de permettre agrave celui qui le souhaite de deacutefinir une foispour toutes un format approprieacute agrave une application donneacutee et de ne plus avoir agrave sen soucierpar la suite

Comme nous lavons fait pour le statut derreur dun flot nous commencerons par eacutetudier lesdiffeacuterents eacuteleacutements composant le statut de formatage dun flot avant de montrer commenton peut le connaicirctre dune part le modifier dautre part

51 Le statut de formatage dun flotLe statut de formatage dun flot comporte essentiellement

bull un mot deacutetat dans lequel chaque bit est associeacute agrave une signification particuliegravere on peut

dire quon y trouve en quelque sorte toutes les indications de formatage de la forme vrai

faux2

bull les valeurs numeacuteriques preacutecisant les valeurs courantes suivantes

ndash Le gabarit il sagit de la valeur fournie a setw rappelons quelle retombe agrave zeacutero

(qui signifie gabarit standard) apregraves le transfert (lecture ou eacutecriture) dune informa-

tion Drsquoautre part pour un flot drsquoentreacutee elle ne concerne que les caractegraveres les chaicircnes

et les objets de type string

ndash La preacutecision numeacuterique il sagit du nombre de chiffres afficheacutes apregraves le point deacuteci-

mal avec la notation flottante du nombre de chiffres significatifs avec la notation

exponentielle

ndash Le caractegravere de remplissage cest-agrave-dire le caractegravere employeacute pour compleacuteter un ga-

barit dans le cas ougrave lon nutilise pas le gabarit par deacutefaut (par deacutefaut ce caractegravere de

remplissage est un espace)

1 En toute rigueur cette information est preacutevue dans la classe ios dont deacuterivent les classes istream et ostream

2 On retrouve lagrave le mecircme meacutecanisme que pour lentier contenant le statut derreur dun flot Mais comme nous le

verrons ci-dessous le statut de formatage dun flot comporte quant agrave lui dautres types dinformations que ces indi-

cations binaires

5 - Gestion du formatage357

52 Description du mot deacutetat du statut de formatageComme le statut derreur dun flot le mot deacutetat du statut de formatage est formeacute dun entier

dans lequel chaque bit est repeacutereacute par une constante preacutedeacutefinie dans la classe ios Chacune de

ces constantes correspond agrave la valeur prise par cet entier lorsque le bit correspondant ndash et lui

seul ndash est activeacute (agrave 1) Ici encore la valeur de chacune de ces constantes peut servir

bull soit agrave identifier le bit correspondant au sein du mot deacutetat

bull soit agrave fabriquer directement un mot deacutetat

De plus certains champs de bits (au nombre de trois) sont deacutefinis au sein de ce mecircme mot

Nous verrons quils facilitent dans le cas de certaines fonctions membres la manipulation

dun des bits dun champ (on peut citer le bit agrave modifier dans un champ sans avoir agrave se preacute-

occuper de la valeur des bits des autres champs)

Voici la liste des diffeacuterentes constantes accompagneacutees le cas eacutecheacuteant du nom du champ de

bit correspondant

Le mot deacutetat du statut de formatage

Au sein de chacun des trois champs de bits (adjustfield basefield floatfield) un seul des bits

doit ecirctre actif Sil nen va pas ainsi C++ legraveve lambiguiumlteacute en preacutevoyant un comportement par

deacutefaut (right dec scientific)

Nom de champ(srsquoil existe)

Nom du bit Signification

iosskipws saut des espaces blancs (en entreacutee)

iosadjustfield iosleft cadrage agrave gauche (en sortie)

iosright cadrage agrave droite (en sortie)

iosinternal remplissage apregraves signe ou base

iosbasefield iosdec conversion deacutecimale

iosoct conversion octale

ioshex conversion hexadeacutecimale

iosshowbase affichage indicateur de base (en sortie)

iosshowpoint affichage point deacutecimal (en sortie)

iosuppercase affichage caractegraveres hexa en majuscules (en sortie)

iosshowpos affichage nombres positifs preacuteceacutedeacutes du signe + (en sortie)

iosfloatfield iosscientific notation scientifique (en sortie)

iosfixed notation point fixe (en sortie)

iosunitbuf vide les tampons apregraves chaque eacutecriture

iosstdio vide les tampons apregraves chaque eacutecriture sur stdout ou stderr

Les flotsCHAPITRE 16

358

53 Action sur le statut de formatageLes exemples des paragraphes 1 et 2 ont introduit la notion de manipulateur (parameacutetrique ou

non) Comme vous vous en doutez ces manipulateurs permettent dagir sur le statut de for-

matage Mais on peut aussi pour cela utiliser des fonctions membres des classes istream ou

ostream Ces derniegraveres sont geacuteneacuteralement redondantes par rapport aux manipulateurs para-

meacutetriques (nous verrons toutefois quil existe des fonctions membres ne comportant aucun

eacutequivalent sous forme de manipulateur)

Suivant le cas laction portera sur le mot deacutetat ou sur les valeurs numeacuteriques (gabarit preacuteci-

sion caractegravere de remplissage) En outre on peut agir globalement sur le mot deacutetat Nous

verrons que certaines fonctions membres permettront notamment de le sauvegarder pour

pouvoir le restaurer ulteacuterieurement (ce quaucun manipulateur ne permet) Lrsquoaccegraves aux

valeurs numeacuteriques se fait globalement celles-ci doivent donc le cas eacutecheacuteant faire lobjet

de sauvegardes individuelles

531 Les manipulateurs non parameacutetriquesCe sont donc des opeacuterateurs qui sutilisent ainsi

flot ltlt manipulateur

pour un flot de sortie ou ainsi

flot gtgt manipulateur

pour un flot dentreacutee

Ils fournissent comme reacutesultat le flot obtenu apregraves leur action ce qui permet de les traiter de

la mecircme maniegravere que les informations agrave transmettre En particulier ils permettent eux aussi

dappliquer plusieurs fois de suite les opeacuterateurs ltlt ou gtgt

Voici la liste de ces manipulateurs

Manipulatleur Utilisation Action

dec entreacuteesortie Active le bit correspondant

hex entreacuteesortie Active le bit corrrespondant

oct entreacuteesortie Active le bit correspondant

boolalphanoboolalpha entreacuteesortie Activedeacutesactive le bit correspondant

leftbaseinternal sortie Active le bit correspondant

scientificfixed sortie Active le bit correspondant

showbasenoshowbase sortie Activedeacutesactive le bit correspondant

showpointnoshowpoint sortie Activedeacutesactive le bit correspondant

showposnoshowpos sortie Activedeacutesactive le bit correspondant

skipwsnoskipws entreacutee Activedeacutesactive le bit correspondant

uppercasenouppercase sortie Activedeacutesactive le bit correspondant

5 - Gestion du formatage359

Les manipulateurs non parameacutetriques

532 Les manipulateurs parameacutetriquesCe sont donc eacutegalement des manipulateurs cest-agrave-dire des opeacuterateurs agissant sur un flot et

fournissant en retour le flot apregraves modification Mais cette fois ils comportent un paramegravetre

qui leur est fourni sous la forme dun argument entre parenthegraveses En fait ces manipulateurs

parameacutetriques sont des fonctions dont len-tecircte est de la forme

istream amp manipulateur (argument)

ou

ostream amp manipulateur (argument)

Ils semploient comme les manipulateurs non parameacutetriques avec cette diffeacuterence quils

neacutecessitent linclusion du fichier iomanip1

Voici la liste de ces manipulateurs parameacutetriques

Les manipulateurs parameacutetriques

Notez bien que les manipulateurs resetiosflags et setiosflags agissent sur tous les bits speacuteci-

fieacutes par leur argument

ws entreacutee Active le bit saut des caractegraveres blancs

endl sortie Insegravere un saut de ligne et vide le tampon

ends sortie Insegravere un caractegravere de fin de chaicircne C (0)

flush sortie Vide le tampon

Manipulatleur Utilisation Action

1 ltiomaniphgt si lrsquoon utilise encore ltiostreamhgt

Manipulateur Utilisation Rocircle

setbase (int) EntreacuteeSortie Deacutefinit la base de conversion

resetiosflags (long) EntreacuteeSortie Remet agrave zeacutero tous les bits deacutesigneacutes par lrsquoargument (sans modifier les autres)

setiosflags (long) EntreacuteeSortie Active tous les bits speacutecifieacutes par lrsquoargument (sans modifier les autres)

setfill (int) EntreacuteeSortie Deacutefinit le caractegravere de remplissage

setprecision (int) Sortie Deacutefinit la preacutecision des nombres flottants

setw (int) EntreacuteeSodrtie Deacutefinit le gabarit

Les flotsCHAPITRE 16

360

533 Les fonctions membres

Dans les classes istream et ostream il existe cinq fonctions membres que nous navons pas

encore rencontreacutees setf unsetf fill precision et width

setf

Cette fonction permet de modifier le mot deacutetat de formatage Elle est en fait surdeacutefinie Il

existe deux versions

long setf (long)

Son appel active les bits speacutecifieacutes par son argument On obtient en retour lancienne valeur

du mot deacutetat de formatage

Notez bien que comme le manipulateur setiosflags cette fonction ne modifie pas les autres

bits Ainsi en supposant que flot est un flot avec

flotsetf (iosoct)

on activerait le bit iosoct alors quun des autres bits iosdec ou ioshex serait peut-ecirctre

activeacute1 Comme nous allons le voir ci-dessous la deuxiegraveme forme de setf se reacutevegravele plus pra-

tique dans ce cas

long setf (long long)

Son appel active les bits speacutecifieacutes par le premier argument seulement au sein du champ de

bits deacutefini par le second argument Par exemple si flot deacutesigne un flot

flotsetf (iosoct iosbasefield)

active le bit iosoct en deacutesactivant les autres bits du champ iosbasefield

Cette version de setf fournit en retour lancienne valeur du champ de bits concerneacute Cela

permet des sauvegardes pour des restaurations ulteacuterieures Par exemple si flot est un flot

avec

base_a = flotsetf (ioshex iosbasefield)

vous passez en notation hexadeacutecimale Pour revenir agrave lancienne notation quelle quelle soit

il vous suffira de proceacuteder ainsi

flotsetf (base_a iosbasefield)

unsetf

void unsetf (long)

Cette fonction joue le rocircle inverse de la premiegravere version de setf en deacutesactivant les bits men-

tionneacutes par son unique argument

1 Avec les versions de C++ drsquoavant la norme (ou avec ltiostreamhgt) seul le bit voulu eacutetait activeacute

5 - Gestion du formatage361

fill

Cette fonction permet dagir sur le caractegravere de remplissage Elle est eacutegalement surdeacutefinie Il

existe deux versions

char fill ()

Cette version fournit comme valeur de retour lactuel caractegravere de remplissage

char fill (char)

Cette version donne au caractegravere de remplissage la valeur speacutecifieacutee par son argument et

fournit en retour lancienne valeur Si flot est un flot de sortie on peut par exemple imposer

temporairement le caractegravere comme caractegravere de remplissage puis retrouver lancien ca-

ractegravere quel quil soit en proceacutedant ainsi

char car_a car_a = fill () caractegravere de remplissage = fill (car_a) retour agrave lancien caractegravere de remplissage

precision

Cette fonction permet dagir sur la preacutecision numeacuterique Elle est eacutegalement surdeacutefinie Il en

existe deux versions

int precision ()

Cette version fournit comme valeur de retour la valeur actuelle de la preacutecision numeacuterique

int precision (int)

Cette version donne agrave la preacutecision numeacuterique la valeur speacutecifieacutee par son argument et fournit

en retour lancienne valeur Si flot est un flot de sortie on peut par exemple imposer tempo-

rairement une certaine preacutecision (ici prec) puis revenir agrave lancienne quelle quelle soit en

proceacutedant ainsi

int prec_a prec prec_a = flotprecision (prec) on impose la preacutecision deacutefinie par prec flotprecision (prec_a) on revient agrave lancienne preacutecision

width

Cette fonction permet dagir sur le gabarit Elle est eacutegalement surdeacutefinie Il en existe deux

versions

int width()

Cette version fournit comme valeur de retour la valeur actuelle du gabarit

int width(int)

Cette version donne au gabarit la valeur speacutecifieacutee par son argument et fournit en retour lan-

cienne valeur Si flot est un flot de sortie on peut par exemple imposer temporairement un

certain gabarit (ici gab) puis revenir agrave lancien quel quil soit en proceacutedant ainsi

Les flotsCHAPITRE 16

362

int gab_a gab gab_a = flotwidth (gab) on impose un gabarit deacutefini par gab flotwidth (gab_a) on revient agrave lancien gabarit

6 Connexion drsquoun flot agrave un fichierJusquici nous avons parleacute des flots preacutedeacutefinis (cin et cout) et nous vous avons donneacute des

informations sappliquant agrave un flot quelconque (paragraphes 3 et 5) mais sans vous dire com-

ment ce flot pourrait ecirctre associeacute agrave un fichier Ce paragraphe va vous montrer comment y par-

venir et examiner les possibiliteacutes daccegraves direct dont on peut alors beacuteneacuteficier

61 Connexion dun flot de sortie agrave un fichierPour associer un flot de sortie agrave un fichier il suffit de creacuteer un objet de type ofstream classe

deacuterivant de ostream Lemploi de cette nouvelle classe neacutecessite dinclure un fichier en-tecircte

nommeacute fstream en plus du fichier iostream

Le constructeur de la classe ofstream neacutecessite deux arguments

bull le nom du fichier concerneacute (sous forme dune chaicircne de caractegraveres)

bull un mode douverture deacutefini par une constante entiegravere la classe ios comporte lagrave encore un

certain nombre de constantes preacutedeacutefinies (nous les passerons toutes en revue au paragraphe

64)

Voici un exemple de deacuteclaration dun objet (sortie) du type ofstream1

ofstream sortie (trucdat iosout|iosbinary) ou seulement iosout

Lobjet sortie sera donc associeacute au fichier nommeacute trucdat apregraves quil aura eacuteteacute ouvert en eacutecri-

ture

Une fois construit un objet de classe ofstream leacutecriture dans le fichier qui lui est associeacute peut

se faire comme pour nimporte quel flot en faisant appel agrave toutes les faciliteacutes de la classe

ostream (dont deacuterive ofstream)

Par exemple apregraves la deacuteclaration preacuteceacutedente de sortie nous pourrons employer des instruc-

tions telles que

sortie ltlt ltlt ltlt

pour reacutealiser des sorties formateacutees ou encore

sortiewrite ()

pour reacutealiser des eacutecritures binaires De mecircme nous pourrons connaicirctre le statut derreur du

flot correspondant en examinant la valeur de sortie

if (sortie)

1 Le paramegravetre iosbinary nrsquoest utile que dans les environnements qui distinguent les fichiers texte des autres (voir

remarque ci-dessous)

6 - Connexion drsquoun flot agrave un fichier363

Voici un programme complet qui enregistre sous forme binaire dans un fichier de nom

fourni par lutilisateur une suite de nombres entiers quil lui fournit sur lentreacutee standard

include ltcstdlibgt pour exit

include ltiostreamgt

include ltfstreamgt

include ltiomanipgt

using namespace std

const int LGMAX = 20

main()

char nomfich [LGMAX+1] int n

cout ltlt nom du fichier a creer

cin gtgt setw (LGMAX) gtgt nomfich

ofstream sortie (nomfich iosout|iosbinary) ou iosout

if (sortie) cout ltlt creation impossible n exit (1)

do cout ltlt donnez un entier

cin gtgt n

if (n) sortiewrite ((char )ampn sizeof(int) )

while (n ampamp (sortie))

sortieclose ()

Creacuteation seacutequentielle dun fichier dentiers

Nous nous sommes servi du manipulateur setw pour limiter la longueur du nom de fichier

fourni par lutilisateur Par ailleurs nous examinons le statut derreur de sortie comme nous le

ferions pour un flot usuel

Remarque

En toute rigueur le terme connexion (ou association) dun flot agrave un fichier pourrait

laisser entendre

ndash soit quil existe deux types dobjets dune part un flot dautre part un fichier

ndash soit que lon deacuteclare tout dabord un flot que lon associe ulteacuterieurement agrave un fichier

Or il nen est rien puisque lon deacuteclare en une seule fois un objet de ofstream en speacuteci-

fiant le fichier correspondant On pourrait dailleurs dire quun objet de ce type est un

fichier si lon ne craignait pas de le confondre avec ce mecircme terme de fichier en lan-

gage C (ougrave il deacutesigne souvent un nom interne de fichier cest-agrave-dire un pointeur sur une

structure de type FILE)

Les flotsCHAPITRE 16

364

62 Connexion dun flot dentreacutee agrave un fichierPour associer un flot dentreacutee agrave un fichier on emploie un meacutecanisme analogue agrave celui utiliseacute

pour un flot de sortie On creacutee cette fois un objet de type ifstream classe deacuterivant de istream

Il faut toujours inclure le fichier en-tecircte fstreamh en plus du fichier iostreamh Le construc-

teur comporte les mecircmes arguments que preacuteceacutedemment cest-agrave-dire nom de fichier et mode

douverture

Par exemple avec linstruction1

ifstream entree (trucdat iosin|iosbinary) ou seulement iosin

lobjet entree sera associeacute au fichier de nom trucdat apregraves quil aura eacuteteacute ouvert en lecture

Une fois construit un objet de classe ifstream la lecture dans le fichier qui lui est associeacute

pourra se faire comme pour nimporte quel flot dentreacutee en faisant appel agrave toutes les faciliteacutes

de la classe istream (dont deacuterive ifstream)

Par exemple apregraves la deacuteclaration preacuteceacutedente de entree nous pourrions employer des instruc-

tions telles que

entree gtgt gtgt gtgt

pour reacutealiser des lectures formateacutees ou encore

entreeread ()

pour reacutealiser des lectures binaires

Voici un programme complet qui permet de lister le contenu dun fichier quelconque creacuteeacute par

le programme preacuteceacutedent

include ltiostreamgtinclude ltfstreamgtinclude ltiomanipgtusing namespace std const int LGMAX = 20 main() char nomfich [LGMAX+1] int n cout ltlt nom du fichier a lister cin gtgt setw (LGMAX) gtgt nomfich ifstream entree (nomfich iosin|iosbinary) ou iosin if (entree) cout ltlt ouverture impossible n exit (-1) while ( entreeread ( (char)ampn sizeof(int) ) ) cout ltlt n ltlt n entreeclose ()

Lecture seacutequentielle dun fichier dentiers

1 Le paramegravetre iosbinary nrsquoest utile que dans les environnements qui distinguent les fichiers texte des autres ce qui

est le cas de Visual C++ (ou plutocirct de Windows)

6 - Connexion drsquoun flot agrave un fichier365

Remarque

Il existe eacutegalement une classe fstream deacuteriveacutee des deux classes ifstream et ofstream per-

mettant deffectuer agrave la fois des lectures et des eacutecritures avec un mecircme fichier Cela peut

saveacuterer fort pratique dans le cas de laccegraves direct que nous examinons ci-dessous La

deacuteclaration dun objet de type fstream se deacuteroule comme pour les types ifstream ou ofs-

tream Par exemple

fstream fich (trucdat iosin|iosout|iosbinary)

associe lobjet fich au fichier de nom trucdat apregraves lavoir ouvert en lecture et en eacutecri-

ture

63 Les possibiliteacutes daccegraves directComme en langage C en C++ degraves quun flot a eacuteteacute connecteacute agrave un fichier il est possible de

reacutealiser un accegraves direct agrave ce fichier en agissant tout simplement sur un pointeur dans ce

fichier cest-agrave-dire un nombre preacutecisant le rang du prochain octet (caractegravere) agrave lire ou agrave

eacutecrire Apregraves chaque opeacuteration de lecture ou deacutecriture ce pointeur est increacutementeacute du nombre

doctets transfeacutereacutes Ainsi lorsque lon nagit pas explicitement sur ce pointeur on reacutealise un

classique accegraves seacutequentiel cest ce que nous avons fait preacuteceacutedemment

Les possibiliteacutes daccegraves direct se reacutesument donc en fait aux possibiliteacutes daction sur ce poin-

teur ou agrave la deacutetermination de sa valeur

Dans chacune des deux classes ifstream et ofstream une fonction membre nommeacutee seekg

(pour ifstream) et seekp (pour ofstream) permet de donner une certaine valeur au pointeur

(attention chacune de ces deux classes possegravede le sien de sorte quil existe un pointeur pour

la lecture et un pointeur pour leacutecriture) Plus preacuteciseacutement chacune des ces deux fonctions

comporte deux arguments

bull un entier repreacutesentant un deacuteplacement du pointeur par rapport agrave une origine preacuteciseacutee par le

second argument

bull une constante entiegravere choisie parmi trois valeurs preacutedeacutefinies dans ios

ndash iosbeg le deacuteplacement est exprimeacute par rapport au deacutebut du fichier

ndash ioscur le deacuteplacement est exprimeacute par rapport agrave la position actuelle

ndash iosend le deacuteplacement est exprimeacute par rapport agrave la fin du fichier (par deacutefaut cet ar-

gument a la valeur iosbeg)

Notez quon retrouve lagrave les possibiliteacutes offertes par la fonction fseek du langage C

Par ailleurs il existe dans chacune des classes ifstream et ofstream une fonction permettant

de connaicirctre la position courante du pointeur Il sagit de tellg (pour ifstream) et de tellp (pour

ofstream) Celles-ci offrent des possibiliteacutes comparables agrave la fonction ftell du langage C

Les flotsCHAPITRE 16

366

Voici un exemple de programme permettant dacceacuteder agrave nimporte quel entier dun fichier du

type de ceux que pouvait creacuteer le programme du paragraphe 61 (ici nous supposons qursquoil

comporte une dizaine de valeurs entiegraveres)

include ltiostreamgt

include ltfstreamgt

include ltiomanipgt

using namespace std

const int LGMAX_NOM_FICH = 20 main()

char nomfich [LGMAX_NOM_FICH + 1]

int n num

cout ltlt nom du fichier a consulter

cin gtgt setw (LGMAX_NOM_FICH) gtgt nomfich

ifstream entree (nomfich iosin|iosbinary) ou iosin

if (entree) cout ltlt Ouverture impossiblen

exit (-1)

do

cout ltlt Numero de lentier recherche

cin gtgt num if (num)

entreeseekg (sizeof(int) (num-1) iosbeg )

entreeread ( (char ) ampn sizeof(int) )

if (entree) cout ltlt -- Valeur ltlt n ltlt n

else cout ltlt -- Erreurn

entreeclear ()

while (num)

entreeclose ()

nom du fichier a consulter essaidat

Numero de lentier recherche 4

-- Valeur 6

Numero de lentier recherche 15

-- ErreurNumero de lentier recherche 7

-- Valeur 9

Numero de lentier recherche -3

-- Erreur

Numero de lentier recherche 0

Accegraves direct agrave un fichier dentiers

6 - Connexion drsquoun flot agrave un fichier367

64 Les diffeacuterents modes douverture dun fichierNous avons rencontreacute quelques exemples de modes douverture dun fichier Nous allons exa-

miner ici lensemble des possibiliteacutes offertes par les classes ifstream et ofstream (et donc

aussi de fstream)

Le mode douverture est deacutefini par un mot deacutetat dans lequel chaque bit correspond agrave une

signification particuliegravere La valeur correspondant agrave chaque bit est deacutefinie par des constantes

deacuteclareacutees dans la classe ios Pour activer plusieurs bits il suffit de faire appel agrave lopeacuterateur |

Les diffeacuterents modes douverture dun fichier

A titre indicatif voici les modes douverture eacutequivalents aux diffeacuterents modes douverture de

la fonction fopen du C

Les modes drsquoouverture de la fonction fopen du C

Bit Action

iosin Ouverture en lecture (obligatoire pour la classe ifstream)

iosout Ouverture en eacutecriture (obligatoire pour la classe ofstream)

iosapp Ouverture en ajout de donneacutees (eacutecriture en fin de fichier)

iostrunc Si le fichier existe son contenu est perdu (obligatoire si iosout est activeacute sans iosate ni iosapp)

iosbinary Utiliseacute seulement dans les impleacutementations qui distinguent les fichiers textes des autres Le fichier est ouvert en mode binaire ou encore non translateacute (voir remarque ci-dessous)

Combinaison de bits Mode correspondant de fopen

iosout ws

iosout iosapp a

iosout iostrunc w

iosin r

iosin iosout r+

iosin iosout iostrunc wb+

iosout iosbinary wb

iosout iosapp iosbinary ab

iosout iostrunc iosbinary wb

iosin iosbinary rb

iosin iosout iosbinary r+b

iosin iosout iostrunc iosbinary w+b

Les flotsCHAPITRE 16

368

Remarque

Rappelons que certains environnements (PC en particulier) distinguent les fichiers de

texte des autres (quils appellent parfois fichiers binaires1) plus preacuteciseacutement lors de

louverture du fichier on peut speacutecifier si lon souhaite ou non consideacuterer son contenu

comme du texte Cette distinction est en fait principalement motiveacutee par le fait que sur ces

systegravemes le caractegravere de fin de ligne (n) possegravede une repreacutesentation particuliegravere obtenue

par la succession de deux caractegraveres (retour chariot r suivi de fin de ligne n)2 Dans ces

conditions pour quun programme C++ puisse ne voir quun seul caractegravere de fin de

ligne et quil sagisse bien de n il faut opeacuterer un traitement particulier consistant agrave

ndash remplacer chaque occurrence de ce couple de caractegraveres par n dans le cas dune lectu-

re

ndash remplacer chaque demande deacutecriture de n par leacutecriture de ce couple de caractegraveres

Bien entendu de telles substitutions ne doivent pas ecirctre reacutealiseacutees sur de vrais fichiers

binaires Il faut donc bien pouvoir opeacuterer une distinction au sein du programme Cette

distinction se fait au moment de louverture du fichier en activant le bit iosbinary

dans le mode douverture dans le cas dun fichier binaire par deacutefaut ce bit nest pas

activeacute On notera que lrsquoactivation du bit iosbinary correspond aux modes douverture

rb ou wb du langage C

7 Les anciennes possibiliteacutes de formatage en meacutemoire

En langage C

bull sscanf permet dacceacuteder agrave une information situeacutee en meacutemoire de faccedilon comparable agrave ce que

fait scanf sur lentreacutee standard

bull sprintf permet de fabriquer en meacutemoire une chaicircne de caractegraveres correspondant agrave celle qui

serait transmise agrave la sortie standard par printf

En C++ des faciliteacutes comparables existent Jusqursquoagrave la norme elles eacutetaient fournies par les

classes

bull ostrstream pour linsertion de caractegraveres dans un tableau

bull istrstream pour lextraction de caractegraveres depuis un tableau

1 Alors quau bout du compte tout fichier est binaire

2 Notez que dans ces environnements PC le caractegravere CTRLZ (de code deacutecimal 26) est interpreacuteteacute comme une fin

de fichier texte

7 - Les anciennes possibiliteacutes de formatage en meacutemoire369

La norme a introduit de nouvelles classes plus faciles drsquoemploi et faisant appel au type string

(vrai type chaicircne) Elles seront preacutesenteacutees au paragraphe 7 du chapitre 22

Ici nous vous preacutesenterons quand mecircme les anciennes possibiliteacutes afin de vous permettre

drsquoexploiter des programmes existants Notez qursquoelles sont classeacutees deprecaded feature ce

qui signifie qursquoelles sont susceptibles de disparaicirctre dans une version ulteacuterieure de C++

71 La classe ostrstreamUn objet de classe ostrstream peut recevoir des caractegraveres au mecircme titre quun flot de sortie

La seule diffeacuterence est que ces caractegraveres ne sont pas transmis agrave un peacuteripheacuterique ou agrave un

fichier mais simplement conserveacutes dans lobjet lui-mecircme plus preacuteciseacutement dans un tableau

membre de la classe ostrstream ce tableau est creacuteeacute dynamiquement et ne pose donc pas de

problegraveme de limitation de taille

Une fonction membre particuliegravere nommeacutee str permet dobtenir ladresse du tableau en ques-

tion Celui-ci pourra alors ecirctre manipuleacute comme nimporte quel tableau de caractegraveres (repeacutereacute

par un pointeur de type char )

Par exemple avec la deacuteclaration

ostrstream tab

vous pouvez inseacuterer des caractegraveres dans lobjet tab par des instructions telles que

tab ltlt ltlt ltlt

ou

tabput ()

ou encore

tabwrite ()

Ladresse du tableau de caractegraveres ainsi constitueacute pourra ecirctre obtenue par

char adt = tabstr ()

A partir de lagrave vous pourrez agir comme il vous plaira sur les caractegraveres situeacutes agrave cette adresse

(les consulter mais aussi les modifier)

Remarques

1 Lorsque str a eacuteteacute appeleacutee pour un objet il nest plus possible dinseacuterer de nouveaux carac-

tegraveres dans cet objet On peut dire que lappel de cette fonction gegravele deacutefinitivement le

tableau de caractegraveres (noubliez pas quil est alloueacute dynamiquement et que son adresse

peut mecircme eacutevoluer au fil de linsertion de caractegraveres ) avant den fournir en retour une

adresse deacutefinitive On prendra donc bien soin de nappeler str que lorsque lon aura inseacutereacute

dans lobjet tous les caractegraveres voulus

Par souci drsquoexhaustiviteacute signalons qursquoil existe une fonction membre freeze (bool

action) Lrsquoappel tabfreeze (true) fige le tableau mais il vous faut quand mecircme appeler

str pour en obtenir lrsquoadresse En revanche tabfreeze(false) preacutesente bien un inteacuterecirct si

Les flotsCHAPITRE 16

370

tab a deacutejagrave eacuteteacute geleacute il redevient dynamique on peut agrave nouveau y introduire des

informations bien entendu son adresse pourra de nouveau eacutevoluer et il faudra agrave nou-

veau faire appel agrave str pour lrsquoobtenir

2 Si un objet de classe ostrstream devient hors de porteacutee alors que la fonction str na pas

eacuteteacute appeleacutee il est deacutetruit normalement par appel dun destructeur qui deacutetruit alors eacutegale-

ment le tableau de caractegraveres correspondant En revanche si str a eacuteteacute appeleacutee on consi-

degravere que le tableau en question est maintenant sous la responsabiliteacute du programmeur et

il ne sera donc pas deacutetruit lorsque lobjet deviendra hors de porteacutee (bien sucircr le reste de

lobjet le sera) Ce sera au programmeur de le faire lorsquil le souhaitera en proceacutedant

comme pour nimporte quel tableau de caractegraveres alloueacute dynamiquement (par new)

cest-agrave-dire en faisant appel agrave lopeacuterateur delete Par exemple lemplacement meacutemoire

du tableau de lobjet tab preacuteceacutedent dont ladresse a eacuteteacute obtenue dans adt pourra ecirctre

libeacutereacute par

delete adt

72 La classe istrstreamUn objet de classe istrstream est creacuteeacute par un appel de constructeur auquel on fournit en

argument

bull ladresse dun tableau de caractegraveres

bull le nombre de caractegraveres agrave prendre en compte

Il est alors possible dextraire des caractegraveres de cet objet comme on le ferait de nimporte

quel flot dentreacutee

Par exemple avec les deacuteclarations

char t[100]

istrstream tab ( t sizeof(t) )

vous pourrez extraire des caractegraveres du tableau t par des instructions telles que

tab gtgt gtgt gtgt

ou

tabget ()

ou encore

tabread ()

Qui plus est vous pourrez agir sur un pointeur courant dans ce tableau comme vous le feriez

dans un fichier par lappel de la fonction seekg Par exemple avec lobjet tab preacuteceacutedent vous

pourrez replacer le pointeur en deacutebut de tableau par

tabseekg (0 iosbeg)

Cela pourrait permettre par exemple dexploiter plusieurs fois une mecircme information (lue

preacutealablement dans un tableau) en la lisant suivant des formats diffeacuterents

7 - Les anciennes possibiliteacutes de formatage en meacutemoire371

Voici un exemple dutilisation de la classe istrstream montrant comment reacutesoudre les problegrave-

mes engendreacutes par la frappe dun mauvais caractegravere dans le cas de lectures sur lentreacutee stan-

dard (situation que nous avons eacutevoqueacutee au paragraphe 352 du chapitre 3

const int LGMAX = 122 longueur maxi dune ligne clavierinclude ltiostreamgtinclude ltstrstreamgtusing namespace std

main() int n erreur char c char ligne [LGMAX] pour lire une ligne au clavier do cout ltlt donnez un entier et un caractere n cingetline (ligne LGMAX) istrstream tampon (ligne cingcount () ) if (tampon gtgt n gtgt c) erreur = 0 else erreur = 1 while (erreur) cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

donnez un entier et un caractere bofdonnez un entier et un caractere a 125donnez un entier et un caractere 12 bonjourmerci pour 12 et b

Pour lire en toute seacutecuriteacute sur lentreacutee standard

Nous y lisons tout dabord linformation attendue pour toute une ligne sous la forme dune

chaicircne de caractegraveres (agrave laide de la fonction getline) Nous construisons ensuite avec cette

chaicircne un objet de type istrstream sur lequel nous appliquons nos opeacuterations de lecture (ici

lecture formateacutee dun entier puis dun caractegravere) Comme vous le constatez aucun problegraveme

ne se pose plus lorsque lutilisateur fournit un caractegravere invalide (par rapport agrave lusage quon

doit en faire) contrairement agrave ce qui se serait passeacute en cas de lecture directe sur cin

17

La gestion des exceptions

Pour la mise au point drsquoun programme bon nombre drsquoenvironnements proposent des outils

de deacutebogage tregraves performants Si tel nrsquoest pas le cas il reste toujours possible de faire appel

aux possibiliteacutes heacuteriteacutees du langage C que constituent la compilation conditionnelle (ifdef)

et la macro assert

Mais mecircme lorsqursquoil est au point un programme peut rencontrer des conditions exception-

nelles qui risquent de compromettre la poursuite de son exeacutecution Dans des programmes

relativement importants il est rare que la deacutetection de lrsquoincident et son traitement puissent se

faire dans la mecircme partie de code Cette dissociation devient encore plus neacutecessaire lorsque

lrsquoon deacuteveloppe des composants reacuteutilisables destineacutes agrave ecirctre exploiteacutes par de nombreux pro-

grammes

Certes on peut toujours reacutesoudre un tel problegraveme en srsquoappuyant sur les deacutemarches utiliseacutees

en C La plus reacutepandue consistait agrave srsquoinspirer de la philosophie utiliseacutee dans la bibliothegraveque

standard fournir un code drsquoerreur comme valeur de retour des diffeacuterentes fonctions Si une

telle meacutethode preacutesente lrsquoavantage de seacuteparer la deacutetection drsquoune anomalie de son traitement

elle nrsquoen reste pas moins tregraves fastidieuse elle implique en effet lrsquoexamen systeacutematique des

valeurs de retour en de nombreux points du programme ainsi qursquoune freacutequente retransmis-

sion agrave travers la hieacuterarchie des appels Une autre deacutemarche consistait agrave exploiter les fonctions

setjmp et longjmp pour provoquer un branchement srsquoaffranchissant de la hieacuterarchie des

appels cependant aucune gestion des variables automatiques nrsquoeacutetait alors assureacutee1

1 Pour plus drsquoinformations sur les fonctions setjmp et longjmp on pourra consulter Langage C norme ANSI du mecircme

auteur chez le mecircme eacutediteur

La gestion des exceptionsCHAPITRE 17

374

La version 3 de C++ a inteacutegreacute dans le langage un meacutecanisme tregraves puissant de traitement de

ces anomalies nommeacute gestion des exceptions Il a le meacuterite de deacutecoupler totalement la deacutetec-

tion drsquoune anomalie (exception) de son traitement en srsquoaffranchissant de la hieacuterarchie des

appels tout en assurant une gestion convenable des objets automatiques

Drsquoune maniegravere geacuteneacuterale une exception est une rupture de seacutequence deacuteclencheacutee (on dit aussi

leveacutee ou lanceacutee) par une instruction throw comportant une expression drsquoun type donneacute

Il y a alors branchement agrave un ensemble drsquoinstructions nommeacute gestionnaire drsquoexception (on

parle aussi de capture par un gestionnaire) dont le nom est deacutetermineacute par la nature de

lrsquoexception Plus preacuteciseacutement chaque exception est caracteacuteriseacutee par un type et le choix du

bon gestionnaire se fait en fonction de la nature de lexpression mentionneacutee agrave throw

Compte tenu de lrsquooriginaliteacute de cette nouvelle notion nous introduirons les notions de lance-

ment et de capture drsquoune exception sur quelques exemples Nous verrons ensuite quelles sont

les diffeacuterentes faccedilons de poursuivre lrsquoexeacutecution apregraves la capture drsquoune exception Nous eacutetu-

dierons en deacutetail lrsquoalgorithme utiliseacute pour effectuer le choix du gestionnaire drsquointerruption

ainsi que le rocircle de la fonction terminate dans le cas ougrave aucun gestionnaire nrsquoest trouveacute

Nous verrons ensuite comment une fonction peut speacutecifier les exceptions qursquoelle est suscep-

tible de lancer sans les traiter et quel est alors le rocircle de la fonction unexpected Puis nous

examinerons les diffeacuterentes classes drsquoexceptions fournies par la bibliothegraveque standard et

utiliseacutees par les fonctions standards ainsi que lrsquointeacuterecirct qursquoil peut y avoir agrave les exploiter dans

la creacuteation de ses propres exceptions

1 Premier exemple drsquoexceptionDans cet exemple complet nous allons reprendre la classe vect preacutesenteacutee au paragraphe 5 du

chapitre 9 cest-agrave-dire munie de la surdeacutefinition de lopeacuterateur [] Celui-ci neacutetait alors pas

proteacutegeacute contre lutilisation dindices situeacutes en dehors des bornes Ici nous allons compleacuteter

notre classe pour quelle deacuteclenche une exception dans ce cas Puis nous verrons comment

intercepter une telle exception en eacutecrivant un gestionnaire approprieacute

11 Comment lancer une exception linstruction throwAu sein de la surdeacutefinition de [] nous introduisons donc une veacuterification de lindice lorsque

celui-ci est incorrect nous deacuteclenchons une exception agrave laide de linstruction throw Celle-ci

neacutecessite une expression quelconque dont le type (classe ou non) sert agrave identifier lrsquoexception

En geacuteneacuteral pour bien distinguer les exceptions les unes des autres il est preacutefeacuterable drsquoutiliser

un type classe deacutefini uniquement pour repreacutesenter lrsquoexception concerneacutee Crsquoest ce que nous

ferons ici Nous introduisons donc artificiellement avec la deacuteclaration de notre classe vect

une classe nommeacutee vect_limite (sans aucun membre) Son existence nous permet de creacuteer un

objet l de type vect_limite objet que nous associons agrave linstruction throw par linstruction

throw l

1 - Premier exemple drsquoexception375

Voici la deacutefinition complegravete de la classe vect

deacuteclaration de la classe vect class vect

int nelem int adr public vect (int)

~vect () int amp operator [] (int) deacuteclaration et deacutefinition dune classe vect_limite (vide pour linstant)

class vect_limite deacutefinition de la classe vect vectvect (int n)

adr = new int [nelem = n] vect~vect () delete adr

int amp vectoperator [] (int i) if (ilt0 || igtnelem) vect_limite l

throw (l) deacuteclenche une exception de type vect_limite return adr [i]

Deacutefinition dune classe provoquant une exception vect_limite

12 Utilisation dun gestionnaire dexceptionDisposant de notre classe vect voyons maintenant comment proceacuteder pour pouvoir geacuterer

convenablement les eacuteventuelles exceptions de type vect_limite que son emploi peut provo-

quer Pour ce faire il est neacutecessaire de respecter deux conditions

bull inclure dans un bloc particulier dit bloc try toutes les instructions dans lesquelles on sou-

haite pouvoir deacutetecter une exception un tel bloc se preacutesente ainsi

try instructions

bull faire suivre ce bloc de la deacutefinition des diffeacuterents gestionnaires dexceptions neacutecessaires

(ici un seul suffit) Chaque deacutefinition est preacuteceacutedeacutee dun en-tecircte introduit par le mot cleacute catch

(comme si catch eacutetait le nom dune fonction gestionnaire) Dans notre cas voici ce que

La gestion des exceptionsCHAPITRE 17

376

pourrait ecirctre notre unique gestionnaire destineacute agrave intercepter les exceptions de type

vect_limite

catch (vect_limite l) nom dargument superflu ici cout ltlt exception limite n exit (-1)

Nous nous contentons ici dafficher un message et dinterrompre lexeacutecution du programme

13 ReacutecapitulatifA titre indicatif voici la liste complegravete de la deacutefinition des diffeacuterentes classes concerneacutees

Elle est accompagneacutee dun petit programme dessai dans lequel nous deacuteclenchons volontaire-

ment une exception vect_limite en apliquant lopeacuterateur [] agrave un objet de type vect avec un

indice trop grand)

include ltiostreamgtinclude ltcstdlibgt ancien ltstdlibhgt pour exit using namespace std deacuteclaration de la classe vect class vect int nelem int adr public vect (int) ~vect () int amp operator [] (int)

deacuteclaration et deacutefinition dune classe vect_limite (vide pour linstant) class vect_limite deacutefinition de la classe vect vectvect (int n) adr = new int [nelem = n] vect~vect () delete adr int amp vectoperator [] (int i) if (ilt0 || igtnelem) vect_limite l throw (l) return adr [i]

test interception exception vect_limite main () try vect v(10) v[11] = 5 indice trop grand

1 - Premier exemple drsquoexception377

catch (vect_limite l) nom dargument superflu ici

cout ltlt exception limite n

exit (-1)

exception limite

Premier exemple de gestion dexception

Remarques

1 Ce premier exemple destineacute agrave vous preacutesenter le meacutecanisme de gestion des exceptions est

fort simple notamment

ndash il ne comporte quun seul type dexception de sorte quil ne met pas vraiment en eacutevi-

dence le meacutecanisme de choix du bon gestionnaire

ndash le gestionnaire ne reccediloit pas dinformation particuliegravere (largument l eacutetant ici artificiel)

2 Dune maniegravere geacuteneacuterale le gestionnaire dune exception est deacutefini indeacutependamment des

fonctions susceptibles de la deacuteclencher Ainsi agrave partir du moment ougrave la deacutefinition dune

classe est seacutepareacutee de son utilisation (ce qui est souvent le cas en pratique) il est tout agrave

fait possible de preacutevoir un gestionnaire dexception diffeacuterent dune utilisation agrave une

autre dune mecircme classe Dans lrsquoexemple preacuteceacutedent tel utilisateur peut vouloir afficher

un message avant de sinterrompre tel autre preacutefeacuterera ne rien afficher ou encore tenter

de preacutevoir une solution par deacutefaut

3 Nous aurions pu preacutevoir un gestionnaire drsquoexception dans la classe vect elle-mecircme Il

en sera rarement ainsi en pratique dans la mesure ougrave lrsquoun des buts primordiaux du

meacutecanisme proposeacute par C++ est de seacuteparer la deacutetection drsquoune exception de son traite-

ment

4 Ici nous avons preacutevu une instruction exit agrave linteacuterieur du gestionnaire dexception Nous

verrons au paragraphe 31 que dans le cas contraire lrsquoexeacutecution se poursuivrait agrave la

suite du bloc try concerneacute Mais dores et deacutejagrave nous pouvons remarquer que le modegravele

de gestion des exceptions proposeacute par C++ ne permet pas de reprendre lrsquoexeacutecution agrave

partir de lrsquoinstruction ayant leveacute lrsquoexception1

5 Si nous nrsquoavions pas preacutevu de bloc try lrsquoexception limite deacuteclencheacutee par lrsquoopeacuterateur []

et non prise en compte aurait alors simplement provoqueacute un arrecirct de lrsquoexeacutecution

1 Il en ira de mecircme en Java En revanche ADA dispose drsquoun meacutecanisme de reprise drsquoexeacutecution

La gestion des exceptionsCHAPITRE 17

378

2 Second exempleExaminons maintenant un exemple un peu plus reacutealiste dans lequel on trouve deux excep-

tions diffeacuterentes et ougrave il y a transmission dinformations aux gestionnaires Nous allons

reprendre la classe vect preacuteceacutedente en lui permettant de lancer deux sortes dexceptions

bull une exception de type vect_limite comme preacuteceacutedemment mais cette fois on preacutevoit de

transmettre au gestionnaire la valeur de lindice qui a deacuteclencheacute lrsquoexception

bull une exception vect_creation deacuteclencheacutee lorsque lon transmet au constructeur un nombre

deacuteleacutements incorrect1 (neacutegatif ou nul) lagrave encore on preacutevoit de transmettre ce nombre au

gestionnaire

Il suffit dappliquer le meacutecanisme preacuteceacutedent en notant simplement que lobjet indiqueacute agrave

throw et reacutecupeacutereacute par catch peut nous servir agrave communiquer toute information de notre

choix Nous preacutevoirons donc dans nos nouvelles classes vect_limite et vect_creation un

champ public de type entier destineacute agrave recevoir linformation agrave transmettre au gestionnaire

Voici un exemple complet (ici encore la deacutefinition et lutilisation des classes figurent dans le

mecircme source en pratique il en ira rarement ainsi)

include ltiostreamgtinclude ltcstdlibgt ancien ltstdlibhgt pour exitusing namespace std

deacuteclaration de la classe vect class vect int nelem int adr public vect (int) ~vect () int amp operator [] (int)

deacuteclaration - deacutefinition des deux classes exception class vect_limite public int hors valeur indice hors limites (public) vect_limite (int i) constructeur hors = i

1 Dans un cas reacuteel on pourrait aussi lancer cette interruption en cas de manque de meacutemoire

2 - Second exemple379

class vect_creation

public int nb nombre elements demandes (public)

vect_creation (int i) constructeur

nb = i

deacutefinition de la classe vect

vectvect (int n)

if (n lt= 0) vect_creation c(n) anomalie

throw c

adr = new int [nelem = n] construction normale

vect~vect ()

delete adr

int amp vectoperator [] (int i)

if (ilt0 || igtnelem)

vect_limite l(i) anomalie throw l

return adr [i] fonctionnement normal

test exception

main ()

try vect v(-3) provoque lexception vect_creation

v[11] = 5 provoquerait lexception vect_limite

catch (vect_limite l) cout ltlt exception indice ltlt lhors ltlt hors limites n

exit (-1)

catch (vect_creation c) cout ltlt exception creation vect nb elem = ltlt cnb ltlt n

exit (-1)

exception creation vect nb elem = -3

Exemple de gestion de deux exceptions

La gestion des exceptionsCHAPITRE 17

380

Bien entendu la premiegravere exception (deacuteclencheacutee par vect v(-3)) ayant provoqueacute la sorite du

bloc try nous navons aucune chance de mettre en eacutevidence celle quaurait provoqueacute v[11] =

5 Si la creacuteation de v avait eacuteteacute correcte cette derniegravere instruction aurait entraicircneacute laffichage du

message

exception indice 11 hors limites

Remarques

1 Dans un exemple reacuteel on pourrait avoir inteacuterecirct agrave transmettre dans vect_limite non seule-

ment la valeur de lindice mais aussi les limites preacutevues Il suffirait dintroduire les mem-

bres correspondants dans la classe vect_limite

2 Ici chaque type dexception nest deacuteclencheacute quen un seul endroit Mais bien entendu

nimporte quelle fonction (pas neacutecessairement membre de la classe vect ) disposant de

la deacutefinition des deux classes (vect_limite et vect_creation) peut deacuteclencher ces excep-

tions

3 Le meacutecanisme de gestion des exceptionsDans tous les exemples preacuteceacutedents le gestionnaire drsquoexception interrompait lexeacutecution par

un appel de exit (nous aurions pu eacutegalement utiliser la fonction standard abort1) Mais le

meacutecanisme offert par C++ autorise drsquoautres possibiliteacutes que nous allons examiner mainte-

nant en distinguant deux aspects

bull la possibiliteacute de poursuivre lrsquoexeacutecution du programme apregraves lrsquoexeacutecution du gestionnaire

drsquoexception

bull la maniegravere dont sont prises en compte les diffeacuterentes sorties de blocs (donc de fonctions) qui

peuvent en deacutecouler

31 Poursuite de lexeacutecution du programme Le gestionnaire drsquoexception peut tregraves bien ne pas comporter drsquoinstruction drsquoarrecirct de lrsquoexeacutecu-

tion (exit abort) Dans ce cas apregraves lexeacutecution des intructions du gestionnaire concerneacute on

passe tout simplement agrave la suite du bloc try concerneacute Cela revient agrave dire qursquoon passe agrave la pre-

miegravere instruction suivant le dernier gestionnaire

Observez cet exemple qui utilise les mecircmes classes vect vect_limite et vect_creation que

preacuteceacutedemment Nous y appelons agrave deux reprises une fonction f lrsquoexeacutecution de f se deacuteroule

normalement la premiegravere fois elle deacuteclenche une exception la seconde

1 Pour plus drsquoinformation sur le rocircle de ces fonctions on pourra consulter Langage C du mecircme auteur chez le mecircme

eacutediteur

3 - Le meacutecanisme de gestion des exceptions381

deacuteclaration et deacutefinition des classes vect vect_limite vect_creation

comme dans le paragraphe 2

main()

void f(int)

cout ltlt avant appel de f(3) n

f(3)

cout ltlt avant appel de f(8) n

f(8)

cout ltlt apres appel de f(8) n

void f(int n)

try

cout ltlt debut bloc tryn

vect v(5)

v[n] = 0 OK pour n=3 deacuteclenche une exception pour n=8

cout ltlt fin bloc tryn

catch (vect_limite l)

cout ltlt exception indice ltlt lhors ltlt hors limites n

catch (vect_creation c)

cout ltlt exception creationn

apregraves le bloc try

cout ltlt dans f apres bloc try - valeur de n = ltlt n ltlt n

avant appel de f(3)

debut bloc try

fin bloc try

dans f apres bloc try - valeur de n = 3

avant appel de f(8)

debut bloc try

exception indice 8 hors limites

dans f apres bloc try - valeur de n = 8

apres appel de f(8)

Lorsquon passe agrave travers un gestionnaire dexception

On constate qursquoapregraves lrsquoexeacutecution du gestionnaire drsquoexception vect_limite on exeacutecute lrsquoins-

truction cout figurant agrave la suite des gestionnaires On notera bien qursquoon peut y afficher la

valeur de n puisqursquoon est encore dans la porteacutee de cette variable

Freacutequemment un bloc try couvre toute une fonction de sorte qursquoapregraves exeacutecution drsquoun ges-

tionnaire drsquoexception ne provoquant pas drsquoarrecirct il y a retour de ladite fonction

La gestion des exceptionsCHAPITRE 17

382

32 Prise en compte des sorties de blocsLrsquoexemple preacuteceacutedent montrait deacutejagrave que le branchement provoqueacute par la deacutetection drsquoune

exception respectait le changement de contexte qui en deacutecoulait la valeur de n eacutetait connue

dans la suite du bloc try qursquoon y soit parvenu naturellement ou suite agrave une exception Voici

un autre exemple dans lequel nous avons simplement modifieacute la fonction f de lrsquoexemple

preacuteceacutedent

void f(int n) vect v1(5) try vect v2(5) v2[n] = 0 catch (vect_limite l) cout ltlt exception indice ltlt lhors ltlt hors limites n apregraves le bloc try ici v1 est connu v2 ne lrsquoest pas et il a eacuteteacute convenablement deacutetruit

Cette fois nous y creacuteons un vecteur en dehors du bloc try un autre agrave lrsquointeacuterieur comme preacute-

ceacutedemment Bien entendu si f srsquoexeacutecute sans deacuteclencher drsquoexception on exeacutecutera tout natu-

rellement les instructions suivant le bloc try dans ces derniegraveres v1 sera connu tandis que v2

ne le sera plus Mais il en ira encore de mecircme si f provoque une exception vect_limite apregraves

son traitement par le gestionnaire correspondant

De plus dans les deux cas le destructeur de v2 aura eacuteteacute appeleacute

Drsquoune maniegravere geacuteneacuterale le meacutecanisme associeacute au traitement drsquoune exception ne se contente

pas de supprimer les variables automatiques des blocs dont on provoque la sortie Il entraicircne

lrsquoappel du destructeur de tout objet automatique deacutejagrave construit et devenant hors de

porteacutee

Remarque

Comme on peut srsquoy attendre ce meacutecanisme de destruction ne pourra pas srsquoappliquer aux

objets dynamiques Certaines preacutecautions devront ecirctre prises degraves lors qursquoon souhaite

poursuivre lrsquoexeacutecution apregraves le traitement drsquoune exception Ce point sera examineacute en

deacutetail en Annexe C

4 Choix du gestionnaireDans les exemples que nous avons rencontreacutes jusqursquoici le choix du gestionnaire eacutetait relati-

vement intuitif Nous allons maintenant preacuteciser lrsquoensemble des regravegles utiliseacutees par C++ pour

effectuer ce choix Puis nous verrons comment la recherche se poursuit dans des blocs try

4 - Choix du gestionnaire383

englobants lorsqursquoaucun gestionnaire convenable nrsquoest trouveacute pour un bloc try donneacute Aupa-

ravant nous allons apporter quelques preacutecisions concernant la maniegravere (particuliegravere) dont

lrsquoinformation est effectivement transmise au gestionnaire

41 Le gestionnaire reccediloit toujours une copieEn ce qui concerne lrsquoinformation transmise au gestionnaire agrave savoir lrsquoexpression mentionneacutee

agrave throw le gestionnaire en reccediloit toujours une copie mecircme si lrsquoon a utiliseacute une transmission

par reacutefeacuterence Il srsquoagit lagrave drsquoune neacutecessiteacute compte tenu du changement de contexte deacutejagrave eacutevo-

queacute1 En revanche lorsque cette information consistera en un pointeur on eacutevitera qursquoil pointe

sur une variable automatique qui se trouverait deacutetruite avant lrsquoentreacutee dans le gestionnaire

c = new A () throw (c) erreur probable

42 Regravegles de choix drsquoun gestionnaire drsquoexceptionLorqursquoune exception est transmise agrave un bloc try on recherche dans les diffeacuterents blocs catch

associeacutes un gestionnaire approprieacute au type de lrsquoexpression mentionneacutee dans lrsquoinstruction

throw Comme pour la recherche drsquoune fonction surdeacutefinie on procegravede en plusieurs eacutetapes

1 Recherche drsquoun gestionnaire correspondant au type exact mentionneacute dans throw Le qua-

lificatif const nrsquointervient pas ici (il y a toujours transmission par valeur) Autrement dit

si lrsquoexpression mentionneacutee dans throw est de type T les gestionnaires suivants

conviennent

catch (T t)

catch (T amp t)catch (const T t)

catch (const T amp t)

2 Recherche drsquoun gestionnaire correspondant agrave une classe de base du type mentionneacute dans

throw Cette possibiliteacute est preacutecieuse pour regrouper plusieurs exceptions quon peut traiter

plus ou moins finement Consideacuterons cet exemple dans lequel les exceptions

vect_creation et vect_limite sont deacuteriveacutees drsquoune mecircme classe vect_erreur

class vect_erreur class vect_creation public vect_erreur

class vect_limite public vect_erreur void f()

throw vect_creation () exception 1

throw vect_limite () exception 2

1 Certains auteurs preacuteconisent drsquoutiliser toujours cette transmission par reacutefeacuterence pour eacuteviter la copie suppleacutementaire

que certains compilateurs introduisent dans le cas drsquoune transmission par valeur

La gestion des exceptionsCHAPITRE 17

384

Dans un programme utilisant f on peut geacuterer les exceptions qursquoelle est susceptible de deacute-

clencher de cette premiegravere faccedilon

main() try f() catch (vect_erreur e) on intercepte ici exception_1 et exception_2

Mais on peut aussi les geacuterer ainsi

main() try f() catch (vect_cration v) on intercepte ici exception_1 catch (vect_limite v) on intercepte ici exception_2

3 Recherche drsquoun gestionnaire correspondant agrave un pointeur sur une classe deacuteriveacutee du type

mentionneacute dans throw (lorsque ce type est lui-mecircme un pointeur)

4 Recherche drsquoun gestionnaire correspondant agrave un type quelconque repreacutesenteacute dans catch

par des points de suspension ()

Degraves quun gestionnaire correspond on lexeacutecute sans se preacuteoccuper de lexistence dautres

gestionnaires Ainsi avec

catch (truc) gestionnaire 1 catch () gestionnaire 2 (type quelconque) catch (chose) gestionnaire 3

le gestionnaire 3 na aucune chance decirctre exeacutecuteacute puisque le gestionnaire 2 interceptera tou-

tes les exceptions non intercepteacutees par le gestionnaire 1

43 Le cheminement des exceptionsQuand une exception est leveacutee par une fonction on cherche tout dabord un gestionnaire dans

leacuteventuel bloc try associeacute agrave cette fonction en appliquant les regravegles exposeacutees au paragraphe

42 Si lon ne trouve pas de gestionnaire ou si aucun bloc try nest associeacute on poursuit la

recherche dans un eacuteventuel bloc try associeacute agrave une fonction appelante1 et ainsi de suite Con-

sideacuterons cet exemple (utilisant toujours les mecircmes classes que preacuteceacutedemment)

4 - Choix du gestionnaire385

test exception

main ()

try void f1 ()

f1 ()

catch (vect_limite l)

cout ltlt dans main exception indice n

exit (-1)

void f1 ()

try

vect v(10) v[12] = 0 affiche dans main exception indice

vect v1 (-1) affiche dans f1 exception creation

(agrave condition que linstruction preacuteceacutedente

nrsquoait pas deacutejagrave provoqueacute une exception)

catch (vect_creation v)

cout ltlt dans f1 exception creation n

Si aucun gestionnaire dexception nest trouveacute on appelle la fonction terminate Par deacutefaut

cette derniegravere appelle la fonction abort Cette particulariteacute donne beaucoup de souplesse au

meacutecanisme de gestion drsquoexception En effet on peut ainsi se permettre de ne traiter que cer-

taines exceptions susceptibles drsquoecirctre deacuteclencheacutees par un programme les eacuteventuelles excep-

tions non deacutetecteacutees mettant simplement fin agrave lrsquoexeacutecution

Vous pouvez toujours demander qursquoagrave la place de terminate soit appeleacutee une fonction de votre

choix dont vous fournissez lrsquoadresse agrave set_terminate (de faccedilon comparable agrave ce que vous fai-

tes avec set_new_handler) Il est cependant neacutecessaire que cette fonction mette fin agrave lrsquoexeacutecu-

tion du programme elle ne doit pas effectuer de retour et elle ne peut pas lever drsquoexception

Remarques

1 Il est theacuteoriquement possible drsquoimbriquer des blocs try Dans ce cas lrsquoalgorithme de

recherche drsquoun gestionnaire se geacuteneacuteralise tout naturellement en prenant en compte les

eacuteventuels blocs englobants avant de remonter aux fonctions appelantes

2 Retenez bien que degraves qursquoun gestionnaire convenable a eacuteteacute trouveacute dans un bloc aucune

recherche nrsquoa lieu dans un eacuteventuel bloc englobant mecircme srsquoil contient un gestionnaire

assurant une meilleure correspondance de type

1 En fait on est presque toujours dans cette situation car il est rare que le bloc try figure dans le mecircme bloc que celui

qui contient lrsquoinstruction throw

La gestion des exceptionsCHAPITRE 17

386

44 Redeacuteclenchement drsquoune exceptionDans un gestionnaire lrsquoinstruction throw (sans expression) retransmet lrsquoexception au niveau

englobant Cette possibiliteacute permet par exemple de compleacuteter un traitement standard drsquoune

exception par un traitement compleacutementaire speacutecifique En voici un exemple dans lequel une

exception (ici de type int)1 est tout drsquoabord traiteacutee dans f avant drsquoecirctre traiteacutee dans main

include ltiostreamgtinclude ltcstdlibgt pour exit (ancien stdlibhgtusing namespace std main() try void f() f() catch (int) cout ltlt exception int dans mainn exit(-1) void f() try int n=2 throw n deacuteclenche une exception de type int catch (int) cout ltlt exception int dans fn throw

exception int dans fexception int dans main

Exemple de redeacuteclenchement drsquoune exception

Remarques

1 Dans le cas drsquoun gestionnaire drsquoexception figurant dans un constructeur ou un destruc-

teur lrsquoexception correspondante est automatiquement retransmise au niveau englobant si

lrsquoon atteint la fin du gestionnaire Tout se passe comme si le gestionnaire se terminait par

lrsquoinstruction

1 Il srsquoagit drsquoun exemple drsquoeacutecole En pratique lrsquoutilisation drsquoun type de base pour caracteacuteriser une exception nrsquoest

guegravere conseilleacutee

5 - Speacutecification dinterface la fonction unexpected387

throw geacuteneacutereacutee automatiquement agrave la fin drsquoun gestionnaire drsquoexception figurant dans un constructeur ou un destructeur

2 La relance drsquoune exception par throw srsquoavegravere surtout utile lorsqursquoun mecircme gestionnaire

risque de traiter une famille drsquoexceptions Dans le cas contraire on peut toujours la

remplacer par le deacuteclenchement explicite drsquoune nouvelle exception de mecircme type

Ainsi dans le gestionnaire

catch (A a) intercepte les exceptions de type A ou deacuteriveacute

on peut utiliser

throw a relance une exception de type A quel que soit le type de celle reacuteellement intercepteacutee (A ou deacuteriveacute)throw relance une exception du type de celle reacuteellement intercepteacutee

5 Speacutecification dinterface la fonction unexpected

Une fonction peut speacutecifier les exceptions quelle est susceptible de deacuteclencher sans les traiter

(ou de traiter et de redeacuteclencher par throw) Elle le fait agrave laide du mot cleacute throw suivi entre

parenthegraveses de la liste des exceptions concerneacutees Dans ce cas toute exception non preacutevue et

deacuteclencheacutee agrave linteacuterieur de la fonction (ou dune fonction appeleacutee) entraicircne lappel dune fonc-

tion particuliegravere nommeacutee unexpected

On peut dire que

void f() throw (A B) f est censeacutee ne deacuteclencher que des exceptions de type A et B

est eacutequivalent agrave

void f() try catch (A a) throw lrsquoexception A est retransmise catch (B b) throw lrsquoexception B est retransmise catch () unexpected() les autres appelent unexpected

Malheureusement le comportement par deacutefaut de unexpected nrsquoest pas entiegraverement deacutefini

par la norme Plus preacuteciseacutement cette fonction peut

bull soit appeler la fonction terminate (qui par deacutefaut appelle abort ce qui met fin agrave lrsquoexeacutecu-

tion)

bull soit redeacuteclencher une exception preacutevue dans la speacutecification drsquointerface de la fonction con-

cerneacutee Ce cadre assez large est essentiellement preacutevu pour permettre agrave unexpected de deacute-

clencher une exception standard bad_exception (les exceptions standard seront eacutetudieacutees au

paragraphe 6)

La gestion des exceptionsCHAPITRE 17

388

Vous pouvez eacutegalement fournir votre propre fonctionen remplacement de unexpected en

lindiquant par set_unexpected Lagrave encore cette fonction ne peut pas effectuer de retour en

revanche contrairement agrave la fonction se substituant agrave terminate elle peut lancer une excep-

tion agrave son tour

Voici un exemple dans lequel une fonction f deacuteclenche suivant la valeur de son argument

une exception de lrsquoun des types double int ou float1 Les premiegraveres disposent drsquoun gestion-

naire interne agrave f mais pas les autres Par ailleurs f a eacuteteacute deacuteclareacutee throw(int) ce qui laisse

entendre que vue de lrsquoexteacuterieur elle ne deacuteclenche que des exceptions de type int Nous exeacute-

cutons agrave trois reprises le programme de faccedilon agrave amener f agrave deacuteclencher successivement cha-

cune des trois exceptions

include ltiostreamgtusing namespace std main() void f(int) throw (int) int n cout ltlt entier (0 a 2) cin gtgt n try f(n) catch (int) cout ltlt exception int dans mainn cout ltlt suite du bloc try du mainn

void f(int n) throw (int) try cout ltlt n = ltlt n ltlt n switch (n) case 0 double d throw d break case 1 int n throw n break case 2 float f throw f break catch (double) cout ltlt exception double dans fn cout ltlt suite du bloc try dans f et retour appelantn

1 Ici encore il srsquoagit drsquoun exemple drsquoeacutecole En pratique lrsquoutilisation drsquoun type de base pour caracteacuteriser une

exception nrsquoest guegravere conseilleacutee

5 - Speacutecification dinterface la fonction unexpected389

entier (0 a 2) 0n = 0exception double dans fsuite du bloc try dans f et retour appelantsuite du bloc try du main

entier (0 a 2) 1n = 1exception int dans mainsuite du bloc try du main

entier (0 a 2) 2n = 2 ici appel de abort (fin anormale)

Exemple de speacutecification drsquointerface

On notera que dans la troisiegraveme exeacutecution du programme il y a appel de la fonction unex-

pected Comme rien nrsquoest preacutevu pour traiter lrsquoexception standard bad_alloc quel que soit le

comportement preacutevu par lrsquoimpleacutementation nous aboutirons en deacutefinitive agrave un appel de abort

Remarques

1 Lrsquoabsence de speacutecification drsquointerface revient agrave speacutecifier toutes les exceptions possibles

En revanche une speacutecification vide nrsquoautorise aucune exception

void fct throw () aucune exception permise - toute exception non traiteacutee dans la fonction appelle unexpected

2 En cas de redeacutefinition de fonction membre dans une classe deacuteriveacutee la speacutecification

drsquointerface de la fonction redeacutefinie ne peut pas mentionner drsquoautres exceptions que cel-

les preacutevues dans la classe de base en revanche elle peut nrsquoen speacutecifier que certaines

voire aucune

3 Drsquoune maniegravere geacuteneacuterale la speacutecification drsquoexceptions ne doit ecirctre utiliseacutee qursquoavec preacute-

cautions En effet eacutenumeacuterer les exceptions susceptibles drsquoecirctre leveacutees par une fonction

suppose qursquoon connaicirct avec certitude toutes les exceptions susceptibles drsquoecirctre leveacutees

par toutes les fonctions appeleacutees

La gestion des exceptionsCHAPITRE 17

390

6 Les exceptions standard

61 GeacuteneacuteraliteacutesLa bibliothegraveque standard comporte quelques classes fournissant des exceptions speacutecifiques

susceptibles drsquoecirctre deacuteclencheacutees par un programme Certaines peuvent ecirctre deacuteclencheacutees par

des fonctions ou des opeacuterateurs de la bibliothegraveque standard

Toutes ces classes deacuterivent drsquoune classe de base nommeacutee exception et sont organiseacutees suivant

la hieacuterarchie suivante (leur deacuteclaration figure dans le fichier en-tecircte ltstdexceptgt)

exception

logic_error

domain_error

invalid_argument

length_error

out_of_range

runtime_error

range_error

overflow_error

underflow_error

bad_alloc

bad_cast

bad_exception

bad_typeid

62 Les exceptions deacuteclencheacutees par la bibliothegraveque standardSept des exceptions standard sont susceptibles drsquoecirctre deacuteclencheacutees par une fonction ou un

opeacuterateur de la bibliothegraveque standard Voici leur signification

bull bad_alloc eacutechec drsquoallocation meacutemoire par new

bull bad_cast eacutechec de lrsquoopeacuterateur dynamic_cast

bull bad_typeid eacutechec de la fonction typpeid

bull bad_exception erreur de speacutecification drsquoexception cette exception peut ecirctre deacuteclencheacutee

dans certaines impleacutementations par la fonction unexpected

bull out_of_range erreur drsquoindice cette exception est deacuteclencheacutee par les fonctions at membres

des diffeacuterentes classes conteneurs (deacutecrites au chapitre 19 et au chapitre 20) ainsi que par

lrsquoopeacuterateur [] du conteneur bitset

bull invalid_argument deacuteclencheacutee par le constructeur du conteneur bitset

bull overflow_error deacuteclencheacutee par la fonction to_ulong du conteneur bitset

6 - Les exceptions standard391

63 Les exceptions utilisables dans un programmeA priori toutes les classes preacuteceacutedentes sont utilisables pour les exceptions deacuteclencheacutees par

lrsquoutilisateur soit telles quelles soit sous forme de classes deacuteriveacutees Il est cependant preacutefeacutera-

ble drsquoassurer une certaine coheacuterence agrave son programme par exemple il ne serait guegravere rai-

sonnable de deacuteclencher une exception bad_alloc pour signaler une anomalie sans rapport

avec une allocation meacutemoire

Pour utiliser ces classes quelques connaissances sont neacutecessaires

bull la classe de base exception dispose drsquoune fonction membre what censeacutee fournir comme va-

leur de retour un pointeur sur une chaicircne expliquant la nature de lrsquoexception Cette fonction

virtuelle dans exception doit ecirctre redeacutefinie dans les classes deacuteriveacutees et elle lrsquoest dans toutes

les classes citeacutees ci-dessus (la chaicircne obtenue deacutepend cependant de lrsquoimpleacutementation)

bull toutes ces classes disposent drsquoun constructeur recevant un argument de type chaicircne dont la

valeur pourra ensuite ecirctre reacutecupeacutereacutee par what

Voici un exemple de programme utilisant ces proprieacuteteacutes pour deacuteclencher deux exception de

type range_error avec deux messages explicatifs diffeacuterents

include ltiostreamgt

include ltstdexceptgt

include ltcstdlibgt

using namespace std

main()

try

throw range_error (anomalie 1) afficherait exception anomalie 1

throw range_error (anomalie 2) afficherait exception anomalie 2

catch (range_error amp re)

cout ltlt exception ltlt rewhat() ltlt n

exit (-1)

64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exceptionJusqursquoici nous avions deacutefini nos propres classes exception de faccedilon indeacutependante de la

classe standard exception On voit maintenant qursquoil peut srsquoaveacuterer inteacuteressant de creacuteer ses pro-

pres classes deacuteriveacutees de exception pour au moins deux raisons

1 On facilite le traitement ulteacuterieur des exceptions A la limite on est sucircr drsquointercepter toutes

les exceptions avec le simple gestionnaire

catch (exception amp e)

Ce ne serait pas le cas pour des exceptions non rattacheacutees agrave la classe exception

La gestion des exceptionsCHAPITRE 17

392

2 On peut srsquoappuyer sur la fonction what deacutecrite ci-dessus agrave condition de la redeacutefinir de fa-

ccedilon approprieacutee dans ses propres classes Il est alors facile drsquoafficher un message explicatif

concernant lrsquoexception deacutetecteacutee agrave lrsquoaide du simple gestionnaire suivant

catch (exception amp e) attention agrave la reacutefeacuterence pour beacuteneacuteficier de la

ligature dynamique de la fonction virtuelle what

cout ltlt exception intercepteacutee ltlt ewhat ltlt n

641 Exemple 1

Voici un premier exemple dans lequel nous creacuteons deux classes exception_1 et exception_2

deacuteriveacutees de la classe exception et dans lesquelles nous redeacutefinissons la fonction membre

what

include ltiostreamgtinclude ltstdexceptgt

using namespace std class mon_exception_1 public exception

public

mon_exception_1 () const char what() const return mon exception nummero 1

class mon_exception_2 public exception

public

mon_exception_2 () const char what() const return mon exception nummero 2

main()

try

cout ltlt bloc try 1n throw mon_exception_1()

catch (exception amp e) cout ltlt exception ltlt ewhat() ltlt n

try

cout ltlt bloc try 2n

throw mon_exception_2()

catch (exception amp e) cout ltlt exception ltlt ewhat() ltlt n

bloc try 1

exception mon exception nummero 1

bloc try 2exception mon exception nummero 2

Utilisation de classes exception deacuteriveacutees de exception (1)

Notez qursquoil est important de deacutefinir what sous la forme drsquoune fonction membre constante

sous peine de ne pas la voir appeleacutee

642 Exemple 2

Dans ce deuxiegraveme exemple nous creacuteons une seule classe mon_exception deacuteriveacutee de la classe

exception Mais nous preacutevoyons que son constructeur conserve la valeur reccedilue (chaicircne) en

argument et nous redeacutefinissons what de faccedilon qursquoelle fournisse cette valeur Il reste ainsi pos-

sible de distinguer entre plusieurs sortes drsquoexceptions (ici 2)

include ltiostreamgt

include ltstdexceptgt

using namespace std

class mon_exception public exception

public

mon_exception (char texte) ad_texte = texte

const char what() const return ad_texte

private

char ad_texte

main()

try

cout ltlt bloc try 1n

throw mon_exception (premier type)

catch (exception amp e)

cout ltlt exception ltlt ewhat() ltlt n

try

cout ltlt bloc try 2n

throw mon_exception (deuxieme type)

catch (exception amp e)

cout ltlt exception ltlt ewhat() ltlt n

bloc try 1

exception premier type

bloc try 2

exception deuxieme type

Utilisation drsquoune classe exception deacuteriveacutee de exception (2)

6 - Les exceptions standard393

18

Geacuteneacuteraliteacutes surla bibliothegraveque standard

Comme celle du C la norme du C++ comprend la deacutefinition dune bibliothegraveque standard

Bien entendu on y trouve toutes les fonctions preacutevues dans les versions C++ davant la

norme quil sagisse des flots deacutecrits preacuteceacutedemment ou des fonctions de la bibliothegraveque stan-

dard du C Mais on y deacutecouvre surtout bon nombre de nouveauteacutes originales La plupart

dentre elles sont constitueacutees de patrons de classes et de fonctions provenant en majoriteacute

dune bibliothegraveque du domaine public nommeacutee Standard Template Library (en abreacutegeacute STL)

et deacuteveloppeacutee chez Hewlett Packard

Lobjectif de ce chapitre est de vous familiariser avec les notions de base concernant lutilisa-

tion des principaux composants de cette bibliothegraveque agrave savoir les conteneurs les iteacuterateurs

les algorithmes les geacuteneacuterateurs dopeacuterateurs les preacutedicats et lutilisation dune relation

dordre

1 Notions de conteneur diteacuterateur et dalgorithme

Ces trois notions sont eacutetroitement lieacutees et la plupart du temps elles interviennent simultaneacute-

ment dans un programme utilisant des conteneurs

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

396

11 Notion de conteneur La bibliothegraveque standard fournit un ensemble de classes dites conteneurs permettant de

repreacutesenter les structures de donneacutees les plus reacutepandues telles que les vecteurs les listes les

ensembles ou les tableaux associatifs Il sagit de patrons de classes parameacutetreacutes tout naturelle-

ment par le type de leurs eacuteleacutements Par exemple on pourra construire une liste dentiers un

vecteur de flottants ou une liste de points (point eacutetant une classe) par les

deacuteclarations suivantes

list ltintgt li liste vide drsquoeacuteleacutements de type int

vector ltdoublegt ld vecteur vide drsquoeacuteleacutements de type double

list ltpointgt lp liste vide drsquoeacuteleacutements de type point

Chacune de ces classes conteneur dispose de fonctionnaliteacutes approprieacutees dont on pourrait

penser a priori quelles sont tregraves diffeacuterentes dun conteneur agrave lautre En reacutealiteacute les concep-

teurs de STL ont fait un gros effort dhomogeacuteneacuteisation et beaucoup de fonctions membres

sont communes agrave diffeacuterents conteneurs On peut dire que degraves quune action donneacutee est reacuteali-

sable avec deux conteneurs diffeacuterents elle se programme de la mecircme maniegravere

Remarque

En toute rigueur les patrons de conteneurs sont parameacutetreacutes agrave la fois par le type de leurs

eacuteleacutements et par une fonction dite allocateur utiliseacutee pour les allocations et les libeacuterations

de meacutemoire Ce second paramegravetre possegravede une valeur par deacutefaut qui est geacuteneacuteralement

satisfaisante Cependant certaines impleacutementations nacceptent pas encore les paramegravetres

par deacutefaut dans les patrons de classes et dans ce cas il est neacutecessaire de preacuteciser lalloca-

teur agrave utiliser mecircme sil sagit de celui par deacutefaut Il faut alors savoir que ce dernier est

une fonction patron de nom allocator parameacutetreacutee par le type des eacuteleacutements concerneacutes

Voici ce que deviendraient les deacuteclarations preacuteceacutedentes dans un tel cas

list ltint allocatorltintgt gt li ne pas oublier lrsquoespace

vector ltdouble allocatorltdoublegt gt ld entre intgt et gt sinon gtgt

list ltpoint allocatorltpointgt gt lp repreacutesentera lopeacuterateur gtgt

12 Notion diteacuterateur Cest dans ce souci dhomogeacuteneacuteisation des actions sur un conteneur qua eacuteteacute introduite la

notion diteacuterateur Un iteacuterateur est un objet deacutefini geacuteneacuteralement par la classe conteneur con-

cerneacutee qui geacuteneacuteralise la notion de pointeur

bull agrave un instant donneacute un iteacuterateur possegravede une valeur qui deacutesigne un eacuteleacutement donneacute dun

conteneur on dira souvent quun iteacuterateur pointe sur un eacuteleacutement dun conteneur

bull un iteacuterateur peut ecirctre increacutementeacute par lopeacuterateur ++ de maniegravere agrave pointer sur leacuteleacutement sui-

vant du mecircme conteneur on notera que ceci nest possible que comme on le verra plus loin

parce que les conteneurs sont toujours ordonneacutes suivant une certaine seacutequence

1 - Notions de conteneur diteacuterateur et dalgorithme397

bull un iteacuterateur peut ecirctre deacutereacutefeacuterenceacute comme un pointeur en utilisant lopeacuterateur par exem-

ple si it est un iteacuterateur sur une liste de points it deacutesigne un point de cette liste

bull deux iteacuterateurs sur un mecircme conteneur peuvent ecirctre compareacutes par eacutegaliteacute ou ineacutegaliteacute

Tous les conteneurs fournissent un iteacuterateur portant le nom iterator et posseacutedant au minimum

les proprieacuteteacutes que nous venons deacutenumeacuterer qui correspondent agrave ce quon nomme un iteacuterateur

unidirectionnel Certains iteacuterateurs pourront posseacuteder des proprieacuteteacutes suppleacutementaires en

particulier

bull deacutecreacutementation par lopeacuterateur -- comme cette possibiliteacute sajoute alors agrave celle qui est of-

ferte par ++ liteacuterateur est alors dit bidirectionnel

bull accegraves direct dans ce cas si it est un tel iteacuterateur lexpression it+i a un sens souvent lopeacute-

rateur [] est alors deacutefini de maniegravere que it[i] soit eacutequivalent agrave (it+i) en outre un tel iteacute-

rateur peut ecirctre compareacute par ineacutegaliteacute

Remarque

Ici nous avons eacutevoqueacute trois cateacutegories diteacuterateur unidirectionnel bidirectionnel et

accegraves direct Au chapitre 21 nous verrons quil existe deux autres cateacutegories (entreacutee et

sortie) qui sont dun usage plus limiteacute De mecircme on verra quil existe ce quon appelle des

adaptateurs diteacuterateur lesquels permettent den modifier les proprieacuteteacutes les plus impor-

tants seront liteacuterateur de flux et liteacuterateur dinsertion

13 Parcours dun conteneur avec un iteacuterateur

131 Parcours directTous les conteneurs fournissent des valeurs particuliegraveres de type iterator sous forme des

fonctions membres begin() et end() de sorte que quel que soit le conteneur le canevas sui-

vant preacutesenteacute ici sur une liste de points est toujours utilisable pour parcourir seacutequentielle-

ment un conteneur de son deacutebut jusquagrave sa fin

listltpointgt lp listltpointgtiterator il iteacuterateur sur une liste de points for (il = lpbegin() il = lpend() il++) ici il deacutesigne leacuteleacutement courant de la liste de points lp

On notera la particulariteacute des valeurs des iteacuterateurs de fin qui consiste agrave pointer non pas sur

le dernier eacuteleacutement dun conteneur mais juste apregraves Dailleurs lorsquun conteneur est vide

begin() possegravede la mecircme valeur que end() de sorte que le canevas preacuteceacutedent fonctionne tou-

jours convenablement

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

398

Remarque

Attention on ne peut pas utiliser comme condition darrecirct de la boucle for une expression

telle que il lt lpend car lopeacuterateur lt ne peut sappliquer quagrave des iteacuterateurs agrave accegraves direct

132 Parcours inverseToutes les classes conteneur pour lesquelles iterator est au moins bidirectionnel (on peut

donc lui appliquer ++ et --) disposent dun second iteacuterateur noteacute reverse_iterator Construit agrave

partir du premier il permet dexplorer le conteneur suivant lordre inverse Dans ce cas la

signification de ++ et -- appliqueacutes agrave cet iteacuterateur est alors adapteacutee en conseacutequence en outre

il existe eacutegalement des valeurs particuliegraveres de type reverse_iterator fournies par les fonc-

tions membres rbegin() et rend() on peut dire que rbegin() pointe sur le dernier eacuteleacutement du

conteneur tandis que rend() pointe juste avant le premier Voici comment parcourir une liste

de points dans lordre inverse

listltpointgt lp listltpointgtreverse_iterator ril iteacuterateur inverse sur une liste de points for (ril = lprbegin() ril = lprend() ril++) ici ril deacutesigne leacuteleacutement courant de la liste de points lp

14 Intervalle diteacuterateur Comme nous lavons deacutejagrave fait remarquer tous les conteneurs sont ordonneacutes de sorte quon

peut toujours les parcourir dun deacutebut jusquagrave une fin Plus geacuteneacuteralement on peut deacutefinir ce

quon nomme un intervalle drsquoiteacuterateur en preacutecisant les bornes sous forme de deux valeurs

diteacuterateur Supposons que lon ait deacuteclareacute

vectorltpointgtiterator ip1 ip2 ip1 et ip2 sont des iteacuterateurs sur un vecteur de points

Supposons de plus que ip1 et ip2 possegravedent des valeurs telles que ip2 soit accessible

depuis ip1 autrement dit que apregraves un certain nombre dincreacutementations de ip1 par ++ on

obtienne la valeur de ip2 Dans ces conditions le couple de valeurs ip1 ip2 deacutefinit un inter-

valle dun conteneur du type vectorltpointgt seacutetendant de leacuteleacutement pointeacute par ip1 jusquagrave

(mais non compris) celui pointeacute par ip2 Cet intervalle se note souvent [ip1 ip2) On dit eacutega-

lement que les eacuteleacutements deacutesigneacutes par cet intervalle forment une seacutequence

Cette notion dintervalle diteacuterateur sera tregraves utiliseacutee par les algorithmes et par certaines fonc-

tions membres

1 - Notions de conteneur diteacuterateur et dalgorithme399

15 Notion dalgorithme La notion dalgorithme est tout aussi originale que les deux preacuteceacutedentes Elle se fonde sur le

fait que par le biais dun iteacuterateur beaucoup dopeacuterations peuvent ecirctre appliqueacutees agrave un conte-

neur quels que soient sa nature et le type de ses eacuteleacutements Par exemple on pourra trouver le

premier eacuteleacutement ayant une valeur donneacutee aussi bien dans une liste un vecteur ou ensemble

il faudra cependant que leacutegaliteacute de deux eacuteleacutements soit convenablement deacutefinie soit par

deacutefaut soit par surdeacutefinition de lopeacuterateur == De mecircme on pourra trier un conteneur

dobjets de type T pour peu que ce conteneur dispose dun iteacuterateur agrave accegraves direct et que lon

ait deacutefini une relation dordre sur le type T par exemple en surdeacutefinissant lopeacuterateur lt

Les diffeacuterents algorithmes sont fournis sous forme de patrons de fonctions parameacutetreacutes par le

type des iteacuterateurs qui leurs sont fournis en argument Lagrave encore cela conduit agrave des program-

mes tregraves homogegravenes puisque les mecircmes fonctions pourront ecirctre appliqueacutees agrave des conteneurs

diffeacuterents Par exemple pour compter le nombre deacuteleacutements eacutegaux agrave un dans un vecteur

deacuteclareacute par

vectorltintgt v vecteur dentiers

on pourra proceacuteder ainsi

n = count (vbegin() vend() 1) compte le nombre deacuteleacutements valant 1

dans la seacutequence [vbegin() vend())

autrement dit dans tout le conteneur v

Pour compter le nombre deacuteleacutements eacutegaux agrave un dans une liste deacuteclareacutee

listltintgt l liste dentiers

on proceacutedera de faccedilon similaire (en se contentant de remplacer v par l)

n = count (lbegin() lend() 1) compte le nombre deacuteleacutements valant 1

dans la seacutequence [lbegin() lend())

autrement dit dans tout le conteneur l

Dune maniegravere geacuteneacuterale comme le laissent entendre ces deux exemples les algorithmes

sappliquent non pas agrave un conteneur mais agrave une seacutequence deacutefinie par un intervalle

diteacuterateur ici cette seacutequence correspondait agrave linteacutegraliteacute du conteneur

Certains algorithmes permettront facilement de recopier des informations dun conteneur

dun type donneacute vers un conteneur dun autre type pour peu que ses eacuteleacutements soient du mecircme

type que ceux du premier conteneur Voici par exemple comment recopier un vecteur

dentiers dans une liste dentiers

vectorltintgt v vecteur dentiers

listltintgt l liste dentiers

copy (vbegin() vend() lbegin() )

recopie lintervalle [vbegin() vend())

agrave partir de lemplacement pointeacute par lbegin()

Notez que si lon fournit lintervalle de deacutepart on ne mentionne que le deacutebut de celui darri-

veacutee

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

400

Remarque

On pourra parfois ecirctre gecircneacute par le fait que lhomogeacuteneacuteisation eacutevoqueacutee nest pas absolue

Ainsi on verra quil existe un algorithme de recherche dune valeur donneacutee nommeacute find

alors mecircme quun conteneur comme list dispose dune fonction membre comparable La

justification reacutesidera dans des consideacuterations defficaciteacute

16 Iteacuterateurs et pointeurs La maniegravere dont les algorithmes ou les fonctions membres utilisent un iteacuterateur fait que tout

objet ou toute variable posseacutedant les proprieacuteteacutes attendues (deacutereacutefeacuterenciation increacutementa-

tion) peut ecirctre utiliseacute agrave la place dun objet tel que iterator

Or les pointeurs usuels possegravedent tout naturellement les proprieacuteteacutes dun iteacuterateur agrave accegraves

direct Cela leur permet decirctre employeacutes dans bon nombre dalgorithmes Cette possibiliteacute est

freacutequemment utiliseacutee pour la recopie des eacuteleacutements dun tableau ordinaire dans un conteneur

int t[6] = 2 9 1 8 2 11 listltintgt l copy (t t+6 lbegin()) copie de lintervalle [t t+6) dans la liste l

Bien entendu ici il nest pas question dutiliser une notation telle que tbegin() qui naurait

aucun sens t neacutetant pas un objet

Remarque

Par souci de simpliciteacute nous parlerons encore de seacutequence deacuteleacutements (mais plus de

seacutequence de conteneur) pour deacutesigner les eacuteleacutements ainsi deacutefinis par un intervalle de poin-

teurs

2 Les diffeacuterentes sortes de conteneurs

21 Conteneurs et structures de donneacutees classiques On dit souvent que les conteneurs correspondent agrave des structures de donneacutees usuelles Mais agrave

partir du moment ougrave ces conteneurs sont des classes qui encapsulent convenablement leurs

donneacutees leurs caracteacuteristiques doivent ecirctre indeacutependantes de leur impleacutementation Dans ces

conditions les diffeacuterents conteneurs devraient se distinguer les uns des autres uniquement

par leurs fonctionnaliteacutes et en aucun cas par les structures de donneacutees sous-jacentes Beau-

coup de conteneurs posseacutederaient alors des fonctionnaliteacutes voisines voire identiques

En reacutealiteacute les diffeacuterents conteneurs se caracteacuterisent outre leurs fonctionnaliteacutes par leffica-

citeacute de certaines opeacuterations Par exemple on verra quun vecteur permet des insertions deacuteleacute-

3 - Les conteneurs dont les eacuteleacutements sont des objets401

ments en nimporte quel point mais celles-ci sont moins efficaces quavec une liste En

revanche on peut acceacuteder plus rapidement agrave un eacuteleacutement existant dans le cas dun vecteur que

dans celui dune liste Ainsi bien que la norme nimpose pas limpleacutementation des conte-

neurs elle introduit des contraintes defficaciteacute qui la conditionneront largement

En deacutefinitive on peut dire que le nom choisi pour un conteneur eacutevoque la structure de donneacutee

classique qui en est proche sur le plan des fonctionnaliteacutes sans pour autant coiumlncider avec

elle Dans ces conditions un bon usage des diffeacuterents conteneurs passe par un apprentissage

de leurs possibiliteacutes comme sil sagissait bel et bien de classes diffeacuterentes

22 Les diffeacuterentes cateacutegories de conteneurs La norme classe les diffeacuterents conteneurs en deux cateacutegories

bull les conteneurs en seacutequence (ou conteneurs seacutequentiels)

bull les conteneurs associatifs

La notion de conteneur en seacutequence correspond agrave des eacuteleacutements qui sont ordonneacutes comme

ceux dun vecteur ou dune liste On peut parcourir le conteneur suivant cet ordre Quand on

insegravere ou quon supprime un eacuteleacutement on le fait en un endroit quon a explicitement choisi

La notion de conteneur associatif peut ecirctre illustreacutee par un reacutepertoire teacuteleacutephonique Dans ce

cas on associe une valeur (numeacutero de teacuteleacutephone adresse) agrave ce quon nomme une cleacute (ici le

nom) A partir de la cleacute on accegravede agrave la valeur associeacutee Pour inseacuterer un nouvel eacuteleacutement dans

ce conteneur il ne sera theacuteoriquement plus utile de preacuteciser un emplacement

Il semble donc quun conteneur associatif ne soit plus ordonneacute En fait pour deacutevidentes

questions defficaciteacute un tel conteneur devra ecirctre ordonneacute mais cette fois de faccedilon intrinsegrave-

que crsquoest-agrave-dire suivant un ordre qui nest plus deacutefini par le programme La principale conseacute-

quence est quil restera toujours possible de parcourir seacutequentiellement les eacuteleacutements dun tel

conteneur qui disposera toujours au moins dun iteacuterateur nommeacute iterator et des valeurs

begin() et end() Cet aspect peut dailleurs precircter agrave confusion dans la mesure ougrave certaines

opeacuterations preacutevues pour des conteneurs seacutequentiels pourront sappliquer agrave des conteneurs

associatifs tandis que dautres poseront problegraveme Par exemple il ny aura aucun risque agrave

examiner seacutequentiellement chacun des eacuteleacutements dun conteneur associatif il y en aura mani-

festement en revanche si lon cherche agrave modifier seacutequentiellement les valeurs deacuteleacutements

existants puisqualors on risque de perturber lordre intrinsegraveque du conteneur Nous y

reviendrons le moment venu

3 Les conteneurs dont les eacuteleacutements sont des objets

Le patron de classe deacutefinissant un conteneur peut ecirctre appliqueacute agrave nimporte quel type et donc

en particulier agrave des eacuteleacutements de type classe Dans ce cas il ne faut pas perdre de vue que bon

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

402

nombre de manipulations de ces eacuteleacutements vont entraicircner des appels automatiques de certai-

nes fonctions membres

31 Construction copie et affectationToute construction drsquoun conteneur non vide dont les eacuteleacutements sont des objets entraicircne

pour chacun de ces eacuteleacutements

bull soit lrsquoappel drsquoun constructeur il peut srsquoagir drsquoun constructeur par deacutefaut lorsqursquoaucun ar-

gument nrsquoest neacutecessaire

bull soit lrsquoappel drsquoun constructeur par recopie

Par exemple on verra que la deacuteclaration suivante (point eacutetant une classe) construit un vecteur

de trois eacuteleacutements de type point

vectorltpointgt v(3) construction drsquoun vecteur de 3 points

Pour chacun des trois eacuteleacutements il y aura appel drsquoun constructeur sans argument de point Si

lrsquoon construit un autre vecteur agrave partir de v

vectorltpointgt w (v) ou vector v = w

il y aura appel du constructeur par recopie de la classe vectorltpointgt lequel appellera le

constructeur par recopie de la classe point pour chacun des trois eacuteleacutements de type point agrave

recopier

On pourrait srsquoattendre agrave des choses comparables avec lrsquoopeacuterateur drsquoaffectation dans un cas

tel que

w = v le vecteur v est affecteacute agrave w

Cependant ici les choses sont un peu moins simples En effet geacuteneacuteralement si la taille de w

est suffisante on se contentera effectivement drsquoappeler lrsquoopeacuterateur drsquoaffectation pour tous les

eacuteleacutements de v (on appellera le destructeur pour les eacuteleacutements exceacutedentaires de w) En revan-

che si la taille de w est insuffisante il y aura destruction de tous ses eacuteleacutements et creacuteation drsquoun

nouveau vecteur par appel du constructeur par recopie lequel appellera tout naturellement le

constructeur par recopie de la classe point pour tous les eacuteleacutements de v

Par ailleurs il ne faudra pas perdre de vue que par deacutefaut la transmission drsquoun conteneur en

argument drsquoune fonction se fait par valeur ce qui entraicircne la recopie de tous ses eacuteleacutements

Les trois circonstances que nous venons drsquoeacutevoquer concernent des opeacuterations portant sur

lrsquoensemble drsquoun conteneur Mais il va de soi qursquoil existe eacutegalement drsquoautres opeacuterations por-

tant sur un eacuteleacutement drsquoun conteneur et qui elles aussi feront appel au constructeur de

recopie (insertion) ou agrave lrsquoaffectation

Drsquoune maniegravere geacuteneacuterale si les objets concerneacutes ne possegravedent pas de partie dynamique les

fonctions membres preacutevues par deacutefaut seront satisfaisantes Dans le cas contraire il faudra

preacutevoir les fonctions approprieacutees ce qui sera bien sucircr le cas si la classe concerneacutee respecte le

4 - Efficaciteacute des opeacuterations sur des conteneurs403

scheacutema de classe canonique proposeacute au paragraphe 4 du chapitre 9 (et compleacuteteacute au paragra-

phe 8 du chapitre 13) Notez bien que

Remarque

Dans les descriptions des diffeacuterents conteneurs ou algorithmes nous ne rappellerons pas

ces diffeacuterents points dans la mesure ougrave ils concernent systeacutematiquement tous les objets

32 Autres opeacuterations Il existe dautres opeacuterations que les constructions ou recopies de conteneur qui peuvent

entraicircner des appels automatiques de certaines fonctions membres

Lun des exemples les plus eacutevidents est celui de la recherche dun eacuteleacutement de valeur donneacutee

comme le fait la fonction membre find du conteneur list Dans ce cas la classe concerneacutee

devra manifestement disposer de lopeacuterateur == lequel cette fois ne possegravede plus de version

par deacutefaut

Un autre exemple reacuteside dans les possibiliteacutes dites de comparaisons lexicographiques que

nous examinerons au chapitre 19 nous verrons que celles-ci se fondent sur la comparaison

par lun des opeacuterateurs lt gt lt= ou gt= des diffeacuterents eacuteleacutements du conteneur Manifestement

lagrave encore il faudra deacutefinir au moins lopeacuterateur lt pour la classe concerneacutee les possibiliteacutes de

geacuteneacuteration automatique preacutesenteacutees ci-dessus pourront eacuteviter les deacutefinitions des trois autres

Dune maniegravere geacuteneacuterale cette fois compte tenu de laspect eacutepisodique de ce type de besoin

nous le preacuteciserons chaque fois que ce sera neacutecessaire

4 Efficaciteacute des opeacuterations sur des conteneurs Pour juger de lefficaciteacute dune fonction membre dun conteneur ou dun algorithme appliqueacute

agrave un conteneur on choisit geacuteneacuteralement la notation dite de Landau (O()) qui se deacutefinit

ainsi

Le temps t dune opeacuteration est dit O(x) sil existe une constante k telle que dans tous les cas

on ait t lt= kx

Comme on peut sy attendre le nombre N deacuteleacutements dun conteneur (ou dune seacutequence de

conteneur) pourra intervenir Cest ainsi quon rencontrera typiquement

Degraves qursquoune classe est destineacutee agrave donner naissance agrave des objets susceptibles drsquoecirctre introduits dans des conteneurs il nrsquoest plus possible drsquoen deacutesactiver la recopie etou lrsquoaffectation

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

404

bull des opeacuterations en O(1) crsquoest-agrave-dire pour lesquelles le temps est constant (plutocirct borneacute par

une constante indeacutependante du nombre deacuteleacutements de la seacutequence) on verra que ce sera le

cas des insertions dans une liste ou des insertions en fin de vecteur

bull des opeacuterations en O(N) crsquoest-agrave-dire pour lesquelles le temps est proportionnel au nombre

deacuteleacutements de la seacutequence on verra que ce sera le cas des insertions en un point quelconque

dun vecteur

bull des opeacuterations en O(LogN)

Dune maniegravere geacuteneacuterale on ne perdra pas de vue quune telle information na quun caractegravere

relativement indicatif pour ecirctre preacutecis il faudrait indiquer sil sagit dun maximum ou dune

moyenne et mentionner la nature des opeacuterations concerneacutees Cest dailleurs ce que nous

ferons dans lannexe C deacutecrivant lensemble des algorithmes standard

5 Fonctions preacutedicats et classes fonctions

51 Fonction unaireBeaucoup dalgorithmes et quelques fonctions membres permettent dappliquer une fonction

donneacutee aux diffeacuterents eacuteleacutements dune seacutequence (deacutefinie par un intervalle diteacuterateur) Cette

fonction est alors passeacutee simplement en argument de lalgorithme comme dans

for_each(it1 it2 f) applique la fonction f agrave chacun des eacuteleacutements de la seacutequence [it1 it2)

Bien entendu la fonction f doit posseacuteder un argument du type des eacuteleacutements correspondants

(dans le cas contraire on obtiendrait une erreur de compilation) Il nest pas interdit quune

telle fonction possegravede une valeur de retour mais quoi quil en soit elle ne sera pas utiliseacutee

Voici un exemple montrant comment utiliser cette technique pour afficher tous les eacuteleacutements

dune liste

main() listltfloatgt lf void affiche (float) for_each (lfbegin() lfend() affiche) cout ltlt n void affiche (float x) cout ltlt x ltlt

Bien entendu on obtiendrait le mecircme reacutesultat en proceacutedant simplement ainsi

main() listltfloatgt lf void affiche (listltfloatgt) lfaffiche()

5 - Fonctions preacutedicats et classes fonctions405

void affiche (listltfloatgt l) listltfloatgtiterator il

for (il=lbegin() il=lend() il++) cout ltlt (il) ltlt cout ltlt n

52 Preacutedicats On parle de preacutedicat pour caracteacuteriser une fonction qui renvoie une valeur de type bool

Compte tenu des conversions implicites qui sont mises en place automatiquement cette

valeur peut eacuteventuellement ecirctre entiegravere sachant qualors 0 correspondra agrave false et que tout

autre valeur correspondra agrave true

On rencontrera des preacutedicats unaires crsquoest-agrave-dire disposant dun seul argument et des preacutedi-

cats binaires crsquoest-agrave-dire disposant de deux arguments de mecircme type

Lagrave encore certains algorithmes et certaines fonctions membres neacutecessiteront quon leur four-

nisse un preacutedicat en argument Par exemple lalgorithme find_if permet de trouver le premier

eacuteleacutement dune seacutequence veacuterifiant un preacutedicat passeacute en argument

main()

listltintgt l listltintgtiterator il

bool impair (int) il = find_if (lbegin() lend() impair) il deacutesigne le premier

eacuteleacutement de l veacuterifiant le preacutedicat impair

bool impair (int n) deacutefinition du preacutedicat unaire impair return n2

53 Classes et objets fonctions

531 Utilisation dobjet fonction comme fonction de rappel

Nous venons de voir que certains algorithmes ou fonctions membres neacutecessitaient un preacutedi-

cat en argument Dune maniegravere geacuteneacuterale ils peuvent neacutecessiter une fonction quelconque et

lon parle souvent de fonction de rappel pour eacutevoquer un tel meacutecanisme dans lequel une

fonction est ameneacutee agrave appeler une autre fonction quon lui a transmise en argument

La plupart du temps cette fonction de rappel est preacutevue dans la deacutefinition du patron corres-

pondant non pas sous forme dune fonction mais bel et bien sous forme dun objet de type

quelconque Les classes et les objets fonction ont eacuteteacute preacutesenteacutes au paragraphe 6 du chapitre 9

et nous en avions alors donneacute un exemple simple dutilisation En voici un autre qui montre

linteacuterecirct quils preacutesentent dans le cas de patrons de fonctions Ici le patron de fonction essai

deacutefinit une famille de fonctions recevant en argument une fonction de rappel sous forme dun

objet fonction f de type quelconque Les exemples dappels de la fonction essai montrent

quon peut lui fournir indiffeacuteremment comme fonction de rappel soit une fonction usuelle

soit un objet fonction

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

406

include ltiostreamgt

using namespace std

class cl_fonc definition dune classe fonction

int coef

public

cl_fonc(int n) coef = n

int operator () (int p) return coefp

int fct (int n) definition dune fonction usuelle

return 5n

template ltclass Tgtvoid essai (T f) deacutefinition de essai qui reccediloit en

cout ltlt f(1) ltlt f(1) ltlt n argument un objet de type quelconque

cout ltlt f(4) ltlt f(4) ltlt n et qui lutilise comme une fonction

main()

essai (fct) appel essai avec une fonction de rappel usuelle

essai (cl_fonc(3)) appel essai avec 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

Exemple dutilisation dobjets fonctions

On voit quun algorithme attendant un objet fonction peut recevoir une fonction usuelle En

revanche on notera que la reacuteciproque est fausse Cest pourquoi tous les algorithmes ont

preacutevu leurs fonctions de rappel sous forme dobjets fonction

532 Classes fonction preacutedeacutefinies

Dans ltfunctionalgt il existe un certain nombre de patrons de classes fonction correspondant

agrave des preacutedicats binaires de comparaison de deux eacuteleacutements de mecircme type Par exemple

lessltintgt instancie une fonction patron correspondant agrave la comparaison par lt (less) de deux

eacuteleacutements de type int Comme on peut sy attendre lessltpointgt instanciera une fonction

patron correspondant agrave la comparaison de deux objets de type point par lopeacuterateur lt qui

devra alors ecirctre convenablement deacutefini dans la classe point

Voici les diffeacuterents noms de patrons existants et les opeacuterateurs correspondants equal_to

(==) not_equal_to (=) greater (gt) less (lt) greater_equal (gt=) less_equal (lt=)

6 - Conteneurs algorithmes et relation dordre407

Toutes ces classes fonction disposent dun constructeur sans argument ce qui leur permet

decirctre citeacutees comme fonction de rappel Dautre part elles seront eacutegalement utiliseacutees comme

argument de type dans la construction de certaines classes

Remarque

Il existe eacutegalement des classes fonction correspondant aux opeacuterations binaires usuelles

par exemple plusltintgt pour la somme de deux int Voici les diffeacuterents noms des autres

patrons existants et les opeacuterateurs correspondants modulus () minus (-) times ()

divides () On trouve eacutegalement les preacutedicats correspondant aux opeacuterations logiques

logical_and (ampamp) logical_or (||) logical_not () Ces classes sont cependant dun usage

moins freacutequent que celles qui ont eacuteteacute eacutetudieacutees preacuteceacutedemment

6 Conteneurs algorithmes et relation dordre

61 Introduction Un certain nombre de situations neacutecessiteront la connaissance dune relation permettant

dordonner les diffeacuterents eacuteleacutements dun conteneur Citons-en quelques exemples

bull pour des questions defficaciteacute comme il a deacutejagrave eacuteteacute dit les eacuteleacutements dun conteneur associa-

tif seront ordonneacutes en permanence

bull un conteneur list disposera dune fonction membre sort permettant de reacutearranger ses eacuteleacute-

ments suivant un certain ordre

bull il existe beaucoup dalgorithmes de tri qui eux aussi reacuteorganisent les eacuteleacutements dun conte-

neur suivant un certain ordre

Bien entendu tant que les eacuteleacutements du conteneur concerneacute sont dun type scalaire ou string

pour lequel il existe une relation naturelle (lt) permettant dordonner les eacuteleacutements on peut se

permettre dappliquer ces diffeacuterentes opeacuterations dordonnancement sans trop se poser de

questions

En revanche si les eacuteleacutements concerneacutes sont dun type classe qui ne dispose pas par deacutefaut de

lopeacuterateur lt il faudra surdeacutefinir convenablement cet opeacuterateur Dans ce cas et comme on

peut sy attendre cet opeacuterateur devra respecter un certain nombre de proprieacuteteacutes neacutecessaires

au bon fonctionnement de la fonction ou de lalgorithme utiliseacute

Par ailleurs et quel que soit le type des eacuteleacutements (classe type de base) on peut choisir

dutiliser une relation autre que celle qui correspond agrave lopeacuterateur lt (par deacutefaut ou surdeacutefini)

bull soit en choisissant un autre opeacuterateur (par deacutefaut ou surdeacutefini)

bull soit en fournissant explicitement une fonction de comparaison de deux eacuteleacutements

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

408

Lagrave encore cet opeacuterateur ou cette fonction devra respecter les proprieacuteteacutes eacutevoqueacutees que nous

allons examiner maintenant

62 Proprieacuteteacutes agrave respecter Pour simplifier les notations nous noterons toujours R la relation binaire en question quelle

soit deacutefinie par un opeacuterateur ou par une fonction La norme preacutecise que R doit ecirctre une rela-

tion drsquoordre faible strict laquelle se deacutefinit ainsi

bull forall a (a R a)

bull R est transitive crsquoest-agrave-dire que forall a b c tels que a R b et b R c alors a R c

bull forall a b c tels que (a R b) et (b R c) alors (a R c)

On notera que leacutegaliteacute na pas besoin decirctre deacutefinie pour que R respecte les proprieacuteteacutes requi-

ses

Bien entendu on peut sans problegraveme utiliser les opeacuterateurs lt et gt pour les types numeacuteriques

on prendra garde cependant agrave ne pas utiliser lt= ou gt= qui ne reacutepondent pas agrave la deacutefinition

On peut montrer que ces contraintes deacutefinissent une relation dordre total non pas sur

lensemble des eacuteleacutements concerneacutes mais simplement sur les classes deacutequivalence induites

par la relation R une classe deacutequivalence eacutetant telle que a et b appartiennent agrave la mecircme

classe si lon a agrave la fois (a R b) et (b R a) A titre dexemple consideacuterons des eacuteleacutements dun

type classe (point) posseacutedant deux coordonneacutees x et y supposons quon y deacutefinisse la rela-

tion R par

p1(x1 y1) R p2(x2 y2) si x1 lt x2

On peut montrer que R satisfait les contraintes requises et que les classes deacutequivalence sont

formeacutees des points ayant la mecircme abscisse

Dans ces conditions si lon utilise R pour trier un conteneur de points ceux-ci apparaicirctront

ordonneacutes suivant la premiegravere coordonneacutee Cela nest pas tregraves grave car dans une telle opeacutera-

tion de tri tous les points seront conserveacutes En revanche si lon utilise cette mecircme relation R

pour ordonner intrinsegravequement un conteneur associatif de type map (dont on verra que deux

eacuteleacutements ne peuvent avoir de cleacutes eacutequivalentes) deux points de mecircme abscisse apparaicirctront

comme identiques et un seul sera conserveacute dans le conteneur

Ainsi lorsquon sera ameneacute agrave deacutefinir sa propre relation dordre il faudra bien ecirctre en mesure

den preacutevoir correctement les conseacutequences au niveau des opeacuterations qui en deacutependront

Notamment dans certains cas il faudra savoir si leacutegaliteacute de deux eacuteleacutements se fonde sur

lopeacuterateur == (surdeacutefini ou non) ou sur les classes deacutequivalence induites par une relation

dordre (par deacutefaut il sagira alors de lt surdeacutefini ou non) Par exemple lalgorithme find se

fonde sur == tandis que la fonction membre find dun conteneur associatif se fonde sur

lordre intrinsegraveque du conteneur Bien entendu aucune diffeacuterence napparaicirctra avec des eacuteleacute-

ments de type numeacuterique ou string tant quon se limitera agrave lordre induit par lt puisqualors

les classes deacutequivalence en question seront reacuteduites agrave un seul eacuteleacutement

Bien entendu nous attirerons agrave nouveau votre attention sur ce point au moment voulu

7 - Les geacuteneacuterateurs dopeacuterateurs409

7 Les geacuteneacuterateurs dopeacuterateurs NB Ce paragraphe peut ecirctre ignoreacute dans un premier temps

Le meacutecanisme de surdeacutefinition dopeacuterateurs utiliseacute par C++ fait que lon peut theacuteoriquement

deacutefinir pour une classe donneacutee agrave la fois lopeacuterateur == et lopeacuterateur = de maniegravere totale-

ment indeacutependante voir incoheacuterente Il en va de mecircme pour les opeacuterateurs lt lt= gt et gt=

Mais la bibliothegraveque standard dispose de patrons de fonctions permettant de deacutefinir

bull lopeacuterateur = agrave partir de lopeacuterateur ==

bull les opeacuterateurs gt lt= et gt= agrave partir de lopeacuterateur lt

Comme on peut sy attendre si a et b sont dun type classe pour laquelle on a deacutefini == =

sera deacutefini par

a = b si (a == b)

De la mecircme maniegravere les opeacuterateurs lt= gt et gt= peuvent ecirctre deacuteduits de lt par les deacutefinitions

suivantes

a gt b si b lt a

a lt= b si (a gt b)

a gt= b si (a lt b)

Dans ces conditions on voit quil suffit de munir une classe des opeacuterateurs == et lt pour

quelle dispose automatiquement des autres

Bien entendu il reste toujours possible de donner sa propre deacutefinition de lun quelconque de

ces quatre opeacuterateurs Elle sera alors utiliseacutee en tant que speacutecialisation dune fonction patron

Il est tregraves important de noter quil nexiste aucun lien entre la deacutefinition automatique de lt= et

celle de == Ainsi rien nimpose hormis le bon sens que a==b implique alt=b comme le

montre ce petit exemple deacutecole dans lequel nous deacutefinissons lopeacuterateur lt dune maniegravere

artificielle et incoheacuterente avec la deacutefinition de ==

include ltiostreamgtinclude ltutilitygt pour les geacuteneacuterateurs dopeacuterateurs using namespace std class point int x y public point(int abs=0 int ord=0) x=abs y=ord friend int operator== (point point) friend int operatorlt (point point)

int operator== (point a point b) return ( (ax == bx) ampamp (ay == by) )

Geacuteneacuteraliteacutes sur la bibliothegraveque standardCHAPITRE 18

410

int operatorlt(point a point b) return ( (ax lt bx) ampamp (ay lt by) ) main() point a(1 2) b(3 1) cout ltlt a == b ltlt (a==b) ltlt a = b ltlt (a=b) ltlt n cout ltlt a lt b ltlt (altb) ltlt a lt= b ltlt (alt=b) ltlt n char c cin gtgt c

a == b 0 a = b 1a lt b 0 a lt= b 1

Exemple de geacuteneacuteration non satisfaisante des opeacuterateurs = gt lt= et gt=

Remarque

Le manque de coheacuterence entre les deacutefinitions des opeacuterateurs == et lt est ici sans conseacute-

quence En revanche nous avons vu que lopeacuterateur lt pouvait intervenir par exemple

pour ordonner un conteneur associatif ou pour trier un conteneur de type list lorsquon uti-

lise la fonction membre sort Dans ce cas sa deacutefinition devra respecter les contraintes

eacutevoqueacutees au paragraphe 6

19

Les conteneurs seacutequentiels

Nous avons vu dans le preacuteceacutedent chapitre que les conteneurs pouvaient se classer en deux

cateacutegories tregraves diffeacuterentes les conteneurs seacutequentiels et les conteneurs associatifs les pre-

miers sont ordonneacutes suivant un ordre imposeacute explicitement par le programme lui-mecircme tan-

dis que les seconds le sont de maniegravere intrinsegraveque Les trois conteneurs seacutequentiels

principaux sont les classes vector list et deque La classe vector geacuteneacuteralise la notion de

tableau tandis que la classe list correspond agrave la notion de liste doublement chaicircneacutee Comme

on peut sy attendre vector disposera dun iteacuterateur agrave accegraves direct tandis que list ne disposera

que dun iteacuterateur bidirectionnel Quant agrave la classe deque on verra quil sagit dune classe

intermeacutediaire entre les deux preacuteceacutedentes dont la preacutesence ne se justifie que pour des ques-

tions defficaciteacute

Nous commencerons par eacutetudier les fonctionnaliteacutes communes agrave ces trois conteneurs cons-

truction affectation globale initialisation par un autre conteneur insertion et suppression

deacuteleacutements comparaisons Puis nous examinerons en deacutetail les fonctionnaliteacutes speacutecifiques agrave

chacun des conteneurs vector deque et list Nous terminerons par une bregraveve description des

trois adaptateurs de conteneurs que sont stack queue et priority_queue

Les conteneurs seacutequentielsCHAPITRE 19

412

1 Fonctionnaliteacutes communes aux conteneurs vector list et deque

Comme tous les conteneurs vector list et deque sont de taille dynamique crsquoest-agrave-dire sus-

ceptibles de varier au fil de lexeacutecution Malgreacute leur diffeacuterence de nature ces trois conteneurs

possegravedent des fonctionnaliteacutes communes que nous allons eacutetudier ici Elles concernent

bull leur construction

bull laffectation globale

bull leur comparaison

bull linsertion de nouveaux eacuteleacutements ou la suppression deacuteleacutements existants

11 Construction Les trois classes vector list et deque disposent de diffeacuterents constructeurs conteneur vide

avec nombre deacuteleacutements donneacute agrave partir dun autre conteneur

111 Construction dun conteneur vide

Lappel dun constructeur sans argument construit un conteneur vide crsquoest-agrave-dire ne compor-

tant aucun eacuteleacutement

listltfloatgt lf la liste lf est construite vide lfsize() vaudra 0 et lfbegin() == lfend( )

112 Construction avec un nombre donneacute deacuteleacutements

De faccedilon comparable agrave ce qui se passe avec la deacuteclaration dun tableau classique lappel dun

constructeur avec un seul argument entier n construit un conteneur comprenant n eacuteleacutements

En ce qui concerne linitialisation de ces eacuteleacutements elle est reacutegie par les regravegles habituelles

dans le cas deacuteleacutements de type standard (0 pour la classe statique indeacutetermineacute sinon)

Lorsquil sagit deacuteleacutements de type classe ils sont tout naturellement initialiseacutes par appel dun

constructeur sans argument

listltfloatgt lf(5) lf est construite avec 5 eacuteleacutements de type float lfsize() vaut 5 vectorltpointgt vp(5) vp est construit avec 5 eacuteleacutements de type point initialiseacutes par le constructeur sans argument

113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur

Le premier argument du constructeur fournit le nombre deacuteleacutements le second argument en

fournit la valeur

listltintgt li(5 999) li est construite avec 5 eacuteleacutements de type int ayant tous la valeur 999 point a(3 8) on suppose que point est une classe

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque413

listltpointgt lp (10 a) lp est construite avec 10 points ayant tous la valeur de a il y a appel du constructeur par recopie (eacuteventuellement par deacutefaut) de point

114 Construction agrave partir dune seacutequenceOn peut construire un conteneur agrave partir dune seacutequence deacuteleacutements de mecircme type Dans ce

cas on fournit simplement au constructeur deux arguments repreacutesentant les bornes de linter-

valle correspondant Voici des exemples utilisant des seacutequences de conteneur de type

listltpointgt

listltpointgt lp(6) liste de 6 points vectorltpointgt vp (lpbegin() lpend()) construit un vecteur de points en recopiant les points de la liste lp le constructeur par recopie de point sera appeleacute pour chacun des points listltpointgt lpi (lprbegin() lprend()) construit une liste obtenue en inversant lordre des points de la liste lp

Ici les seacutequences correspondaient agrave lensemble du conteneur il sagit de la situation la plus

usuelle mais rien nempecirccherait dutiliser des intervalles diteacuterateurs quelconques pour peu

que la seconde borne soit accessible agrave partir de la premiegravere

Voici un autre exemple de construction de conteneurs agrave partir de seacutequences de valeurs issues

dun tableau classique utilisant des intervalles deacutefinis par des pointeurs

int t[6] = 2 9 1 8 2 11 vectorltintgt vi(t t+6) construit un vecteur formeacute des 6 valeurs de t vectorltintgt vi2(t+1 t+5) construit un vecteur formeacute des valeurs t[1] agrave t[5]

Dans le premier cas si lon souhaite une formulation indeacutependante de la taille effective de t

on pourra proceacuteder ainsi

int t[] = nombre quelconque de valeurs qui seront vectorltintgt vi(t t + sizeof(t)sizeof(int)) recopieacutees dans vi

115 Construction agrave partir dun autre conteneur de mecircme typeIl sagit dun classique constructeur par recopie qui comme on peut sy attendre appelle le

constructeur de recopie des eacuteleacutements concerneacutes lorsquil sagit dobjets

vectorltintgt vi1 vecteur dentiers vectorltintgt vi2(vi1) ou encore vectorltintgt vi2 = vi1

12 Modifications globales Les trois classes vector deque et list deacutefinissent convenablement lopeacuterateur daffectation de

plus elles proposent une fonction membre assign comportant plusieurs deacutefinitions ainsi

quune fonction clear

Les conteneurs seacutequentielsCHAPITRE 19

414

121 Opeacuterateur daffectationOn peut affecter un conteneur dun type donneacute agrave un autre conteneur de mecircme type crsquoest-agrave-dire

ayant le mecircme nom de patron et le mecircme type deacuteleacutements Bien entendu il nest nullement neacuteces-

saire que le nombre deacuteleacutements de chacun des conteneurs soit le mecircme Voici quelques exemples

vectorltintgt vi1 () vi2 () vectorltfloatgt vf () vi1 = vi2 correct quels que soient le nombre deacuteleacutements de vi1 et de vi2 le contenu de vi1 est remplaceacute par celui de vi2 qui reste inchangeacute vf = vi1 incorrect (refuseacute en compilation) les eacuteleacutements de vf et de vi1 ne sont pas du mecircme type

Voici un autre exemple avec un conteneur dont les eacuteleacutements sont des objets

vectorltpointgt vp1 () vp2 () vp1 = vp2

Dans ce cas comme nous lavons deacutejagrave fait remarquer au paragraphe 31 du chapitre 18 il

existe deux faccedilons de parvenir au reacutesultat escompteacute suivant les tailles relatives des vecteurs

vp1 et vp2 agrave savoir soit lutilisation du constructeur par recopie de la classe point soit lutili-

sation de lopeacuterateur daffectation de la classe point

122 La fonction membre assignAlors que laffectation nest possible quentre conteneurs de mecircme type la fonction assign

permet daffecter agrave un conteneur existant les eacuteleacutements dune seacutequence deacutefinie par un inter-

valle [debut fin) agrave condition que les eacuteleacutements deacutesigneacutes soient du type voulu (et pas seule-

ment dun type compatible par affectation)

assign (deacutebut fin) fin doit ecirctre accessible depuis deacutebut

Il existe eacutegalement une autre version permettant daffecter agrave un conteneur un nombre donneacute

deacuteleacutements ayant une valeur imposeacutee

assign (nb_fois valeur)

Dans les deux cas les eacuteleacutements existants seront remplaceacutes par les eacuteleacutements voulus comme

sil y avait eu affectation

point a () listltpointgt lp () vectorltpointgt vp () lpassign (vpbegin() vpend()) maintenant lpsize() = vpsize() vpassign (10 a) maintenant vpsize()=10

char t[] = hello listltchargt lc(7 x) lc contient x x x x x x x

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque415

lcassign(t t+4) lc contient maintenant h e l l o lcassign(3 z) lc contient maintenant z z z

123 La fonction clearLa fonction clear() vide le conteneur de son contenu

vectorltpointgt vp(10) vpsize() = 0 vpclear () appel du destructeur de chacun des points de vp maintenant vpsize() = 0

124 La fonction swapLa fonction membre swap (conteneur) permet deacutechanger le contenu de deux conteneurs de

mecircme type Par exemple

vectorltintgt v1 v2 v1swap(v2) ou v2swap(v1)

Laffectation preacuteceacutedente sera plus efficace que la deacutemarche traditionnelle

vectorltintgt v3=v1 v1=v2 v2=v3

Remarque

Comme on peut le constater les possibiliteacutes de modifications globales dun conteneur

sont similaires agrave celles qui sont offertes au moment de la construction la seule possibiliteacute

absente eacutetant laffectation dun nombre deacuteleacutements donneacutes eacuteventuellement non initialiseacutes

13 Comparaison de conteneurs Les trois conteneurs vector deque et list disposent des opeacuterateurs == et lt par le biais des

geacuteneacuterations automatiques dopeacuterateurs ils disposent donc eacutegalement de = lt= gt et gt= Le

rocircle de == correspond agrave ce quon attend dun tel opeacuterateur tandis que celui de lt sappuie sur

ce que lon nomme parfois une comparaison lexicographique analogue agrave celle qui permet de

classer des mots par ordre alphabeacutetique

131 Lopeacuterateur ==Il ne preacutesente pas de difficulteacutes particuliegraveres Si c1 et c2 sont deux conteneurs de mecircme type

leur comparaison par == sera vraie sils ont la mecircme taille et si les eacuteleacutements de mecircme rang

sont eacutegaux

On notera cependant que si les eacuteleacutements concerneacutes sont de type classe il sera neacutecessaire que

cette derniegravere dispose elle-mecircme de lopeacuterateur ==

Les conteneurs seacutequentielsCHAPITRE 19

416

132 Lopeacuterateur ltIl effectue une comparaison lexicographique des eacuteleacutements des deux conteneurs Pour ce faire

il compare les eacuteleacutements de mecircme rang par lopeacuterateur lt en commenccedilant par les premiers

sils existent Il sinterrompt degraves que lune des conditions suivantes est reacutealiseacutee

bull fin de lun des conteneurs atteinte le reacutesultat de la comparaison est vrai

bull comparaison de deux eacuteleacutements fausse le reacutesultat de la comparaison des conteneurs est alors

faux

Si un seul des deux conteneurs est vide il apparaicirct comme lt agrave lautre Si les deux conteneurs

sont vides aucun nest infeacuterieur agrave lautre (ils sont eacutegaux)

On notera lagrave encore que si les eacuteleacutements concerneacutes sont de type classe il sera neacutecessaire que

cette derniegravere dispose elle-mecircme dun opeacuterateur lt approprieacute

133 ExemplesAvec ces deacuteclarations

int t1[] = 2 5 2 4 8 int t2[] = 2 5 2 8 vectorltintgt v1 (t1 t1+5) v1 contient 2 5 2 4 8 vectorltintgt v2 (t2 t2+4) v2 contient 2 5 2 8 vectorltintgt v3 (t2 t2+3) v3 contient 2 5 2 vectorltintgt v4 (v3) v4 contient 2 5 2 vectorltintgt v5 v5 est vide

Voici quelques comparaisons possibles et la valeur correspondante

v2 lt v1 faux v3 lt v2 vrai v3 lt v4 faux v4 lt v3 faux v3 == v4 vrai v4 gt v5 vrai v5 gt v5 faux v5 lt v5 faux

14 Insertion ou suppression deacuteleacutements Chacun des trois conteneurs vector deque et list dispose naturellement de possibiliteacutes daccegraves

agrave un eacuteleacutement existant soit pour en connaicirctre la valeur soit pour la modifier Comme ces pos-

sibiliteacutes varient quelque peu dun conteneur agrave lautre elles seront deacutecrites dans les paragra-

phes ulteacuterieurs Par ailleurs ces trois conteneurs (comme tous les conteneurs) permettent des

modifications dynamiques fondeacutees sur des insertions de nouveaux eacuteleacutements ou des suppres-

sions deacuteleacutements existants On notera que de telles possibiliteacutes nexistaient pas dans le cas

dun tableau classique alors quelles existent pour le conteneur vector mecircme si manifeste-

ment elles sont davantage utiliseacutees dans le cas dune liste

Rappelons toutefois que bien quen theacuteorie les trois conteneurs offrent les mecircmes possibili-

teacutes dinsertions et de suppressions leur efficaciteacute sera diffeacuterente dun conteneur agrave un autre

Nous verrons dans les paragraphes suivants que dans une liste elles seront toujours en O(1)

tandis que dans les conteneurs vector et deque elles seront en O(N) excepteacute lorsquelles

auront lieu en fin de vector ou en deacutebut ou en fin de deque ougrave elles se feront en O(1) dans

ces derniers cas on verra dailleurs quil existe des fonctions membres speacutecialiseacutees

1 - Fonctionnaliteacutes communes aux conteneurs vector list et deque417

141 InsertionLa fonction insert permet dinseacuterer

bull une valeur avant une position donneacutee

insert (position valeur) insegravere valeur avant leacuteleacutement pointeacute par position

fournit un iteacuterateur sur leacuteleacutement inseacutereacute

bull n fois une valeur donneacutee avant une position donneacutee

insert (position nb_fois valeur) insegravere nb_fois valeur avant leacuteleacutement

pointeacute par position

fournit un iteacuterateur sur leacuteleacutement inseacutereacute

bull les eacuteleacutements dun intervalle agrave partir dune position donneacutee

insert (debut fin position) insegravere les valeurs de lintervalle [debut fin)

avant leacuteleacutement pointeacute par position

En voici quelques exemples

listltdoublegt ld listltdoublegtiterator il on suppose que il pointe correctement dans la liste ld ldinsert(il 25) insegravere 25 dans ld avant leacuteleacutement pointeacute par il ldinsert(ldbegin() 67) insegravere 67 au deacutebut de ld ldinsert (ldend() 32) insegravere 32 en fin de ld ldinsert(il 10 -1) insegravere 10 fois -1 avant leacuteleacutement pointeacute par il vectorltdoublegt vd () ldinsert(ldbegin() vdbegin() vdend()) insegravere tous les eacuteleacutements de vd en deacutebut de la liste ld

142 SuppressionLa fonction erase permet de supprimer

bull un eacuteleacutement de position donneacutee

erase (position) supprime leacuteleacutement deacutesigneacute par position - fournit un iteacuterateur

sur leacuteleacutement suivant ou sur la fin de la seacutequence

bull les eacuteleacutements dun intervalle

erase (deacutebut fin) supprime les valeurs de lintervalle [deacutebut fin) - fournit un

iteacuterateur sur leacuteleacutement suivant ou sur la fin de la seacutequence

En voici quelques exemples

listltdoublegt ld listltdoublegtiterator il1 il2

on suppose que il1 et il2 pointent correctement dans la liste ld et que il2 est accessible agrave partir de il1 lderase(il1 il2) supprime les eacuteleacutements de lintervalle [il1 il2) lderase(ldbegin()) supprime leacuteleacutement de deacutebut de ld

Les conteneurs seacutequentielsCHAPITRE 19

418

Remarques

1 Les deux fonctions erase renvoient la valeur de liteacuterateur suivant le dernier eacuteleacutement sup-

primeacute sil en existe un ou sinon la valeur end() Voyez par exemple la construction sui-

vante dans laquelle il est un iteacuterateur de valeur convenable sur une liste dentiers ld

while (il = lderase(il) = ldend())

Elle est eacutequivalente agrave

erase (il ldend())

2 Les conteneurs seacutequentiels ne sont pas adapteacutes agrave la recherche de valeurs donneacutees ou agrave

leur suppression Il nexistera dailleurs aucune fonction membre agrave cet effet contraire-

ment agrave ce qui se produira avec les conteneurs associatifs Il nen reste pas moins quune

telle recherche peut toujours se faire agrave laide dun algorithme standard tel que find ou

find_if mais au prix dune efficaciteacute meacutediocre (en O(N))

143 Cas des insertionssuppressions en fin pop_back et push_backSi lon sen tient aux possibiliteacutes geacuteneacuterales preacutesenteacutees ci-dessus on constate que sil est possi-

ble de supprimer le premier eacuteleacutement dun conteneur en appliquant erase agrave la position begin()

il nest pas possible de supprimer le dernier eacuteleacutement dun conteneur en appliquant erase agrave la

position end() Un tel reacutesultat peut toutefois sobtenir en appliquant erase agrave la position rbe-

gin() Quoi quil en soit comme lefficaciteacute de cette suppression est en O(1) pour les trois

conteneurs il existe une fonction membre speacutecialiseacutee pop_back() qui reacutealise cette opeacuteration

si c est un conteneur cpop_back() est eacutequivalente agrave cerase(crbegin())

Dune maniegravere semblable et bien que ce ne soit guegravere indispensable il existe une fonction

speacutecialiseacutee dinsertion en fin push_back Si c est un conteneur cpush_back(valeur) est eacutequi-

valent agrave cinsert (cend() valeur)

2 Le conteneur vector Il reprend la notion usuelle de tableau en autorisant un accegraves direct agrave un eacuteleacutement quelconque

avec une efficaciteacute en O(1) crsquoest-agrave-dire indeacutependante du nombre de ses eacuteleacutements Cet accegraves

peut se faire soit par le biais dun iteacuterateur agrave accegraves direct soit de faccedilon plus classique par

lopeacuterateur [ ] ou par la fonction membre at Mais il offre un cadre plus geacuteneacuteral que le tableau

puisque

bull la taille crsquoest-agrave-dire le nombre deacuteleacutements peut varier au fil de lexeacutecution (comme celle de

tous les conteneurs)

bull on peut effectuer toutes les opeacuterations de construction daffectation et de comparaisons deacute-

crites aux paragraphes 11 12 et 13

bull on dispose des possibiliteacutes geacuteneacuterales dinsertion ou de suppressions deacutecrites au paragraphe

14 (avec cependant une efficaciteacute en O(N) dans le cas geacuteneacuteral)

2 - Le conteneur vector419

Ici nous nous contenterons dexaminer les fonctionnaliteacutes speacutecifiques de la classe vector qui

viennent donc en compleacutement de celles qui sont examineacutees au paragraphe 1

21 Accegraves aux eacuteleacutements existants On accegravede aux diffeacuterents eacuteleacutements dun vecteur aussi bien pour en connaicirctre la valeur que

pour la modifier de diffeacuterentes maniegraveres par iteacuterateur (iterator ou reverse_iterator) ou par

indice (opeacuterateur [ ] ou fonction membre at) En outre laccegraves au dernier eacuteleacutement peut se

faire par une fonction membre approprieacutee back Dans tous les cas lefficaciteacute de cet accegraves est

en O(1) ce qui constitue manifestement le point fort de ce type de conteneur

211 Accegraves par iteacuterateur

Les iteacuterateurs iterator et reverse_iterator dun conteneur de type vector sont agrave accegraves direct

Si par exemple iv est une variable de type vectorltintgtiterator une expression telle que

iv+i a alors un sens elle deacutesigne leacuteleacutement du vecteur v situeacute i eacuteleacutements plus loin que celui

qui est deacutesigneacute par iv agrave condition que la valeur de i soit compatible avec le nombre deacuteleacute-

ments de v

Liteacuterateur iv peut bien sucircr comme tout iteacuterateur bidirectionnel ecirctre increacutementeacute ou deacutecreacute-

menteacute par ++ ou -- Mais comme il est agrave accegraves direct il peut eacutegalement ecirctre increacutementeacute ou

deacutecreacutementeacute dune quantiteacute quelconque comme dans

iv += n iv -= p

Voici un petit exemple deacutecole

vectorltintgt v(10) vecteur de 10 eacuteleacutements vectorltintgtiterator iv = vbegin() iv pointe sur le premier eacuteleacutem de v iv = vibegin() iv=0 place 0 dans le premier eacuteleacutement de vi iv+=3 iv=30 place 30 dans le quatriegraveme eacuteleacutement de vi iv = viend()-2 iv=70 place 70 dans le huitiegraveme eacuteleacutement de vi

212 Accegraves par indice

Lopeacuterateur [ ] est en fait utilisable de faccedilon naturelle Si v est de type vector lexpression

v[i] est une reacutefeacuterence agrave leacuteleacutement de rang i de sorte que les deux instructions suivantes sont

eacutequivalentes

v[i] = (vbegin()+i) =

Mais il existe eacutegalement une fonction membre at telle que vat(i) soit eacutequivalente agrave v[i] Sa

seule raison decirctre est de geacuteneacuterer une exception out_of_range en cas dindice incorrect ce que

lopeacuterateur [ ] ne fait theacuteoriquement pas Bien entendu en contrepartie at est leacutegegraverement

moins rapide que lopeacuterateur [ ]

Lexemple deacutecole preacuteceacutedent peut manifestement seacutecrire plus simplement

vi[0] = 0 ou viat(0) = 0 vi[3] = 30 ou viat(3) = 30 vi[7] = 70 ou vi[visize()-2] = 70 ou viat(7) = 70

Les conteneurs seacutequentielsCHAPITRE 19

420

Il est geacuteneacuteralement preacutefeacuterable dutiliser les indices plutocirct que les iteacuterateurs dont le principal

avantage reacuteside dans lhomogeacuteneacuteiumlsation de notation avec les autres conteneurs

213 Cas de laccegraves au dernier eacuteleacutement

Comme le vecteur est particuliegraverement adapteacute aux insertions ou aux suppressions en fin il

existe une fonction membre back qui permet dacceacuteder directement au dernier eacuteleacutement

vectorltintgt v(10) vback() = 25 eacutequivalent quand v est de taille 10 agrave v[9] = 25 eacutequivalent dans tous les cas agrave v[vsize()-1] = 25

On notera bien que cette fonction se contente de fournir une reacutefeacuterence agrave un eacuteleacutement existant

Elle ne permet en aucun cas des insertions ou des suppressions en fin lesquelles sont eacutetu-

dieacutees ci-dessous

22 Insertions et suppressions Le conteneur vector dispose des possibiliteacutes geacuteneacuterales dinsertion et de suppression deacutecrites

au paragraphe 14 Toutefois leur efficaciteacute est meacutediocre puisquen O(N) alors que dans le

cas des listes elle sera en O(1) Cest lagrave le prix agrave payer pour disposer daccegraves aux eacuteleacutements

existant en O(1) En revanche nous avons vu que comme les deux autres conteneurs vector

disposait de fonctions membres dinsertion ou de suppression du dernier eacuteleacutement dont leffi-

caciteacute est en O(1)

bull la fonction push_back(valeur) pour inseacuterer un nouvel eacuteleacutement en fin

bull la fonction pop_back() pour supprimer le dernier eacuteleacutement

Voici un petit exemple deacutecole

vectorltintgt v(5 99) vecteur de 5 eacuteleacutements valant 99 vsize() = 5 vpush_back(10) ajoute un eacuteleacutement de valeur 10 vsize() = 6 et v[5] = 10 ici v[6] nexiste pas vpush_back(20) ajoute un eacuteleacutement de valeur 20 vsize() = 7 et v[6] = 20 vpop_back() supprime le dernier eacuteleacutement vsize() = 6

23 Gestion de lemplacement meacutemoire

231 Introduction

La norme nimpose pas explicitement la maniegravere dont une impleacutementation doit geacuterer lempla-

cement alloueacute agrave un vecteur Cependant comme nous lavons vu elle impose des contraintes

defficaciteacute agrave certaines opeacuterations ce qui comme on sen doute limite seacutevegraverement la marge

de manœuvre de limpleacutementation

Par ailleurs la classe vector dispose doutils fournissant des informations relatives agrave la ges-

tion des emplacements meacutemoire et permettant eacuteventuellement dintervenir dans leur alloca-

2 - Le conteneur vector421

tion Bien entendu le rocircle de tels outils est plus facile agrave appreacutehender lorsque lon connaicirct la

maniegravere exacte dont une impleacutementation gegravere un vecteur

Enfin la norme preacutevoit que suite agrave certaines opeacuterations des reacutefeacuterences ou des valeurs diteacute-

rateurs peuvent devenir invalides crsquoest-agrave-dire inutilisables pour acceacuteder aux eacuteleacutements corres-

pondants Lagrave encore il est plus facile de comprendre les regravegles imposeacutees si lon connaicirct la

maniegravere dont limpleacutementation gegravere les emplacements meacutemoire

Or preacuteciseacutement les impleacutementations actuelles allouent toujours lemplacement dun vecteur

en un seul bloc Mecircme si ce nest pas la seule solution envisageable cest certainement la plus

plausible

232 Invalidation diteacuterateurs ou de reacutefeacuterences

Un certain nombre dopeacuterations sur un vecteur entraicircnent linvalidation des iteacuterateurs ou des

reacutefeacuterences sur certains des eacuteleacutements de ce vecteur Les eacuteleacutements concerneacutes sont exactement

ceux auxquels on peut sattendre dans le cas ougrave lemplacement meacutemoire est geacutereacute en un seul

bloc agrave savoir

bull tous les eacuteleacutements en cas daugmentation de la taille en effet il se peut quune recopie de

lensemble du vecteur ait eacuteteacute neacutecessaire on verra toutefois quil est possible deacuteviter certai-

nes recopies en reacuteservant plus demplacements que neacutecessaire

bull tous les eacuteleacutements en cas dinsertion dun eacuteleacutement la raison en est la mecircme

bull les eacuteleacutements situeacutes agrave la suite dun eacuteleacutement supprimeacute ainsi que leacuteleacutement supprimeacute (ce qui va

de soi ) ici on voit que seuls les eacuteleacutements situeacutes agrave la suite de leacuteleacutement supprimeacute ont ducirc

ecirctre deacuteplaceacutes

233 Outils de gestion de lemplacement meacutemoire dun vecteur

La norme propose un certain nombre doutils fournissant des informations concernant

lemplacement meacutemoire alloueacute agrave un vecteur et permettant eacuteventuellement dintervenir dans

son allocation Comme on la dit en introduction le rocircle de ces outils est plus facile agrave appreacute-

hender si lon fait lhypothegravese que lemplacement dun vecteur est toujours alloueacute sous forme

dun bloc unique

On a deacutejagrave vu que la fonction size() permettait de connaicirctre le nombre deacuteleacutements dun vecteur

Mais il existe une fonction voisine capacity() qui fournit la taille potentielle du vecteur

crsquoest-agrave-dire le nombre deacuteleacutements quil pourra accepter sans avoir agrave effectuer de nouvelle

allocation Dans le cas usuel ougrave le vecteur est alloueacute sous forme dun seul bloc cette fonction

en fournit simplement la taille (luniteacute utiliseacutee restant leacuteleacutement du vecteur) Bien entendu agrave

tout instant on a toujours capacity() gt= size() La diffeacuterence capacity()-size() permet de con-

naicirctre le nombre deacuteleacutements quon pourra inseacuterer dans un vecteur sans quune reacuteallocation de

meacutemoire soit neacutecessaire

Mais une telle information ne serait guegravere inteacuteressante si lon ne pouvait pas agir sur cette

allocation Or la fonction membre reserve(taille) permet preacuteciseacutement dimposer la taille

minimale de lemplacement alloueacute agrave un vecteur agrave un moment donneacute Bien entendu lappel de

Les conteneurs seacutequentielsCHAPITRE 19

422

cette fonction peut tregraves bien amener agrave une recopie de tous les eacuteleacutements du vecteur en un autre

emplacement Cependant une fois ce travail accompli tant que la taille du vecteur ne deacutepas-

sera pas la limite alloueacutee on est assureacute de limiter au maximum les recopies deacuteleacutements en cas

dinsertion ou de suppression En particulier en cas dinsertion dun nouvel eacuteleacutement les eacuteleacute-

ments situeacutes avant ne seront pas deacuteplaceacutes et les reacutefeacuterences ou iteacuterateurs correspondants reste-

ront valides

Par ailleurs la fonction max_size() permet de connaicirctre la taille maximale quon peut allouer

au vecteur agrave un instant donneacute

Enfin il existe une fonction resize(taille) peu usiteacutee qui permet de modifier la taille effec-

tive du vecteur aussi bien dans le sens de laccroissement que dans celui de la reacuteduction

Attention il ne sagit plus ici comme avec reserve dagir sur la taille de lemplacement

alloueacute mais bel et bien sur le nombre deacuteleacutements du vecteur Si lappel de resize conduit agrave

augmenter la taille du vecteur on lui insegravere en fin de nouveaux eacuteleacutements Si en revanche

lappel conduit agrave diminuer la taille du vecteur on supprime en fin le nombre deacuteleacutements vou-

lus avec naturellement appel de leur destructeur sil sagit dobjets

24 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

vector que nous venons dexaminer dans ce paragraphe et dans le preacuteceacutedent Nous y avons

adjoint une recherche de valeur par lalgorithme find qui ne sera preacutesenteacute quulteacuterieurement

mais dont la signification est assez eacutevidente rechercher une valeur donneacutee

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

main() void affiche (vectorltintgt) int i int t[] = 1 2 3 4 5 6 7 8 9 10 vectorltintgt v1(4 99) vecteur de 4 entiers egaux agrave 99 vectorltintgt v2(7 0) vecteur de 7 entiers vectorltintgt v3(t t+6) vecteur construit a partir de t cout ltlt V1 init = affiche(v1) for (i=0 iltv2size() i++) v2[i] = ii v3 = v2 cout ltlt V2 = affiche(v2) cout ltlt V3 = affiche(v3) v1assign (t+1 t+6) cout ltlt v1 apres assign affiche(v1) cout ltlt dernier element de v1 ltlt v1back() ltlt n v1push_back(99) cout ltlt v1 apres push_back affiche(v1) v2pop_back() cout ltlt v2 apres pop_back affiche(v2) cout ltlt v1size() ltlt v1size() ltlt v1capacity() ltlt v1capacity() ltlt V1max_size() ltlt v1max_size() ltlt n

2 - Le conteneur vector423

vectorltintgtiterator iv iv = find (v1begin() v1end() 16) recherche de 16 dans v1 if (iv = v1end()) v1insert (iv v2begin() v2end()) attention ici iv nest plus utilisable cout ltlt v1 apres insert affiche(v1)

void affiche (vectorltintgt v) voir remarque ci-dessous unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

V1 init = 99 99 99 99V2 = 0 1 4 9 16 25 36V3 = 0 1 4 9 16 25 36v1 apres assign 2 3 4 5 6dernier element de v1 6v1 apres push_back 2 3 4 5 6 99v2 apres pop_back 0 1 4 9 16 25v1size() 6 v1capacity() 10 V1max_size() 1073741823v1 apres insert 2 3 4 5 6 99

Exemple dutilisation de la classe vector

Remarque

La transmission drsquoun vecteur agrave la fonction affiche se fait par valeur ce qui dans une situa-

tion reacuteelle peut srsquoaveacuterer peacutenalisant en temps drsquoexeacutecution Si lrsquoon souhaite eacuteviter cela il

reste possible drsquoutiliser une transmission par reacutefeacuterence ou drsquoutiliser des iteacuterateurs Par

exemple la fonction affiche pourrait alors ecirctre deacutefinie ainsi

void affiche (vectorltintgtiterator deb vectorltintgtiterator fin) vectorltintgtiterator it for (it=deb it = fin it++) cout ltlt it ltlt cout ltlt n

et ses diffeacuterents appels se preacutesenteraient de cette faccedilon

affiche (v1begin() v1end())

25 Cas particulier des vecteurs de booleacuteens La norme preacutevoit lexistence dune speacutecialisation du patron vector lorsque son argument est

de type bool Lobjectif principal est de permettre agrave limpleacutementation doptimiser le stockage

sur un seul bit des informations correspondant agrave chaque eacuteleacutement Les fonctionnaliteacutes de la

Les conteneurs seacutequentielsCHAPITRE 19

424

classe vectorltboolgt sont donc celles que nous avons eacutetudieacutees preacuteceacutedemment Il faut cepen-

dant lui adjoindre une fonction membre flip destineacutee agrave inverser tous les bits dun tel vecteur

Drsquoautre part il existe eacutegalement un patron de classes nommeacute bitset parameacutetreacute par un entier

qui permet de repreacutesenter des suites de bits de taille fixe et de les manipuler efficacement

comme on le fait avec les motifs binaires contenus dans des entiers Mais ce patron ne dis-

pose plus de toute les fonctionnaliteacutes des conteneurs deacutecrites ici Il sera deacutecrit au chapitre

3 Le conteneur deque

31 Preacutesentation geacuteneacuterale Le conteneur deque offre des fonctionnaliteacutes assez voisines de celles dun vecteur En parti-

culier il permet toujours laccegraves direct en O(1) agrave un eacuteleacutement quelconque tandis que les sup-

pressions et insertions en un point quelconque restent en O(N) En revanche il offre en plus

de linsertion ou suppression en fin une insertion ou suppression en deacutebut eacutegalement en

O(1) ce que ne permettait pas le vecteur En fait il ne faut pas en conclure pour autant que

deque est plus efficace que vector car cette possibiliteacute suppleacutementaire se paye agrave diffeacuterents

niveaux

bull une opeacuteration en O(1) sur un conteneur de type deque sera moins rapide que la mecircme opeacute-

ration toujours en O(1) sur un conteneur de type vector

bull certains outils de gestion de lemplacement meacutemoire dun conteneur de type vector nexis-

tent plus pour un conteneur de type deque plus preacuteciseacutement on disposera bien de size() et

de max_size() mais plus de capacity et de reserve

Lagrave encore et comme nous lavons fait remarquer au paragraphe 23 la norme nimpose pas

explicitement la maniegravere de geacuterer lemplacement meacutemoire dun conteneur de type deque

neacuteanmoins les choses deviennent beaucoup plus compreacutehensibles si lon admet que pour

satisfaire aux contraintes imposeacutees il nest pas raisonnable dallouer un deque en un seul bloc

mais plutocirct sous forme de plusieurs blocs contenant chacun un ou geacuteneacuteralement plusieurs

eacuteleacutements Dans ces conditions on voit bien que linsertion ou la suppression en deacutebut de con-

teneur ne neacutecessitera plus le deacuteplacement de lensemble des autres eacuteleacutements comme ceacutetait le

cas avec un vecteur mais seulement de quelques-uns dentre eux En revanche plus la taille

des blocs sera petite plus la rapiditeacute de laccegraves direct (bien que toujours en O(1)) diminuera

Au contraire les insertions et les suppressions bien quayant une efficaciteacute en O(N) seront

dautant plus performantes que les blocs seront petits

Si lon fait abstraction de ces diffeacuterences de performances les fonctionnaliteacutes de deque sont

celles de vector auxquelles il faut tout naturellement ajouter les fonctions speacutecialiseacutees con-

cernant le premier eacuteleacutement

bull front() pour acceacuteder au premier eacuteleacutement elle complegravete la fonction back permettant laccegraves

au dernier eacuteleacutement

3 - Le conteneur deque425

bull push_front(valeur) pour inseacuterer un nouvel eacuteleacutement en deacutebut elle complegravete la fonction

push_back()

bull pop_front() pour supprimer le premier eacuteleacutement elle complegravete la fonction pop_back()

Les regravegles dinvalidation des iteacuterateurs et des reacutefeacuterences restent exactement les mecircmes que

celles de la classe vector mecircme si dans certains cas elles peuvent apparaicirctre tregraves contrai-

gnantes Par exemple si un conteneur de type deque est impleacutementeacute sous forme de 5 blocs

diffeacuterents il est certain que linsertion en deacutebut ninvalidera que les iteacuterateurs sur des eacuteleacute-

ments du premier bloc qui sera le seul soumis agrave une recopie mais en pratique on ne pourra

jamais profiter de cette remarque dailleurs on ne connaicirctra mecircme pas la taille des blocs

Dune maniegravere geacuteneacuterale le conteneur deque est beaucoup moins utiliseacute que les conteneurs

vector et list qui possegravedent des fonctionnaliteacutes bien distinctes Il peut saveacuterer inteacuteressant dans

des situations de pile de type FIFO (First In First Out) ougrave il est neacutecessaire dintroduire des

informations agrave une extreacutemiteacute et de les recueillir agrave lautre En fait dans ce cas si lon na plus

besoin dacceacuteder directement aux diffeacuterents eacuteleacutements il est preacutefeacuterable dutiliser ladaptateur

de conteneur queue dont nous parlerons au paragraphe 5

32 Exemple Voici un petit exemple deacutecole illustrant quelques-unes des fonctionnaliteacutes du conteneur

deque

include ltiostreamgt

include ltdequegt

include ltalgorithmgt

using namespace std

main()

void affiche (dequeltchargt)

char mot[] = xyz

dequeltchargt pile(mot mot+3) affiche(pile)

pilepush_front(a) affiche(pile)

pile[2] = +

pilepush_front(b)

pilepop_back() affiche(pile)

dequeltchargtiterator ip

ip = find (pilebegin() pileend() x)

pileerase(pilebegin() ip) affiche(pile)

void affiche (dequeltchargt p) voir remarque paragraphe 24

int i

for (i=0 iltpsize() i++) cout ltlt p[i] ltlt

cout ltlt n

Les conteneurs seacutequentielsCHAPITRE 19

426

x y za x y zb a x +x +

Exemple dutilisation de la classe deque

4 Le conteneur list Le conteneur list correspond au concept de liste doublement chaicircneacutee ce qui signifie quon y

disposera dun iteacuterateur bidirectionnel permettant de parcourir la liste agrave lendroit ou agrave lenvers

Cette fois les insertions ou suppressions vont se faire avec une efficaciteacute en O(1) quelle que

soit leur position ce qui constitue latout majeur de ce conteneur par rapport aux deux classes

preacuteceacutedentes vector et deque En contrepartie le conteneur list ne dispose plus dun iteacuterateur agrave

accegraves direct Rappelons que toutes les possibiliteacutes exposeacutees dans le paragraphe 1 sappliquent

aux listes nous ne les reprendrons donc pas ici

41 Accegraves aux eacuteleacutements existants Les conteneurs vector et deque permettaient dacceacuteder aux eacuteleacutements existants de deux

maniegraveres par iteacuterateur ou par indice en fait il existait un lien entre ces deux possibiliteacutes

parce que les iteacuterateurs de ces classes eacutetaient agrave accegraves direct Le conteneur list offre toujours

les iteacuterateurs iterator et reverse_iterator mais cette fois ils sont seulement bidirectionnels

Si it deacutesigne un tel iteacuterateur on pourra toujours consulter leacuteleacutement pointeacute par la valeur de

lexpression it ou le modifier par une affectation de la forme

it =

Liteacuterateur it pourra ecirctre increacutementeacute par ++ ou -- mais il ne sera plus possible de lincreacutemen-

ter dune quantiteacute quelconque Ainsi pour acceacuteder une premiegravere fois agrave un eacuteleacutement dune liste

il aura fallu obligatoirement la parcourir depuis son deacutebut ou depuis sa fin eacuteleacutement par eacuteleacute-

ment jusquagrave leacuteleacutement concerneacute et ceci quel que soit linteacuterecirct quon peut attacher aux eacuteleacute-

ments intermeacutediaires

La classe list dispose des fonctions front() et back() avec la mecircme signification que pour la

classe deque la premiegravere est une reacutefeacuterence au premier eacuteleacutement la seconde est une reacutefeacuterence

au dernier eacuteleacutement

listltintgt l ()

if (lfront()=99) lfront=0 si le premier eacuteleacutement vaut 99

on lui donne la valeur 0

On ne confondra pas la modification de lun de ces eacuteleacutements opeacuteration qui ne modifie pas le

nombre deacuteleacutements de la liste avec linsertion en deacutebut ou en fin de liste qui modifie le nom-

bre deacuteleacutements de la liste

4 - Le conteneur list427

42 Insertions et suppressions Le conteneur list dispose des possibiliteacutes geacuteneacuterales dinsertion et de suppression procureacutees

par les fonctions insert et erase et deacutecrites au paragraphe 14 Mais cette fois leur efficaciteacute

est toujours en O(1) ce qui neacutetait pas le cas en geacuteneacuteral des conteneurs vector et deque On

dispose eacutegalement des fonctions speacutecialiseacutees dinsertion en deacutebut push_front(valeur) ou en

fin push_back(valeur) ou de suppression en deacutebut pop_front() ou en fin pop_back() rencon-

treacutees dans les classes vector et deque

En outre la classe list dispose de fonctions de suppressions conditionnelles que ne posseacute-

daient pas les conteneurs preacuteceacutedents

bull suppression de tous les eacuteleacutements ayant une valeur donneacutee

bull suppression des eacuteleacutements satisfaisant agrave une condition donneacutee

421 Suppression des eacuteleacutements de valeur donneacutee

remove(valeur) supprime tous eacuteleacutements eacutegaux agrave valeur

Comme on peut sy attendre cette fonction se fonde sur lopeacuterateur == qui doit donc ecirctre

deacutefini dans le cas ougrave les eacuteleacutements concerneacutes sont des objets

int t[] = 1 3 1 6 4 1 5 2 1 listltintgt li(t t+9) li contient 1 3 1 6 4 1 5 2 1 liremove (1) li contient maintenant 3 6 4 5 2

422 Suppression des eacuteleacutements reacutepondant agrave une condition

remove_if (preacutedicat) supprime tous les eacuteleacutements reacutepondant au preacutedicat

Cette fonction supprime tous les eacuteleacutements pour lesquels le preacutedicat unaire fourni en argument

est vrai La notion de preacutedicat a eacuteteacute abordeacutee au paragraphe 5 du chapitre 18 Voici un exem-

ple utilisant le preacutedicat est_paire deacutefini ainsi

bool est_paire (int n) ne pas oublier include ltfunctionalgt return (n2)

int t[] = 1 6 3 9 11 18 5 listltintgt li(t t+7) li contient 1 6 3 9 11 18 5 liremove_if(est_paire) li contient maintenant 1 3 9 11 5

Remarques

1 La fonction membre remove ne fournit aucun reacutesultat de sorte quil nest pas possible de

savoir sil existait des eacuteleacutements reacutepondant aux conditions speacutecifieacutees Il est toujours possi-

ble de recourir auparavant agrave un algorithme tel que count pour obtenir cette information

2 Il existe une fonction membre unique dont la vocation est eacutegalement la suppression

deacuteleacutements cependant nous vous la preacutesenterons dans le paragraphe suivant consacreacute

agrave la fonction de tri (sort) car elle est souvent utiliseacutee conjointement avec la fonction

unique

Les conteneurs seacutequentielsCHAPITRE 19

428

43 Opeacuterations globales En plus des possibiliteacutes geacuteneacuterales offertes par laffectation et la fonction membre assign

deacutecrites au paragraphe 12 la classe list en offre dautres assez originales tri de ses eacuteleacutements

avec suppression eacuteventuelle des occurrences multiples fusion de deux listes preacutealablement

ordonneacutees transfert de tout ou partie dune liste dans une autre liste de mecircme type

431 Tri dune liste

Il existe des algorithmes de tri des eacuteleacutements dun conteneur mais la plupart neacutecessitent des

iteacuterateurs agrave accegraves direct En fait la classe list dispose de sa propre fonction sort eacutecrite speacuteci-

fiquement pour ce type de conteneur et relativement efficace puisquen O (Log N)

Comme tout ce qui touche agrave lordonnancement dun conteneur la fonction sort sappuie sur

une relation dordre faible strict telle quelle a eacuteteacute preacutesenteacutee dans le chapitre preacuteceacutedent On

pourra utiliser par deacutefaut lopeacuterateur lt y compris pour un type classe pour peu que cette der-

niegravere lait convenablement deacutefini On aura la possibiliteacute dans tous les cas dimposer une rela-

tion de son choix par le biais dun preacutedicat binaire preacutedeacutefini ou non

sort () trie la liste concerneacutee en sappuyant sur lopeacuterateur lt

listltintgt li() on suppose que li contient 1 6 3 9 11 18 5

lisort () maintenenant li contient 1 3 5 6 9 11 18

sort (preacutedicat) trie la liste concerneacutee en sappuyant sur le

preacutedicat binaire preacutedicat

listltintgt li() on suppose que li contient 1 6 3 9 11 18 5

lisort(greaterltintgt) maintenenant li contient 18 11 9 6 5 3 1

432 Suppression des eacuteleacutements en double

La fonction unique permet deacuteliminer les eacuteleacutements en double agrave condition de la faire porter

sur une liste preacutealablement trieacutee Dans le cas contraire elle peut fonctionner mais alors elle

se contente de remplacer par un seul eacuteleacutement les seacutequences de valeurs conseacutecutives identi-

ques ce qui signifie que en deacutefinitive la liste pourra encore contenir des valeurs identiques

mais non conseacutecutives

Comme on peut sy attendre cette fonction se fonde par deacutefaut sur lopeacuterateur == pour deacuteci-

der de leacutegaliteacute de deux eacuteleacutements cet opeacuterateur devant bien sucircr ecirctre deacutefini convenablement en

cas deacuteleacutements de type classe Mais on pourra aussi dans tous les cas imposer une relation de

comparaison de son choix par le biais dun preacutedicat binaire preacutedeacutefini ou non

On notera bien que si lon applique unique agrave une liste trieacutee deacuteleacutements de type classe il sera

preacutefeacuterable dassurer la compatibiliteacute entre la relation dordre utiliseacutee pour le tri (mecircme sil

sagit de lopeacuterateur lt) et le preacutedicat binaire deacutegaliteacute (mecircme sil sagit de ==) Plus preacuteciseacute-

ment pour obtenir un fonctionnement logique de lalgorithme il faudra que les classes

deacutequivalence induites par la relation == soient les mecircmes que celles qui sont induites par la

relation dordre du tri

4 - Le conteneur list429

unique() ne conserve que le premier eacuteleacutement drsquoune suite de valeurs

conseacutecutives eacutegales (==)

unique (preacutedicat) ne conserve que le premier eacuteleacutement drsquoune suite de valeurs

conseacutecutives satisfaisant au preacutedicat binaire preacutedicat

Voici un exemple qui montre clairement la diffeacuterence deffet obtenu suivant que la liste est

trieacutee ou non

int t[] = 1 6 6 4 6 5 5 4 2 listltintgt li1(t t+9) li1 contient 1 6 6 4 6 5 5 4 2 listltintgt li2=li1 li2 contient 1 6 6 4 6 5 5 4 2 li1unique() li1 contient maintenant 1 6 4 6 5 4 2 li2sort() li2 contient maintenant 1 2 4 4 5 5 6 6 6 li2unique() li2 contient maintenant 1 2 4 5 6

433 Fusion de deux listesBien quil existe un algorithme geacuteneacuteral de fusion pouvant sappliquer agrave deux conteneurs con-

venablement trieacutes la classe list dispose dune fonction membre speacutecialiseacutee geacuteneacuteralement

leacutegegraverement plus performante mecircme si dans les deux cas lefficaciteacute est en O(N1+N2) N1 et

N2 deacutesignant le nombre deacuteleacutements de chacune des listes concerneacutees

La fonction membre merge permet de venir fusionner une autre liste de mecircme type avec la

liste concerneacutee La liste fusionneacutee est videacutee de son contenu Comme on peut sy attendre la

fonction merge sappuie comme sort sur une relation dordre faible strict par deacutefaut il

sagira de lopeacuterateur lt

merge (liste) fusionne liste avec la liste concerneacutee en sappuyant sur

lrsquoopeacuterateur gt agrave la fin liste est vide

merge (liste preacutedicat) fusionne liste avec la liste concerneacutee

en srsquoappuyant sur le preacutedicat binaire preacutedicat

On notera quen theacuteorie aucune contrainte ne pegravese sur lordonnancement des deux listes con-

cerneacutees Cependant la fonction merge suppose que les deux listes sont trieacutees suivant la mecircme

relation dordre que celle qui est utiliseacutee par la fusion Voici un premier exemple dans lequel

nous avons preacutealablement trieacute les deux listes

int t1[] = 1 6 3 9 11 18 5 int t2[] = 12 4 9 8 listltintgt li1(t1 t1+7) listltintgt li2(t2 t2+4) li1sort() li1 contient 1 3 5 6 9 11 18 li2sort() li2 contient 4 8 9 12 li1merge(li2) li1 contient maintenant 1 3 4 5 6 8 9 9 11 12 18 et li2 est vide

A simple titre indicatif voici le mecircme exemple sans tri preacutealable des deux listes

int t1[] = 1 6 3 9 11 18 5 int t2[] = 12 4 9 8 listltintgt li1(t1 t1+7) li1 contient 1 6 3 9 11 18 5 listltintgt li2(t2 t2+4) li2 contient 12 4 9 8 li1merge(li2) li1 contient maintenant 1 6 3 9 11 12 4 9 8 18 5 et li2 est vide

Les conteneurs seacutequentielsCHAPITRE 19

430

434 Transfert dune partie de liste dans une autreLa fonction splice permet de deacuteplacer des eacuteleacutements dune autre liste dans la liste concerneacutee

On notera bien comme avec merge les eacuteleacutements deacuteplaceacutes sont supprimeacutes de la liste dorigine

et pas seulement copieacutes

splice (position liste_or) deacuteplace les eacuteleacutements de liste_or agrave

lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il il = li1begin() il++ il pointe sur le deuxiegraveme eacuteleacutement de li1 li1splice(il li2) li1 contient x a b c d e f y z li2 est vide

splice (position liste_or position_or)

deacuteplace leacuteleacutement de liste_or pointeacute par position_or agrave lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il1=li1begin() listltchargtiterator il2=li2end() il2-- pointe sur avant dernier li1splice(il1 li2 il2) li1 contient f x y z li2 contient a b c d e

splice (position liste_or debut_or fin_or)

deacuteplace lintervalle [debut_or fin_or) de liste_or agrave lemplacement position

char t1[] = xyz t2[] = abcdef listltchargt li1(t1 t1+3) li1 contient x y z listltchargt li2(t2 t2+6) li2 contient a b c d e f listltchargtiterator il1=li1begin() listltchargtiterator il2=li2begin() il2++ li1splice(il1 li2 il2 li2end()) li1 contient b c d e f x y z li2 contient a

44 Gestion de lemplacement meacutemoire La norme nimpose pas explicitement la maniegravere de geacuterer les emplacements meacutemoire alloueacutes

agrave une liste pas plus quelle ne le fait pour les autres conteneurs Cependant elle impose agrave la

fois des contraintes defficaciteacute et des regravegles dinvalidation des iteacuterateurs et des reacutefeacuterences sur

des eacuteleacutements dune liste Notamment elle preacutecise quen cas dinsertions ou de suppressions

deacuteleacutements dans une liste seuls les iteacuterateurs ou reacutefeacuterences concernant les eacuteleacutements inseacutereacutes ou

supprimeacutes deviennent invalides Cela signifie donc que les autres nont pas ducirc changer de

place Ainsi indirectement la norme impose que chaque eacuteleacutement dispose de son propre bloc

de meacutemoire

Dans ces conditions si le conteneur list dispose toujours des fonctions dinformation size() et

max_size() on ny retrouve en revanche aucune fonction permettant dagir sur les allocations

et en particulier capacity et reserve

4 - Le conteneur list431

45 Exemple Voici un exemple complet de programme illustrant bon nombre des fonctionnaliteacutes de la

classe list que nous avons examineacutees dans ce paragraphe ainsi que dans le paragraphe 1

include ltiostreamgt

include ltlistgt

using namespace std

main()

void affiche(listltchargt)

char mot[] = anticonstitutionnellement

listltchargt lc1 (mot mot+sizeof(mot)-1)

listltchargt lc2

cout ltlt lc1 init affiche(lc1)

cout ltlt lc2 init affiche(lc2)

listltchargtiterator il1 il2

il2 = lc2begin()

for (il1=lc1begin() il1=lc1end() il1++)

if (il1=t) lc2push_back(il1) equivaut a lc2=lc1

lc2remove(t)

cout ltlt lc2 apres affiche(lc2)

lc1remove(t)

cout ltlt lc1 remove affiche(lc1)

if (lc1==lc2) cout ltlt les deux listes sont egalesn

lc1sort()

cout ltlt lc1 sort affiche(lc1)

lc1unique()

cout ltlt lc1 unique affiche(lc1)

void affiche(listltchargt lc) voir remarque paragraphe 24

listltchargtiterator il

for (il=lcbegin() il=lcend() il++) cout ltlt (il) ltlt

cout ltlt 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

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

Exemple dutilisation de la classe list

Les conteneurs seacutequentielsCHAPITRE 19

432

5 Les adaptateurs de conteneur queue stack et priority_queue

La bibliothegraveque standard dispose de trois patrons particuliers stack queue et priority_queue

dits adaptateurs de conteneurs Il sagit de classes patrons construites sur un conteneur dun

type donneacute qui en modifient linterface agrave la fois en la restreignant et en ladaptant agrave des fonc-

tionnaliteacutes donneacutees Ils disposent tous dun constructeur sans argument

51 Ladaptateur stack Le patron stack est destineacute agrave la gestion de piles de type LIFO (Last In First Out) il peut ecirctre

construit agrave partir de lun des trois conteneurs seacutequentiels vector deque ou list comme dans

ces deacuteclarations

stack ltint vectorltintgt gt s1 pile de int utilisant un conteneur vector stack ltint dequeltintgt gt s2 pile de int utilisant un conteneur deque

stack ltint listltintgt gt s3 pile de int utilisant un conteneur list

Dans un tel conteneur on ne peut quintroduire (push) des informations quon empile les unes

sur les autres et quon recueille agrave raison dune seule agrave la fois en extrayant la derniegravere intro-

duite On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la pile est vide

bull size() fournit le nombre deacuteleacutements de la pile

bull top() accegraves agrave linformation situeacutee au sommet de la pile quon peut connaicirctre ou modifier

(sans la supprimer)

bull push (valeur) place valeur sur la pile

bull pop() fournit la valeur de leacuteleacutement situeacute au sommet en le supprimant de la pile

Voici un petit exemple de programme utilisant une pile

include ltiostreamgtinclude ltstackgt

include ltvectorgtusing namespace std main()

int i stackltint vectorltintgt gt q cout ltlt taille initiale ltlt qsize() ltlt n for (i=0 ilt10 i++) qpush(ii)

cout ltlt taille apres for ltlt qsize() ltlt n cout ltlt sommet de la pile ltlt qtop() ltlt n qtop() = 99 on modifie le sommet de la pile cout ltlt on depile

for (i=0 ilt10 i++) cout ltlt qtop() ltlt qpop()

5 - Les adaptateurs de conteneur queue stack et priority_queue433

taille initiale 0taille apres for 10sommet de la pile 81on depile 99 64 49 36 25 16 9 4 1 0

Exemple dutilisation de ladaptateur de conteneur stack

52 Ladaptateur queue Le patron queue est destineacute agrave la gestion de files dattentes dites aussi queues ou encore piles

de type FIFO (First In First Out) On y place des informations quon introduit en fin et quon

recueille en tecircte dans lordre inverse de leur introduction Un tel conteneur peut ecirctre construit

agrave partir de lun des deux conteneurs seacutequentiels deque ou list (le conteneur vector ne serait

pas approprieacute puisquil ne dispose pas dinsertions efficaces en deacutebut) comme dans ces

deacuteclarations

queue ltint dequeltintgt gt q1 queue de int utilisant un conteneur deque queue ltint listltintgt gt q2 queue de int utilisant un conteneur list

On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la queue est vide

bull size() fournit le nombre deacuteleacutements de la queue

bull front() accegraves agrave linformation situeacutee en tecircte de la queue quon peut ainsi connaicirctre ou modi-

fier sans la supprimer

bull back() accegraves agrave linformation situeacutee en fin de la queue quon peut ainsi connaicirctre ou modi-

fier sans la supprimer

bull push (valeur) place valeur dans la queue

bull pop() fournit leacuteleacutement situeacute en tecircte de la queue en le supprimant

Voici un petit exemple de programme utilisant une queue

include ltiostreamgtinclude ltqueuegtinclude ltdequegtusing namespace std main() int i queueltint dequeltintgt gt q for (i=0 ilt10 i++) qpush(ii) cout ltlt tete de la queue ltlt qfront() ltlt n cout ltlt fin de la queue ltlt qback() ltlt n qfront() = 99 on modifie la tete de la queue qback() = -99 on modifie la fin de la queue cout ltlt on depile la queue for (i=0 ilt10 i++) cout ltlt qfront() ltlt qpop()

Les conteneurs seacutequentielsCHAPITRE 19

434

tete de la queue 0fin de la queue 81on depile la queue 99 1 4 9 16 25 36 49 64 -99

Exemple dutilisation de ladaptateur de conteneur stack

53 Ladaptateur priority_queue Un tel conteneur ressemble agrave une file dattente dans laquelle on introduit toujours des eacuteleacute-

ments en fin en revanche lemplacement des eacuteleacutements dans la queue est modifieacute agrave chaque

introduction de maniegravere agrave respecter une certaine prioriteacute deacutefinie par une relation dordre

quon peut fournir sous forme dun preacutedicat binaire On parle parfois de file dattente avec

prioriteacutes Un tel conteneur ne peut ecirctre construit quagrave partir dun conteneur deque comme

dans ces deacuteclarations

priority_queue ltint dequeltintgt gt q1 priority_queue ltint dequeltintgt greaterltintgt gt q2

En revanche ici on peut le construire classiquement agrave partir dune seacutequence

On y trouve uniquement les fonctions membres suivantes

bull empty() fournit true si la queue est vide

bull size() fournit le nombre deacuteleacutements de la queue

bull push (valeur) place valeur dans la queue

bull top() accegraves agrave linformation situeacutee en tecircte de la queue quon peut connaicirctre ou theacuteorique-

ment modifier (sans la supprimer) actuellement nous recommandons de ne pas utiliser la

possibiliteacute de modification qui dans certaines impleacutementations nassure plus le respect de

lordre des eacuteleacutements de la queue

bull pop() fournit leacuteleacutement situeacute en tecircte de la queue en le supprimant

Voici un petit exemple de programme utilisant une file dattente avec prioriteacutes

include ltiostreamgtinclude ltqueuegtinclude ltdequegtusing namespace std main() int i priority_queue ltint dequeltintgt greaterltintgt gt q qpush (10) qpush(5) qpush(12) qpush(8) cout ltlt tete de la queue ltlt qtop() ltlt n cout ltlt on depile for (i=0 ilt4 i++) cout ltlt qtop() ltlt qpop()

5 - Les adaptateurs de conteneur queue stack et priority_queue435

tete de la queue 5on depile 5 8 10 12

Exemple dutilisation de ladaptateur de conteneur priority_queue

20

Les conteneurs associatifs

Comme il a eacuteteacute dit au chapitre 18 les conteneurs se classent en deux cateacutegories les conte-

neurs seacutequentiels et les conteneurs associatifs Les conteneurs seacutequentiels que nous avons

eacutetudieacutes dans le preacuteceacutedent chapitre sont ordonneacutes suivant un ordre imposeacute explicitement par

le programme lui-mecircme on accegravede agrave un de leurs eacuteleacutements en tenant compte de cet ordre que

lon utilise un indice ou un iteacuterateur

Les conteneurs associatifs ont pour principale vocation de retrouver une information non

plus en fonction de sa place dans le conteneur mais en fonction de sa valeur ou dune partie

de sa valeur nommeacutee cleacute Nous avons deacutejagrave citeacute lexemple du reacutepertoire teacuteleacutephonique dans

lequel on retrouve le numeacutero de teacuteleacutephone agrave partir dune cleacute formeacutee du nom de la personne

concerneacutee Malgreacute tout pour de simples questions defficaciteacute un conteneur associatif se

trouve ordonneacute intrinsegravequement en permanence en se fondant sur une relation (par deacutefaut lt)

choisie agrave la construction

Les deux conteneurs associatifs les plus importants sont map et multimap Ils correspondent

pleinement au concept de conteneur associatif en associant une cleacute et une valeur Mais alors

que map impose luniciteacute des cleacutes autrement dit labsence de deux eacuteleacutements ayant la mecircme

cleacute multimap ne limpose pas et on pourra y trouver plusieurs eacuteleacutements de mecircme cleacute qui

apparaicirctront alors conseacutecutivement Si lon reprend notre exemple de reacutepertoire teacuteleacutephonique

on peut dire que multimap autorise la preacutesence de plusieurs personnes de mecircme nom (avec

des numeacuteros associeacutes diffeacuterents ou non) tandis que map ne lautorise pas Cette distinction

permet preacuteciseacutement de redeacutefinir lopeacuterateur [ ] sur un conteneur de type map Par exemple

avec un conteneur nommeacute annuaire dans lequel les cleacutes sont des chaicircnes on pourra utiliser

lexpression annuaire [Dupont] pour deacutesigner leacuteleacutement correspondant agrave la cleacute Dupont

cette possibiliteacute nexistera naturellement plus avec multimap

Les conteneurs associatifsCHAPITRE 20

438

Il existe deux autres conteneurs qui correspondent agrave des cas particuliers de map et multimap

dans le cas ougrave la valeur associeacutee agrave la cleacute nexiste plus ce qui revient agrave dire que les eacuteleacutements se

limitent agrave la seule cleacute Dans ces conditions la notion dassociation entre une cleacute et une valeur

disparaicirct et il ne reste plus que la notion dappartenance Ces conteneurs se nomment set et

multiset et lon verra queffectivement ils permettront de repreacutesenter des ensembles au sens

matheacutematique agrave condition toutefois de disposer comme pour tout conteneur associatif dune

relation dordre approprieacutee sur les eacuteleacutements ce qui nest pas neacutecessaire en matheacutematiques en

outre multiset autorisera la preacutesence de plusieurs eacuteleacutements identiques ce qui nest manifeste-

ment pas le cas dun ensemble usuel

1 Le conteneur map Le conteneur map est donc formeacute deacuteleacutements composeacutes de deux parties une cleacute et une

valeur Pour repreacutesenter de tels eacuteleacutements il existe un patron de classe approprieacute nommeacute pair

parameacutetreacute par le type de la cleacute et par celui de la valeur Un conteneur map permet dacceacuteder

rapidement agrave la valeur associeacutee agrave une cleacute en utilisant lopeacuterateur [] lefficaciteacute de lopeacuteration

est en O(Log N) Comme un tel conteneur est ordonneacute en permanence cela suppose le

recours agrave une relation dordre qui comme agrave laccoutumeacutee doit posseacuteder les proprieacuteteacutes dune

relation dordre faible strict telles quelles ont eacuteteacute preacutesenteacutees au paragraphe 62 du chapitre

18

Comme la notion de tableau associatif est moins connue que celle de tableau de vecteur ou

mecircme que celle de liste nous commencerons par un exemple introductif dutilisation dun

conteneur de type map avant den eacutetudier les proprieacuteteacutes en deacutetail

11 Exemple introductif Une deacuteclaration telle que

mapltchar intgt m

creacutee un conteneur de type map dans lequel les cleacutes sont de type char et les valeurs associeacutees

de type int Pour linstant ce conteneur est vide msize() vaut 0

Une instruction telle que

m[S] = 5

insegravere dans le conteneur m un eacuteleacutement formeacute de lassociation de la cleacute S et de la valeur 5

On voit deacutejagrave lagrave une diffeacuterence fondamentale entre un vecteur et un conteneur de type map

dans un vecteur on ne peut acceacuteder par lopeacuterateur [ ] quaux eacuteleacutements existants et en aucun

cas en inseacuterer de nouveaux

Qui plus est si lon cherche agrave utiliser une valeur associeacutee agrave une cleacute inexistante comme dans

cout ltlt valeur associeacutee a la cleacute X m[X]

le simple fait de chercher agrave consulter m[X] creacuteera leacuteleacutement correspondant en initialisant la

valeur associeacutee agrave 0

1 - Le conteneur map439

Pour afficher tous les eacuteleacutements dun map tel que m on pourra le parcourir avec un iteacuterateur

bidirectionnel classique iterator fourni par la classe map Ceci nest possible que parce que

comme nous lavons dit agrave plusieurs reprises les conteneurs associatifs sont ordonneacutes intrinsegrave-

quement On pourra classiquement parcourir tous les eacuteleacutements de m par lun des deux scheacute-

mas suivants

mapltchar intgt iterator im iteacuterateur sur un mapltcharintgt for (im=mbegin() im=mend() im++) im parcourt tout le map m ici im deacutesigne leacuteleacutement courant de m

mapltchar intgt reverse_iterator im iteacuterateur inverse sur un mapltcharintgt for (im=mrbegin() im=mrend() im++) im parcourt tout le map m ici im deacutesigne leacuteleacutement courant de m

Cependant on constate quune petite difficulteacute apparaicirct im deacutesigne bien leacuteleacutement courant

de m mais la plupart du temps on aura besoin dacceacuteder seacutepareacutement agrave la cleacute et agrave la valeur

correspondante En fait les eacuteleacutements dun conteneur map sont dun type classe particulier

nommeacute pair qui dispose de deux membres publics

bull first correspondant agrave la cleacute

bull second correspondant agrave la valeur associeacutee

En deacutefinitive voici par exemple comment afficher suivant lordre naturel toutes les valeurs

de m sous la forme (cleacute valeur)

for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt )

Voici un petit programme complet reprenant les diffeacuterents points que nous venons dexaminer

(attention la position relative de la cleacute c peut deacutependre de limpleacutementation)

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche (mapltchar intgt) mapltchar intgt m cout ltlt map initial affiche(m) m[S] = 5 la cle S nexiste pas encore lelement est cree m[C] = 12 idem cout ltlt map SC affiche(m) cout ltlt valeur associee a la cle S ltlt m[S] ltlt n cout ltlt valeur associee a la cle X ltlt m[X] ltlt n cout ltlt map X affiche(m) m[S] = m[c] on a utilise m[c] au lieu de m[C] la cle c est creee cout ltlt map final affiche(m)

Les conteneurs associatifsCHAPITRE 20

440

void affiche (mapltchar intgt m) voir remarque paragraphe 24 du chapitre 19 mapltchar intgt iterator im for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt ) cout ltlt n

map initial map SC (C12) (S5)valeur associee a la cle S 5valeur associee a la cle X 0map X (C12) (S5) (X0)map final (C12) (S0) (X0) (c0)

Exemple introductif dutilisation dun conteneur map

12 Le patron de classes pair Comme nous venons de le voir il existe un patron de classe pair comportant deux paramegrave-

tres de type et permettant de regrouper dans un objet deux valeurs On y trouve un construc-

teur agrave deux arguments

pair ltint floatgt p(3 125) creacutee une paire formeacutee dun int de valeur 3 et dun float de valeur 125

Pour affecter des valeurs donneacutees agrave une telle paire on peut theacuteoriquement proceacuteder comme

dans

p = pairltintfloatgt (4 335) ici les arguments peuvent ecirctre dun type compatible par affectation avec celui attendu

Mais les choses sont un peu plus simples si lon fait appel agrave une fonction standard

make_pair

p = make_pair (4 335f) attention 335f car le type des arguments sert agrave instancier la fonction patron make_pair

Comme on la vu dans notre exemple introductif la classe pair dispose de deux membres

publics nommeacutes first et second Ainsi linstruction preacuteceacutedente pourrait eacutegalement seacutecrire

pfirst = 4 psecond = 335 ici 335 (double) sera converti en float

La classe pair dispose des deux opeacuterateurs == et lt Le second correspond agrave une comparaison

lexicographique crsquoest-agrave-dire quil applique dabord lt agrave la cleacute puis agrave la valeur Bien entendu

dans le cas ougrave lun des eacuteleacutements au moins de la paire est de type classe ces opeacuterateurs doivent

ecirctre convenablement surdeacutefinis

13 Construction dun conteneur de type map Les possibiliteacutes de construction dun tel conteneur sont beaucoup plus restreintes que pour les

conteneurs seacutequentiels elles se limitent agrave trois possibiliteacutes

bull construction dun conteneur vide (comme dans notre exemple du paragraphe 11)

1 - Le conteneur map441

bull construction agrave partir dun autre conteneur de mecircme type

bull construction agrave partir dune seacutequence

En outre il est possible de choisir la relation dordre qui sera utiliseacutee pour ordonner intrinsegrave-

quement le conteneur Pour plus de clarteacute nous examinerons ce point agrave part

131 Constructions utilisant la relation dordre par deacutefaut

Construction dun conteneur vide

On se contente de preacuteciser les types voulus pour la cleacute et pour la valeur comme dans ces

exemples (on suppose que point est un type classe)

map ltint longgt m1 cleacutes de type int valeurs de type long map ltchar pointgt m2 cleacutes de type char valeurs de type point map ltstring longgt repert cleacutes de type string valeurs de type long

Construction agrave partir dun autre conteneur de mecircme type

Il sagit dun classique constructeur par recopie qui comme on peut sy attendre appelle le

constructeur par recopie des eacuteleacutements concerneacutes lorsquil sagit dobjets

map ltint longgt m1 map ltint longgt m2(m1) ou encore map ltint longgt m2 = m1

Construction agrave partir dune seacutequence

Il sagit dune possibiliteacute deacutejagrave rencontreacutee pour les conteneurs seacutequentiels avec cependant une

diffeacuterence importante les eacuteleacutements concerneacutes doivent ecirctre de type pairlttype_des_cleacutes

type_des_valeursgt Par exemple sil existe une liste lr construite ainsi

listltpairltchar longgt gt lr ()

et convenablement remplie on pourra lutiliser en partie ou en totaliteacute pour construire

map ltchar longgt repert (lrbegin() lrend() )

En pratique ce type de construction est peu utiliseacute

132 Choix de lordre intrinsegraveque du conteneur

Comme on la deacutejagrave dit les conteneurs sont intrinsegravequement ordonneacutes en faisant appel agrave une

relation dordre faible strict pour ordonner convenablement les cleacutes Par deacutefaut on utilise la

relation lt quil sagisse de la relation preacutedeacutefinie pour les types scalaires ou string ou dune

surdeacutefinition de lopeacuterateur gt lorsque les cleacutes sont des objets

Il est possible dimposer agrave un conteneur decirctre ordonneacute en utilisant une autre relation que lon

fournit sous forme dun preacutedicat binaire preacutedeacutefini (comme lessltintgt) ou non Dans ce dernier

cas il est alors neacutecessaire de fournir un type et non pas un nom de fonction ce qui signifie

quil est neacutecessaire de recourir agrave une classe fonction (dont nous avons parleacute au paragraphe 53

du chapitre 18) Voici quelques exemples

map ltchar long greaterltchargt gt m1 les cleacutes seront ordonneacutees par valeurs deacutecroissantes - attention gt gt et non gtgt map ltchar long greaterltchargt gt m2(m1) si m2 nest pas ordonneacute par la mecircme relation on obtient une erreur de compilation

Les conteneurs associatifsCHAPITRE 20

442

class mon_ordre public bool operator () (int n int p) ordre faible strict map ltint float mon_ordregt m_perso cleacutes ordonneacutees par le preacutedicat mon_ordre qui doit ecirctre une classe fonction

Remarque

Certaines impleacutementations peuvent ne pas accepter le choix dune valeur par deacutefaut pour

la relation dordre des cleacutes Dans ce cas il faut toujours preacuteciser lesslttypegt comme troi-

siegraveme argument type correspondant au type des cleacutes pour instancier convenablement le

conteneur La lourdeur des notations qui en deacutecoule peut parfois inciter agrave recourir agrave lins-

truction typedef

133 Pour connaicirctre la relation dordre utiliseacutee par un conteneurLes classes map disposent dune fonction membre key_comp() fournissant la fonction utiliseacutee

pour ordonner les cleacutes Par exemple avec le conteneur de notre exemple introductif

mapltchar intgt m

on peut certes comparer deux cleacutes de type char de faccedilon directe comme dans

if (a lt c)

mais on obtiendra le mecircme reacutesultat avec

if mkey_comp() (a c) notez bien key_comp() ()

Certes tant que lon se contente dordonner de tels conteneurs en utilisant la relation dordre

par deacutefaut ceci ne preacutesente guegravere dinteacuterecirct dans le cas contraire cela peut eacuteviter davoir agrave se

demander agrave chaque fois quon compare des cleacutes quelle relation dordre a eacuteteacute utiliseacutee lors de

la construction

Dune maniegravere similaire la classe map dispose dune fonction membre value_comp() fournis-

sant la fonction utilisable pour comparer deux eacuteleacutements toujours selon la valeur des cleacutes

Linteacuterecirct de cette fonction est de permettre de comparer deux eacuteleacutements (donc deux paires)

suivant lordre des cleacutes sans avoir agrave en extraire les membres first On notera bien que con-

trairement agrave key_comp cette fonction nest jamais choisie librement elle est simplement

deacuteduite de key_comp Par exemple avec

map ltchar intgt m map ltchar intgtiterator im1 im2

on pourra comparer les cleacutes relatives aux eacuteleacutements pointeacutes par im1 et im2 de cette maniegravere

if ( value_comp() (im1 im2) )

Avec key_comp il aurait fallu proceacuteder ainsi

if ( key_comp() ( (im1)first (im2)first) )

1 - Le conteneur map443

134 Conseacutequences du choix de lordre dun conteneur

Tant que lon utilise des cleacutes de type scalaire ou string et quon se limite agrave la relation par

deacutefaut (lt) aucun problegraveme particulier ne se pose Il nen va plus neacutecessairement de mecircme

dans les autres cas

Par exemple on dit geacuteneacuteralement que dans un conteneur de type map les cleacutes sont uniques

En fait pour ecirctre plus preacutecis il faudrait dire quun nouvel eacuteleacutement nest introduit dans un tel

conteneur que sil nexiste pas dautre eacuteleacutement posseacutedant une cleacute eacutequivalente leacutequivalence

eacutetant celle qui est induite par la relation dordre tel quil a eacuteteacute expliqueacute au paragraphe 62 du

chapitre 18 Par exemple consideacuterons un map utilisant comme cleacute des objets de type point et

supposons que la relation lt ait eacuteteacute deacutefinie dans la classe point en sappuyant uniquement sur

les abscisses des points dans ces conditions les cleacutes correspondant agrave des points de mecircme

abscisse apparaicirctront comme eacutequivalentes

De plus comme on aura loccasion de le voir plus loin la recherche dun eacuteleacutement de cleacute don-

neacutee se fondera non pas sur une hypotheacutetique relation deacutegaliteacute mais bel et bien sur la relation

dordre utiliseacutee pour ordonner le conteneur Autrement dit toujours avec notre exemple de

points utiliseacutes en guise de cleacutes on pourra rechercher la cleacute (1 9) et trouver la cleacute (1 5)

14 Accegraves aux eacuteleacutements Comme tout conteneur map permet theacuteoriquement dacceacuteder aux eacuteleacutements existants soit

pour en connaicirctre la valeur soit pour la modifier Cependant par rapport aux conteneurs

seacutequentiels ces opeacuterations prennent un tour un peu particulier lieacute agrave la nature mecircme des conte-

neurs associatifs En effet dune part une tentative daccegraves agrave une cleacute inexistante amegravene agrave la

creacuteation dun nouvel eacuteleacutement dautre part comme on le verra un peu plus loin une tentative

de modification globale (cleacute + valeur) dun eacuteleacutement existant sera fortement deacuteconseilleacutee

141 Accegraves par lopeacuterateur [ ]

Le paragraphe 1 a deacutejagrave montreacute en quoi cet accegraves par lopeacuterateur est ambigu puisquil peut con-

duire agrave la creacuteation dun nouvel eacuteleacutement degraves lors quon lapplique agrave une cleacute inexistante et cela

aussi bien en consultation quen modification Par exemple

mapltchar intgt m m [S] = 2 si la cleacute S nexiste pas on creacutee lrsquoeacuteleacutement make_pair (S 2) si la cleacute existe on modifie la valeur de leacuteleacutement qui ne change pas de place = m[T] si la cleacute T nexiste pas on creacutee leacuteleacutement make_pair (T 0)

142 Accegraves par iteacuterateur

Comme on peut sy attendre et comme on la deacutejagrave fait dans les exemples preacuteceacutedents si it est

un iteacuterateur valide sur un conteneur de type map lexpression it deacutesigne leacuteleacutement

correspondant rappelons quil sagit dune paire formeacutee de la cleacute (it)first et de la valeur

Les conteneurs associatifsCHAPITRE 20

444

associeacutee (it)second en geacuteneacuteral dailleurs on sera plutocirct ameneacute agrave sinteacuteresser agrave ces deux

derniegraveres valeurs (ou agrave lune dentre elles) plutocirct quagrave la paire complegravete it

En theacuteorie il nest pas interdit de modifier la valeur de leacuteleacutement deacutesigneacute par it par exemple

pour un conteneur de type mapltchar intgt on pourrait eacutecrire

it = make_pair (R 5) remplace theacuteoriquement leacuteleacutement deacutesigneacute par ip

fortement deacuteconseilleacute en pratique

Mais le rocircle exact dun telle opeacuteration nest actuellement pas totalement speacutecifieacute par la norme

Or certaines ambiguiumlteacutes apparaissent En effet dune part comme une telle opeacuteration modi-

fie la valeur de la cleacute le nouvel eacuteleacutement risque de ne plus ecirctre agrave sa place il devrait donc ecirctre

deacuteplaceacute dautre part que doit-il se passer si la cleacute R existe deacutejagrave La seule deacutemarche raison-

nable nous semble ecirctre de dire quune telle modification devrait ecirctre eacutequivalente agrave une des-

truction de leacuteleacutement deacutesigneacute par it suivie dune insertion du nouvel eacuteleacutement En pratique ce

nest pas ce que lon constate dans toutes les impleacutementations actuelles Dans ces conditions

Il est fortement deacuteconseilleacute de modifier la valeur dun eacuteleacutement dun map par le biais

dun iteacuterateur

143 Recherche par la fonction membre find

La fonction membre

find (cleacute)

a un rocircle naturel fournir un iteacuterateur sur un eacuteleacutement ayant une cleacute donneacutee (ou une cleacute eacutequi-

valente au sens de la relation dordre utiliseacutee par le conteneur) Si aucun eacuteleacutement nest trouveacute

cette fonction fournit la valeur end()

Remarque

Attention la fonction find ne se base pas sur lopeacuterateur == cette remarque est surtout

sensible lorsque lon a affaire agrave des eacuteleacutements de type classe classe dans laquelle on a sur-

deacutefini lopeacuterateur == de maniegravere incompatible avec le preacutedicat binaire utiliseacute pour ordon-

ner le conteneur Les reacutesultats peuvent alors ecirctre deacuteconcertants

15 Insertions et suppressions Comme on peut sy attendre le conteneur map offre des possibiliteacutes de modifications dyna-

miques fondeacutees sur des insertions et des suppressions analogues agrave celles qui sont offertes par

les conteneurs seacutequentiels Toutefois si la notion de suppression dun eacuteleacutement deacutesigneacute par un

iteacuterateur conserve la mecircme signification celle dinsertion agrave un emplacement donneacute na plus

guegravere de raison decirctre puisquon ne peut plus agir sur la maniegravere dont sont intrinsegravequement

ordonneacutes les eacuteleacutements dun conteneur associatif On verra quil existe quand mecircme une fonc-

tion dinsertion recevant un tel argument mais que ce dernier a en fait un rocircle un peu particu-

lier

1 - Le conteneur map445

En outre alors quune insertion dans un conteneur seacutequentiel aboutissait toujours dans le cas

dun conteneur de type map elle naboutit que sil nexiste pas deacuteleacutement de cleacute eacutequivalente

Dune maniegravere geacuteneacuterale lefficaciteacute de ces opeacuterations est en O(Log N) Nous apporterons

quelques preacutecisions par la suite pour chacune des opeacuterations

151 InsertionsLa fonction membre insert permet dinseacuterer

bull un eacuteleacutement de valeur donneacutee

insert (eacuteleacutement) insegravere la paire eacuteleacutement

bull les eacuteleacutements dun intervalle

insert (deacutebut fin) insegravere les paires de la seacutequence [deacutebut fin)

On notera bien dans les deux cas que les eacuteleacutements concerneacutes doivent ecirctre des paires dun

type approprieacute

Lefficaciteacute de la premiegravere fonction est en O(Log N) celle de la seconde est en

O(Log(N+M)) M deacutesignant le nombre deacuteleacutements de lintervalle Toutefois si cet intervalle

est trieacute suivant lordre voulu lefficaciteacute est en O(M)

Voici quelques exemples

mapltint floatgt m1 m2 mapltint floatgtiterator im1 m1insert (make_pair(5 625f)) tentative dinsertion dun eacuteleacutement m1insert (m2begin() m2end()) tentative dinsertion dune seacutequence

Remarques

1 En toute rigueur il existe une troisiegraveme version de insert de la forme

insert (position paire)

Liteacuterateur position est une suggestion qui est faite pour faciliter la recherche de

lemplacement exact dinsertion Si la valeur fournie correspond exactement au point

dinsertion on obtient alors une efficaciteacute en O(1) ce qui sexplique par le fait que la

fonction na besoin que de comparer deux valeurs conseacutecutives

2 Les deux fonctions dinsertion dun eacuteleacutement fournissent une valeur de retour qui est une

paire de la forme pair(position indic) dans laquelle le booleacuteen indic preacutecise si linser-

tion a eu lieu et position est liteacuterateur correspondant on notera que son utilisation est

assez laborieuse voici par exemple comment adapter notre preacuteceacutedent exemple dans

ce sens

if(m1insert(make_pair(5 625f))second) cout ltlt insertion effectueacuteen else cout ltlt eacuteleacutement existantn

Les conteneurs associatifsCHAPITRE 20

446

Et encore ici nous navons pas chercheacute agrave placer la valeur de retour dans une variable

Si nous avions voulu le faire il aurait fallu deacuteclarer une variable par exemple resul

dun type pair approprieacute de plus comme pair ne dispose pas de constructeur par

deacutefaut il aurait fallu preacuteciser des arguments fictifs voici une deacuteclaration possible

pairltmapltintfloatgtiterator boolgt resul(m1end()false)

Dans les impleacutementations qui nacceptent pas la valeur lesslttypegt par deacutefaut les cho-

ses seraient encore un peu plus complexes et il serait probablement plus sage de recou-

rir agrave des deacutefinitions de types synonymes (typedef ) pour alleacuteger quelque peu leacutecriture

152 Suppressions

La fonction erase permet de supprimer

bull un eacuteleacutement de position donneacutee

erase (position) supprime leacuteleacutement deacutesigneacute par position

bull les eacuteleacutements dun intervalle

erase (deacutebut fin) supprime les paires de lintervalle [deacutebut fin)

bull leacuteleacutement de cleacute donneacutee

erase (cleacute) supprime les eacuteleacutements1 de cleacute eacutequivalente agrave cleacute

En voici quelques exemples

mapltint floatgt m mapltint floatgtiterator im1 im2 merase (5) supprime leacuteleacutement de cleacute 5 sil existe merase (im1) supprime leacuteleacutement deacutesigneacute par im1 merase (im2 mend()) supprime tous les eacuteleacutements depuis celui deacutesigneacute par im2 jusquagrave la fin du conteneur m

Enfin de faccedilon fort classique la fonction clear() vide le conteneur de tout son contenu

Remarque

Il peut arriver que lon souhaite supprimer tous les eacuteleacutements dont la cleacute appartient agrave un

intervalle donneacute Dans ce cas on pourra avoir recours aux fonctions lower_bound et

upper_bound preacutesenteacutees au paragraphe 2

16 Gestion meacutemoire Contrairement agrave ce qui se passe pour certains conteneurs seacutequentiels les opeacuterations sur les

conteneurs associatifs donc en particulier sur map nentraicircnent jamais dinvalidation des

1 Pour map il y en aura un au plus pour multimap on pourra en trouver plusieurs

1 - Le conteneur map447

reacutefeacuterences et des iteacuterateurs excepteacute bien entendu pour les eacuteleacutements supprimeacutes qui ne sont

plus accessibles apregraves leur destruction

Toutefois comme on la indiqueacute au paragraphe 14 il est theacuteoriquement possible bien que

fortement deacuteconseilleacute de modifier globalement un eacuteleacutement de position donneacutee par exemple

(iv deacutesignant un iteacuterateur valide sur un conteneur de type mapltchar intgt)

iv = make_pair (S 45)

Que la cleacute S soit preacutesente ou non on court outre les risques deacutejagrave eacutevoqueacutes celui que liteacutera-

teur iv devienne invalide

17 Autres possibiliteacutes Les manipulations globales des conteneurs map se limitent agrave la seule affectation et agrave la fonc-

tion swap permettant deacutechanger les contenus de deux conteneurs de mecircme type Il nexiste

pas de fonction assign ni de possibiliteacutes de comparaisons lexicographiques auxquelles il

serait difficile de donner une signification en effet dune part les eacuteleacutements sont des paires

dautre part un tel conteneur est ordonneacute intrinsegravequement et son organisation eacutevolue en per-

manence

En theacuteorie il existe des fonctions membres lower_bound upper_bound equal_range et

count qui sont utilisables aussi bien avec des conteneurs de type map quavec des conteneurs

de type multimap Cest cependant dans ce dernier cas quelles preacutesentent le plus dinteacuterecirct

elles seront eacutetudieacutees au paragraphe 2

18 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

map que nous venons dexaminer

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche(mapltchar intgt) mapltchar intgt m mapltchar intgtiterator im m[c] = 10 m[f] = 20 m[x] = 30 m[p] = 40 cout ltlt map initial affiche(m) im = mfind (f) ici on ne verifie pas que im est = mend() cout ltlt cle f avant insert ltlt (im)first ltlt n minsert (make_pair(a 5)) on insere un element avant f minsert (make_pair(t 7)) et un element apres f cout ltlt map apres insert affiche(m) cout ltlt cle f apres insert ltlt (im)first ltlt n im -gt f merase(c) cout ltlt map apres erase c affiche(m) im = mfind(p) if (im = mend()) merase(im mend()) cout ltlt map apres erase int affiche(m)

Les conteneurs associatifsCHAPITRE 20

448

void affiche(mapltchar intgt m) voir remarque paragraphe 24 du chapitre 19

mapltchar intgtiterator im

for (im=mbegin() im=mend() im++)

cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt )

cout ltlt n

map initial (c10) (f20) (p40) (x30)

cle f avant insert f

map apres insert (a5) (c10) (f20) (p40) (t7) (x30)

cle f apres insert f

map apres erase c (a5) (f20) (p40) (t7) (x30)

map apres erase int (a5) (f20)

Exemple dutilisation de la classe map

2 Le conteneur multimap

21 Preacutesentation geacuteneacuterale Comme nous lavons deacutejagrave dit dans un conteneur de type multimap une mecircme cleacute peut appa-

raicirctre plusieurs fois ou plus geacuteneacuteralement on peut trouver plusieurs cleacutes eacutequivalentes Bien

entendu les eacuteleacutements correspondants apparaissent alors conseacutecutifs Comme on peut sy

attendre lopeacuterateur [ ] nest plus applicable agrave un tel conteneur compte tenu de lambiguiumlteacute

quinduirait la non-uniciteacute des cleacutes Hormis cette restriction les possibiliteacutes des conteneurs

map se geacuteneacuteralisent sans difficulteacutes aux conteneurs multimap qui possegravedent les mecircmes fonc-

tions membres avec quelques nuances qui vont de soi

bull sil existe plusieurs cleacutes eacutequivalentes la fonction membre find fournit un iteacuterateur sur un des

eacuteleacutements ayant la cleacute voulue attention on ne preacutecise pas quil sagit du premier celui-ci

peut cependant ecirctre connu en recourant agrave la fonction lower_bound examineacutee un peu plus

loin

bull la fonction membre erase (cleacute) peut supprimer plusieurs eacuteleacutements tandis quavec un conte-

neur map elle nen supprimait quun seul au maximum

Dautre part comme nous lavons deacutejagrave fait remarquer un certain nombre de fonctions mem-

bres de la classe map prennent tout leur inteacuterecirct lorsquon les applique agrave un conteneur multi-

map On peut en effet

bull connaicirctre le nombre deacuteleacutements ayant une cleacute eacutequivalente agrave une cleacute donneacutee agrave laide de count

(cleacute)

bull obtenir des informations concernant lintervalle deacuteleacutements ayant une cleacute eacutequivalente agrave une

cleacute donneacutee agrave savoir

2 - Le conteneur multimap449

lower_bound (cleacute) fournit un iteacuterateur sur le premier eacuteleacutement ayant

une cleacute eacutequivalente agrave cleacute

upper__bound (cleacute) fournit un iteacuterateur sur le dernier eacuteleacutement ayant

une cleacute eacutequivalente agrave cleacute

equal_range (cleacute) fournit une paire formeacutee des valeurs des deux iteacuterateurs

preacuteceacutedents lower_bound (cleacute) et upper_bound (cleacute)

On notera quon a la relation

mequalrange(cleacute) = make_pair (mlower_bound (cleacute) mupper_bound (cleacute) )

Voici un petit exemple

multimapltchar intgt m merase(mlower_bound(c) mupper_bound(c)) eacutequivalent agrave erase(c) merase(mlower_bound(e) mupper_bound(g)) supprime toutes les cleacutes allant de e agrave g aucun eacutequivalent simple

Remarque

Le deuxiegraveme appel de erase de notre preacuteceacutedent exemple peut preacutesenter un inteacuterecirct dans le

cas dun conteneur de type map en effet malgreacute luniciteacute des cleacutes dans ce cas il nest pas

certain quun appel tel que

merase (mfind(e) mfind(g))

convienne puisquon court le risque que lune au moins des cleacutes e ou g nexiste pas

22 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

multimap que nous venons dexaminer

include ltiostreamgtinclude ltmapgtusing namespace std main() void affiche(multimapltchar intgt) multimapltchar intgt m m_bis multimapltchar intgtiterator im minsert(make_pair(c 10)) minsert(make_pair(f 20)) minsert(make_pair(x 30)) minsert(make_pair(p 40)) minsert(make_pair(y 40)) minsert(make_pair(p 35)) cout ltlt map initial n affiche(m) minsert(make_pair(f 25)) minsert(make_pair(f 20)) minsert(make_pair(x 2)) cout ltlt map avec fff et xx n affiche(m)

Les conteneurs associatifsCHAPITRE 20

450

im=mfind(x) on ne verifie pas que im = mend() m_bis = m on fait une copie de m dans m_bis merase(im) cout ltlt map apres erase(find(x)) n affiche(m) merase(f) cout ltlt map apres erase(f) n affiche(m) mswap(m_bis) cout ltlt map apres swap n affiche(m) cout ltlt il y a ltlt mcount(f) ltlt fois la cle fn merase(mupper_bound(f)) supprime derniere cle f - ici pas de test cout ltlt map apres erase (u_b(f)) n affiche(m) merase(mlower_bound(f)) cout ltlt map apres erase (l_b(f)) n affiche(m) merase(mupper_bound(g)) cout ltlt map apres erase (u_b(g)) n affiche(m) merase(mlower_bound(g)) cout ltlt map apres erase (l_b(g)) n affiche(m) merase(mlower_bound(d) mupper_bound(x)) cout ltlt map apres erase (l_b(d) u_b(x)) n affiche(m) void affiche(multimapltchar intgt m) voir remarque paragraphe 24 du chapitre 19 multimapltchar intgtiterator im for (im=mbegin() im=mend() im++) cout ltlt ( ltlt (im)first ltlt ltlt (im)second ltlt ) cout ltlt n

map initial (c10)(f20)(p40)(p35)(x30)(y40)map avec fff et xx (c10)(f20)(f25)(f20)(p40)(p35)(x30)(x2)(y40)map apres erase(find(x)) (c10)(f20)(f25)(f20)(p40)(p35)(x2)(y40)map apres erase(f) (c10)(p40)(p35)(x2)(y40)map apres swap (c10)(f20)(f25)(f20)(p40)(p35)(x30)(x2)(y40)il y a 3 fois la cle fmap apres erase (u_b(f)) (c10)(f20)(f25)(f20)(p35)(x30)(x2)(y40)map apres erase (l_b(f)) (c10)(f25)(f20)(p35)(x30)(x2)(y40)map apres erase (u_b(g)) (c10)(f25)(f20)(x30)(x2)(y40)map apres erase (l_b(g)) (c10)(f25)(f20)(x2)(y40)map apres erase (l_b(d) u_b(x)) (c10)(y40)

Exemple dutilisation de multimap

3 - Le conteneur set451

3 Le conteneur set

31 Preacutesentation geacuteneacuterale Comme il a eacuteteacute dit en introduction le conteneur set est un cas particulier du conteneur map

dans lequel aucune valeur nest associeacutee agrave la cleacute Les eacuteleacutements dun conteneur set ne sont

donc plus des paires ce qui en facilite naturellement la manipulation Une autre diffeacuterence

entre les conteneurs set et les conteneurs map est quun eacuteleacutement dun conteneur set est une

constante on ne peut pas en modifier la valeur

setltintgt e() ensemble dentiers setltintgtiterator ie iteacuterateur sur un ensemble dentiers cout ltlt ie correct ie = interdit

En dehors de cette contrainte les possibiliteacutes dun conteneur set se deacuteduisent tout naturelle-

ment de celles dun conteneur map aussi bien pour sa construction que pour linsertion ou la

suppression deacuteleacutements qui quant agrave elle reste toujours possible aussi bien agrave partir dune posi-

tion que dune valeur

32 Exemple Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

set (attention le caractegravere espace nest pas tregraves visible dans les reacutesultats )

include ltiostreamgtinclude ltsetgtinclude ltstringgtusing namespace std

main() char t[] = je me figure ce zouave qui joue du xylophone char v[] = aeiouy void affiche (setltchargt ) setltchargt let(t t+sizeof(t)-1) let_bis setltchargt voy(v v+sizeof(v)-1)

cout ltlt lettres presentes affiche (let) cout ltlt il y a ltlt letsize() ltlt lettres differentesn if (letcount(z)) cout ltlt la lettre z est presenten if (letcount(b)) cout ltlt la lettre b nest pas presenten

let_bis = let setltchargt iterator iv for (iv=voybegin() iv=voyend() iv++) leterase(iv)

Les conteneurs associatifsCHAPITRE 20

452

cout ltlt lettres sans voyelles affiche (let) letinsert(voybegin() voyend()) cout ltlt lettres + toutes voyelles affiche (let)

void affiche (setltchargt e ) voir remarque paragraphe 24 du chapitre 19 setltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie ltlt cout ltlt n

lettres presentes a c d e f g h i j l m n o p q r u v x y zil y a 22 lettres differentesla lettre z est presentela lettre b nest pas presentelettres sans voyelles c d f g h j l m n p q r v x zlettres + toutes voyelles a c d e f g h i j l m n o p q r u v x y z

Exemple dutilisation du conteneur set

33 Le conteneur set et lensemble matheacutematique Un conteneur de type set est obligatoirement ordonneacute tandis quun ensemble matheacutematique

ne lest pas neacutecessairement Il faudra tenir compte de cette remarque degraves que lon sera ameneacute

agrave creacuteer un ensemble dobjets puisquil faudra alors munir la classe correspondante dune rela-

tion dordre faible strict En outre il ne faudra pas perdre de vue que cest cette relation qui

sera utiliseacutee pour deacutefinir leacutegaliteacute de deux eacuteleacutements et non une eacuteventuelle surdeacutefinition de

lopeacuterateur ==

Par ailleurs dans la classe set il nexiste pas de fonction membre permettant de reacutealiser les

opeacuterations ensemblistes classiques (intersection reacuteunion) Cependant nous verrons au cha-

pitre 21 quil existe des algorithmes geacuteneacuteraux utilisables avec nimporte quelle seacutequence

ordonneacutee Leur application au cas particulier des ensembles permettra de reacutealiser les opeacutera-

tions en question

4 Le conteneur multisetDe mecircme que le conteneur multimap est un conteneur map dans lequel on autorise plusieurs

cleacutes eacutequivalentes le conteneur multiset est un conteneur set dans lequel on autorise plu-

sieurs eacuteleacutements eacutequivalents agrave apparaicirctre Il correspond agrave la notion matheacutematique de multi-

ensemble (peu reacutepandue) avec cette diffeacuterence que la relation drsquoordre neacutecessaire agrave la deacutefini-

tion drsquoun multiset ne lrsquoest pas dans le multi-ensemble matheacutematique Les algorithmes geacuteneacute-

raux drsquointersection ou de reacuteunion eacutevoqueacutes ci-dessus fonctionneront encore dans le cas des

conteneurs multiset

5 - Conteneurs associatifs et algorithmes453

Voici un exemple complet de programme illustrant les principales fonctionnaliteacutes de la classe

multiset (attention le caractegravere espace nest pas tregraves visible dans les reacutesultats )

include ltiostreamgtinclude ltsetgtusing namespace std

main() char t[] = je me figure ce zouave qui joue du xylophone char v[] = aeiouy void affiche (multisetltchargt ) multisetltchargt let(t t+sizeof(t)-1) let_bis multisetltchargt voy(v v+sizeof(v)-1) cout ltlt lettres presentes affiche (let) cout ltlt il y a ltlt letsize() ltlt lettres en toutn cout ltlt la lettre e est presente ltlt letcount(e) ltlt foisn cout ltlt la lettre b est presente ltlt letcount(b) ltlt foisn let_bis = let multisetltchargt iterator iv for (iv=voybegin() iv=voyend() iv++) leterase(iv) cout ltlt lettres sans voyelles affiche (let)

void affiche (multisetltchargt e ) voir remarque paragraphe 24 du chapitre 19 multisetltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie cout ltlt n

lettres presentes acdeeeeeeefghiijjlmnoooopqruuuuuvxyzil y a 44 lettres en toutla lettre e est presente 7 foisla lettre b est presente 0 foislettres sans voyelles cdfghjjlmnpqrvxz

Exemple dutilisation du conteneur multiset

5 Conteneurs associatifs et algorithmes Il est geacuteneacuteralement difficile dappliquer certains algorithmes geacuteneacuteraux aux conteneurs asso-

ciatifs Il y a plusieurs raisons agrave cela

Tout dabord un conteneur de type map ou multimap est formeacute deacuteleacutements de pair qui se precirc-

tent assez difficilement aux algorithmes usuels Par exemple une recherche par find devrait

Les conteneurs associatifsCHAPITRE 20

454

se faire sur la paire (cleacute valeur) ce qui ne preacutesente geacuteneacuteralement guegravere dinteacuterecirct on preacutefeacute-

rera utiliser la fonction membre find travaillant sur une cleacute donneacutee

De mecircme vouloir trier un conteneur associatif deacutejagrave ordonneacute de faccedilon intrinsegraveque nest guegravere

reacutealiste soit on cherche agrave trier suivant lordre interne ce qui na aucun inteacuterecirct soit on cher-

che agrave trier suivant un autre ordre et alors apparaissent des conflits entre les deux ordres

Neacuteanmoins il reste possible dappliquer tout algorithme qui ne modifie pas les valeurs du

conteneur

Dune maniegravere geacuteneacuterale dans le chapitre 21 consacreacute aux algorithmes nous indiquerons ceux

qui sont utilisables avec des conteneurs associatifs

21

Les algorithmes standard

La notion dalgorithme a deacutejagrave eacuteteacute preacutesenteacutee au chapitre 18 et nous avons eu loccasion den

utiliser quelques-uns dans certains de nos preacuteceacutedents exemples Le preacutesent chapitre expose

les diffeacuterentes possibiliteacutes offertes par les algorithmes de la bibliothegraveque standard Aupara-

vant il preacutesente ou rappelle un certain nombre de notions geacuteneacuterales qui interviennent dans

leur utilisation en particulier les cateacutegories diteacuterateur la notion de seacutequence les iteacuterateurs

de flot et les iteacuterateurs dinsertion

On notera bien que ce chapitre vise avant tout agrave faire comprendre le rocircle des diffeacuterents algo-

rithmes et agrave illustrer les plus importants par des exemples de programmes On trouvera dans

lrsquoAnnexe C une reacutefeacuterence complegravete du rocircle preacutecis de lefficaciteacute et de la syntaxe exacte de

lappel de chacun des algorithmes existants

1 Notions geacuteneacuterales

11 Algorithmes et iteacuterateurs Les algorithmes standard se preacutesentent sous forme de patrons de fonctions Leur code est

eacutecrit sans connaissance preacutecise des eacuteleacutements quils seront ameneacutes agrave manipuler Cependant

cette manipulation ne se fait jamais directement mais toujours par lintermeacutediaire dun iteacutera-

teur qui quant agrave lui possegravede un type donneacute agrave partir duquel se deacuteduit le type des eacuteleacutements

effectivement manipuleacutes Par exemple lorsquun algorithme contient une instruction de la

forme

it =

Les algorithmes standardCHAPITRE 21

456

le code source du programme ne connaicirct effectivement pas le type de leacuteleacutement qui sera ainsi

manipuleacute mais ce type sera parfaitement deacutefini agrave la compilation lors de linstanciation de la

fonction patron correspondant agrave lalgorithme en question

12 Les cateacutegories diteacuterateurs Jusquici nous avons surtout manipuleacute des eacuteleacutements de conteneurs et les iteacuterateurs associeacutes

qui se reacutepartissaient alors en trois cateacutegories unidirectionnel bidirectionnel et agrave accegraves direct

En fait il existe deux autres cateacutegories diteacuterateurs disposant de proprieacuteteacutes plus restrictives

que les iteacuterateurs unidirectionnels il sagit des iteacuterateurs en entreacutee et des iteacuterateurs en sortie

Bien quils ne soient fournis par aucun des conteneurs ils preacutesentent un inteacuterecirct au niveau des

iteacuterateurs de flot qui comme nous le verrons un peu plus loin permettent dacceacuteder agrave un flot

comme agrave une seacutequence

121 Iteacuterateur en entreacuteeUn iteacuterateur en entreacutee possegravede les mecircmes proprieacuteteacutes quun iteacuterateur unidirectionnel avec

cette diffeacuterence quil nautorise que la consultation de la valeur correspondante et plus sa

modification si it est un tel iteacuterateur

= it correct si it est un iteacuterateur en entreacutee it = impossible si it est un iteacuterateur en entreacutee

En outre un iteacuterateur en entreacutee nautorise quun seul passage (on dit aussi une seule passe) sur

les eacuteleacutements quil permet de deacutecrire Autrement dit si agrave un moment donneacute it1==it2 it1++

et it2++ ne deacutesignent pas neacutecessairement la mecircme valeur Cette restriction nexistait pas dans

le cas des iteacuterateurs unidirectionnels Ici elle se justifie degraves lors quon sait que liteacuterateur en

entreacutee est destineacute agrave la lecture dune suite de valeurs de mecircme type sur un flot dune faccedilon

analogue agrave la lecture des informations dune seacutequence Or manifestement il nest pas possi-

ble de lire deux fois une mecircme valeur sur certains flots tels que luniteacute dentreacutee standard

122 Iteacuterateur en sortieDe faccedilon concomitante un iteacuterateur en sortie possegravede les mecircmes proprieacuteteacutes quun iteacuterateur

unidirectionnel avec cette diffeacuterence quil nautorise que la modification et en aucun cas la

consultation Par exemple si it est un tel iteacuterateur

it = correct si it est un iteacuterateur en sortie = it impossible si it est un iteacuterateur en sortie

Comme liteacuterateur en entreacutee liteacuterateur en sortie ne permettra quun seul passage si agrave un

moment donneacute on a it1==it2 les affectations successives

it1++ = it2++ =

entraicircneront la creacuteation de deux valeurs distinctes Lagrave encore pour mieux comprendre ces

restrictions il faut voir que la principale justification de liteacuterateur en sortie est de permettre

deacutecrire une suite de valeur de mecircme type sur un flot de la mecircme faccedilon quon peut introduire

des informations dans une seacutequence Or manifestement il nest pas possible deacutecrire deux

fois en un mecircme endroit de certains flots tels que luniteacute standard de sortie

1 - Notions geacuteneacuterales457

123 Hieacuterarchie des cateacutegories diteacuterateurs

On peut montrer que les proprieacuteteacutes des cinq cateacutegories diteacuterateurs permettent de les ranger

selon une hieacuterarchie dans laquelle toute cateacutegorie possegravede au moins les proprieacuteteacutes de la cateacute-

gorie preacuteceacutedente

iteacuterateur en entreacutee iteacuterateur en sortie

|___________________________|

|

iteacuterateur unidirectionnel

|

iteacuterateur bidirectionnel

|

iteacuterateur agrave accegraves direct

Les iteacuterateurs en entreacutee et en sortie seront freacutequemment utiliseacutes pour associer un iteacuterateur agrave

un flot en faisant appel agrave un adaptateur particulier diteacuterateur dit iteacuterateur de flot nous y

reviendrons au paragraphe 15 En dehors de cela ils preacutesentent un inteacuterecirct indirect agrave propos

de linformation quon peut deacuteduire au vu de la cateacutegorie diteacuterateur attendu par un

algorithme par exemple si un algorithme accepte un iteacuterateur en entreacutee cest que dune

part il ne modifie pas la seacutequence correspondante et que dautre part il neffectue quune

seule passe sur cette seacutequence

13 Algorithmes et seacutequences Beaucoup dalgorithmes sappliquent agrave une seacutequence deacutefinie par un intervalle diteacuterateur de la

forme [deacutebut fin) dans ce cas on lui communiquera simplement en argument les deux

valeurs deacutebut et fin lesquelles devront naturellement ecirctre du mecircme type sous peine derreur

de compilation

Tant que lalgorithme ne modifie pas les eacuteleacutements de cette seacutequence cette derniegravere peut

appartenir agrave un conteneur de nimporte quel type y compris les conteneurs associatifs pour

lesquels rappelons-le la notion de seacutequence a bien un sens compte tenu de leur ordre

interne Cependant dans le cas des types map ou multimap on sera geacuteneacuteralement gecircneacute par le

fait que leurs eacuteleacutements sont des paires

En revanche si lalgorithme modifie les eacuteleacutements de la seacutequence il nest plus possible quelle

appartienne agrave un conteneur de type set et multiset puisque les eacuteleacutements nen sont plus modi-

fiables Bien quil nexiste pas dinterdiction formelle il nest guegravere raisonnable quelle appar-

tienne agrave un conteneur de type map ou multimap compte tenu des risques dincompatibiliteacute

qui apparaissent alors entre lorganisation interne et celle quon chercherait agrave lui imposer

Certains algorithmes sappliquent agrave deux seacutequences de mecircme taille Cest par exemple le cas

de la recopie dune seacutequence dans une autre ayant des eacuteleacutements de mecircme type Dans ce cas

tous ces algorithmes procegravedent de la mecircme faccedilon agrave savoir

bull deux arguments deacutefinissent classiquement un premier intervalle correspondant agrave la premiegrave-

re seacutequence

Les algorithmes standardCHAPITRE 21

458

bull un troisiegraveme argument fournit la valeur dun iteacuterateur deacutesignant le deacutebut de la seconde seacute-

quence

On notera bien que cette faccedilon de proceacuteder preacutesente manifestement le risque que la seacutequence

cible soit trop petite Dans ce cas le comportement du programme est indeacutetermineacute comme il

pouvait lecirctre en cas de deacutebordement dun tableau classique dailleurs rien ninterdit de four-

nir agrave un algorithme un iteacuterateur qui soit un pointeur

Enfin quelques rares algorithmes fournissent comme valeur de retour les limites dun inter-

valle sous forme de deux iteacuterateurs dans ce cas celles-ci seront regroupeacutees au sein dune

structure de type pair

14 Iteacuterateur dinsertion Beaucoup dalgorithmes sont preacutevus pour modifier les valeurs des eacuteleacutements dune seacutequence

cest par exemple le cas de copy

copy (vbegin() vend() lbegin())

recopie lintervalle [vbegin() vend() )

agrave partir de la position lbegin()

De telles opeacuterations imposent naturellement un certain nombre de contraintes

bull les emplacements neacutecessaires agrave la copie doivent deacutejagrave exister

bull leur modification doit ecirctre autoriseacutee ce qui nest pas le cas pour des conteneurs de type set

ou multiset

bull la copie ne doit pas se faire agrave linteacuterieur dun conteneur associatif de type map ou multimap

compte tenu de lincompatibiliteacute qui reacutesulterait entre lordre seacutequentiel imposeacute et lordre in-

terne du conteneur

En fait il existe un meacutecanisme particulier permettant de transformer une succession dopeacutera-

tions de copie agrave partir dune position donneacutee en une succession dinsertions agrave partir de cette

position Pour ce faire on fait appel agrave ce quon nomme un iteacuterateur dinsertion il sagit dun

patron de classes nommeacute insert_iterator et parameacutetreacute par un type de conteneur Par exemple

insert_iterator ltlistltintgt gt ins ins est un iteacuterateur dinsertion

dans un conteneur de type listltintgt

Pour affecter une valeur agrave un tel iteacuterateur on se sert du patron de fonction inserter en voici

un exemple dans lequel on suppose que c est un conteneur et it est une valeur particuliegravere

diteacuterateur sur ce conteneur

ins = inserter(c it) valeur initiale dun iteacuterateur dinsertion

permettant dinseacuterer agrave partir de la

position it dans le conteneur c

Dans ces conditions lutilisation de ins en lieu et place dune valeur initiale diteacuterateur fera

quune instruction telle que ins = inseacuterera un nouvel eacuteleacutement en position it De plus toute

increacutementation de ins suivie dune nouvelle affectation ins= provoquera une nouvelle

insertion agrave la suite de leacuteleacutement preacuteceacutedent

1 - Notions geacuteneacuterales459

Dune maniegravere geacuteneacuterale il existe trois fonctions permettant de deacutefinir une valeur initiale dun

iteacuterateur dinsertion agrave savoir

bull front_inserter (conteneur) pour une insertion en deacutebut du conteneur le conteneur doit dis-

poser de la fonction membre push_front

bull back_inserter (conteneur) pour une insertion en fin du conteneur le conteneur doit dispo-

ser de la fonction membre push_back

bull inserter (conteneur position) pour une insertion agrave partir de position dans le conteneur le

conteneur doit disposer de la fonction membre insert(valeur position)

Voici un exemple de programme utilisant un tel meacutecanisme pour transformer une copie dans

des eacuteleacutements existant en une insertion auparavant on a tenteacute une copie usuelle dans un con-

teneur trop petit pour montrer quelle se deacuteroulait mal en pratique nous deacuteconseillons ce

genre de proceacutedeacute qui peut tregraves bien amener agrave un plantage du programme

include ltiostreamgtinclude ltlistgtinclude ltalgorithmgtusing namespace std main() void affiche (listltchargt) char t[] = essai insert_iterator listltchargt l1(t t+sizeof(t)-1) listltchargt l2 (4 x) listltchargt l3 cout ltlt l1 initiale affiche(l1) cout ltlt l2 initiale affiche(l2) copie avec liste l2 de taille insuffisante deconseille en pratique copy (l1begin() l1end() l2begin()) cout ltlt l2 apres copie usuelle affiche(l2) insertion dans liste non vide on pourrait utiliser aussi front_inserter(l2) copy (l1begin() l1end() inserter(l2 l2begin())) cout ltlt l2 apres copie inser affiche(l2) insertion dans liste vide on pourrait utiliser aussi front_inserter(l3) ou back_inserter(l3) copy (l1begin() l1end() inserter(l3 l3begin())) cout ltlt l3 apres copie inser affiche(l3) void affiche (listltchargt l) void af_car (char) for_each(lbegin() lend() af_car) appelle af_car pour chaque element cout ltlt n void af_car (char c) cout ltlt c ltlt

Les algorithmes standardCHAPITRE 21

460

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

Exemple dutilisation dun iteacuterateur dinsertion

Remarque

Si lon tient agrave mettre en eacutevidence lexistence dune classe insert_iterator la simple instruc-

tion du preacuteceacutedent programme

copy (l1begin() l1end() inserter(l2 l2begin()))

peut se deacutecomposer ainsi

insert_iteratorltlistltchargt gt ins = inserter(l2 l2begin())

copy (l1begin() l1end() ins )

15 Iteacuterateur de flot

151 Iteacuterateur de flot de sortie

Lorsquon lit par exemple sur lentreacutee standard une suite dinformations de mecircme type on

peut consideacuterer quon parcourt une seacutequence Effectivement il est possible de deacutefinir un iteacute-

rateur sur une telle seacutequence ne disposant que des proprieacuteteacutes dun iteacuterateur dentreacutee telles

quelles ont eacuteteacute deacutefinies preacuteceacutedemment Pour ce faire il existe un patron de classes nommeacute

ostream_iterator parameacutetreacute par le type des eacuteleacutements concerneacutes par exemple

ostream_iteratorltchargt type iteacuterateur sur un flot dentreacutee de caractegraveres

Cette classe dispose dun constructeur recevant en argument un flot existant Cest ainsi que

ostream_iteratorltchargt flcar(cout) flcar est un iteacuterateur sur un flot de

caractegraveres connecteacute agrave cout

Dans ces conditions une instruction telle que

flcar = x

envoie le caractegravere x sur le flot cout

On notera quil est theacuteoriquement possible dincreacutementer liteacuterateur flcar en eacutecrivant

flcar++ cependant une telle opeacuteration est sans effet car sans signification agrave ce niveau Son

existence est cependant preacutecieuse puisquelle permettra dutiliser un tel iteacuterateur avec certains

algorithmes standard tels que copy

Voici un exemple reacutesumant ce que nous venons de dire

1 - Notions geacuteneacuterales461

include ltiostreamgt

include ltlistgt

using namespace std

main()

char t[] = essai iterateur de flot

listltchargt l(t t+sizeof(t)-1)

ostream_iteratorltchargt flcar(cout)

flcar = x flcar = -

flcar++ flcar++ pour montrer que lincrementation est inoperante ici

flcar =

copy (lbegin() lend() flcar)

x-essai iterateur de flot

Exemple dutilisation dun iteacuterateur de flot de sortie

Remarque

Ici notre exemple sappliquait agrave la sortie standard dans ces conditions lutilisation

dinformations de type autre que char poserait le problegraveme de leur seacuteparation agrave laffichage

ou dans le fichier texte correspondant En revanche lapplication agrave un fichier binaire quel-

conque ne poserait plus aucun problegraveme

152 Iteacuterateur de flot dentreacutee

De mecircme quon peut deacutefinir des iteacuterateurs de flot de sortie on peut deacutefinir des iteacuterateurs de

flot dentreacutee suivant un proceacutedeacute tregraves voisin Par exemple avec

istream_iteratorltintgt flint(cin)

on deacutefinit un iteacuterateur nommeacute flint sur un flot dentreacutee dentiers connecteacute agrave cin De la mecircme

maniegravere avec

ifstream fich(essai iosin)

istream_iteratorltintgt flint(fich)

on deacutefinit un iteacuterateur nommeacute flint sur un flot dentreacutee dentiers connecteacute au flot fich sup-

poseacute convenablement ouvert

Les iteacuterateurs de flot dentreacutee neacutecessitent cependant la possibiliteacute den deacutetecter la fin Pour ce

faire il existe une convention permettant de construire un iteacuterateur en repreacutesentant la fin agrave

savoir lutilisation dun constructeur sans argument par exemple avec

istream_iteratorltintgt fin fin est un iteacuterateur repreacutesentant une fin

de fichier sur un iteacuterateur de flot dentiers

Les algorithmes standardCHAPITRE 21

462

Voici par exemple comment utiliser un iteacuterateur de flot dentreacutee pour recopier les informa-

tions dun fichier dans une liste ici nous creacuteons une liste vide et nous utilisons un iteacuterateur

dinsertion pour y introduire le reacutesultat de la copie

listltintgt l ifstream fich(essai iosin) istream_iteratorltint ptrdiff_tgt flint(fich) fin copy (flint fin inserter(l lbegin()))

2 Algorithmes dinitialisation de seacutequences existantes

Tous ces algorithmes permettent de donner des valeurs agrave des eacuteleacutements existant dune

seacutequence dont la valeur est donc remplaceacutee De par leur nature mecircme ils ne sont pas adapteacutes

aux conteneurs associatifs agrave moins dutiliser un iteacuterateur dinsertion et de tenir compte de la

nature de type pair de leurs eacuteleacutements

21 Copie dune seacutequence dans une autre Comme on la deacutejagrave vu agrave plusieurs reprises on peut recopier une seacutequence dans une autre

pour peu que les types des eacuteleacutements soient les mecircmes Par exemple si l est une liste dentiers

et v un vecteur dentiers

copy (lbegin() lend() vbegin()) recopie les eacuteleacutements de la liste l dans le vecteur v agrave partir de son deacutebut

Le sens de la copie est imposeacute agrave savoir quon commence bien par recopier lbegin() en

vbegin() La seule contrainte (logique) qui soit imposeacutee aux valeurs des iteacuterateurs est que la

position de la premiegravere copie nappartienne pas agrave lintervalle agrave copier En revanche rien

ninterdirait par exemple

copy (vbegin()+1 vbegin()+10 vbegin()) recopie v[1] dans v[0] v[2] dans v[1] v[9] dans v[8]

Il existe eacutegalement un algorithme copy_backward qui procegravede agrave la copie dans lordre inverse

de copy crsquoest-agrave-dire en commenccedilant par le dernier eacuteleacutement Dans ce cas comme on peut sy

attendre les iteacuterateurs correspondants doivent ecirctre bidirectionnels

Voici un exemple de programme utilisant copy pour reacutealiser des copies usuelles ainsi que des

insertions par le biais dun iteacuterateur dinsertion

include ltiostreamgtinclude ltvectorgtinclude ltlistgtinclude ltalgorithmgtusing namespace std

2 - Algorithmes dinitialisation de seacutequences existantes463

main() int t[5] = 1 2 3 4 5 vectorltintgt v(t t+5) v contient 1 2 3 4 5 listltintgt l(8 0) liste de 8 elements egaux a 0 listltintgt l2(3 0) liste de 3 elements egaux a 0 void affiche(vectorltintgt) void affiche(listltintgt) cout ltlt liste initiale affiche(l) copy (vbegin() vend() lbegin()) cout ltlt liste apres copie 1 affiche(l) l = l2 l contient maintenant 3 elements eacutegaux agrave 0 copy (vbegin() vend() lbegin()) sequence trop courte deconseille cout ltlt liste apres copie 2 affiche(l) lerase(lbegin() lend()) l est maintenant vide on y insere les elem de v copy (vbegin() vend() inserter(l lbegin())) cout ltlt liste apres copie 3 affiche(l) void affiche(listltintgt l) listltintgtiterator il for (il=lbegin() il=lend() il++) cout ltlt il ltlt cout ltlt n

liste initiale 0 0 0 0 0 0 0 0liste apres copie 1 1 2 3 4 5 0 0 0liste apres copie 2 5 2 3liste apres copie 3 1 2 3 4 5

Exemple de copies usuelles et de copies avec insertion

22 Geacuteneacuteration de valeurs par une fonction Il est freacutequent quon ait besoin dinitialiser un conteneur par des valeurs reacutesultant dun calcul

La bibliothegraveque standard offre un outil assez geacuteneacuteral agrave cet effet agrave savoir ce quon nomme

souvent un algorithme geacuteneacuterateur On lui fournit en argument un objet fonction (il peut donc

sagir dune fonction ordinaire) quil appellera pour deacuteterminer la valeur agrave attribuer agrave chaque

eacuteleacutement dun intervalle Une telle fonction ne reccediloit aucun argument Par exemple lappel

generate (vbegin() vend() suite)

utilisera la fonction suite pour donner une valeur agrave chacun des eacuteleacutements de la seacutequence deacutefi-

nie par lintervalle [vbegin() vend())

Voici un premier exemple faisant appel agrave une fonction ordinaire

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

Les algorithmes standardCHAPITRE 21

464

main() int n = 10 vectorltintgt v(n 0) vecteur de n elements initialises a 0 int suite() fonction utilisee pour la generation dentiers void affiche(vectorltintgt) cout ltlt vecteur initial affiche(v) generate (vbegin() vend() suite) cout ltlt vecteur genere affiche(v) int suite() static int n = 0 return n++

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 0 0 0 0 0 0 0 0 0 0vecteur genere 0 1 2 3 4 5 6 7 8 9

Geacuteneacuteration de valeurs par une fonction ordinaire

On constate quil est difficile dimposer une valeur initiale agrave la suite de nombres autrement

quen la fixant dans la fonction elle-mecircme en particulier il nest pas possible de la choisir en

argument Cest lagrave preacuteciseacutement que la notion de classe fonction savegravere inteacuteressante comme le

montre lexemple suivant

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std class sequence classe fonction utilisee pour la generation dentiers public sequence (int i) n = i constructeur int operator() () return n++ ne pas oublier () private int n valeur courante generee

2 - Algorithmes dinitialisation de seacutequences existantes465

main() int n = 10 vectorltintgt v(n 0) vecteur de n elements initialises a 0 void affiche(vectorltintgt) cout ltlt vecteur initial affiche(v) generate (vbegin() vend() sequence(0)) cout ltlt vecteur genere 1 affiche(v) generate (vbegin() vend() sequence(4)) cout ltlt vecteur genere 2 affiche(v)

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 0 0 0 0 0 0 0 0 0 0vecteur genere 1 0 1 2 3 4 5 6 7 8 9vecteur genere 2 4 5 6 7 8 9 10 11 12 13

Geacuteneacuteration de valeurs par une classe fonction

Remarques

1 Si lon compare les deux appels suivants lun du premier exemple lautre du second

generate (vbegin() vend() suite) generate (vbegin() vend() sequence(0))

on constate que dans le premier cas suite est la reacutefeacuterence agrave une fonction tandis que

dans le second sequence(0) est la reacutefeacuterence agrave un objet de type sequence Mais comme

ce dernier a convenablement surdeacutefini lopeacuterateur () lalgorithme generate na pas agrave

tenir compte de cette diffeacuterence

2 Il existe un autre algorithme generate_n comparable agrave generate qui geacutenegravere un nombre

de valeurs preacutevues en argument Dautre part lalgorithme fill permet daffecter une

valeur donneacutee agrave tous les eacuteleacutements dune seacutequence ou agrave un nombre donneacute deacuteleacutements

fill (deacutebut fin valeur)

fill (position NbFois valeur)

Les algorithmes standardCHAPITRE 21

466

3 Algorithmes de recherche Ces algorithmes ne modifient pas la seacutequence sur laquelle ils travaillent On distingue

bull les algorithmes fondeacutes sur une eacutegaliteacute ou sur un preacutedicat unaire

bull les algorithmes fondeacutes sur une relation dordre permettant de trouver le plus grand ou le plus

petit eacuteleacutement

31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire Ces algorithmes permettent de rechercher la premiegravere occurrence de valeurs ou de seacuteries de

valeurs qui sont

bull soit imposeacutees explicitement cela signifie en fait quon se fonde sur la relation deacutegaliteacute in-

duite par lopeacuterateur == quil soit surdeacutefini ou non

bull soit par une condition fournie sous forme dun preacutedicat unaire

Ils fournissent tous un iteacuterateur sur leacuteleacutement rechercheacute sil existe et liteacuterateur sur la fin de la

seacutequence sinon dans ce dernier cas cette valeur nest eacutegale agrave end() que si la seacutequence con-

cerneacutee appartient agrave un conteneur et seacutetend jusquagrave sa fin Sinon on peut obtenir un iteacuterateur

valide sur un eacuteleacutement nayant rien agrave voir avec la recherche en question Dans le cas ougrave les iteacute-

rateurs utiliseacutes sont des pointeurs on peut obtenir un pointeur sur une valeur situeacutee au-delagrave

de la seacutequence examineacutee Il faudra tenir compte de ces remarques dans le test de la valeur de

retour qui constitue le seul moyen de savoir si la recherche a abouti

Lalgorithme find permet de rechercher une valeur donneacutee tandis que find_first_of permet de

rechercher une valeur parmi plusieurs Lalgorithme find_if (deacutebut fin preacutedicat) autorise la

recherche de la premiegravere valeur satisfaisant au preacutedicat unaire fourni en argument

On peut rechercher dans une seacutequence [deacutebut_1 fin_1) la premiegravere apparition complegravete

dune autre seacutequence [deacutebut_2 fin_2) par search (deacutebut_1 fin_1 deacutebut_2 fin_2) De mecircme

search_n (deacutebut fin NbFois valeur) permet de rechercher une suite de NbFois une mecircme

valeur Lagrave encore on se base sur lopeacuterateur == surdeacutefini ou non

On peut rechercher les doublons crsquoest-agrave-dire les valeurs apparaissant deux fois de suite

par adjacent_find (deacutebut fin) Attention ce nest pas un cas particulier de search_n dans la

mesure ougrave lon nimpose pas la valeur dupliqueacutee Pour chercher les autres doublons on peut

soit supprimer lune des valeurs trouveacutees soit simplement recommencer la recherche au-delagrave

de lemplacement ougrave se trouve le doublon preacuteceacutedent

Voici un exemple de programme illustrant la plupart de ces possibiliteacutes (par souci de simpli-

fication nous supposons que les valeurs rechercheacutees existent toujours)

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std

3 - Algorithmes de recherche467

main() char ch1 = anticonstitutionnellement char ch2 = uoie char ch3 = tion vectorltchargt v1 (ch1 ch1+strlen(ch1)) vectorltchargt v2 (ch2 ch2+strlen(ch2)) vectorltchargtiterator iv iv = find_first_of (v1begin() v1end() v2begin() v2end()) cout ltlt npremier de uoie en for ( iv=v1end() iv++) cout ltlt iv iv = find_first_of (v1begin() v1end() v2begin() v2begin()+2) cout ltlt npremier de uo en for ( iv=v1end() iv++) cout ltlt iv v2assign (ch3 ch3+strlen(ch3)) iv = search (v1begin() v1end() v2begin() v2end()) cout ltlt ntion en for ( iv=v1end() iv++) cout ltlt iv iv = search_n(v1begin() v1end() 2 l ) cout ltlt nl 2 fois en for ( iv=v1end() iv++) cout ltlt iv iv = adjacent_find(v1begin() v1end()) cout ltlt npremier doublon en for ( iv=v1end() iv++) cout ltlt iv

premier de uoie en iconstitutionnellementpremier de uo en onstitutionnellementtion en tionnellementl 2 fois en llementpremier doublon en nnellement

Exemple dutilisation des algorithmes de recherche

32 Algorithmes de recherche de maximum ou de minimum Les deux algorithmes max_element et min_element permettent de deacuteterminer le plus grand ou

le plus petit eacuteleacutement dune seacutequence Ils sappuient par deacutefaut sur la relation induite par lopeacute-

rateur lt mais il est eacutegalement possible dimposer sa propre relation sous forme dun preacutedicat

binaire Comme les algorithmes preacuteceacutedents ils fournissent en retour soit un iteacuterateur sur

leacuteleacutement correspondant ou sur le premier dentre eux sil en existe plusieurs soit un iteacuterateur

sur la fin de la seacutequence sil nen existe aucun Mais cette derniegravere situation ne peut se pro-

duire ici quavec une seacutequence vide ou lorsquon choisit son propre preacutedicat de sorte que

lexamen de la valeur de retour est alors moins cruciale

Voici un exemple dans lequel nous appliquons ces algorithmes agrave un tableau usuel (par souci

de simplification nous supposons que les valeurs rechercheacutees existent toujours)

include ltiostreamgtinclude ltalgorithmgtinclude ltfunctionalgt pour greaterltintgt using namespace std

Les algorithmes standardCHAPITRE 21

468

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 ltlt plus grand elem de t en position ltlt ad-t

ltlt valeur ltlt ad ltlt n

ad = min_element(t t+sizeof(t)sizeof(t[0]))

cout ltlt plus petit elem de t en position ltlt ad-t

ltlt valeur ltlt ad ltlt n

ad = max_element(t t+sizeof(t)sizeof(t[0]) greaterltintgt())

cout ltlt plus grand elem avec greaterltintgt en position ltlt ad-t

ltlt valeur ltlt ad ltlt 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 greaterltintgt en position 2 valeur 1

Exemple dutilisation de max_element et de min_element

4 Algorithmes de transformation dune seacutequence

Il sagit des algorithmes qui modifient les valeurs dune seacutequence ou leur ordre sans en modi-

fier le nombre deacuteleacutements Ils ne sont pas applicables aux conteneurs associatifs pour les-

quels lordre est imposeacute de faccedilon intrinsegraveque

On peut distinguer trois cateacutegories dalgorithmes

bull remplacement de valeurs

bull permutation de valeurs

bull partition

Beaucoup de ces algorithmes disposent dune version suffixeacutee par _copy dans ce cas la ver-

sion xxxx_copy reacutealise le mecircme traitement que xxxx avec cette diffeacuterence importante quelle

ne modifie plus la seacutequence dorigine et quelle copie le reacutesultat obtenu dans une autre

seacutequence dont les eacuteleacutements doivent alors exister comme avec copy Ces algorithmes de la

forme xxxx_copy peuvent quant agrave eux sappliquer agrave des conteneurs associatifs agrave condition

toutefois dutiliser un iteacuterateur dinsertion et de tenir compte de la nature de type pair de leurs

eacuteleacutements

4 - Algorithmes de transformation dune seacutequence469

Par ailleurs il existe un algorithme nommeacute transform qui contrairement agrave ce que son nom

pourrait laisser entendre initialise une seacutequence en appliquant une fonction de transforma-

tion agrave une seacutequence ou agrave deux seacutequences de mecircme taille ces derniegraveres neacutetant alors pas modi-

fieacutees

41 Remplacement de valeurs On peut remplacer toutes les occurrences dune valeur donneacutee par une autre valeur en se fon-

dant sur lopeacuterateur == par exemple

replace (lbegin() lend() 0 -1) remplace toutes les occurrences de 0 par -1

On peut eacutegalement remplacer toutes les occurrences dune valeur satisfaisant agrave une

condition par exemple

replace_if (lbegin() lend() impair 0) remplace par 0 toutes les valeurs satisfaisant au preacutedicat

unaire impair quil faut fournir

42 Permutations de valeurs

421 Rotation

Lalgorithme rotate permet deffectuer une permutation circulaire des valeurs dune seacutequence

On notera quon ne dispose que des possibiliteacutes de permutation circulaire inverse compte

tenu de la maniegravere dont on preacutecise lampleur de la permutation agrave savoir non pas par un nom-

bre mais en indiquant quel eacuteleacutement doit venir en premiegravere position En voici un exemple

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 1 2 3 4 5 6 7 8 int decal = 3

vectorltintgt v(t t+8) cout ltlt vecteur initial affiche(v) rotate (vbegin() vbegin()+decal vend()) cout ltlt vecteur decale de 3 affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

Les algorithmes standardCHAPITRE 21

470

vecteur initial 1 2 3 4 5 6 7 8vecteur decale de 3 4 5 6 7 8 1 2 3

Exemple dutilisation de rotate

422 Geacuteneacuteration de permutations

Degraves lors quune seacutequence est ordonneacutee par une relation dordre R il est possible dordonner

les diffeacuterentes permutations possibles des valeurs de cette seacutequence Par exemple si lon con-

sidegravere les trois valeurs 1 4 8 et la relation dordre lt voici la liste ordonneacutee de toutes les per-

mutations possibles

1 4 8

1 8 4

4 1 8

4 8 1

8 1 4

8 4 1

Dans ces conditions il est possible de parler de la permutation suivante ou preacuteceacutedente dune

seacutequence de valeurs donneacutees Dans lexemple ci-dessus la permutation preacuteceacutedente de la

seacutequence 4 1 8 serait la seacutequence 1 8 4 tandis que la permutation suivante serait 4 8 1

Pour eacuteviter tout problegraveme on considegravere que la permutation suivant la derniegravere est la pre-

miegravere et que la permutation preacuteceacutedent la derniegravere est la premiegravere

Les algorithmes next_permutation et prev_permutation permettent de remplacer une

seacutequence donneacutee respectivement par la permutation suivante ou par la permutation preacuteceacute-

dente On peut utiliser soit par deacutefaut lopeacuterateur lt soit une relation imposeacutee sous forme

dun preacutedicat binaire Actuellement il nexiste pas de variantes _copy de ces algorithmes

Voici un exemple (la valeur de retour true ou false des algorithmes permet de savoir si lon a

effectueacute un bouclage dans la liste des permutations)

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 2 1 3 int i vectorltintgt v(t t+3) cout ltlt vecteur initial affiche(v) for (i=0 ilt=10 i++) bool res = next_permutation (vbegin() vend()) cout ltlt permutation ltlt res ltlt affiche(v)

4 - Algorithmes de transformation dune seacutequence471

void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 2 1 3permutation 1 2 3 1permutation 1 3 1 2permutation 1 3 2 1permutation 0 1 2 3permutation 1 1 3 2permutation 1 2 1 3permutation 1 2 3 1permutation 1 3 1 2permutation 1 3 2 1permutation 0 1 2 3permutation 1 1 3 2

Exemple dutilisation de next_permutation et de prev_permutation

423 Permutations aleacuteatoires

Lalgorithme random_shuffle permet deffectuer une permutation aleacuteatoire des valeurs dune

seacutequence En voici un exemple

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) int t[] = 2 1 3 int i

vectorltintgt v(t t+3) cout ltlt vecteur initial affiche(v) for (i=0 ilt=10 i++) random_shuffle (vbegin() vend()) cout ltlt vecteur hasard affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

Les algorithmes standardCHAPITRE 21

472

vecteur initial 2 1 3vecteur hasard 3 2 1vecteur hasard 2 3 1vecteur hasard 1 2 3vecteur hasard 1 3 2vecteur hasard 3 1 2vecteur hasard 3 2 1vecteur hasard 3 1 2vecteur hasard 3 2 1vecteur hasard 2 3 1vecteur hasard 2 3 1vecteur hasard 2 3 1

Exemple dutilisation de random_shuffle

Remarque

Il existe une version de random_shuffle permettant dimposer son geacuteneacuterateur de nombres

aleacuteatoires

43 Partitions On nomme partition dune seacutequence suivant un preacutedicat unaire donneacute un reacutearrangement de

cette seacutequence deacutefini par un iteacuterateur deacutesignant un eacuteleacutement tel que tous les eacuteleacutements le preacuteceacute-

dant veacuterifient la dite condition Par exemple avec la seacutequence

1 3 4 11 2 7 8

et le preacutedicat impair (supposeacute vrai pour un nombre impair et faux sinon) voici des partitions

possibles (dans tous les cas liteacuterateur deacutesignera le quatriegraveme eacuteleacutement)

1 3 11 7 4 2 8 liteacuterateur deacutesignera ici le 4

1 3 11 7 2 8 4 liteacuterateur deacutesignera ici le 2

3 1 7 11 2 4 8 liteacuterateur deacutesignera ici le 2

On dit que la partition obtenue est stable si lordre relatif des eacuteleacutements satisfaisant au preacutedicat

est conserveacute Dans notre exemple seules les deux premiegraveres permutations sont stables

Les algorithmes partition et stable_partition permettent de deacuteterminer une telle partition agrave

partir dun preacutedicat unaire fourni en argument

5 Algorithmes dits de suppression Ces algorithmes permettent deacuteliminer dune seacutequence les eacuteleacutements reacutepondant agrave un certain

critegravere Mais assez curieusement ils ne suppriment pas les eacuteleacutements correspondants ils se

5 - Algorithmes dits de suppression473

contentent de regrouper en deacutebut de seacutequence les eacuteleacutements non concerneacutes par la condition

deacutelimination et de fournir en retour un iteacuterateur sur le premier eacuteleacutement non conserveacute En fait

il faut voir quaucun algorithme ne peut supprimer des eacuteleacutements dune seacutequence pour la

bonne et simple raison quil risque decirctre appliqueacute agrave une structure autre quun conteneur (ne

serait-ce quun tableau usuel) pour laquelle la notion de suppression nexiste pas1 Dautre

part contrairement agrave toute attente il nest pas du tout certain que les valeurs apparaissant en

fin de conteneur soient celles qui ont eacuteteacute eacutelimineacutees du deacutebut

Bien entendu rien nempecircche deffectuer apregraves avoir appeleacute un tel algorithme une suppres-

sion effective des eacuteleacutements concerneacutes en utilisant une fonction membre telle que remove

dans le cas ougrave lon a affaire agrave une seacutequence dun conteneur

Lalgorithme remove (deacutebut fin valeur) permet deacuteliminer tous les eacuteleacutements ayant la valeur

indiqueacutee en se basant sur lopeacuterateur == Il existe une version remove_if qui se fonde sur un

preacutedicat binaire donneacute Seul le premier algorithme est stable crsquoest-agrave-dire quil conserve

lordre relatif des valeurs non eacutelimineacutees

Lalgorithme unique permet de ne conserver que la premiegravere valeur dune seacuterie de valeurs

eacutegales (au sens de ==) ou reacutepondant agrave un preacutedicat binaire donneacute Il nimpose nullement que la

seacutequence soit ordonneacutee suivant un certain ordre

Ces algorithmes disposent dune version avec _copy qui ne modifie pas la seacutequence dorigine

et qui range dans une autre seacutequence les seules valeurs non eacutelimineacutees Utiliseacutes conjointement

avec un iteacuterateur dinsertion ils peuvent permettre de creacuteer une nouvelle seacutequence

Voici un exemple de programme montrant les principales possibiliteacutes eacutevoqueacutees y compris

des insertions dans une seacutequence avec remove_copy_if (dont on remarque clairement

dailleurs quil nest pas stable)

include ltiostreamgtinclude ltlistgtinclude ltalgorithmgtusing namespace std main() void affiche(listltintgt) bool valeur_paire (int) int t[] = 4 3 5 4 4 4 9 4 6 6 3 3 2 listltintgt l (t t+sizeof(t)sizeof(int)) listltintgt l_bis=l listltintgt l2 liste vide listltintgtiterator il cout ltlt liste initiale affiche(l)

il = remove(lbegin() lend() 4) different de lremove(4) cout ltlt liste apres remove(4) affiche(l)

1 Un algorithme ne peut pas davantage inseacuterer un eacuteleacutement dans une seacutequence on peut toutefois y parvenir dans le

cas dun conteneur en recourant agrave un iteacuterateur dinsertion

Les algorithmes standardCHAPITRE 21

474

cout ltlt element places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

l = l_bis il = unique (lbegin() lend()) cout ltlt liste apres unique affiche(l) cout ltlt elements places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

l = l_bis il = remove_if(lbegin() lend() valeur_paire) cout ltlt liste apres remove pairs affiche(l) cout ltlt elements places en fin for ( il=lend() il++) cout ltlt il ltlt cout ltlt n

elimination de valeurs par copie dans liste vide l2 par iterateur dinsertion l = l_bis remove_copy_if(lbegin() lend() front_inserter(l2) valeur_paire) cout ltlt liste avec remove_copy_if paires affiche(l2)

void affiche(listltintgt l) listltintgtiterator il for (il=lbegin() il=lend() il++) cout ltlt (il) ltlt cout ltlt n bool valeur_paire (int n) return (n2)

liste initiale 4 3 5 4 4 4 9 4 6 6 3 3 2liste apres remove(4) 3 5 9 6 6 3 3 2 6 6 3 3 2element places en fin 6 6 3 3 2liste apres unique 4 3 5 4 9 4 6 3 2 6 3 3 2elements places en fin 6 3 3 2liste apres remove pairs 3 5 9 3 3 4 9 4 6 6 3 3 2elements places en fin 4 9 4 6 6 3 3 2liste avec remove_copy_if paires 3 3 9 5 3

Exemple dutilisation des algorithmes de suppression

6 Algorithmes de tris Ces algorithmes sappliquent agrave des seacutequences ordonnables crsquoest-agrave-dire pour lesquelles il aeacuteteacute deacutefini une relation dordre faible strict soit par lopeacuterateur lt soit par un preacutedicat binairedonneacute Ils ne peuvent pas sappliquer agrave un conteneur associatif compte tenu du conflit quiapparaicirctrait alors entre leur ordre interne et celui quon voudrait leur imposer Pour deacuteviden-tes questions defficaciteacute la plupart de ces algorithmes neacutecessitent des iteacuterateurs agrave accegraves

6 - Algorithmes de tris475

direct de sorte quils ne sont pas applicables agrave des listes (mais le conteneur list dispose de safonction membre sort)

On peut reacutealiser des tris complets dune seacutequence Dans ce cas on peut choisir entre un algo-rithme stable stable_sort ou un algorithme non stable plus rapide On peut effectuer eacutegale-ment avec partial_sort des tris partiels crsquoest-agrave-dire qui se contentent de nordonner quuncertain nombre deacuteleacutements Dans ce cas lappel se preacutesente sous la forme partial_sort (deacutebut

milieu fin) et lamplitude du tri est deacutefinie par liteacuterateur milieu deacutesignant le premier eacuteleacutementnon trieacute Enfin avec nth_element il est possible de deacuteterminer seulement le niegraveme eacuteleacutementcrsquoest-agrave-dire de placer dans cette position leacuteleacutement qui sy trouverait si lon avait trieacute toute laseacutequence lagrave encore lappel se preacutesente sous la forme nth_element (deacutebut milieu fin) etmilieu deacutesigne leacuteleacutement en question

Voici un exemple montrant lutilisation des principaux algorithmes de tri

include ltiostreamgtinclude ltvectorgtinclude ltalgorithmgtusing namespace std main() void affiche (vectorltintgt) bool comp (int int) int t[] = 2 1 3 9 2 7 5 8 vectorltintgt v(t t+8) v_bis=v cout ltlt vecteur initial affiche(v) sort (vbegin() vend()) cout ltlt apres sort affiche(v) v = v_bis partial_sort (vbegin() vbegin()+5 vend()) cout ltlt apres partial_sort (5) affiche(v) v = v_bis nth_element (vbegin() vbegin()+ 5 vend()) cout ltlt apres nth_element 6 affiche(v) nth_element (vbegin() vbegin()+ 2 vend()) cout ltlt apres nth_element 3 affiche(v) void affiche (vectorltintgt v) unsigned int i for (i=0 iltvsize() i++) cout ltlt v[i] ltlt cout ltlt n

vecteur initial 2 1 3 9 2 7 5 8apres sort 1 2 2 3 5 7 8 9apres partial_sort (5) 1 2 2 3 5 9 7 8apres nth_element 6 2 1 3 5 2 7 8 9apres nth_element 3 2 1 2 3 5 7 8 9

Exemple dutilisation des algorithmes de tri

Les algorithmes standardCHAPITRE 21

476

7 Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees

Ces algorithmes sappliquent agrave des seacutequences supposeacutees ordonneacutees par une relation dordrefaible strict

71 Algorithmes de recherche binaire Les algorithmes de recherche preacutesenteacutes dans le paragraphe 3 sappliquaient agrave des seacutequencesnon neacutecessairement ordonneacutees Les algorithmes preacutesenteacutes ici supposent que la seacutequence con-cerneacutee soit convenablement ordonneacutee suivant la relation dordre faible strict qui sera utiliseacuteequil sagisse par deacutefaut de lopeacuterateur lt ou dun preacutedicat fourni explicitement Cest ce quileur permet dutiliser des meacutethodes de recherche dichotomique (ou binaire) plus performantesque de simples recherches seacutequentielles

Comme on peut sy attendre ces algorithmes ne modifient pas la seacutequence concerneacutee et ilspeuvent donc en theacuteorie sappliquer agrave des conteneurs de type set ou multiset En revancheleur application agrave des types map et multimap nest guegravere envisageable puisque en geacuteneacuteral cene sont pas leurs eacuteleacutements qui sont ordonneacutes mais seulement les cleacutes Quoi quil en soit lesconteneurs associatifs disposent deacutejagrave de fonctions membres eacutequivalant aux algorithmes exa-mineacutes ici excepteacute pour binary_search

Lalgorithme binary_search permet de savoir sil existe dans la seacutequence une valeur eacutequiva-lente (au sens de leacutequivalence induite par la relation dordre concerneacutee) Par ailleurs on peutlocaliser lemplacement possible pour une valeur donneacutee compte tenu dun certain ordre lower_bound fournit la premiegravere position possible tandis que upper_bound fournit la derniegravereposition possible equal_range fournit les deux informations preacuteceacutedentes sous forme dunepaire

72 Algorithmes de fusion La fusion de deux seacutequences ordonneacutees consiste agrave les reacuteunir en une troisiegraveme seacutequenceordonneacutee suivant le mecircme ordre Lagrave encore ils peuvent sappliquer agrave des conteneurs de typeset ou multiset en revanche leur application agrave des conteneurs de type map ou multimap nestguegravere reacutealiste compte tenu de ce que ces derniers sont ordonneacutes uniquement suivant les cleacutesIl existe deux algorithmes

bull merge qui permet la creacuteation dune troisiegraveme seacutequence par fusion de deux autres

bull inplace_merge qui permet la fusion de deux seacutequences conseacutecutives en une seule qui vientprendre la place des deux seacutequences originales

Voici un exemple dutilisation de ces algorithmes

7 - Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees477

include ltiostreamgt

include ltvectorgt

include ltalgorithmgt

using namespace std

main()

void affiche (vectorltintgt)

int t1[8] = 2 1 3 12 2 18 5 8

int t2[5] = 5 4 15 9 11

vectorltintgt v1(t1 t1+8) v2(t2 t2+6) v

cout ltlt vecteur 1 initial affiche(v1)

sort (v1begin() v1end())

cout ltlt vecteur 1 trie affiche(v1)

cout ltlt vecteur 2 initial affiche(v2)

sort (v2begin() v2end())

cout ltlt vecteur 2 trie affiche(v2)

merge (v1begin() v1end() v2begin() v2end() back_inserter(v))

cout ltlt fusion des deux affiche(v)

random_shuffle (vbegin() vend()) v nest plus ordonne

cout ltlt vecteur v desordonne affiche(v)

sort (vbegin() vbegin()+6) tri des premiers elements de v

sort (vbegin()+6 vend()) tri des derniers elements de v

cout ltlt vecteur v trie par parties affiche(v)

inplace_merge (vbegin() vbegin()+6 vend()) fusion interne

cout ltlt vecteur v apres fusion affiche(v)

void affiche (vectorltintgt v)

unsigned int i

for (i=0 iltvsize() i++)

cout ltlt v[i] ltlt

cout ltlt 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

Exemple dutilisation des algorithmes de fusion

Les algorithmes standardCHAPITRE 21

478

8 Algorithmes agrave caractegravere numeacuterique Nous avons classeacute dans cette rubrique les algorithmes qui effectuent sur les eacuteleacutements duneseacutequence des opeacuterations numeacuteriques fondeacutees sur les opeacuterateurs + - ou Plutocirct destineacutes apriori agrave des eacuteleacutements dun type effectivement numeacuterique ils peuvent neacuteanmoins sappliqueragrave des eacuteleacutements de type classe pour peu que cette derniegravere ait convenablement surdeacutefini lesopeacuterateurs voulus ou quelle fournisse une fonction binaire approprieacutee

Comme on peut sy attendre lalgorithme accumulate fait la somme des eacuteleacutements duneseacutequence tandis que inner_product effectue le produit scalaire de deux seacutequences de mecircmetaille On prendra garde au fait que ces deux algorithmes ajoutent le reacutesultat agrave une valeur ini-tiale fournie en argument (en geacuteneacuteral on choisit 0)

Lalgorithme partial_sum creacutee agrave partir dune seacutequence une nouvelle seacutequence de mecircmetaille formeacutee des cumuls partiels des valeurs de la premiegravere le premier eacuteleacutement est inchangeacutele second est la somme du premier et du second etc Enfin lalgorithme adjacent_difference

creacutee agrave partir dune seacutequence une seacutequence de mecircme taille formeacutee des diffeacuterences de deuxeacuteleacutements conseacutecutifs (le premier eacuteleacutement restant inchangeacute)

Voici un exemple dutilisation de ces diffeacuterents algorithmes

include ltiostreamgt

include ltnumericgt pour les algorithmes numeriquesusing namespace std

main()

void affiche (int )

int v1[5] = 1 3 -1 4 1 int v2[5] = 2 5 1 -3 2

int v3[5] cout ltlt vecteur v1 affiche(v1)

cout ltlt vecteur v2 affiche(v2)

cout ltlt somme des elements de v1 ltlt accumulate (v1 v1+3 0) ltlt n ne pas oublier 0

cout ltlt produit scalaire v1v2 ltlt inner_product (v1 v1+3 v2 0) ltlt n ne pas oublier 0

partial_sum (v1 v1+5 v3)

cout ltlt sommes partielles de v 1 affiche(v3) adjacent_difference (v1 v1+5 v3)

cout ltlt differences ajdacentes de v1 affiche(v3)

void affiche (int v) int i for (i=0 ilt5 i++) cout ltlt v[i] ltlt cout ltlt n

9 - Algorithmes agrave caractegravere ensembliste479

vecteur v1 1 3 -1 4 1vecteur v2 2 5 1 -3 2somme des elements de v1 3produit scalaire v1v2 16sommes partielles de v 1 1 4 3 7 8differences ajdacentes de v1 1 2 -4 5 -3

Exemple dutilisation dalgorithmes numeacuteriques

9 Algorithmes agrave caractegravere ensembliste Comme on a pu le constater dans le chapitre preacuteceacutedent les conteneurs set et multiset ne dis-posent daucune fonction membre permettant de reacutealiser les opeacuterations ensemblistes classi-ques En revanche il existe des algorithmes geacuteneacuteraux qui quant agrave eux peuvent en theacuteoriesappliquer agrave des seacutequences quelconques il faut cependant quelles soient convenablementordonneacutees ce qui constitue une premiegravere diffeacuterence par rapport aux notions matheacutematiquesusuelles dont lordre est manifestement absent De plus ces notions ensemblistes ont ducirc ecirctrequelque peu ameacutenageacutees de maniegravere agrave accepter la preacutesence de plusieurs eacuteleacutements de mecircmevaleur

Leacutegaliteacute entre deux eacuteleacutements se fonde sur lopeacuterateur == ou eacuteventuellement sur un preacutedicatbinaire fourni explicitement Pour que les algorithmes fonctionnent convenablement il estalors neacutecessaire que cette relation deacutegaliteacute soit compatible avec la relation ayant servi agraveordonner les seacutequences correspondantes plus preacuteciseacutement il est neacutecessaire que les classesdeacutequivalence induite par la relation dordre faible strict coiumlncident avec celles qui sont indui-tes par leacutegaliteacute

Par ailleurs les algorithmes creacuteant une nouvelle seacutequence le font comme toujours dans deseacuteleacutements existants ce qui pose manifestement un problegraveme avec des conteneurs de type set

ou multiset qui nautorisent pas la modification des valeurs de leurs eacuteleacutements mais seulementles suppressions ou les insertions Dans ce cas il faudra donc recourir agrave un iteacuterateur dinser-tion pour la seacutequence agrave creacuteer De plus comme ni set ni multiset ne disposent dinsertion endeacutebut ou en fin cet iteacuterateur dinsertion ne pourra ecirctre que inserter

Voici un exemple correspondant agrave lusage le plus courant des algorithmes agrave savoir leur appli-cation agrave des conteneurs de type set

include ltiostreamgtinclude ltsetgtinclude ltalgorithmgtusing namespace std

Les algorithmes standardCHAPITRE 21

480

main() char t1[] = je me figure ce zouave qui joue du xylophone char t2[] = en buvant du whisky void affiche (setltchargt ) setltchargt e1(t1 t1+sizeof(t1)-1) setltchargt e2(t2 t2+sizeof(t2)-1) setltchargt u i d ds cout ltlt ensemble 1 affiche (e1) cout ltlt ensemble 2 affiche (e2) set_union (e1begin() e1end() e2begin() e2end() inserter(u ubegin())) cout ltlt union des deux affiche (u) set_intersection (e1begin() e1end() e2begin() e2end() inserter(i ibegin())) cout ltlt intersecton des deux affiche (i) set_difference (e1begin() e1end() e2begin() e2end() inserter(d dbegin())) cout ltlt difference des deux affiche (d) set_symmetric_difference (e1begin() e1end() e2begin() e2end() inserter(ds dsbegin())) cout ltlt difference_symetrique des deux affiche (ds) void affiche (setltchargt e ) setltchargtiterator ie for (ie=ebegin() ie=eend() ie++) cout ltlt ie ltlt cout ltlt n

ensemble 1 a c d e f g h i j l m n o p q r u v x y zensemble 2 a b d e h i k n s t u v w yunion 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 zintersecton des deux a d e h i n u v ydifference des deux c f g j l m o p q r x zdifference_symetrique des deux b c f g j k l m o p q r s t w x z

Exemple dutilisation dalgorithmes agrave caractegravere ensembliste avec un conteneur de type set

10 Algorithmes de manipulation de tasLa bibliothegraveque standard comporte quelques algorithmes fondeacutes sur la notion de tas (heap enanglais) Il srsquoagit en fait drsquoalgorithmes drsquoassez bas niveau eacuteventuellement utilisables pourlrsquoimpleacutementation drsquoautres algorithmes de plus haut niveau mais qui restent neacuteanmoins utili-

10 - Algorithmes de manipulation de tas481

sables tels quels Ils srsquoappliquent agrave des seacutequences munies drsquoune relation drsquoordre faible strictet drsquoun iteacuterateur agrave accegraves direct

Un tas est une organisation particuliegravere1 (unique) drsquoune seacutequence qui permet drsquoobtenir debonnes performances pour le tri lrsquoajout ou la suppression drsquoune valeur Une des proprieacuteteacutesdrsquoun tas est que sa premiegravere valeur est supeacuterieure agrave toutes les autres

Un algorithme make_heap permet de reacutearranger convenablement une seacutequence sous formedrsquoun tas Lrsquoalgorithme sort_heap permet de trier un tas (le reacutesultat nrsquoest alors plus un tas)

Lrsquoalgorithme pop_heap permet de retirer la premiegravere valeur drsquoun tas celle-ci est placeacutee enfin de seacutequence la seacutequence entiegravere nrsquoest alors plus un tas seule la seacutequence priveacutee de sa(nouvelle) derniegravere valeur en est un

Enfin lrsquoalgorithme push_heap permet drsquoajouter une valeur agrave un tas Cette valeur doit appa-raicirctre juste apregraves la derniegravere valeur du tas

Voici quelques exemples de programmes complets illustrant ces diffeacuterentes possibiliteacutes

include ltiostreamgtinclude ltalgorithmgt

using namespace std

main() int t[] = 5 1 8 0 9 4 6 3 4

void affiche (int []) cout ltlt sequence t initiale affiche (t)

make_heap (t t+9) t est maintenant ordonne en tas cout ltlt tas t initial affiche(t)

sort (t t+9) t est trie mais nest plus un tas cout ltlt sequence t triee affiche(t)

sort (t t+9) resultat incoherent car t nest plus un tas

cout ltlt sequence t triee 2 fois affiche(t) make_heap (t t+9) t est a nouveau ordonne en tas

cout ltlt tas t nouveau affiche(t)

void affiche (int t[]) int i

for (i=0 ilt9 i++) cout ltlt t[i] ltlt

cout ltlt n

1 La notion de tas est fondeacutee sur celle drsquoarbre binaire plein On peut eacutetablir une correspondance biunivoque entre un

tel arbre et un tableau (donc une seacutequence munie drsquoun iteacuterateur agrave accegraves direct) convenablement arrangeacute

Les algorithmes standardCHAPITRE 21

482

sequence t initiale 5 1 8 0 9 4 6 3 4tas t initial 9 5 8 4 1 4 6 3 0sequence t triee 0 1 3 4 4 5 6 8 9sequence t triee 2 fois 0 1 3 4 4 5 6 8 9tas t nouveau 9 8 6 4 4 5 3 1 0

Tri par tas drsquoune seacutequence

include ltiostreamgtinclude ltalgorithmgtusing namespace std main() int t[] = 5 1 7 0 6 4 6 8 9 void affiche (int int) cout ltlt sequence t complete affiche (t 9) make_heap (t t+7) 7 premiers elements de t ordonnes en tas cout ltlt tas t (1-7) initial affiche (t 7) push_heap (t t+8) ajoute t[7] au tas precedent cout ltlt tas t (1-8) apres push affiche (t 8) push_heap (t t+9) ajoute t[8] au tas precedent cout ltlt tas t (1-9) apres push affiche (t 9) sort_heap (t t+9) trie le tas cout ltlt tas t (1-9) trie affiche (t 9)

void affiche (int t int nel) int i for (i=0 iltnel i++) cout ltlt t[i] ltlt cout ltlt n

sequence t complete 5 1 7 0 6 4 6 8 9tas t (1-7) initial 7 6 6 0 1 4 5tas t (1-8) apres push 8 7 6 6 1 4 5 0tas t (1-9) apres push 9 8 6 7 1 4 5 0 6tas t (1-9) trie 0 1 4 5 6 6 7 8 9

Insertion dans un tas

include ltiostreamgtinclude ltalgorithmgtusing namespace std

10 - Algorithmes de manipulation de tas483

main() int t[] = 5 1 7 0 6 4 6 8 9 void affiche (int int) cout ltlt sequence t complete affiche (t 9) make_heap (t t+9) 9 elements de t ordonnes en tas cout ltlt tas t (0-8) initial affiche (t 9) pop_heap (t t+9) enleve t[0] au tas precedent cout ltlt tas t (0-7) apres pop affiche (t 8) cout ltlt valeurs t[8] ltlt t[8] ltlt n pop_heap (t t+8) enleve t[0] du tas precedent cout ltlt tas t (0-8) apres pop affiche (t 7) cout ltlt valeurs t[7-8] ltlt t[7] ltlt ltlt t[8] ltlt n sort_heap (t t+7) trie le tas t[0-6] cout ltlt tas t1 (0-6) trie affiche (t 7) void affiche (int t int nel) int i for (i=0 iltnel i++) cout ltlt t[i] ltlt cout ltlt n

sequence t complete 5 1 7 0 6 4 6 8 9tas t (0-8) initial 9 8 7 5 6 4 6 1 0tas t (0-7) apres pop 8 6 7 5 0 4 6 1 valeurs t[8] 9tas t (0-8) apres pop 7 6 6 5 0 4 1 valeurs t[7-8] 8 9tas t1 (0-6) trie 0 1 4 5 6 6 7

Suppression de la premiegravere valeur drsquoun tas

22

La classe string

Si lon cherche agrave manipuler des chaicircnes de caractegraveres en se fondant uniquement sur les ins-tructions de base du langage C++ les choses ne sont pas plus satisfaisantes quen C enparticulier on ny dispose pas dun type chaicircne agrave part entiegravere et mecircme une opeacuteration aussibanale que laffectation nexiste pas quant aux possibiliteacutes de gestion dynamique on ne peuty acceacuteder quen geacuterant soi mecircme les choses

La bibliothegraveque standard dispose dun patron de classes permettant de manipuler des chaicircnesgeacuteneacuteraliseacutees crsquoest-agrave-dire des suites de valeurs de type quelconque donc en particulier detype char Il sagit du patron basic_string parameacutetreacute par le type des eacuteleacutements Mais il existeune une version speacutecialiseacutee de ce patron nommeacutee string qui est deacutefinie commebasic_stringltchargt1 Ici nous nous limiterons agrave lexamen des proprieacuteteacutes de cette classe quiest de loin la plus utiliseacutee la geacuteneacuteralisation agrave basic_string ne preacutesente de toutes faccedilonsaucune difficulteacute

La classe string propose un cadre tregraves souple de manipulation de chaicircnes de caractegraveres enoffrant les fonctionnaliteacutes traditionnelles quon peut attendre dun tel type gestion dynami-que transparente des emplacements correspondants affectation concateacutenation recherche desous-chaicircnes insertions ou suppression de sous-chaicircnes On verra quelle possegravede non seu-lement beaucoup des fonctionnaliteacutes de la classe vector (plus preacuteciseacutement vectorltchargt

pour string) mais eacutegalement bien dautres Dune maniegravere geacuteneacuterale ces fonctionnaliteacutes semettent en œuvre de faccedilon tregraves naturelle ce qui nous permettra de les preacutesenter assez briegraveve-ment Il faut cependant noter une petite difficulteacute lieacutee agrave la preacutesence de certaines possibiliteacutesredondantes les unes faisant appel agrave des iteacuterateurs usuels les autres agrave des valeurs dindices

1 Il existe eacutegalement une version speacutecialiseacutee pour le type whcar nommeacutee wstring

La classe stringCHAPITRE 22

486

1 Geacuteneacuteraliteacutes Un objet de type string contient agrave un instant donneacute une suite formeacutee dun nombre quelcon-que de caractegraveres quelconques Sa taille peut eacutevoluer dynamiquement au fil de lexeacutecution duprogramme Contrairement aux conventions utiliseacutees pour les (pseudo) chaicircnes du C lanotion de caractegravere de fin de chaicircne nexiste plus et ce caractegravere de code nul peut apparaicirctreau sein de la chaicircne eacuteventuellement agrave plusieurs reprises Un tel objet ressemble donc agrave unconteneur de type vectorltchargt et il possegravede dailleurs un certain nombre de fonctionnaliteacutescommunes

bull laccegraves aux eacuteleacutements existants peut se faire avec lopeacuterateur [] ou avec la fonction membreat comme avec les vecteurs ou les tableaux usuels le premier caractegravere correspond agrave lin-dice 0

bull il possegravede une taille courante fournie par la fonction membre size() agrave noter que la classestring deacutefinit une autre fonction nommeacutee length jouant le mecircme rocircle que size

bull son emplacement est reacuteserveacute sous forme dun seul bloc de meacutemoire (ou du moins tout sepasse comme si cela eacutetait le cas) la fonction capacity fournit le nombre maximal de carac-tegraveres quon pourra y introduire sans quil soit besoin de proceacuteder agrave une nouvelle allocationmeacutemoire on peut recourir aux fonctions reserve et resize

bull on dispose des iteacuterateurs agrave accegraves direct iterator et reverse_iterator ainsi que des valeurs par-ticuliegraveres begin() end() rbegin() rend()

2 Construction La classe string dispose de beaucoup de constructeurs certains correspondent aux construc-teurs dun vecteur

string ch1 construction dune chaicircne vide ch1size() == 0 string ch2 (10 ) construction dune chaicircne de 10 caractegraveres eacutegaux agrave rsquorsquo ch2size() == 10 string ch3 (5 0) construction dune chaicircne de 5 caractegraveres de code nul ch2size() == 5

Dautres permettent dinitialiser une chaicircne lors de sa construction agrave partir de chaicircnes usuel-les constantes ou non

string mess1 (bonjour) construction chaicircne de longueur 7 bonjour ou string mess1 = bonjour char adr = salut string mess2 (adr) construction chaicircne de 5 caractegraveres salut ou string mess2 = adr

Bien entendu on dispose dun constructeur par recopie usuel string s1 string s2(s1) ou string s2 = s1 construction de s2 par recopie de s1 s2size() == s1size()

3 - Opeacuterations globales487

Bien que dun inteacuterecirct limiteacute on peut eacutegalement construire une chaicircne agrave partir dune seacutequencede caractegraveres par exemple si l est de type listltchargt

string chl (lbegin() lend()) construction dune chaicircne en y recopiant

les caractegraveres de la liste l

3 Opeacuterations globales On dispose tout naturellement des opeacuterations globales deacutejagrave rencontreacutees pour les vecteurs agravesavoir laffectation les fonctions assign et swap ainsi que des comparaisons lexicographi-ques

Comme on srsquoy attend les opeacuterateurs ltlt et gtgt sont surdeacutefinis pour le type string et gtgt utilisepar deacutefaut les mecircmes conventions de seacuteparateurs que pour les chaicircnes de style C drsquoougravelrsquoimpossibiliteacute de lire une chaicircne comportant un espace blanc (en particulier un espace ou unefin de ligne)

En revanche il nrsquoexiste pas dans la classe istream de meacutethode jouant pour les objets de typestring le rocircle de getline pour les (pseudo) chaicircnes de C Toutefois il existe une fonction indeacute-pendante nommeacutee eacutegalement getline qui srsquoutilise ainsi

string ch

getline (cin ch) lit une suite de caractegraveres termineacutee par une fin de ligne

et la range dans lrsquoobjet ch (fin de ligne non comprise)

getline (cin ch rsquoxrsquo) lit une suite de caractegraveres termineacutee par le caractegravere rsquoxrsquo

et la range dans lrsquoobjet ch (caractegravere rsquoxrsquo non compris)

Aucune restriction ne pegravese sur le nombre de caractegraveres qui pouront ecirctre rangeacutes dans lrsquoobjetch La longueur de la chaicircne ainsi constitueacutee pourra ecirctre obtenue par chlength() ou chsize()

Agrave titre drsquoexemple voici comment reacuteeacutecrire le programme du paragraphe 23 du chapitre 16qui affichait des lignes de caractegraveres entreacutees au clavier Comme vous le constatez il nrsquoestplus neacutecessaire de deacutefinir une longueur maximale de ligne

include ltiostreamgt

using namespace std

main()

string ch pour lire une ligne

int lg longueur courante drsquoune ligne

do

getline (cin ch)

lg = chlength()

cout ltlt ligne de ltlt lg ltlt caracteres ltlt ch ltlt n

while (lg gt1)

La classe stringCHAPITRE 22

488

bonjour

ligne de 7 caracteres bonjour

9 fois 5 font 45

ligne de 16 caracteres 9 fois 5 font 45

nrsquoimporte quoi ltampeacutersquo(-egrave_ccedilagrave))=

ligne de 29 caracteres nrsquoimporte quoi ltampeacutersquo(-egrave_ccedilagrave))=

ligne de 0 caracteres

Exemple drsquoutilisation de la fonction indeacutependante getline

4 Concateacutenation Lopeacuterateur + a eacuteteacute surdeacutefini de maniegravere agrave permettre la concateacutenation

bull de deux objets de type string

bull dun objet de type string avec une chaicircne usuelle ou avec un caractegravere et ceci dans nimportequel ordre

Lopeacuterateur += est deacutefini de faccedilon concomitante

Voici quelques exemples

string ch1 (bon) ch1length() == 3

string ch2 (jour) ch2length() == 4

string ch3 ch3length() == 0 ch3 = ch1 + ch2 ch3length() == 7 ch3 contient la chaicircne bonjour

ch3 = ch1 + ch3length() == 4

ch3 += ch2 ch3length() == 8 ch3 contient la chaicircne bon jour

ch3 += monsieur ch3 contient la chaicircne bon jour monsieur

On notera cependant quil nest pas possible de concateacutener deux chaicircnes usuelles ou unechaicircne usuelle et un caractegravere

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 Recherche dans une chaicircne Ces fonctions permettent de retrouver la premiegravere ou la derniegravere occurrence dune chaicircne oudun caractegravere donneacutes dun caractegravere appartenant agrave une suite de caractegraveres donneacutes duncaractegravere nappartenant pas agrave une suite de caractegraveres donneacutes

Lorsquune telle chaicircne ou un tel caractegravere a eacuteteacute localiseacute on obtient en retour lindice corres-pondant au premier caractegravere concerneacute si la recherche naboutit pas on obtient une valeur

5 - Recherche dans une chaicircne489

dindice en dehors des limites permises pour la chaicircne ce qui rend quelque peu difficile lexa-men de sa valeur

51 Recherche dune chaicircne ou dun caractegravere La fonction membre find permet de rechercher dans une chaicircne donneacutee la premiegravereoccurrence

bull dune autre chaicircne (on parle souvent de sous-chaicircne) fournie soit par un objet de type stringsoit par une chaicircne usuelle

bull dun caractegravere donneacute

Par deacutefaut la recherche commence au deacutebut de la chaicircne mais on peut la faire deacutebuter agrave uncaractegravere de rang donneacute

Voici quelques exemples string ch = anticonstitutionnellement string mot (on)char ad = ti int i i = chfind (elle) i == 17 i = chfind (elles) i lt0 ou i gt chlength() i = chfind (mot) i == 5 i = chfind (ad) i == 2 i = chfind (n) i == 1 i = chfind (n 5) i == 6 car ici la recherche deacutebute agrave ch[5] i = chfind (p) i lt0 ou i gt chlength()

De maniegravere semblable la fonction rfind permet de rechercher la derniegravere occurrence duneautre chaicircne ou dun caractegravere

string ch = anticonstitutionnellement string mot (on)char ad = ti int i i = chrfind (elle) i == 17 i = chrfind (elles) i lt0 ou i gt chlength() i = chrfind (mot) i == 14 i = chrfind (ad) i == 12 i = chrfind (n) i == 23 i = chrfind (n 18) i == 16

52 Recherche dun caractegravere preacutesent ou absent dune suite La fonction find_first_of recherche la premiegravere occurrence de lun des caractegraveres dune autrechaicircne (string ou usuelle) tandis que find_last_of en recherche la derniegravere occurrence Lafonction find_first_not_of recherche la premiegravere occurrence dun caractegravere nappartenant pasagrave une autre chaicircne tandis que find_last_not_of en recherche la derniegravere Voici quelquesexemples

La classe stringCHAPITRE 22

490

string ch = anticonstitutionnellement

char ad = oie

int i

i = chfind_first_of (aeiou) i == 0

i = chfind_first_not_of (aeiou) i == 1

i = chfind_first_of (aeiou 6) i == 9

i = chfind_first_not_of (aeiou 6) i == 6

i = chfind_first_of (ad) i == 3

i = chfind_last_of (aeiou) i == 22

i = chfind_last_not_of (aeiou) i == 24

i = chfind_last_of (aeiou 6) i == 5

i = chfind_last_not_of (aeiou 6) i == 6

i = chfind_last_of (ad) i == 22

6 Insertions suppressions et remplacements Ces possibiliteacutes sont relativement classiques mais elles se recoupent partiellement dans lamesure ougrave lon peut

bull dune part utiliser non seulement des objets de type string mais aussi des chaicircnes usuelles(char ) ou des caractegraveres

bull dautre part deacutefinir une sous-chaicircne soit par indice soit par iteacuterateur cette derniegravere possibi-liteacute neacutetant cependant pas offerte systeacutematiquement

61 Insertions La fonction insert permet dinseacuterer

bull agrave une position donneacutee deacutefinie par un indice

ndash une autre chaicircne (objet de type string) ou une partie de chaicircne deacutefinie par un indice dedeacutebut et une eacuteventuelle longueur

ndash une chaicircne usuelle (type char ) ou une partie de chaicircne usuelle deacutefinie par une lon-gueur

ndash un certain nombre de fois un caractegravere donneacute

bull agrave une position donneacutee deacutefinie par un iteacuterateur

ndash une seacutequence deacuteleacutements de type char deacutefinie par un iteacuterateur de deacutebut et un iteacuterateurde fin

ndash une ou plusieurs fois un caractegravere donneacute

Voici quelques exemples

6 - Insertions suppressions et remplacements491

include ltiostreamgt

include ltstringgt

include ltlistgt

using namespace std

main()

string ch (0123456)

string voy (aeiou)

char t[] = 778899

insere le caractere a en chbegin()+1

chinsert (chbegin()+1 a) cout ltlt ch ltlt n

insere le caractere b en position dindice 4

chinsert (4 1 b) cout ltlt ch ltlt n

insere 3 fois le caractere x en fin de ch

chinsert (chend() 3 x) cout ltlt ch ltlt n

insere 3 fois le caractere x en position dindice 6

chinsert (6 3 x) cout ltlt ch ltlt n

insere la chaine voy en position 0

chinsert (0 voy) cout ltlt ch ltlt n

insere en debut la chaine voy a partir de position 1 longueur 3

chinsert (0 voy 1 3) cout ltlt ch ltlt n

insertion dune sequence

chinsert (chbegin()+2 t t+6) cout ltlt ch ltlt n

0a123456

0a12b3456

0a12b3456xxx

0a12b3xxx456xxx

aeiou0a12b3xxx456xxx

eioaeiou0a12b3xxx456xxx

ei778899oaeiou0a12b3xxx456xxx

Exemple dinsertions dans une chaicircne

62 Suppressions La fonction erase permet de supprimer

bull une partie dune chaicircne deacutefinie soit par un iteacuterateur de deacutebut et un iteacuterateur de fin soit parun indice de deacutebut et une longueur

bull un caractegravere donneacute deacutefini par un iteacuterateur de deacutebut

Voici quelques exemples

La classe stringCHAPITRE 22

492

include ltiostreamgt

include ltstringgt

include ltlistgt

using namespace std

main()

string ch (0123456789) ch_bis=ch

supprime a partir de position dindice 3 pour une longueur de 2

cherase (3 2) cout ltlt A ltlt ch ltlt n

ch = ch_bis

supprime de begin()+3 agrave begin()+6

cherase (chbegin()+3 chbegin()+6) cout ltlt B ltlt ch ltlt n

supprime a partir de position dindice 3

cherase (3) cout ltlt C ltlt ch ltlt n

ch = ch_bis

supprime le caractere de position begin()+4

cherase (chbegin()+4) cout ltlt D ltlt ch ltlt n

A 01256789

B 0126789

C 012

D 012356789

Exemples de suppressions dans une chaicircne

63 Remplacements La fonction replace permet de remplacer une partie dune chaicircne deacutefinie soit par un indice etune longueur soit par un intervalle diteacuterateur par

bull une autre chaicircne (objet de type string)

bull une partie dune autre chaicircne deacutefinie par un indice de deacutebut et eacuteventuellement une lon-gueur

bull une chaicircne usuelle (type char ) ou une partie de longueur donneacutee

bull un certain nombre de fois un caractegravere donneacute

En outre on peut remplacer une partie dune chaicircne deacutefinie par un intervalle par une autreseacutequence deacuteleacutements de type char deacutefinie par un iteacuterateur de deacutebut et un iteacuterateur de fin

Voici quelques exemples

include ltiostreamgt

include ltstringgt

using namespace std

7 - Les possibiliteacutes de formatage en meacutemoire493

main() string ch (0123456) string voy (aeiou) char t[] = +-=ltgt char message = hello remplace a partir de indice 2 sur longueur 3 par voy chreplace (2 3 voy) cout ltlt ch ltlt n remplace a partir de indice 0 sur longueur 1 par voy a partir de indice 2 longueur 3 chreplace (0 1 voy 1 2) cout ltlt ch ltlt n remplace a partir de indice 1 sur longueur 2 par 8 fois chreplace (1 2 8 ) cout ltlt ch ltlt n remplace a partir de indice 1 sur longueur 2 par 5 fois chreplace (1 2 5 ) cout ltlt ch ltlt n remplace a partir de indice 2 sur longueur 4 par xxxxxx chreplace (2 4 xxxxxx ) cout ltlt ch ltlt n remplace les 7 derniers caracteres par les 3 premiers de message chreplace (chlength()-7 chlength() message 3) cout ltlt ch ltlt n remplace tous les caracteres sauf le dernier par (t t+5) chreplace (chbegin() chbegin()+chlength()-1 t t+5) cout ltlt ch ltlt n

01aeiou56ei1aeiou56eaeiou56eaeiou56exxxxxxaeiou56exxxxxxhel+-=l

Exemples de remplacements dans une chaicircne

7 Les possibiliteacutes de formatage en meacutemoireEn langage C

bull sscanf permet dacceacuteder agrave une information situeacutee en meacutemoire de faccedilon comparable agrave ce quefait scanf sur lentreacutee standard

bull sprintf permet de fabriquer en meacutemoire une chaicircne de caractegraveres correspondant agrave celle quiserait transmise agrave la sortie standard par printf

En C++ des faciliteacutes comparables existent Jusqursquoagrave la norme elles eacutetaient fournies par lesclasses ostrstrream et istrstream preacutesenteacutees au paragraphe 7 du chapitre 16 Doreacutenavant ilest conseilleacute drsquoutiliser agrave leur place les classes ostringstream et istringstream qui utilisent toutnaturellement un objet de type string

La classe stringCHAPITRE 22

494

71 La classe ostringstreamUn objet de classe ostringstream peut recevoir des caractegraveres au mecircme titre qursquoun flot desortie La fonction membre str permet drsquoobtenir une chaicircne (objet de type string) contenantune copie instantaneacutee de ces caractegraveres

ostringstream sortie

sortie ltlt ltlt ltlt on envoie des caractegraveres dans sortie

comme on le ferait pour un flot

string ch = sortiestr() ch contient les caractegraveres ainsi engrangeacutes

dans sortie

sortie ltlt ltlt on peut continuer agrave engranger des

dans sortie sans affecter ch

Voici un petit exemple illustrant ces possibiliteacutes

include ltiostreamgt

include ltsstreamgt

using namespace std

main()

ostringstream sortie

int n=12 p=1234

float x=125

sortie ltlt n = ltlt n ltlt p = ltlt p on envoie des caractegraveres dans

sortie comme on le ferait pour un flot

string ch1 = sortiestr() ch1 contient maintenant une copie

des caractegraveres engrangeacutes dans sortie

cout ltlt ch1 premiere fois = ltlt ch1 ltlt n

sortie ltlt x = ltlt x on peut continuer agrave engranger des caractegraveres

dans sortie sans affecter ch1

cout ltlt ch1 deuxieme fois = ltlt ch1 ltlt n

string ch2 = sortiestr() ch2 contient maintenant une copie

des caractegraveres engrangeacutes dans sortie

cout ltlt ch2 = ltlt ch2 ltlt n

ch1 premiere fois = n = 12 p = 1234

ch1 deuxieme fois = n = 12 p = 1234

ch2 = n = 12 p = 1234 x = 125

Exemple drsquoutilisation de la classe ostringstream

7 - Les possibiliteacutes de formatage en meacutemoire495

72 La classe istringstream

721 Preacutesentation

Un objet de classe istringstream peut ecirctre creacuteeacute agrave partir drsquoun tableau de caractegraveres drsquounechaicircne constante ou drsquoun objet de type string Ainsi ces trois exemples creacuteent le mecircme objetch

istringstream entree (123 452 salut)

string ch = 123 452 salut istringstream entree (ch)

char ch[] = 123 452 salut istringstream entree (ch)

On peut alors extraire des caractegraveres du flot ch par des instructions usuelles telles que ch gtgt gtgt gtgt

Voici un petit exemple illustrant ces possibiliteacutes

include ltiostreamgtinclude ltsstreamgtusing namespace std main() string ch = 123 452 salut istringstream entree (ch) int n float x string s entree gtgt n gtgt x gtgt s cout ltlt n = ltlt n ltlt x = ltlt x ltlt s = ltlt s ltlt n if (entree gtgt s) cout ltlt s = ltlt s ltlt n else cout ltlt fin flot entreen

n = 123 x = 452 s = salutfin flot entree

Exemple drsquoutilisation de la classe istringstream

722 Utilisation pour fiabiliser les lectures au clavier

On voit que drsquoune maniegravere geacuteneacuterale la deacutemarche qui consiste agrave lire une ligne en meacutemoireavant de lrsquoexploiter peut ecirctre utiliseacutee pour (revoyez eacuteventuellement le paragraphe 35 du cha-pitre 3)

bull reacutegler le problegraveme de deacutesynchronisation entre lrsquoentreacutee et la sortie

bull supprimer les risques de blocage et de bouclage en cas de preacutesence drsquoun caractegravere invalidedans le flot drsquoentreacutee

La classe stringCHAPITRE 22

496

Voici un exemple montrant comment reacutesoudre les problegravemes engendreacutes par la frappe drsquounmauvais caractegravere dans le cas de la lecture sur lrsquoentreacutee standard Il srsquoagit en fait de lrsquoadapta-tion du programme preacutesenteacute auparagraphe 352 du chapitre 3 et dont nous avions proposeacuteune ameacutelioration au paragraphe 72 du chapitre 16 (en utilisant la classe istrstream appeleacutee agravedisparaicirctre dans le futur)

include ltiostreamgt

include ltsstreamgt

using namespace std

main()

int n

bool ok = false

char c

string ligne pour lire une ligne au clavier

do cout ltlt donnez un entier et un caractere n

getline (cin ligne)

istringstream tampon (ligne)

if (tampon gtgt n gtgt c) ok = true

else ok = false

while ( ok)

cout ltlt merci pour ltlt n ltlt et ltlt c ltlt n

donnez un entier et un caractere

bof

donnez un entier et un caractere

x 123

donnez un entier et un caractere

12 bonjour

merci pour 12 et b

Pour lire en toute seacutecuriteacute sur lrsquoentreacutee standard (1)

Nous y lisons tout drsquoabord lrsquoinformation attendue pour toute une ligne sous forme drsquounechaicircne de caractegraveres agrave lrsquoaide de la fonction getline (pour pouvoir lire tous les caractegraveres seacutepa-rateurs agrave lrsquoexception de la fin de ligne) Nous construisons ensuite avec cette chaicircne unobjet de type istrsingtream sur lequel nous appliquons nos opeacuterations de lecture (ici lectureformateacutee drsquoun entier puis drsquoun caractegravere) Comme vous le constatez aucun problegraveme ne sepose plus lorsque lrsquoutilisateur fournit un caractegravere invalide

Voici eacutegalement une ameacutelioration du programme proposeacute au paragraphe 353 du chapitre 3

include ltiostreamgt

include ltsstreamgt

using namespace std

7 - Les possibiliteacutes de formatage en meacutemoire497

main() int n bool ok = false string ligne pour lire une ligne au clavier do ok = false cout ltlt donnez un nombre entier while ( ok) do getline (cin ligne) istringstream tampon (ligne) if (tampon gtgt n) ok = true else ok = false cout ltlt information incorrecte - donnez un nombre entier while ( ok) cout ltlt voici son carre ltlt nn ltlt n while (n)

donnez un nombre entier 4voici son carre 16donnez un nombre entier ampinformation incorrecte - donnez un nombre entier 7voici son carre 49donnez un nombre entier ze 25 8information incorrecte - donnez un nombre entier 5voici son carre 25donnez un nombre entier 0voici son carre 0

Pour lire en toute seacutecuriteacute sur lrsquoentreacutee standard (2)

23

Les outils numeacuteriques

La bibliothegraveque standard offre quelques patrons de classes destineacutes agrave faciliter les opeacuterationsmatheacutematiques usuelles sur les nombres complexes et sur les vecteurs de maniegravere agrave doterC++ de possibiliteacutes voisines de celles de Fortran 90 et agrave favoriser son utilisation sur des cal-culateurs vectoriels ou parallegraveles Il sagit essentiellement

bull des classes complex

bull des classes valarray et des classes associeacutees

Drsquoautre part on dispose de classes bitset permettant de manipuler efficacement des suites debits

On notera bien que les classes deacutecrites dans ce chapitre ne sont pas des conteneurs agrave partentiegravere mecircme si elles disposent de certaines de leurs proprieacuteteacutes

1 La classe complex Le patron de classe complex offre de tregraves riches outils de manipulation des nombres comple-xes Il peut ecirctre parameacutetreacute par nimporte quel type flottant float double ou long double Ilcomporte

bull les opeacuterations arithmeacutetiques usuelles + -

bull laffectation (ordinaire ou composeacutee comme += -=)

bull les fonctions de base

ndash abs module

Les outils numeacuteriquesCHAPITRE 23

500

ndash arg argument

ndash real partie reacuteelle

ndash imag partie imaginaire

ndash conj complexe conjugueacute

bull les fonctions transcendantes

ndash cos sin tan

ndash acos asin atan

ndash cosh sinh tanh

ndash exp log

bull le patron de fonctions polar (parameacutetreacute par un type) qui permet de construire un nombrecomplexe agrave partir de son module et de son argument

Voici un exemple dutilisation de la plupart de ces possibiliteacutes

include ltiostreamgtinclude ltcomplexgtusing namespace std main() complexltdoublegt z1(1 2) z2(2 5) z zr cout ltlt z1 ltlt z1 ltlt z2 ltlt z2 ltlt n cout ltlt Re(z1) ltlt real(z1) ltlt Im(z1) ltlt imag(z1) ltlt n cout ltlt abs(z1) ltlt abs(z1) ltlt arg(z1) ltlt arg(z1) ltlt n cout ltlt conj(z1) ltlt conj(z1) ltlt n cout ltlt z1 + z2 ltlt (z1+z2) ltlt z1z2 ltlt (z1z2) ltlt z1z2 ltlt (z1z2) ltlt n

complexltdoublegt i(0 1) on definit la constante i z = 10+i zr = exp(z) cout ltlt exp(1+i) ltlt zr ltlt exp(i) ltlt exp(i) ltlt n zr = log(i) cout ltlt log(i) ltlt zr ltlt n zr = log(10+i) cout ltlt log(1+i) ltlt zr ltlt n double rho theta norme rho = abs(z) theta = arg(z) norme = norm(z) cout ltlt abs(1+i) ltlt rho ltlt arg(1+i) ltlt theta ltlt norm(1+i) ltlt norme ltlt n double pi = 31415926535 cout ltlt cos(i) ltlt cos(i) ltlt sinh(pii) ltlt sinh(pii) ltlt cosh(pii) ltlt cosh(pii) ltlt n

z = polarltdoublegt (1 pi4) cout ltlt polar (1 pi4) ltlt z ltlt n

2 - La classe valarray et les classes associeacutees501

z1 (12) z2 (25)Re(z1) 1 Im(z1) 2abs(z1) 223607 arg(z1) 110715conj(z1) (1-2)z1 + z2 (37) z1z2 (-89) z1z2 (0413793-00344828)exp(1+i) (146869228736) exp(i) (05403020841471)log(i) (015708)log(1+i) (03465740785398)abs(1+i) 141421 arg(1+i) 0785398 norm(1+i) 2cos(i) (1543080) sinh(pii) (0897932e-011) cosh(pii) (-10)polar (1 pi4) (07071070707107)

Exemples dutilisation de nombres complexes

2 La classe valarray et les classes associeacuteesLa bibliothegraveque standard dispose drsquoun patron de classes valarray particuliegraverement bienadapteacute agrave la manipulation de vecteurs (au sens matheacutematique du terme) crsquoest-agrave-dire detableaux numeacuteriques Il offre en particulier des possibliteacutes de calcul vectoriel comparables agravecelles qursquoon trouve dans un langage scientifique tel que Fortran 90 En outre quelques clas-ses utilitaires permettent de manipuler des sections de vecteurs certaines drsquoentre elles facili-tent la manipulation de tableaux agrave plusieurs dimensions (deux ou plus)

21 Constructeurs des classes valarrayOn peut construire des vecteurs dont les eacuteleacutements sont dun type de base bool char int floatdouble ou drsquoun type complex1

Voici quelques exemples de construction include ltvalarraygtusing namespace std valarrayltintgt vi1 (10) vecteur de 10 int non initialiseacutes2 valarrayltfloatgt vf (01 20) vecteur de 20 float initialiseacutes agrave 01 int t[] = 1 3 5 7 9 valarray ltintgt vi2 (t 5) vecteur de 5 int intialiseacute avec les 5 (premiegraveres) valeurs de t valarray ltcomplexltfloatgt gt vcf (20) vecteur de 20 complexes valarray ltintgt v vecteur vide pour lrsquoinstant

1 En fait on peut utiliser comme paramegravetre de type du patron valarray tout type classe muni drsquoun constructeur par

recopie drsquoun destructeur drsquoun opeacuterateur drsquoaffectation et doteacute de tous les opeacuterateurs et de toutes les fonctions

applicables agrave un type numeacuterique

2 En toute rigueur si le vecteur vi1 est de classe statique ses eacuteleacutements seront initialiseacutes agrave 0 Dans le cas de vecteurs

dont les eacuteleacutements sont des objets ces derniers seront initialiseacutes par appel du constructeur par deacutefaut

Les outils numeacuteriquesCHAPITRE 23

502

On notera que la classe valarray nrsquoest pas un vrai conteneur en particulier il nrsquoest pas pos-sible de construire directement un objet de ce type agrave partir drsquoune seacutequence sauf si cetteseacutequence est celle deacutecrite par un pointeur usuel (comme dans le cas de vi2)

22 Lrsquoopeacuterateur []Une fois un vecteur construit on peut acceacuteder agrave ses eacuteleacutements de faccedilon classique en utilisantlrsquoopeacuterateur [] comme dans

valarray ltintgt vi (5) int n i v[3] = 1 n = v[i] + 2

Aucune protection nrsquoest preacutevue sur la valeur utiliseacutee comme indice

23 Affectation et changement de tailleLrsquoaffectation entre vecteurs dont les eacuteleacutements sont de mecircme type est possible mecircme srsquoilsnrsquoont pas le mecircme nombre drsquoeacuteleacutements En revanche lrsquoaffectation nrsquoest pas possible si les eacuteleacute-ments ne sont pas de mecircme type

valarray ltfloatgt vf1 (01 20) vecteur de 20 float eacutegaux agrave 01 valarray ltfloatgt vf2 (05 10) vecteur de 10 float eacutegaux agrave 05 valarray ltfloatgt vf3 vecteur vide pour lrsquoinstant valarray ltintgt vi (1 10) vecteur de 10 int eacutegaux agrave 1 vf1 = vf2 OK vf1 et vf2 sont deux vecteurs de 10 float eacutegaux agrave 05 les anciennes valeurs de vf1 sont perdues vf3 = vf2 OK vf3 comporte maintenant 10 eacuteleacutements vf1 = vi incorrect on peut faire for (i=0 iltvf1size() i++) vf1[i] = vi [i]

La fonction membre resize permet de modifier la taille drsquoun vecteur vf1resize(15) vf1 comporte maintenant 15 eacuteleacutements les 10 premiers ont conserveacute leur valeur vf3resize (6) vf3 ne comporte plus que 6 eacuteleacutements (leur valeur nrsquoa pas changeacute)

24 Calcul vectorielLes classes valarray permettent deffectuer des opeacuterations usuelles de calcul vectoriel engeacuteneacuteralisant le rocircle des opeacuterateurs et des fonctions numeacuteriques un opeacuterateur unaire appliqueacuteagrave un vecteur fournit en reacutesultat le vecteur obtenu en appliquant cet opeacuterateur agrave chacun de seseacuteleacutements un opeacuterateur binaire appliqueacute agrave deux vecteurs de mecircme taille fournit en reacutesultat levecteur obtenu en appliquant cet opeacuterateur agrave chacun des eacuteleacutements de mecircme rang Parexemple

2 - La classe valarray et les classes associeacutees503

valarrayltfloatgt v1(5) v2(5) v3(5)

v3 = -v1 v3[i] = -v1[i] pour i de 0 agrave 4

v3 = cos(v1) v3[i] = cos(v1[i]) pour i de 0 agrave 4

v3 = v1 + v2 v3[i] = v2[i] + v1[i] pour i de 0 agrave 4

v3 = v1v2 + exp(v1) v3[i] = v1[i]v2[i] + exp(v1[i]) pour i de 0 agrave 4

On peut mecircme appliquer une fonction de son choix agrave tous les eacuteleacutements drsquoun vecteur en utili-sant la fonction membre apply Par exemple si fct est une fonction recevant un float et ren-voyant un float

v3 = v1apply(fct) v3[i] = fct (v1[i]) pour i de 0 agrave 4

On trouve eacutegalement des opeacuterateurs de comparaison (== = lt lt=) qui sappliquent agrave deuxopeacuterandes (de type valarray) de mecircme nombre deacuteleacutements et qui fournissent en reacutesultat unvecteur de booleacuteens

int dim =

valarrayltfloatgt v1(dim) v2(dim)

valarrayltboolgt egal(dim) inf(dim)

egal = (v1 == v2) egal[i] = (v1[i] == v2[i]) pour i de 0 agrave dim-1

inf = (v1 lt v2) inf[i] = (v1[i] lt v2[i]) pour i de 0 agrave dim-1

Les fonctions max et min permettent drsquoobtenir le plus grand1 ou le plus petit eacuteleacutement drsquounvecteur

int vmax vmin t[] = 3 9 12 4 7 6

valarray ltintgt vi (t 6)

vmax = max (vi) vmax vaut 12

vmin = min (vi) vmin vaut 3

La fonction membre shift permet drsquoeffectuer des deacutecalages des eacuteleacutements drsquoun vecteur Ellefournit un vecteur de mecircme taille que lrsquoobjet lrsquoayant appeleacute dans lequel les eacuteleacutements ont eacuteteacutedeacutecaleacutes drsquoun nombre de positions indiqueacute par son unique argument (vers la gauche pour lesvaleurs positives vers la droite pour les valeurs neacutegatives) Les valeurs sortantes sont per-dues les valeurs entrantes sont agrave zeacutero Enfin la fonction membre cshift permet drsquoeffecteurdes deacutecalages circulaires

int t[] = 3 9 12 4 7 6

valarray ltintgt vi (t 6) vig vid vic

vig = vishift (2) vi est inchangeacute - vig contient 12 4 7 6 0 0

vid = vishift (-3) vi est inchangeacute - vid contient 0 0 0 3 9 12

vic = vicshift (3) vi est inchangeacute - vic contient 4 7 6 3 9 12

1 Lorsque les eacuteleacutements sont des objets on utilise operator lt qui doit alors avoir eacuteteacute surdeacutefini

Les outils numeacuteriquesCHAPITRE 23

504

25 Seacutelection de valeurs par masqueOn peut seacutelectionner certaines des valeurs drsquoun vecteur afin de constituer un vecteur de tailleinfeacuterieure ou eacutegale Pour ce faire on utilise un masque crsquoest-agrave-dire un vecteur de type valar-

rayltboolgt dans lequel chacun des eacuteleacutements preacutecise si lrsquoon seacutelectionne (true) ou non (false)lrsquoeacuteleacutement correspondant Supposons par exemple que lrsquoon dispose de ces deacuteclarations

valarray ltboolgt masque(6) on suppose que masque contient true true false true false true valarray ltintgt vi(6) on suppose que vi contient 5 8 2 7 3 9

Lrsquoexpression vi[masque] deacutesigne un vecteur formeacute des seuls eacuteleacutements de vi pour lesquelslrsquoeacuteleacutement correspondant de masque a la valeur true Ici il srsquoagit donc drsquoun vecteur de quatreentiers (5 8 7 9) Par exemple

valarray ltintgt vi1 vecteur vide pour lrsquoinstant vi1 = vi[masque] vi1 est un vecteur de 4 entiers 5 8 7 9

Qui plus est une telle notation reste utilisable comme lvalue En voici deux exemples utili-sant les mecircmes deacuteclarations que ci-dessus

vi[masque] = -1 place la valeur -1 dans les eacuteleacutements de vi pour lesquels la valeur de lrsquoeacuteleacutement correspondant de masque est true valarrayltintgt v(12 4) vecteur de 4 eacuteleacutements vi[masque] = v recopie les premiers eacuteleacutements de v dans les eacuteleacutements de vi pour lesquels la valeur de lrsquoeacuteleacutement correspondant de masque est true

Voici un exemple de programme complet illustrant ces diffeacuterentes possibiliteacutes

include ltiostreamgtinclude ltvalarraygtinclude ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtusing namespace std main() int i int t[] = 1 2 3 4 5 6 bool mt[] = true true false true false true valarray ltintgt v1 (t 6) v2 v2 vide pour linstant valarray ltboolgt masque (mt 6) v2 = v1[masque] cout ltlt v2 for (i=0 iltv2size() i++) cout ltlt setw(4) ltlt v2[i] cout ltlt n

v1[masque] = -1 cout ltlt v1 for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

2 - La classe valarray et les classes associeacutees505

valarray ltintgt v3(8) il faut au moins 4 elements dans v3 for (i=0 iltv3size() i++) v3[i] = 10(i+1) v1[masque] = v3 cout ltlt v1 for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

v2 1 2 4 6v1 -1 -1 3 -1 5 -1v1 10 20 3 30 5 40

Exemple drsquoutilisation de masques

26 Sections de vecteursIl est possible de deacutefinir des sections de vecteurs on nomme ainsi un sous-ensemble deseacuteleacutements dun vecteur sur lequel on peut travailler comme sil sagissait dun vecteur Parexemple si v est deacuteclareacute ainsi

valarray ltintgt v(12)

lrsquoexpression v[slice(0 4 2)] deacutesigne le vecteur obtenu en ne consideacuterant de v que les eacuteleacute-ments de rang 0 2 4 et 6 (on part de 0 on considegravere 4 valeurs en progressant par pas de 2)

Lagrave encore une telle notation est utilisable comme lvalue v1 [slice(0 4 2)] = 99 place la valeur 99 dans les eacuteleacutements v1[0] v1[2] v1[4] et v1[6]

Voici un exemple de programme complet illustrant ces possibiliteacutes

include ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtusing namespace std main() int i int t [] = 0 1 2 3 4 5 6 7 8 9 valarray ltintgt v1 (t 10) v2 cout ltlt v1 initial for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n

v1[slice(0 4 2)] = -1 v1[0] = -1 v1[2] = -1 v1[4] = -1 v1[6] = -1 cout ltlt v1 modifie for (i=0 iltv1size() i++) cout ltlt setw(4) ltlt v1[i] cout ltlt n v2 = v1[slice(1 3 4)] on considegravere v1[1] v1[5] et v1[9] cout ltlt v2 for (i=0 iltv2size() i++) cout ltlt setw(4) ltlt v2[i] cout ltlt n

Les outils numeacuteriquesCHAPITRE 23

506

v1 initial 0 1 2 3 4 5 6 7 8 9v1 modifie -1 1 -1 3 -1 5 -1 7 8 9v2 1 5 9

Exemple drsquoutilisation de sections de vecteurs

On notera que les sections de vecteurs peuvent srsquoaveacuterer utiles pour manipuler des tableaux agravedeux dimensions et en particulier des matrices Consideacuterons ces deacuteclarations dans lesquellesmat est un vecteur dont les NLIGNCOL eacuteleacutements peuvent servir agrave repreacutesenter une matricede NLIG lignes et de NCOL colonnes

define NLIG 5define NCOL 12 valarray ltfloatgt v(NLIG) vecteur de NLIG eacuteleacutements valarray ltfloatgt mat (NLIGNCOL) pour repreacutesenter une matrice

Si lrsquoon convient drsquoutiliser les conventions du C pour ranger les eacuteleacutements de notre matricedans le vecteur mat voici quelques exemples drsquoopeacuterations faciliteacutees par lrsquoutilisation desections

bull placer la valeur 12 dans la ligne i de la matrice mat

mat [slice (iNCOL NCOL 1)] = 12

bull placer la valeur 15 dans la colonne j de la matrice mat

mat [slice (j NLIG NCOL)] = 15

bull recopier le vecteur v dans la colonne j de la matrice mat

mat [slice (j NLIG NCOL)] = v

Remarque

La notion de section de vecteur peut permettre de manipuler non seulement des matrices

mais aussi des tableaux agrave plus de deux dimensions Dans ce dernier cas on peut eacutegale-

ment recourir agrave la notion de sections multiples obtenues en utilisant gslice agrave la place de

slice

27 Vecteurs drsquoindicesLes sections de vecteurs obtenues par slice sont dites reacuteguliegraveres dans la mesure ougrave les eacuteleacute-

ments seacutelectionneacutes sont reacuteguliegraverement espaceacutes les uns des autres On peut aussi obtenir des

sections quelconques en recourant agrave ce que lrsquoon nomme un vecteur drsquoindices Par exemple

si les vecteurs indices et vf sont deacuteclareacutes ainsi

valarray ltfloatgt vf(12) valarray ltintgt indices (5) on suppose que indices contient les valeurs 1 4 2 3 0

3 - La classe bitset507

lrsquoexpression v[indices] deacutesigne le vecteur obtenu en consideacuterant les eacuteleacutements de vf2 suivant

lrsquoordre mentionneacute par le vecteur drsquoindices indices crsquoest-agrave-dire ici 1 4 2 3 0 Lagrave encore

cette notation peut ecirctre utiliseacutee comme lvalue

Voici un exemple de programme complet illustrant ces possibiliteacutes

include ltiostreamgtinclude ltiomanipgtinclude ltvalarraygtinclude ltcstdlibgt pour size_tusing namespace std main() size_t ind[] = 1 4 2 3 0 float tf [] = 125 25 52 83 54 int i valarray ltsize_tgt indices (ind 5) contient 1 4 2 3 0 for (i=0 ilt5 i++) cout ltlt setw(8) ltlt indices[i] cout ltlt n valarray ltfloatgt vf1 (tf 5) vf2(5) vf2[indices] = vf1 affecte vf1[i] agrave vf2 [indices[i]] for (i=0 ilt5 i++) cout ltlt setw(8) ltlt vf2[i] cout ltlt n

1 4 2 3 0 54 125 52 83 25

Exemple drsquoutilisation de vecteurs drsquoindices

On notera qursquoil nrsquoest pas neacutecessaire que tous les eacuteleacutements de vf2 soient concerneacutes par les

indices mentionneacutes (le vecteur drsquoindice peut comporter moins drsquoeacuteleacutements que vf2) En revan-

che comme on peut srsquoy attendre il faut eacuteviter qursquoun mecircme indice ne figure deux fois dans le

vecteur drsquoindice dans ce cas le comportement du programme est indeacutetermineacute (en pratique

un mecircme eacuteleacutement est modifieacute deux fois)

3 La classe bitsetLe patron de classes bitsetltNgt permet de manipuler efficacement des suites de bits dont la

taille N apparaicirct en paramegravetre (expression) du patron Lrsquoaffectation nrsquoest donc possible

qursquoentre suites de mecircme taille On dispose notamment des opeacuterations classiques de manipu-

lation globale des bits agrave lrsquoaide des opeacuterateurs amp | ~ amp= |= ltlt= gtgt= ~= == = qui fonc-

tionnent comme les mecircmes opeacuterateurs appliqueacutes agrave des entiers

On peut acceacuteder agrave un bit de la suite agrave lrsquoaide de lrsquoopeacuterateur [] il deacuteclenche une exception

out_of_range si son second opeacuterande nrsquoest pas dans les limites permises

Les outils numeacuteriquesCHAPITRE 23

508

Il existe trois constructeurs

bull sans argument on obtient une suite de bits nuls

bull agrave partir drsquoun unsigned long on obtient la suite correspondant au motif binaire contenu dans

lrsquoargument

bull agrave partir drsquoune chaicircne de caractegraveres (string) on peut aussi utiliser une chaicircne usuelle (notam-

ment une constante) gracircce aux possibiliteacutes de conversions

Voici un exemple illustrant la plupart des fonctionnaliteacutes de ces patrons de classes

include ltiostreamgtinclude ltbitsetgtusing namespace std main() bitsetlt12gt bs1 (1101101101) bitset initialise par une chaine long n=0x0FFF bitsetlt12gt bs2 (n) bitset initialise par un entier bitsetlt12gt bs3 bitset initialise a zero cout ltlt bs1 = ltlt bs1 ltlt n cout ltlt bs2 = ltlt bs2 ltlt n cout ltlt bs3 = ltlt bs3 ltlt n if (bs3 = bs1) cout ltlt bs3 differe de bs1n bs3 = bs1 affectation entre bitset de mecircme taille cout ltlt bs3 = ltlt bs3 ltlt n if (bs3 == bs1) cout ltlt bs3 est maintenant egal a bs1n cout ltlt bit de rang 3 de bs3 ltlt boolalpha ltlt bs3[3] ltlt n bs3[3] = 0 cout ltlt bit de rang 3 de bs3 ltlt boolalpha ltlt bs3[3] ltlt n try bs3[15] = 1 indice hors limite --gt exception catch (exception ampe) cout ltlt exception ltlt ewhat() ltlt n

cout ltlt bs3 ltlt amp ltlt bs2 ltlt = bs3 amp= bs2 cout ltlt bs3 ltlt n cout ltlt bs3 ltlt | ltlt bs2 ltlt = bs3 |= bs2 cout ltlt bs3 ltlt n cout ltlt ~ ltlt bs3 ltlt = ltlt ~bs3 ltlt n cout ltlt dans ltlt bs3 ltlt il y a ltlt bs3count() ltlt bits a unn cout ltlt bs3 ltlt decale de 4 a gauche = ltlt (bs3 ltlt= 4) ltlt n

bitsetlt14gt bs4 bs4 = bs1 serait incorrect car bs1 et bs4 nrsquoont pas la mecircme taille

3 - La classe bitset509

bs1 = 001101101101bs2 = 111111111111bs3 = 000000000000bs3 differe de bs1bs3 = 001101101101bs3 est maintenant egal a bs1bit de rang 3 de bs3 truebit de rang 3 de bs3 falseexception invalid bitsetltNgt position001101100101 amp 111111111111 = 001101100101001101100101 | 111111111111 = 111111111111~ 111111111111 = 000000000000dans 111111111111 il y a 12 bits a un111111110000 decalle de 4 a gauche = 111111110000

Exemples drsquoutilisation du patron de classes bitset

24

Les espaces de noms

La notion drsquoespace de noms a eacuteteacute preacutesenteacutee succinctement au paragraphe 8 du chapitre 4 afin

de vous permettre drsquoutiliser convenablement la bibliothegraveque standard du C++

Drsquoune maniegravere geacuteneacuterale elle permet de deacutefinir des ensembles disjoints drsquoidentificateurs cha-

que ensemble eacutetant repeacutereacute par un nom qursquoon utilise pour qualifier les symboles concerneacutes Il

devient ainsi possible drsquoutiliser le mecircme identificateur pour deacutesigner deux choses diffeacuterentes

(ou deux versions diffeacuterentes drsquoune mecircme chose par exemple une classe) pour peu qursquoelles

appartiennent agrave deux espaces de noms diffeacuterents Cette notion preacutesente surtout un inteacuterecirct dans

le cadre de deacuteveloppement de gros programmes ou de bibliothegraveques Crsquoest ce qui justifie sa

preacutesentation deacutetailleacutee dans un chapitre seacutepareacute aussi tardif

Nous commencerons par vous montrer comment deacutefinir un nouvel espace de noms et com-

ment deacutesigner les symboles qursquoil contient Puis nous verrons comment lrsquoinstruction using

permet de simplifier les notations soit en citant une seule fois les symboles concerneacutes soit en

citant lrsquoespace de noms lui-mecircme (comme vous le faites actuellement avec using namespace

std) Nous montrerons ensuite comment la surdeacutefinition des fonctions franchit les limites des

espaces de noms Enfin nous apporterons quelques informations compleacutementaires concer-

nant lrsquoimbrication des espaces de noms la transitiviteacute de lrsquoinstruction using et les espaces de

noms anonymes

1 Creacuteation drsquoespaces de nomsIci nous allons vous montrer comment creacuteer un ou plusieurs nouveaux espaces de noms et

comment utiliser les symboles correspondants

Les espaces de nomsCHAPITRE 24

512

11 Exemple de creacuteation drsquoun nouvel espace de nomsConsideacuterons ces instructions

namespace A les symbole deacuteclareacutes agrave partir drsquoici appartiennent agrave lrsquoespace de noms nommeacute A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) fin de la deacutefinition de lrsquoespace de noms A

A lrsquointeacuterieur du bloc

namespace A

on trouve des deacuteclarations usuelles ici de types de variables (n et x) et de deacutefinition de classe

(point) Le fait que ces deacuteclarations figurent dans un espace de noms ne modifie pas la

maniegravere de les eacutecrire En revanche les symboles correspondants ne seront utilisables agrave lrsquoexteacute-

rieur de ce bloc que moyennant lrsquoutilisation drsquoun preacutefixe approprieacute A Voici quelques

exemples

la deacutefinition de A est supposeacutee connue icimain() Ax=25 utilise la variable globale x deacuteclareacutee dans A Apoint p1 on utilise le type point de A Apoint p2 (1 3) idem An = 1 on utilise la variable globale n deacuteclareacutee dans A

Ces symboles peuvent cohabiter sans problegraveme avec des symboles deacuteclareacutes en dehors de tout

espace de noms comme nous lrsquoavons fait jusqursquoici

la deacutefinition de A est supposeacutee connue icilong n variable globale n sans rapport avec An main() double x variable x locale agrave main sans rapport avec Ax Ax = 25 utilise toujours la variable globale x deacuteclareacutee dans A point p incorrect le type point nrsquoest pas connu An = 12 utilise la variable globale n deacuteclareacutee dans A n = 5 utilise la variable globale n deacuteclareacutee en dehors de A

On notera bien que le preacutefixe A est neacutecessaire degraves lors qursquoon est en dehors de la porteacutee de la

deacutefinition de lrsquoespace de noms A mecircme si lrsquoon se trouve dans le mecircme fichier source Crsquoest

drsquoailleurs gracircce agrave cette regravegle que nous pouvons utiliser conjointement les identificateurs n et

An

1 - Creacuteation drsquoespaces de noms513

On dit des symboles comme n ou x deacuteclareacutes en dehors de tout espace de noms qursquoils appar-

tiennent agrave lrsquoespace global1 Ces symboles pourraient drsquoailleurs ecirctre aussi deacutesigneacutes sous la

forme x ou n2

Remarque

Nous verrons au paragraphe 2 que les deux formes de lrsquoinstruction using permettent de

simplifier lrsquoutilisation de symboles deacutefinis dans des espaces de noms en eacutevitant drsquoavoir agrave

utiliser le preacutefixe correspondant

12 Exemple avec deux espaces de nomsConsideacuterons maintenant ces instructions deacutefinissant et utilisant deux espaces de noms nom-

meacutes A et B

namespace A deacutebut deacutefinition espace de noms A

int n

double x

class point

int x y

public

point (int abs=0 int ord=0) x(abs) y(ord)

fin deacutefinition espace de noms A

namespace B deacutebut deacutefinition espace de noms B

float x

class point

int x y

public

point () x(0) y(0)

fin deacutefinition espace de noms B

main()

Apoint pA1(3) OK utilise le type point de A

Bpoint pB1 OK utilise le type point de B

Bpoint pb2 (3) erreur pas de constructeur agrave un argument

dans le type point de B

Ax = 25 utilise la variable globale x de lrsquoespace A

Bx = 32 utilise la variable globale x de lrsquoespace B

1 On ne confondra pas cette notion drsquoespace global avec celle drsquoespace anonyme (preacutesenteacutee au paragraphe 7)

2 Cette forme sera surtout utiliseacutee pour lever une ambiguiumlteacute

Les espaces de nomsCHAPITRE 24

514

13 Espace de noms et fichier en-tecircteDans nos preacuteceacutedents exemples drsquointroduction la deacutefinition de lrsquoespace de noms et lrsquoutilisa-

tion des symboles correspondants se trouvaient dans le mecircme fichier source Il va de soi qursquoil

nrsquoen ira pratiquement jamais ainsi la deacutefinition drsquoun espace de noms figurera dans un fichier

en-tecircte qursquoon incorporera classiquement par une directive include on notera bien qursquoalors

lrsquoabsence de cette directive conduira agrave une erreur

main() Ax = 2 si la deacutefinition de lrsquoespace de noms A nrsquoa pas eacuteteacute compileacutee agrave ce niveau on obtiendra une erreur

14 Instructions figurant dans un espace de nomsIl faut tout drsquoabord remarquer que la deacutefinition drsquoun espace de noms a toujours lieu agrave un

niveau global1 Il nrsquoest (heureusement) pas permis de lrsquoeffectuer au sein drsquoune classe ou

drsquoune fonction

main() intx namespace A incorrect

Comme on srsquoy attend un espace de noms peut renfermer des deacutefinitions de fonctions ou de

classes comme dans cet exemple

namespace A deacutebut deacutefinition espace de noms A class point int x y public point () deacuteclaration constructeur void affiche () deacuteclaration fonction membre affiche pointpoint() deacutefinition du constructeur de Apoint void pointaffiche() deacutefinition de la fonction affiche de Apoint void f (int n) deacutefinition de f fin deacutefinition espace de noms A

Dans ce cas il est cependant preacutefeacuterable de dissocier la deacuteclaration des classes et des fonc-

tions de leur deacutefinition en preacutevoyant

1 Nous verrons toutefois au paragraphe 4 que les deacutefinitions drsquoespaces de noms peuvent srsquoimbriquer

1 - Creacuteation drsquoespaces de noms515

bull un fichier en-tecircte contenant la deacutefinition de lrsquoespace de noms limiteacutee aux deacuteclarations des

fonctions et des classes

fichier en-tecircte Ah

deacuteclaration des symboles figurant dans lrsquoespace A

namespace A deacutebut deacutefinition espace de noms A

class point

int x y

public

point () deacuteclaration constructeur

void affiche () deacuteclaration fonction membre affiche

void f (int n) deacuteclaration de f

fin deacutefinition espace de noms A

bull un fichier source contenant la deacutefinition des classes et des fonctions

deacutefinition des symboles figurant dans lrsquoespace A

include Ah incorporation de la deacutefinition de lrsquoespace A

void Apointpoint()

deacutefinition du constructeur de Apoint

Apointaffiche()

deacutefinition de la fonction affiche de Apoint

void f (int n) deacutefinition de la fonction f

15 Creacuteation increacutementale drsquoespaces de nomsIl est tout agrave fait possible de deacutefinir un mecircme espace de noms en plusieurs fois Par exemple

namespace A

int n

namespace B

float x

namespace A

double x

Cette deacutefinition est ici eacutequivalente agrave

namespace A

int n

double x

namespace B

float x

Les espaces de nomsCHAPITRE 24

516

A ce propos il faut signaler que si un identificateur deacuteclareacute dans un espace de noms peut

ensuite ecirctre deacutefini agrave lrsquoexteacuterieur (voir paragraphe 14) il nrsquoest pas possible de deacuteclarer un nou-

vel identificateur de cette mecircme maniegravere

namespace A int n namespace B float x double Ax erreur

Cette possibiliteacute de creacuteation increacutementale srsquoavegravere extrecircmement inteacuteressante dans le cas drsquoune

bibliothegraveque En effet elle permet de la deacutecouper en plusieurs parties relativement indeacutepen-

dantes tout en nrsquoutilisant qursquoun seul espace de noms pour lrsquoensemble Lrsquoutilisateur peut ainsi

nrsquointroduire que les seules deacutefinitions utiles Crsquoest drsquoailleurs exactement ce qui se produit

avec la bibliothegraveque standard dont les symboles sont deacutefinis dans lrsquoespace de noms std Une

directive telle que include ltiostreamgt incorpore en fait une deacutefinition partielle de lrsquoespace

de noms std une directive include ltvectorgt en incorpore une autre

2 Les instructions usingNous venons de voir comment utiliser un symbole deacutefini dans un espace de noms en le qua-

lifiant explicitement par le nom de lrsquoespace (comme dans Ax) Cette meacutethode peut toutefois

devenir fastidieuse lorsqursquoon recourt systeacutematiquement aux espaces de noms dans un gros

programme En fait C++ offre deux faccedilons drsquoabreacuteger lrsquoeacutecriture

bull lrsquoune ougrave lrsquoon nomme une fois chacun des symboles qursquoon deacutesire utiliser

bull lrsquoautre ougrave lrsquoon se contente de citer lrsquoespace de noms lui-mecircme

Toutes les deux utilisent le mot cleacute using mais de maniegravere diffeacuterente on parle souvent de

deacuteclaration using dans le premier cas et de directive using dans le second

21 La deacuteclaration using pour les symboles

211 Preacutesentation geacuteneacuterale

La deacuteclaration using permet de citer un symbole appartenant agrave un espace de noms (dont la

deacutefinition est supposeacutee connue) En voici un exemple

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord)

2 - Les instructions using517

using Ax doreacutenavant x est synonyme de Axusing Apoint doreacutenavant point est synonyme de Apointlong n variable globale n sans rapport avec An main() x = 25 idem Ax = 25 n = 5 n deacutesigne la variable globale sans rapport avec An An = 10 correct point p1 (3) idem Apoint p1 (3)

La deacuteclaration using peut ecirctre locale comme dans cet exemple

namespace A int n double x long n variable globale n sans rapport avec Anmain () using An ici n est synonyme de Anvoid f () ici n nrsquoest plus synonyme de An mais de n

Bien entendu mecircme lorsque using est locale elle ne concerne que des symboles globaux

puisque les espaces de noms sont toujours deacutefinis agrave un niveau global

Voici un autre exemple utilisant plusieurs espaces de noms

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) namespace B float x class point int x y public point () x(0) y(0) using An n sera synonyme de Anusing Bx x sera synonyme de Bx

Les espaces de nomsCHAPITRE 24

518

main()

using Bpoint point sera (localement) synonyme de Bpoint

n = 2 idem An = 2

x = 5 idem Bx = 5

Ax = 3 correct

point pB1 idem Bpoint pB1

Apoint pA1(3) correct

void f()

using Apoint point sera (localement) synonyme de Apoint

using Ax x sera (localement agrave f) synonyme de Bx

point p (2) idem Apoint p (2)

212 Masquage et ambiguiumlteacutes

Comme on srsquoy attend un synonyme peut en cacher un autre drsquoune porteacutee englobante

les deacutefinitions des espaces de noms A et B sont supposeacutees connues ici

using Ax

ici x est synonyme de Ax

main()

using Bx

ici x est synonyme de Bx on peut toujours utiliser Ax

En revanche dans une mecircme porteacutee la deacuteclaration drsquoun synonyme ne doit pas creacuteer drsquoambi-

guiumlteacute comme dans

using Ax x est synonyme de Ax

using Bx x ne peut pas eacutegalement ecirctre synonyme de Bx

dans la mecircme porteacutee

ou dans

void g()

float x

using Ax incorrect on change la signification de x

On notera bien que ce genre drsquoambiguiumlteacute peut toujours ecirctre leveacutee en recourant agrave la notation

deacuteveloppeacutee des symboles

Remarque

Comme on le verra au paragraphe 3 cette notion drsquoambiguiumlteacute nrsquoexistera pas dans le cas

des fonctions afin de preacuteserver les possibiliteacutes de surdeacutefinition

2 - Les instructions using519

22 La directive using pour les espaces de nomsAvec la deacuteclaration using on peut choisir les symboles qursquoon souhaite utiliser dans une

espace de noms mais il est neacutecessaire drsquoutiliser une instruction par symbole Avec une seule

directive using on va pouvoir utiliser tous les symboles drsquoun espace de noms mais bien sucircr

on ne pourra plus opeacuterer de seacutelection

Voici un premier exemple

namespace A int n double x class point int x y public point (int abs=0 int ord=0) x(abs) y(ord) using namespace A tous les symboles deacutefinis dans A peuvent ecirctre utiliseacutes sans Amain() x = 25 idem Ax = 25 n = 5 idem An = 5 An = 10 toujours possible point p1 (3) idem Apoint p1 (3)

Comme la deacuteclaration using la directive using peut ecirctre locale

namespace A int n double x float x main () using namespace A ici n est synonyme de Anvoid f () ici x est synonyme de x

Les diffeacuterentes directives using se cumulent sans qursquoune quelconque prioriteacute ne permette de

les deacutepartager en cas drsquoambiguiumlteacute Il faut cependant noter que cette fois on nrsquoaboutit agrave une

erreur (de compilation) que lors de la tentative drsquoutilisation drsquoun symbole ambigu Voyez cet

exemple

namespace A int n double x class point int x y public point (int abs int ord) x(abs) y(ord) constructeur 2 arg

Les espaces de nomsCHAPITRE 24

520

namespace B float x class point int x y public point () x(0) y(0) constructeur 0 arg using namespace A using namespace B main() n = 2 idem An = 2 point p1 (3 5) ambiguuml Apoint ou Bpoint x = 5 ambiguuml Ax ou Bx

Le symbole n ne preacutesente aucune ambiguiumlteacute car il nrsquoest deacutefini que dans lrsquoespace A En revan-

che les symboles point et x eacutetant deacutefinis agrave la fois dans A et B il y ambiguiumlteacute Bien entendu il

reste toujours possible de la lever en preacutefixant explicitement les symboles concerneacutes par

exemple

Apoint p1 (3 5) Bx = 5

On notera qursquoavec la directive using la notion de masquage nrsquoexiste plus Une directive

situeacutee dans une porteacutee donneacutee ne se substitue pas agrave une directive drsquoune porteacutee englobante

elle la complegravete Par exemple avec les mecircmes espaces de noms A et B que preacuteceacutedemment

mecircmes deacutefinitions des espaces de noms A et B que preacuteceacutedemmentusing namespace A main() using namespace B n = 2 idem An = 2 point p1 (3 5) toujours ambigu Apoint ou Bpoint x = 5 ambigu Ax ou Bx

Remarques

1 Lagrave encore et comme on le verra au paragraphe 3 cette notion drsquoambiguiumlteacute nrsquoexistera pas

dans le cas des fonctions afin de preacuteserver les possibiliteacutes de surdeacutefinition On notera agrave ce

propos que dans lrsquoexemple preacuteceacutedent lrsquoambiguiumlteacute portait sur le nom de classe point et

non pas sur le nom drsquoune fonction (constructeur)

2 Notez que la plupart de nos exemples de programmes utilisent ces deux instructions

include ltiostreamgt using namespace std

Il faut bien prendre garde agrave ne pas en inverser lrsquoordre ainsi avec

using namespace std include ltiostreamgt

3 - Espaces de noms et surdeacutefinition521

on obtiendrait une erreur de compilation due agrave ce que lrsquoinstruction using mentionnerait

un espace de noms (std) inexistant (il est deacutefini de faccedilon increacutementale dans chacun

des fichiers en-tecircte comme iostream) En revanche avec ces instructions

include ltvectorgt

using namespace std

include ltiostreamgt

on nrsquoobtiendrait plus drsquoerreurs car le fichier en-tecircte vector contient deacutejagrave une deacutefinition

(partielle) de lrsquoespace de noms std

3 Espaces de noms et surdeacutefinitionLrsquointroduction drsquoun nom de fonction drsquoun espace de noms introduit simultaneacutement toutes les

deacuteclarations correspondantes

include ltiostreamgt

namespace A

void f(char c) stdcout ltlt f(char)n std car pas de using1

void f(int n) stdcout ltlt f(int)n

using Af on aurait la mecircme chose avec using namespace A

main()

int n=10 char c=a

f(n)

f(c)

f(int)

f(char)

Espaces de noms et surdeacutefinition de fonctions (1)

Lrsquointroduction drsquoun synonyme de fonction ne masque pas les autres fonctions de mecircme nom

deacutejagrave accessibles2 Voici un exemple ougrave la fonction f est deacutefinie dans deux espaces de noms

ainsi que dans lrsquoespace global

1 Ici par souci de clarteacute nous nrsquoavons pas utiliseacute drsquoinstruction using namespace std dans ces conditions il est alors

neacutecessaire de preacutefixer les noms de flots cin et cout par std

2 On dit parfois que la recherche drsquoune fonction surdeacutefinie franchit les espaces de noms

Les espaces de nomsCHAPITRE 24

522

include ltiostreamgtnamespace A void f(char c) stdcout ltlt Af(char)n void f(float x) stdcout ltlt Af(float)n namespace B void f(int n) stdcout ltlt Bf(int)n void f(double y) stdcout ltlt f(double)n using Af idem avec using namespace A using Bf idem avec using namespace B

main() int n=10 char c=a float x=25 double y=13 f(n) f(c) f(x) f(y)

Bf(int)Af(char)Af(float)f(double)

Espaces de noms et surdeacutefinition de fonctions (2)

Aux diffeacuterents espaces de noms susceptibles drsquoecirctre consideacutereacutes dans la reacutesolution drsquoun appel

de fonction il faut ajouter les espaces de noms de ses arguments effectifs Consideacuterez

namespace A class C void f(C) main() using AC introduit la classe C

C c f(c) recherche dans espace courant et dans celui de c (A) appelle bien Af(C) comme si on avait fait using Af

Ici nous nrsquointroduisons que le symbole C de lrsquoespace A Lrsquoappel de f est reacutesolu en examinant

non seulement les espaces concerneacutes (ici il ne srsquoagit que de lrsquoespace global qui ne possegravede

pas de fonction f) mais aussi celui dans lequel est deacutefini lrsquoargument effectif c crsquoest-agrave-dire

lrsquoespace de noms A Drsquoune maniegravere geacuteneacuterale si les argments effectifs appartiennent agrave des

espaces de noms diffeacuterents la recherche se fera dans ces diffeacuterentes porteacutees

4 - Imbrication des espaces de noms523

4 Imbrication des espaces de nomsLes deacutefinitions drsquoespaces de noms peuvent srsquoimbriquer comme dans cet exemple

namespace A deacutebut deacutefinition de lrsquoespace A int n An namespace B deacutebut deacutefinition de lrsquoespace AB float x ABx int n ABn fin deacutefinition de lrsquoespace AB float y Ay fin deacutefinition de lrsquoespace A

Disposant de ces deacuteclarations on pourra tout naturellement se reacutefeacuterer aux symboles corres-

pondants en utilisant les preacutefixes A ou AB De mecircme on pourra utiliser lrsquoune de ces

deacuteclarations1

using An n sera synonyme de Anusing ABn n sera synonyme de ABn

De la mecircme maniegravere on pourra recourir agrave des directives using comme dans

using namespace A on peut preacutefixer les symboles par A ici n deacutesigne An

ou dans

using namespace AB on peut preacutefixer les symboles par AB ici n deacutesigne ABn

ou encore dans

using namespace A ici x nrsquoa pas de signification (ni x ni Ax nrsquoexistent) Bx deacutesigne ABx

Ce dernier exemple montre que le fait de citer le nom drsquoun espace dans using nrsquointroduit pas

drsquooffice les noms des espaces imbriqueacutes

5 Transitiviteacute de la directive usingLa directive using peut srsquoutiliser dans la deacutefinition drsquoun espace de noms ce qui ne pose pas

de problegraveme particulier si lrsquoon sait que cette directive est transitive Autrement dit si une

directive using concerne un espace de noms qui contient lui-mecircme une directive using tout

se passe comme si lrsquoon avait eacutegalement mentionneacute cette seconde directive dans la porteacutee con-

cerneacutee Consideacuterons par exemple ces deacutefinitions

namespace A deacutebut deacutefinition espace A int n float y fin deacutefinition espace A

1 Bien entendu leur utilisation simultaneacutee conduirait agrave une ambiguiumlteacute

Les espaces de nomsCHAPITRE 24

524

namespace B deacutebut deacutefinition espace B using namepace A mecircme reacutesultat avec using An using Ay float x fin deacutefinition espace B

Avec une seule directive using namespace B on accegravede aux symboles deacutefinis effectivement

dans B mais eacutegalement agrave ceux deacutefinis dans A

using namepsace B ici x deacutesigne Bx n deacutesigne An et y deacutesigne Ay

On ne confondra pas cette situation avec lrsquoimbrication des espaces de noms eacutetudieacutee au para-

graphe 4

6 Les aliasIl est possible de deacutefinir un alias drsquoun espace de noms autrement dit un synonyme Par

exemple

namespace mon_espace_de_noms_favoris deacutefinition de mon_espace_de_noms_favorisnamespace MEF mon_espace_de_noms_favoris MEF est doreacutenavant un synonyme de mon_espace_de_noms_favorisusing namespace MEF eacutequivalent agrave using namespace mon_espace_de_noms_favoris

Cette possibiliteacute srsquoavegravere inteacuteressante pour deacutefinir des noms abreacutegeacutes drsquoespaces de noms jugeacutes

un peu trop longs comme nous lrsquoavons fait dans notre exemple

Elle permet eacutegalement agrave un programme de travailler avec diffeacuterentes bibliothegraveques posseacutedant

les mecircmes interfaces sans neacutecessiter de modification du code Par exemple supposons que

nous ayons deacutefini ces trois espaces de noms

namespace Win bibliothegraveque pour Windowsnamespace Unix bibliothegraveque pour Unixnamespace Linux bibliothegraveque pour Linux

Avec cette simple instruction

namespace Bibli Win

on pourra eacutecrire un programme travaillant avec un espace de nom fictif (Bibli) quelle que

soit la maniegravere drsquoacceacuteder aux symboles par une directive using namespace Bibli par une

deacuteclaration using individuelle using Biblixxx ou mecircme en les citant explicitement sous la

forme Biblixxx

7 Les espaces anonymesIl est possible de deacutefinir des espaces de noms anonymes crsquoest-agrave-dire ne posseacutedant pas de

nom explicite comme dans

namespace deacutebut deacutefinition espace anonyme fin deacutefinition espace anonyme

8 - Espaces de noms et deacuteclaration drsquoamitieacute525

Un tel espace de noms nrsquoest utilisable que dans la porteacutee ougrave il a eacuteteacute deacuteclareacute On peut dire que

tout se passe comme si le compilateur attribuait agrave cet espace un nom choisi de faccedilon agrave ecirctre

toujours diffeacuterent drsquoun fichier source agrave un autre Autrement dit les deacuteclarations preacuteceacutedentes

sont eacutequivalentes agrave

namespace nom_unique deacutebut deacutefinition espace nom_unique fin deacutefinition espace nom_uniqueusing nom_unique

En fait la vocation des espaces anonymes est de deacutefinir des symboles agrave porteacutee limiteacutee au

fichier source Le comiteacute ANSI recommande drsquoailleurs drsquoutiliser cette possibiliteacute de preacutefeacute-

rence agrave static voueacute agrave disparaicirctre1 dans une future actualisation de la norme

Par exemple on preacutefeacuterera ces deacuteclarations

namespace deacuteclaration des identificateurs cacheacutes dans le fichier source int globale_cachee void f(float) fonction de service non utilisable en dehors du source

agrave celles-ci

static int globale_cachee static void f(float)

8 Espaces de noms et deacuteclaration drsquoamitieacuteLorsqursquoune deacuteclaration drsquoamitieacute figure dans une classe la fonction ou la classe concerneacutee est

censeacutee se trouver dans le mecircme espace de noms ou dans un espace englobant

namespace A class X friend void f (int) obligatoirement Af namespace A namespace B class X friend void f (int) ABf ou Af

1 Cela concerne lrsquoutilisation de static pour cacher un symbole dans un fichier et nullement la deacuteclaration de membres

statiques dans une classe

Les espaces de nomsCHAPITRE 24

526

Drsquoautre part lors de lrsquoappel drsquoune fonction amie la recherche srsquoeffectue dans les espaces de

noms de ses diffeacuterents arguments

Annexes

Annexe A

Mise en correspondancedrsquoarguments

Voici lrsquoensemble des regravegles preacutesidant agrave la mise en correspondance drsquoarguments lors de

lrsquoappel drsquoune fonction surdeacutefinie ou drsquoun opeacuterateur Nous commencerons par voir comment

srsquoeacutetablit la liste des fonctions candidates Nous deacutecrirons ensuite lrsquoalgorithme utiliseacute pour

choisir la bonne fonction en examinant tout drsquoabord le cas particulier des fonctions agrave un

argument avant de voir comment il se geacuteneacuteralise aux fonctions agrave plusieurs arguments

NB Comme nous lrsquoavons signaleacute dans les chapitres correspondants ces regravegles ne srsquoappli-

quent pas inteacutegralement agrave lrsquoinstanciation drsquoune fonction patron

1 Deacutetermination des fonctions candidatesPour reacutesoudre un appel donneacute de fonction on eacutetablit une liste de fonctions candidates il

srsquoagit de toutes les fonctions ayant le nom voulu

bull situeacutees dans la porteacutee courante

bull situeacutees dans les espaces de noms introduits par une directive using (de la forme

using namespace xxx)

bull introduites par une instruction using (de la forme using xf) on introduit alors toutes les

fonctions de mecircme nom (ici f) de lrsquoespace de noms mentionneacute (ici x)

bull situeacutees dans les espaces de noms dans lesquels se situent les arguments effectifs de lrsquoappel

Mise en correspondance drsquoargumentsANNEXE A

530

On notera que les droits drsquoaccegraves agrave la fonction (publique priveacutee proteacutegeacutee) nrsquointerviennent pas

dans cette deacutetermination des fonctions candidates

Apregraves avoir deacutecrit la deacutemarche employeacutee pour les fonctions agrave un seul argument nous verrons

comment elle se geacuteneacuteralise aux fonctions agrave plusieurs arguments

2 Algorithme de recherche drsquoune fonction agrave un seul argument

21 Recherche dune correspondance exacteDans la recherche dune correspondance exacte

bull On distingue bien les diffeacuterents types entiers (char short int et long) avec leur attribut de

signe ainsi que les diffeacuterents types flottants (float double et long double) Notez que assez

curieusement char est agrave la fois diffeacuterent de signed char et de unsigned char (alors que dans

une impleacutementation donneacutee1 char est eacutequivalent agrave lun de ces deux types )

bull On ne tient pas compte des eacuteventuels qualificatifs volatile et const avec deux exceptions

pour const

ndash On distingue un pointeur de type t ( t eacutetant un type quelconque) dun pointeur de type

const t cest-agrave-dire un pointeur sur une valeur constante de type t

Plus preacuteciseacutement il peut exister deux fonctions lune pour le type t lautre pour le

type const t La preacutesence ou labsence du qualificatif const permettra de choisir la

bonne fonction

Sil nexiste quune seule de ces deux fonctions correspondant au type const t t cons-

titue quand mecircme une correspondance exacte pour const t (lagrave encore cela se justifie

par le fait que le traitement preacutevu pour quelque chose de constant peut sappliquer agrave

quelque chose de non constant) En revanche sil nexiste quune fonction correspon-

dant au type t const t ne constitue pas une correspondance exacte pour ce type t

(ce qui signifie quon ne pourra pas appliquer agrave quelque chose de constant le traitement

preacutevu pour quelque chose de non constant)

ndash On distingue le type t amp (t eacutetant un type quelconque et amp deacutesignant un transfert par reacute-

feacuterence) du type const t amp Le raisonnement preacuteceacutedent sapplique en remplaccedilant sim-

plement t par t amp2

Srsquoil existe une fonction reacutealisant une correspondance exacte la recherche srsquoarrecircte lagrave et la

fonction trouveacutee est appeleacutee agrave condition qursquoelle soit accessible (ce qui ne serait par exemple

1 Du moins pour des options de compilation donneacutees

2 En toute rigueur on distingue eacutegalement volatile t de t et volatile t amp de t amp

2 - Algorithme de recherche drsquoune fonction agrave un seul argument531

pas le cas pour une fonction priveacutee drsquoune classe A appeleacutee depuis une fonction non membre

de A) On notera qursquoagrave ce niveau un telle fonction est obligatoirement unique Dans le cas

contraire les deacuteclarations des diffeacuterentes fonctions auraient en effet eacuteteacute rejeteacutees lors de leur

compilation (par exemple vous ne pourrez jamais deacutefinir f(int) et f(const int) ou encore f(int)

et f(int amp))

22 Promotions numeacuteriquesSi la recherche preacuteceacutedente na pas abouti on effectue une nouvelle recherche en faisant inter-

venir les conversions suivantes

char signed char unsigned char short ndashgt int

unsigned short ndashgt int ou unsigned int1

enum ndashgt int

float ndashgt double

Rappelons que ces conversions ne peuvent pas ecirctre appliqueacutees agrave une transmission par reacutefeacute-

rence (T amp) sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante2 (const T amp)

Ici encore si une fonction est trouveacutee elle est obligatoirement unique

23 Conversions standardSi la recherche na toujours pas abouti on fait intervenir les conversions standard suivantes

bull type numeacuterique en un autre type numeacuterique (y compris des conversions deacutegradantes ain-

si un float conviendra lagrave ougrave un int est attendu)

bull enum en un autre type numeacuterique

bull 0 ndashgt numeacuterique

bull 0 ndashgt pointeur quelconque

bull pointeur quelconque ndashgt void 3

bull pointeur sur une classe deacuteriveacutee ndashgt pointeur sur une classe de base

Ici encore ces conversions ne peuvent pas ecirctre appliqueacutees agrave une transmission par reacutefeacuterence

(T amp) sauf srsquoil srsquoagit drsquoune reacutefeacuterence agrave une constante4 (const T amp)

1 Selon qursquoun int suffit ou non agrave accueillir un unsigned short (il ne le peut pas lorsque short et int correspondent au

mecircme nombre de bits)

2 Le qualificatif volatile ne doit pas ecirctre employeacute dans ce cas

3 La conversion inverse nest pas preacutevue Cela est coheacuterent avec le fait quen C++ ANSI contrairement agrave ce qui se

passe en C ANSI un pointeur de type void ne peut pas ecirctre affecteacute agrave un pointeur quelconque

4 Le qualificatif volatile ne doit pas ecirctre employeacute dans ce cas

Mise en correspondance drsquoargumentsANNEXE A

532

Cette fois il est possible que plusieurs fonctions conviennent Il y a alors ambiguiumlteacute excepteacute

dans certaines situations

bull la conversion dun pointeur sur une classe deacuteriveacutee en un pointeur sur une classe de base est

preacutefeacutereacutee agrave la conversion en void

bull si C deacuterive de B et B deacuterive de A la conversion C en B est preacutefeacutereacutee agrave la conversion en

A il en va de mecircme pour la conversion C amp en B amp qui est preacutefeacutereacutee agrave la conversion en A

amp

24 Conversions deacutefinies par lutilisateurSi aucune fonction ne convient on fera intervenir les conversions deacutefinies par lutilisateur

(CDU)

Une seule CDU pourra intervenir mais elle pourra ecirctre associeacutee agrave dautres conversions

Toutefois lorsquune chaicircne de conversions peut ecirctre simplifieacutee en une chaicircne plus courte

seule cette derniegravere est consideacutereacutee Par exemple dans char ndashgt int ndashgt float et char -gt float

on ne considegravere que char -gt float Ici encore si plusieurs combinaisons de conversions exis-

tent (apregraves les eacuteventuelles simplifications eacutevoqueacutees) le compilateur refusera lappel agrave cause

de son ambiguiumlteacute

25 Fonctions agrave arguments variablesLorsquune fonction a preacutevu des arguments de types quelconques (notation ) nimporte

quel type drsquoargument effectif convient

Notez bien que cette possibiliteacute nest examineacutee quen dernier Cette remarque prendra tout

son inteacuterecirct dans le cas de fonctions agrave plusieurs arguments

26 Exception cas des champs de bitsLorsqursquoun argument effectif est un champ de bits il est consideacutereacute comme un int dans la

recherche de la meilleure fonction Si lrsquounique fonction seacutelectionneacutee reccediloit cet argument par

reacutefeacuterence (int amp) elle est rejeteacutee et lrsquoon aboutit agrave une erreur1 sauf lagrave encore srsquoil srsquoagit drsquoune

reacutefeacuterence agrave une constante (const int amp)

3 Fonctions agrave plusieurs argumentsLe compilateur recherche une fonction meilleure que toutes les autres Pour ce faire il

applique les regravegles de recherche preacuteceacutedentes agrave chacun des arguments ce qui le conduit agrave

1 On notera bien que le rejet a lieu en fin de processus en particulier aucune recherche nrsquoest faite pour trouver de

moins bonnes correspondances

4 - Fonctions membres533

seacutelectionner pour chaque argument une ou plusieurs fonctions reacutealisant la meilleure corres-

pondance Cette fois il peut y en avoir plusieurs car la deacutetermination finale de la bonne fonc-

tion nest pas encore faite (toutefois si aucune fonction nest seacutelectionneacutee pour un argument

donneacute on est deacutejagrave sucircr quaucune fonction ne conviendra) Ensuite parmi toutes les fonctions

ainsi seacutelectionneacutees le compilateur deacutetermine celle si elle existe et si elle est unique qui reacutea-

lise la meilleure correspondance cest-agrave-dire celle pour laquelle la correspondance de chaque

argument est eacutegale ou supeacuterieure agrave celle des autres1

Remarque

Les fonctions comportant un ou plusieurs arguments par deacutefaut sont traiteacutees comme si

plusieurs fonctions diffeacuterentes avaient eacuteteacute deacutefinies avec un nombre croissant darguments

4 Fonctions membresUn appel de fonction membre (non statique2) peut ecirctre consideacutereacute comme un appel dune fonc-

tion ordinaire auquel sajoute un argument effectif ayant le type de lobjet ayant effectueacute

lappel Toutefois cet argument nest pas soumis aux regravegles de correspondance dont nous

parlons ici En effet cest son type qui deacutetermine la fonction membre agrave appeler en tenant

compte eacuteventuellement

bull du meacutecanisme dheacuteritage eacutetudieacute en deacutetail au chapitre 13

bull des attributs const et volatile il est possible de distinguer une fonction membre agissant sur

des objets constants dune fonction membre agissant sur des objets non constants Une fonc-

tion membre constante peut toujours agir sur des objets non constants la reacuteciproque est

bien sucircr fausse La mecircme remarque sapplique agrave lattribut volatile

1 Cela revient agrave dire en termes ensemblistes quon considegravere lintersection des diffeacuterents ensembles formeacutes des

fonctions reacutealisant la meilleure correspondance pour chaque argument Cette intersection doit comporter exactement

un eacuteleacutement

2 Une fonction membre statique ne comporte aucun argument implicite de type classe

Annexe B

Utilisation de code eacutecrit en C

Afin de vous faciliter la reacuteutilisation de code eacutecrit en C nous reacutecapitulons ici lensemble des

incompatibiliteacutes existant entre le C ANSI et le C++ (dans ce sens) cest-agrave-dire les diffeacuterents

points accepteacutes par le C ANSI et refuseacutes par le C++ Notez que les cinq premiers points ont

eacuteteacute exposeacutes en deacutetail dans le chapitre II le dernier la eacuteteacute dans le chapitre IV Les autres cor-

respondent agrave des usages assez peu freacutequents

1 PrototypesEn C++ toute fonction non deacutefinie preacutealablement dans un fichier source ougrave elle est utiliseacutee

doit faire lobjet dune deacuteclaration sous forme dun prototype

2 Fonctions sans argumentsEn C++ une fonction sans arguments se deacutefinit (en-tecircte) et se deacuteclare (prototype) en fournis-

sant une liste vide darguments comme dans

float fct ()

3 Fonctions sans valeur de retourEn C++ une fonction sans valeur de retour se deacutefinit (en-tecircte) et se deacuteclare (prototype) obli-

gatoirement agrave laide du mot void comme dans

Utilisation de code eacutecrit en CANNEXE B

536

void fct (int double)

4 Le qualificatif constEn C++ un symbole accompagneacute dans sa deacuteclaration du qualificatif const a une porteacutee limi-

teacutee au fichier source concerneacute alors quen C ANSI il est consideacutereacute comme un symbole

externe De plus en C++ un tel symbole peut intervenir dans une expression constante (il ne

sagit toutefois plus dune incompatibiliteacute mais dune liberteacute offerte par C++)

5 Les pointeurs de type void En C++ un pointeur de type void ne peut pas ecirctre converti implicitement en un pointeur

dun autre type

6 Mots-cleacutesC++ possegravede par rapport agrave C les mots-cleacutes suppleacutementaires suivants1

bool catch class const_cast

delete dynamic_cast explicit export

false friend inline mutable

namespace new operator private

protected public reinterpret_cast static_cast

template this true throw

try typeid typename using

virtual

Voici la liste complegravete des mots cleacutes de C++ Ceux qui existent deacutejagrave en C sont en romain

ceux qui sont propres agrave C++ sont en italique A simple titre indicatif les mots cleacutes introduits

tardivement par la norme ANSI sont en gras (et en italique)

asm auto bool break case

catch char class const const_cast

continue default delete do double

dynamic_cast else enum explicit export

extern false float for friend

goto if inline int long

mutable namespace new operator private

protected public register reinterpret_cast return

1 Le mot cleacute overload a existeacute dans les versions anteacuterieures agrave la 20 Sil reste reconnu de certaines impleacutementations

en eacutetant alors sans effet il ne figure cependant pas dans la norme

7 - Les constantes de type caractegravere537

short signed sizeof static static_cast

struct switch template this throw

true try typedef typeid typename

union unsigned using virtual void

volatile wchar_t while

7 Les constantes de type caractegravereEn C++ (depuis la version 20) une constante caractegravere telle que a z ou n est de type

char alors quelle est implicitement convertie en int en C ANSI Cest ainsi que lopeacuterateur ltlt

de la classe ostream peut fonctionner correctement avec des caractegraveres (dans les versions

anteacuterieures agrave la 20 on obtenait le code numeacuterique du caractegravere)

Notez bien quune expression telle que

sizeof (a)

vaut 1 en C++ alors quelle vaut davantage (geacuteneacuteralement 2 ou 4) en C

8 Les deacutefinitions multiplesEn C ANSI il est permis de trouver plusieurs deacuteclarations dune mecircme variable dans un

fichier source Par exemple avec

int n int n

C considegravere que la premiegravere instruction est une simple deacuteclaration tandis que la seconde est

une deacutefinition cest cette derniegravere qui provoque la reacuteservation de lemplacement meacutemoire

pour n

En C++ cela est interdit La raison principale vient de ce que dans le cas ougrave de telles deacutecla-

rations porteraient sur des objets par exemple dans

point a point a

il faudrait que le compilateur distingue deacuteclaration et deacutefinition de lobjet point et quil preacute-

voie de nappeler le constructeur que dans le second cas Cela aurait eacuteteacute particuliegraverement dan-

gereux dougrave linterdiction adopteacutee

Utilisation de code eacutecrit en CANNEXE B

538

9 Linstruction gotoEn C++ une instruction goto ne peut pas faire sauter une deacuteclaration comportant un initiali-

seur (par exemple int n = 2 ) sauf si cette deacuteclaration figure dans un bloc et que ce bloc est

sauteacute complegravetement

10 Les eacutenumeacuterationsEn C++ les eacuteleacutements dune eacutenumeacuteration (mot cleacute enum) ont une porteacutee limiteacutee agrave lespace de

visibiliteacute dans lequel ils sont deacutefinis Par exemple avec

struct chose enum (rouge = 1 bleu vert)

les symboles rouge bleu et vert ne peuvent pas ecirctre employeacutes en dehors dun objet de type

chose Ils peuvent eacuteventuellement ecirctre redeacutefinis avec une signification diffeacuterente En C ces

symboles sont accessibles de toute la partie du fichier source suivant leur deacuteclaration et il

nest alors plus possible de les redeacutefinir

11 Initialisation de tableaux de caractegraveresEn C++ linitialisation de tableaux de caractegraveres par une chaicircne de mecircme longueur nest pas

possible Par exemple linstruction

char t[5] = hello

provoquera une erreur due agrave ce que t na pas une dimension suffisante pour recevoir le carac-

tegravere (0) de fin de chaicircne

En C ANSI cette mecircme deacuteclaration serait accepteacutee et le tableau t se verrait simplement ini-

tialiseacute avec les 5 caractegraveres h e l l et o (sans caractegravere de fin de chaicircne)

Notez que linstruction

char t[] = hello

convient indiffeacuteremment en C et en C++ et quelle reacuteserve dans les deux cas un tableau de 6

caractegraveres h e l l o et 0

12 Les noms de fonctionsEn C++ depuis la version 20 le compilateur attribue agrave toutes les fonctions un nom externe

baseacute dune faccedilon deacuteterministe

bull sur son nom interne

bull sur la nature de ses arguments

Si lon veut obtenir les mecircmes noms de fonction quen C on peut faire appel au mot cleacute

extern Pour plus de deacutetails voyez le paragraphe 53 du chapitre 4

Annexe C

Compleacutements sur les exceptions

Comme nous lrsquoavons examineacute au chapitre 17 le meacutecanisme proposeacute par C++ pour la gestion

des exceptions permet de poursuivre lrsquoexeacutecution du programme apregraves le traitement drsquoune

exception1 On a vu qursquoalors les diffeacuterentes sorties de blocs provoqueacutees par le transfert du

point de deacuteclenchement de lrsquoexception agrave celui de son traitement sont convenablement prises

en compte les objets automatiques entiegraverement construits au moment de la deacutetection de

lrsquoexception sont convenablement deacutetruits (avec appel de leur destructeur) srsquoils deviennent

hors de porteacutee Neacuteanmoins aucune gestion de cette sorte nrsquoexiste pour les objets ou les

emplacements alloueacutes dynamiquement Apregraves avoir illustreacute les problegravemes que cela peut

poser nous verrons comment les reacutesoudre en utilisant une technique dite de gestion des res-

sources par initialisation ou dans certains cas en recourant agrave des pointeurs intelligents

(auto_ptr)

1 Les problegravemes poseacutes par les objets automatiques

Voici un petit exemple montrant les problegravemes que peuvent poser la poursuite de lrsquoexeacutecution

apregraves deacutetection drsquoune exception Il srsquoagit drsquoune modification de la fonction f de lrsquoexemple du

paragraphe 31 du chapitre 17 il se fonde sur les mecircmes classes vect et vect_creation La

1 Rappelons toutefois qursquoil ne srsquoagit pas veacuteritablement drsquoune reprise de lrsquoexeacutecution mais simplement drsquoune

poursuite apregraves le bloc try concerneacute

Compleacutements sur les exceptionsANNEXE C

540

principale diffeacuterence vient de ce que la fonction f y alloue dynamiquement un objet de type

vect

void f(int) try v1 = new vect(5) allocation dynamique drsquoun objet v1 de type vect de 5 eacuteleacutements v1[n] = 0 OK pour 0 lt= n lt 5 exception vect_limite sinon delete v1 v1 sera convenablement deacutetruit en cas de fin normale du bloc try catch (vect_limite vl) instructions de gestion de lrsquoexception vect_limite instructions exeacutecuteacutees dans tous les cas srsquoil nrsquoy a pas eu exception v1 a eacuteteacute deacutetruit srsquoil y a eu exception v1 nrsquoa pas eacuteteacute deacutetruit

On voit que lrsquoobjet v1 nrsquoest pas deacutetruit degraves lors qursquoune exception de type vect_limite a eacuteteacute

deacuteclencheacutee Bien entendu dans cet exemple simpliste on pourrait encore preacutevoir de le faire

dans le gestionnaire catch (vect_limite) On pourrait mecircme apregraves cette destruction redeacuteclen-

cher lrsquoexception par throw En pratique les choses seront rarement aussi simples et il ne sera

pas toujours possible de savoir agrave coup sucircr quels objets doivent ecirctre deacutetruits mecircme dans le cas

drsquoun gestionnaire local

2 La technique de gestion de ressources par initialisation

Drsquoune maniegravere geacuteneacuterale on peut dire que la poursuite de lrsquoexeacutecution apregraves traitement drsquoune

exception pose un problegraveme drsquoacquisition de ressource dont la libeacuteration peut ne pas ecirctre reacutea-

liseacutee On range sous ce terme drsquoacquisition de ressource toute action qui neacutecessite une action

contraire pour la bonne poursuite des opeacuterations On peut y trouver des actions aussi diverses

que

bull creacuteation dynamique drsquoun objet

bull allocation dynamique drsquoun emplacement meacutemoire

bull ouverture drsquoun fichier

bull verrouillage drsquoun fichier en eacutecriture

bull eacutetablisssement drsquoune connexion par exemple avec un site Web

bull ouverture drsquoune de session de communication avec un utilisateur distant

Si lrsquoon souhaite que toute ressource acquise dans un programme soit convenablement libeacutereacutee

il est neacutecessaire qursquoen cas drsquoexception quelle qursquoelle soit on puisse libeacuterer les ressources

deacutejagrave acquises et uniquement celles-lagrave Comme le laisse pressentir lrsquoexemple preacuteceacutedent les

2 - La technique de gestion de ressources par initialisation541

choses peuvent devenir extrecircmement complexes degraves que le programme prend quelque impor-

tance En effet toute utilisation drsquoune ressource doit se faire dans un bloc try assorti de ges-

tionnaires interceptant toutes les exceptions possibles (les redeacuteclenchant eacuteventuellement par

throw) et capables de libeacuterer les ressources en question

En fait il existe une deacutemarche dite gestion de ressources par initialisation1 qui srsquoappuie sur

lrsquoappel automatique du destructeur des objets automatiques Elle consiste simplement agrave faire

acqueacuterir une ressource dans un constructeur drsquoune classe speacutecifiquement creacuteee agrave cet effet la

libeacuteration de la ressource se faisant dans le destructeur de cette mecircme classe Par exemple on

sera ameneacute agrave creacuteer une classe telle que

class ressource1 public ressource1 () acquisition de la ressource 1 ~ressource1 () libeacuteration de la ressource 1

Un programme ayant besoin drsquoacqueacuterir la ressource correspondante se preacutesentera ainsi

ressource 1 () acquisition de la ressource 1 par appel du constructeur de la classe ressource1

Le bloc preacuteceacutedent peut ecirctre ou non un bloc try Dans tous les cas de sortie de ce bloc (que ce

soit naturellement ou suite agrave une exception dont le gestionnaire peut se trouver dans

nrsquoimporte quel bloc englobant) il y aura appel du destructeur ~ressource1 et donc libeacuteration

de la ressource 1

Il faut cependant srsquoassurer qursquoaucun problegraveme ne risque de se poser si le constructeur de

ressource1 deacuteclenche lui-mecircme une exception Dans ce cas en effet ~ressource1 ne sera pas

appeleacute (puisqursquoen cas drsquoexception il nrsquoy a appel que des destructeurs des objets entiegraverement

creacuteeacutes) et la ressource ne sera pas libeacutereacutee Si un tel problegraveme risque drsquoapparaicirctre crsquoest proba-

blement que le constructeur associeacute agrave une ressource fait plus qursquoacqueacuterir une ressource Il

faut alors chercher agrave isoler lrsquoacquisition de ressource dans un sous-objet comme dans cet

exemple

class ressource1 public ressource1 () acquis_ressource1 () traitement agrave reacutealiser apregraves lrsquoacquisition de ressource

1 On parle souvent en anglais de RAII (Ressource Acquisition Is Initialization)

Compleacutements sur les exceptionsANNEXE C

542

class acquis_ressource1 public alloc_ressource1 () censeacute ne pas deacuteclencher drsquoexception ~alloc_ressource1 ()

Cette fois aucun problegraveme ne se pose plus si une exception est deacuteclencheacutee pendant le traite-

ment effectueacute dans ressource1 apregraves lrsquoacquisition de la ressource

3 Le concept de pointeur intelligent la classe auto_ptr

Parmi les diffeacuterentes ressources neacutecessaires agrave un programme la plus importante est geacuteneacuterale-

ment la meacutemoire Nous venons de voir comment la technique de gestion de ressources par

initialisation permet de geacuterer convenablement les situations drsquoexception La bibliothegraveque

standard du C++ propose un autre outil sous la forme de pointeurs intelligents procureacutes par le

patron de classes auto_ptr Lrsquoideacutee consiste agrave associer dans un objet de type auto_ptr un objet

pointeacute agrave la variable pointeur qui en contient lrsquoadresse si la variable devient hors de porteacutee

on deacutetruit automatiquement lrsquoobjet pointeacute Pour qursquoun tel meacutecanisme puisse ecirctre mis en

oeuvre il faut respecter une contrainte importante agrave savoir nrsquoassocier un objet donneacute qursquoagrave

une seule variable pointeur agrave la fois Crsquoest pourquoi apregraves copie drsquoobjets de type auto_ptr

seul lrsquoobjet recevant la copie reste associeacute agrave la partie pointeacutee lrsquoautre en ayant perdu le lien

(on dit parfois qursquoun seul objet de type auto_ptr est proprieacutetaire de la partie pointeacutee) Cette

particulariteacute srsquoapplique aussi bien au constructeur par recopie qursquoagrave lrsquoaffectation

Comme on peut srsquoy attendre le patron de classes auto_ptr est parameacutetreacute par le type de lrsquoobjet

pointeacute On peut construire un pointeur intelligent agrave partir de la valeur drsquoun pointeur usuel

double add auto_ptrltdoublegt apd1(add) auto_ptr sur le double pointeacute par addauto_ptrltdoublegt apd2(new double) auto_ptr sur un double qursquoon a a alloueacute dynamiquement

On peut aussi construire un pointeur intelligent sans lrsquoinitialiser

auto_ptrltdoublegt apd auto_ptr sur un double

Dans ce cas apd ne pourra ecirctre utiliseacute qursquoapregraves qursquoon lui aura affecteacute la valeur drsquoun autre

objet de type auto_ptrltdoublegt

Voici deux exemples complets de programmes illustrant lrsquoemploi de ces pointeurs

intelligents1

1 Dans les deux cas nous avons introduit artificiellement un bloc drsquoinstructions pour mieux montrer le

fonctionnement des pointeurs intelligents

3 - Le concept de pointeur intelligent la classe auto_ptr543

include ltiostreamgtinclude ltmemorygt pour la classe auto_ptrinclude ltvectorgtusing namespace std main() auto_ptrltvectorltintgt gt apvi2 int v[] = 1 2 3 4 5 auto_ptrltvectorltintgt gt apvi1(new vectorltintgt (v v+5)) (apvi1)[2] = 12 cout ltlt (apvi1)[1] ltlt ltlt (apvi1)[2] ltlt n affiche 2 12 apvi2 = apvi1 apvi1 et apvi2 pointent sur le meme vector mais seul apvi2 est proprietaire du vector pointe (apvi1)[2] = 20 OK cout ltlt (apvi2)[1] ltlt ltlt (apvi2)[2] ltlt n affiche 2 20 ici apvi1 nexiste plus mais le vector pointe appartient a vpi2 cout ltlt (apvi1)[1] conduirait a une erreur de compilation cout ltlt (apvi2)[1] ltlt ltlt (apvi2)[2] ltlt n affiche toujours 2 20 ici apvi2 nexiste plus et le vector pointe est detruit

Exemple drsquoutilisation de pointeurs intelligents (1)

include ltiostreamgtinclude ltmemorygt pour la classe auto_ptrusing namespace std class point public int x y champs exceptionnellement publics ici point(int abs=0 int ord=0) x(abs) y(ord) cout ltltconstruction point ltlt x ltlt ltlt y ltlt ltlt n ~point() cout ltltdestruction point ltlt x ltlt ltlt y ltlt ltlt n void affiche () cout ltlt coordonnees ltlt x ltlt ltlt y ltlt n

main() auto_ptrltpointgt ap1

auto_ptrltpointgt ap2 (new point(1 2)) (ap2)affiche() ou ap2-gtaffiche()

ap1 = ap2 ap1 et ap2 pointe sur le meme point mais seul ap1 en est maintenant proprietaire

ap2-gtx=12 on modifie lobjet par le biais de ap2

Compleacutements sur les exceptionsANNEXE C

544

ici ap2 nexiste plus une tentative dutilisation telle que ap2-gt affiche() serait rejetee en compilation mais lobjet pointe na pas ete detruit

ap1-gtaffiche() ap1 pointe toujours sur le point

Exemple drsquoutilisation de pointeurs intelligents (2)

Remarques

1 Les pointeurs intelligents sont utilisables en dehors du contexte de gestion des exceptions

mecircme si crsquoest dans cette situation qursquoils se reacutevegravelent le plus utile

2 Les meacutethodes exposeacutees preacuteceacutedemment pour acqueacuterir une ressource regraveglent convenable-

ment le problegraveme de leur libeacuteration Malgreacute tout il reste possible de creacuteer un objet dans

un eacutetat tel que son utilisation pose problegraveme Citons quelques exemples

ndash la creacuteation drsquoun objet comportant une partie dynamique peut avoir eacutechoueacute pour cause

de manque de meacutemoire le fait de geacuterer convenablement lrsquoacquisition de ressource

qursquoest lrsquoallocation meacutemoire nrsquoempecircche pas qursquoon risque de fournir un objet avec un

pointeur mal initialiseacute le mecircme type de problegraveme peut se poser en cas drsquoaffectation

entre objets comportant des parties dynamiques

ndash lrsquoallocation de certaines ressources neacutecessaires agrave un objet peut avoir reacuteussi alors que

drsquoautres auront eacutechoueacute

Si lrsquoon souhaite que lrsquoexeacutecution du programme puisse se poursuivre apregraves une excep-

tion il est alors conseilleacute de ne creacuteer que des objets integravegres crsquoest-agrave-dire dont lrsquoutilisa-

tion ne comporte pas de risque mecircme si lrsquoobjet est incomplet

Annexe D

Les diffeacuterentes sortesde fonctions en C++

Nous vous fournissons ici la liste des diffeacuterentes sortes de fonctions que lon peut rencontrer

en C++ en preacutecisant dans chaque cas si elle peut ecirctre deacutefinie comme fonction membre ou

amie sil existe une version par deacutefaut si elle est heacuteriteacutee et si elle peut ecirctre virtuelle

Type de fonction Membre ou amie Version par deacutefaut

Heacuteriteacutee Peut ecirctre virtuelle

constructeur membre oui non non

destructeur membre oui non oui

conversion membre non oui oui

affectation membre oui non oui

() membre non oui oui

[] membre non oui oui

-gt membre non oui oui

new membre statique non oui oui

delete membre statique non oui oui

autre opeacuterateur lun ou lautre non oui oui

autre fonction membre membre non oui oui

fonction amie amie non non non

Annexe E

Comptage de reacutefeacuterences

Nous avons vu que degraves quun objet comporte une partie dynamique il est neacutecessaire de pro-

ceacuteder agrave des copies profondes plutocirct quagrave des copies superficielles et ce aussi bien dans le

constructeur de recopie que dans lopeacuterateur daffectation Cette faccedilon de proceacuteder conduit agrave

ce que lrsquoon pourrait nommer la seacutemantique naturelle de lrsquoaffectation et de la copie Ainsi

avec

vect a(5) b(12) a contient 5 eacuteleacutements b en contient 12 a = b a et b contiennent maintenant 12 eacuteleacutements mais ils restent indeacutependantsa[2] = 12 la valeur de a[2] est modifieacutee pas celle de b[2]

Mais il est possible drsquoeacuteviter la duplication de cette partie dynamique en faisant appel agrave la

technique du compteur de reacutefeacuterences Elle consiste agrave compter en permanence le nombre

de reacutefeacuterences agrave un emplacement dynamique cest-agrave-dire le nombre de pointeurs diffeacuterents la

deacutesignant agrave un instant donneacute Dans ces conditions lorsquun objet est deacutetruit il suffit de nen

deacutetruire la partie dynamique correspondante que si son compteur de reacutefeacuterences est nul pour

eacuteviter les risques de libeacuteration multiple que nous avons souvent eacutevoqueacutes

Cette technique conduit cependant agrave une seacutemantique totalement diffeacuterente de la copie et de

lrsquoaffectation

vect a(5) b(12) a contient 5 eacuteleacutements b en contient 12 a = b a et b deacutesignent maintenant le mecircme vecteur de 12 eacuteleacutements a[i] et b[i] deacutesignent le mecircme eacuteleacutementa[2] = 12 la valeur de a[2] est modifieacutee il en va de mecircme de celle de b[2] puisqursquoil srsquoagit du mecircme eacuteleacutement

Comptage de reacutefeacuterencesANNEXE E

548

Pour mettre en œuvre cette technique deux points doivent ecirctre preacuteciseacutes

a) Lemplacement du compteur de reacutefeacuterences

A priori deux possibiliteacutes viennent agrave lesprit dans lobjet lui-mecircme ou dans la partie dyna-

mique associeacutee agrave lobjet La premiegravere solution nest guegravere exploitable car elle obligerait agrave

dupliquer ce compteur autant de fois quil y a dobjets pointant sur une mecircme zone en outre

il serait tregraves difficile deffectuer la mise agrave jour des compteurs de tous les objets deacutesignant la

mecircme zone Manifestement donc le compteur de reacutefeacuterence doit ecirctre associeacute non pas agrave un

objet mais agrave sa partie dynamique

b) Les meacutethodes devant agir sur le compteur de reacutefeacuterences

Le compteur de reacutefeacuterences doit ecirctre mis agrave jour chaque fois que le nombre dobjets deacutesignant

lemplacement correspondant risque decirctre modifieacute Cela concerne donc

bull le constructeur de recopie il doit initialiser un nouvel objet pointant sur un emplacement

deacutejagrave reacutefeacuterenceacute et donc increacutementer son compteur de reacutefeacuterences

bull lopeacuterateur daffectation une instruction telle que a = b doit

ndash deacutecreacutementer le compteur de reacutefeacuterences de lemplacement reacutefeacuterenceacute par a et proceacuteder agrave

sa libeacuteration lorsque le compteur est nul

ndash increacutementer le compteur de reacutefeacuterences de lemplacement reacutefeacuterenceacute par b

Bien entendu il est indispensable que le constructeur de recopie existe et que lopeacuterateur

daffectation soit surdeacutefini Le non-respect de lune de ces deux conditions et lutilisation des

meacutethodes par deacutefaut qui en deacutecoule entraicircneraient des recopies dobjets sans mise agrave jour des

compteurs de reacutefeacuterences

Nous vous proposons un canevas geacuteneacuteral applicable agrave toute classe de type X posseacutedant une

partie dynamique de type T Ici pour reacutealiser lassociation de la partie dynamique et du

compteur associeacute nous utilisons une structure de nom partie_dyn La partie dynamique de X

sera geacutereacutee par un pointeur sur une structure de type partie_dyn

T deacutesigne un type quelconque (eacuteventuellement classe)

struct partie_dyn structure de service pour la partie dynamique de lobjet long nref compteur de reacutefeacuterence associeacute T adr pointeur sur partie dynamique (de type T) class X membres donneacutee non dynamiques partie_dyn adyn pointeur sur partie dynamique void decremente () fonction de service - deacutecreacutemente le if (--adyn-gtnref) compteur de reacutefeacuterence et deacutetruit delete adyn-gtadr la partie dynamique si neacutecessaire delete adyn

549

public X ( ) constructeur usuel construction partie non dynamique construction partie dynamique adyn = new partie_dyn adyn-gtadr = new T adyn-gtnref = 1

X (X amp x) constructeur de recopie recopie partie non dynamique recopie partie dynamique adyn = xadyn adyn-gtnref++ increacutementation compteur reacutefeacuterences ~X () destructeur decremente () X amp operator = (X amp x) surdeacutefinition opeacuterateur affectation if (this = ampx) on ne fait rien pour a=a

traitement partie non dynamique traitement partie dynamique decremente () xadyn-gtnref++ adyn = xadyn return this

Un canevas geacuteneacuteral pour le comptage de reacutefeacuterences

Remarque

La classe auto_ptr preacutesenteacutee en Annexe C conduit agrave une autre forme de seacutemantique de

copie et drsquoaffectation on y dispose toujours de plusieurs reacutefeacuterences agrave un mecircme emplace-

ment meacutemoire mais une seule drsquoentre elles en est proprieacutetaire

En Java

La seacutemantique de lrsquoaffectation et de la copie correspond agrave celle induite par le comptage de

reacutefeacuterences

Annexe F

Les pointeurs sur des membres

C++ permet de deacutefinir ce que lrsquoon nomme des pointeurs sur des membres Il srsquoagit drsquoune

notion peu utiliseacutee en pratique ce qui justifie sa place en annexe Elle srsquoapplique theacuteorique-

ment aux membres donneacutees comme aux membres fonctions mais elle nrsquoest presque jamais

utiliseacutee dans la premiegravere situation

1 Rappels sur les pointeurs sur des fonctions en C

Le langage C permet de deacutefinir des pointeurs sur des fonctions Leur emploi permet en parti-

culier de programmer ce que lon pourrait nommer des appels variables de fonctions A

titre de rappel consideacuterez ces deacuteclarations

int f1 (char double) int f2 (char double) int ( adf) (char double)

La derniegravere signifie que adf est un pointeur sur une fonction recevant deux arguments ndash lun

de type char lautre de type double ndash et fournissant un reacutesultat de type int Les affectations

suivantes sont alors possibles

adf = f1 affecte agrave adf ladresse de la fonction f1 on peut aussi eacutecrire adf = amp f1 adf = f2 affecte agrave adf ladresse de la fonction f2

Les pointeurs sur des membresANNEXE F

552

Linstruction

( adf) (c 525)

reacutealise lappel de la fonction dont ladresse figure dans adf en lui fournissant en arguments les

valeurs c et 525

On notera que comme les autres pointeurs du C les pointeurs sur les fonctions sont forte-

ment typeacutes en ce sens que leur type preacutecise agrave la fois la nature de la valeur de retour de la

fonction et la nature de chacun de ses arguments

2 Les pointeurs sur des fonctions membresBien entendu C++ vous offre toutes les possibiliteacutes eacutevoqueacutees ci-dessus Mais il permet de

surcroicirct de les eacutetendre au cas des fonctions membres moyennant une geacuteneacuteralisation de la

syntaxe preacuteceacutedente En effet il faut pouvoir tenir compte de ce quune fonction membre se

deacutefinit

bull dune part comme une fonction ordinaire cest-agrave-dire dapregraves le type de ses arguments et de

sa valeur de retour

bull dautre part dapregraves le type de la classe agrave laquelle elle sapplique le type de lobjet layant

appeleacute constituant en quelque sorte le type dun argument suppleacutementaire

Si une classe point comporte deux fonctions membres de prototypes

void dep_hor (int)

void dep_vert (int)

la deacuteclaration

void (point adf) (int)

preacutecisera que adf est un pointeur sur une fonction membre de la classe point recevant un

argument de type int et ne renvoyant aucune valeur Les affectations suivantes seront alors

possibles

adf = pointdep_hor ou adf = amp pointdep_hor

adf = pointdep_vert

Si a est un objet de type point une instruction telle que

(aadf) (3)

provoquera pour le point a lappel de la fonction membre dont ladresse est contenue dans

adf en lui transmettant en argument la valeur 3

De mecircme si adp est lrsquoadresse drsquoun objet de type point

point adp

lrsquoinstruction

(adp -gtadf) (3)

provoquera pour le point drsquoadresse adp lappel de la fonction membre dont ladresse est con-

tenue dans adf en lui transmettant en argument la valeur 3

3 - Les pointeurs sur des membres donneacutees553

On notera que en toute rigueur un pointeur sur une fonction membre ne contient pas une

adresse au mecircme titre que nrsquoimporte quel pointeur Il srsquoagit simplement drsquoune information

permettant de localiser convenablement le membre en question agrave lrsquointeacuterieur drsquoun objet donneacute

ou drsquoun objet drsquoadresse donneacutee Crsquoest donc par abus de langage que nous parlons de lrsquoadresse

contenue dans adf

Drsquoautre part les notations a(adf) ou a-gtadf nrsquoont ici aucune signification contrairement agrave

ce qui se produirait si adf eacutetait un pointeur usuel En fait

bull lrsquoexpression adf nrsquoa pas de signification on ne pourrait pas en stocker la valeur

bull et -gt sont de nouveaux opeacuterateurs indeacutependants de et de -gt

3 Les pointeurs sur des membres donneacuteesComme nous lrsquoavons dit cette notion est tregraves rarement utiliseacutee On peut la consideacuterer comme

un cas particulier des pointeurs sur des fonctions membres

Si une classe point comporte deux membres donneacutees x et y de type int la deacuteclaration

int point adm

preacutecisera que adm est un pointeur sur un membre donneacutee de type int de la classe point

Les affectations suivantes seront alors possibles

adm = amppointx adm pointe vers le membre x de la classe pointadf = amppointy adm pointe vers le membre y de la classe point

Si a est un objet de type point lrsquoexpression aadm deacutesignera le membre drsquoadresse contenue

dans adm du point a Ces instructions seront correctes

aadm = 5 le membre drsquoadresse adm du point a reccediloit la valeur 5int n = aadm n reccediloit la valeur du membre du point a drsquoadresse adm

De mecircme si adp est lrsquoadresse drsquoun objet de type point

point adp

lrsquoexpression adp -gtadm deacutesignera le membre drsquoadresse adm pour le point dont lrsquoadresse est

contenue dans adp Ces instructions seront correctes

adp-gtadm = 5 le membre drsquoadresse adm du point drsquoadresse adp reccediloit la valeur 5int n = a-gtadm n reccediloit la valeur du membre drsquoadresse adm du point drsquoadresse adp

Bien entendu les remarques faites agrave propos de lrsquoabus de langage consistant agrave parler drsquoadresse

drsquoun membre restent valables ici Il en va de mecircme pour lrsquoexpression adm qui reste sans

signification

Les pointeurs sur des membresANNEXE F

554

Remarque

Si a est un objet de type point lrsquoaffectation suivante nrsquoa pas de signification et elle est

illeacutegale

adm = ampax incorrecte

On notera que les deux opeacuterandes de lrsquoaffectaion sont de types diffeacuterents pointeur sur

un membre entier de point pour le premier pointeur sur le membre x de lrsquoobjet a pour le

second

4 Lrsquoheacuteritage et les pointeurs sur des membresNous venons de voir comment deacuteclarer et utiliser des pointeurs sur des membres (fonctions

ou donneacutees) Voyons ce que devient cette notion dans le contexte de lheacuteritage Nous nous

limiterons au cas le moins rare celui des pointeurs sur des fonctions membres sa geacuteneacuteralisa-

tion aux pointeurs sur des membres donneacutees est triviale

Consideacuterons ces deux classes

class point class pointcol public point public public void dep_hor (int) void colore (int) void dep_vert (int)

Consideacuterons ces deacuteclarations

void (point adfp) (int) void (pointcol adfpc) (int)

Bien entendu ces affectations sont leacutegales

adfp = pointdep_hor adfp = pointdep_vert adfpc = pointcolcolore

Il en va de mecircme pour

adfpc = pointcoldep_hor adfpc = pointcoldep_vert

puisque les fonctions dep_hor et dep_vert sont eacutegalement des membres de pointcol1

Mais on peut sinterroger sur la compatibiliteacute existant entre adfp et adfpc Autrement dit

lequel peut ecirctre affecteacute agrave lautre

C++ agrave preacutevu la regravegle suivante

1 Pour le compilateur pointdep_hor et pointcoldep_hor sont de types diffeacuterents Cela nempecircche pas ces deux

symboles de deacutesigner la mecircme adresse

4 - Lrsquoheacuteritage et les pointeurs sur des membres555

Il existe une conversion implicite dun pointeur sur une fonction membre dune classe

deacuteriveacutee en un pointeur sur une fonction membre (de mecircme prototype) dune classe de

base

Pour comprendre la pertinence de cette regravegle il suffit de penser que ces pointeurs servent en

deacutefinitive agrave lrsquoappel de la fonction correspondante Le fait drsquoaccepter ici que adfpc reccediloive

une valeur du type pointeur sur une fonction membre de point (de mecircme prototype) implique

quon pourra ecirctre ameneacute agrave appeler une fonction heacuteriteacutee de point pour un objet de type point-

col1 Cela ne pose donc aucun problegraveme En revanche si lon acceptait que adfp reccediloive une

valeur du type pointeur sur une fonction membre de pointcol cela signifierait quon pourrait

ecirctre ameneacute agrave appeler nimporte quelle fonction de pointcol pour un objet de type point Mani-

festement certaines fonctions (celles deacutefinies dans pointcol cest-agrave-dire celles qui ne sont pas

heacuteriteacutees de point) risqueraient de ne pas pouvoir travailler correctement

Remarque

Si on se limite aux apparences (cest-agrave-dire si on ne cherche pas agrave en comprendre les rai-

sons profondes) cette regravegle semble diverger par rapport aux conversions implicites entre

objets ou pointeurs sur des objets ces derniegraveres se font dans le sens deacuteriveacutee ndashgt base

alors que pour les fonctions membres elles ont lieu dans le sens base ndashgt deacuteriveacutee

1 Car bien entendu une affectation telle que adfpc = adfp ne modifie pas le type de adfpc

Annexe G

Les algorithmes standard

Cette annexe fournit le rocircle exact des algorithmes proposeacutes par la bibliothegraveque standard Ils

sont classeacutes suivant les mecircmes cateacutegories que celles du chapitre 21 qui explique le fonction-

nement de la plupart dentre eux La nature des iteacuterateurs reccedilus en argument est preacuteciseacutee en

utilisant les abreacuteviations suivantes

bull IeIteacuterateur dentreacutee

bull IsIteacuterateur de sortie

bull IuIteacuterateur unidirectionnel

bull IbIteacuterateur bidirectionnel

bull IaIteacuterateur agrave accegraves direct

Nous indiquons la complexiteacute de chaque algorithme dans le cas ougrave elle nest pas triviale

Comme le fait la norme nous lexprimons en un nombre preacutecis dopeacuterations (eacuteventuellement

sous forme dun maximum) plutocirct quavec la notation de Landau moins preacutecise Pour alleacuteger

le texte nous avons convenu que lorsquune seule seacutequence est concerneacutee N deacutesigne son

nombre deacuteleacutements lorsque deux seacutequences sont concerneacutees N1 deacutesigne le nombre deacuteleacute-

ments de la premiegravere et N2 celui de la seconde Dans quelques rares cas dautres notations

seront neacutecessaires elles seront alors expliciteacutees dans le texte

Notez que par souci de simpliciteacute lorsquaucune ambiguiumlteacute nexistera nous utiliserons sou-

vent labus de langage qui consiste agrave parler des eacuteleacutements dun intervalle [deacutebut fin) plutocirct que

des eacuteleacutements deacutesigneacutes par cet intervalle Dautre part les preacutedicats ou fonctions de rappel preacute-

vus dans les algorithmes correspondent toujours agrave des objets fonction cela signifie quon

peut recourir agrave des classes fonction preacutedeacutefinies agrave ses propres classes fonction ou agrave des fonc-

tions ordinaires

Les algorithmes standardANNEXE G

558

1 Algorithmes dinitialisation de seacutequences existantes

FILL void fill (Iu deacutebut Iu fin valeur)

Place valeur dans lintervalle [deacutebut fin)

FILL_N void fill_n (Is position NbFois valeur)

Place valeur NbFois conseacutecutives agrave partir de position les emplacements cor-

respondants doivent exister

COPY Is copy (Ie deacutebut Ie fin Is position)

Copie lintervalle [deacutebut fin) agrave partir de position les emplacements corre-

spondants doivent exister la valeur de position (et seulement celle-ci) ne doit

pas appartenir agrave lintervalle [deacutebut fin) si tel est le cas on peut toujours

recourir agrave copy_backward renvoie un iteacuterateur sur la fin de lintervalle ougrave sest

faite la copie

COPY_BACKWARD Ib copy_backward (Ib deacutebut Ib fin Ib position)

Comme copy copie lintervalle [deacutebut fin) en progressant du dernier eacuteleacutement

vers le premier agrave partir de position qui deacutesigne donc lemplacement de la

premiegravere copie mais aussi la fin de lintervalle les emplacements correspon-

dants doivent exister la valeur de position (et seulement celle-ci) ne doit pas

appartenir agrave lintervalle [deacutebut fin) renvoie un iteacuterateur sur le deacutebut de linter-

valle (derniegravere valeur copieacutee) ougrave sest faite la copie cet algorithme est surtout

utile en remplacement de copy lorsque le deacutebut de lintervalle darriveacutee appar-

tient agrave lintervalle de deacutepart

GENERATE void generate (Iu deacutebut Iu fin fct_gen)

Appelle pour chacune des valeurs de lintervalle [deacutebut fin) la fonction

fct_gen et affecte la valeur fournie agrave lemplacement correspondant

GENERATE_N void generate_n (Iu deacutebut NbFois fct_gen)

Mecircme chose que generate mais lintervalle est deacutefini par sa position deacutebut et

son nombre de valeurs NbFois (la fonction fct_gen est bien appeleacutee NfFois)

SWAP_RANGES Iu swap_ranges (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2)

Echange les eacuteleacutements de lintervalle [deacutebut fin) avec lintervalle de mecircme taille

commenccedilant en deacutebut_2 Les deux intervalles ne doivent pas se chevaucher

Complexiteacute N eacutechanges

2 - Algorithmes de recherche559

2 Algorithmes de recherche FIND Ie find (Ie deacutebut Ie fin valeur)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) eacutegal agrave

valeur (au sens de ==) sil existe la valeur fin sinon (attention il ne sagit pas

neacutecessairement de end()) Complexiteacute au maximum N comparaisons deacutegal-

iteacute

FIND_IF Ie find_if (Ie deacutebut Ie fin preacutedicat_u)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) satisfai-

sant au preacutedicat unaire preacutedicat_u speacutecifieacute sil existe la valeur fin sinon

(attention il ne sagit pas neacutecessairement de end()) Complexiteacute au maximum

N appels du preacutedicat

FIND_END Iu find_end (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Fournit un iteacuterateur sur le dernier eacuteleacutement de lintervalle [deacutebut_1 fin_1) tel

que les eacuteleacutements de la seacutequence deacutebutant en deacutebut_1 soit eacutegaux (au sens de ==)

aux eacuteleacutements de lintervalle [deacutebut_2 fin_2) Si un tel eacuteleacutement nexiste pas

fournit la valeur fin_1 (attention il ne sagit pas neacutecessairement de end() Com-

plexiteacute au maximum (N1- N2 + 1) N2 comparaisons

Iu find_end (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la com-

paraison deacutegaliteacute est remplaceacutee par lapplication du preacutedicat binaire

preacutedicat_b Complexiteacute au maximum (N1- N2 + 1) N2 appels du preacutedicat

FIND_FIRST_OF

Iu find_first_of (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Recherche dans lintervalle [deacutebut_1 fin_1) le premier eacuteleacutement eacutegal (au sens

de ==) agrave lun des eacuteleacutements de lintervalle [deacutebut_2 fin_2) Fournit un iteacuterateur

sur cet eacuteleacutement sil existe la valeur de fin_1 dans le cas contraire

Complexiteacute au maximum N1 N2 comparaisons

Iu find_first_of (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Recherche dans lintervalle [deacutebut_1 fin_1) le premier eacuteleacutement satisfaisant

avec lun des eacuteleacutements de lintervalle [deacutebut_2 fin_2) au preacutedicat binaire

preacutedicat_b Fournit un iteacuterateur sur cet eacuteleacutement sil existe la valeur de fin_1

dans le cas contraire Complexiteacute au maximum N1 N2 appels du preacutedicat

Les algorithmes standardANNEXE G

560

ADJACENT_FIND

Iu adjacent_find (Iu deacutebut Iu fin)

Recherche dans lintervalle [deacutebut fin) la premiegravere occurrence de deux eacuteleacute-

ments successifs eacutegaux (==) fournit un iteacuterateur sur le premier des deux eacuteleacute-

ments eacutegaux sils existent la valeur fin sinon

Iu adjacent_find (Iu deacutebut Iu fin preacutedicat_b)

Recherche dans lintervalle [deacutebut fin) la premiegravere occurrence de deux eacuteleacute-

ments successifs satisfaisant au preacutedicat binaire preacutedicat_b fournit un iteacutera-

teur sur le premier des deux eacuteleacutements sils existent la valeur fin sinon

SEARCH Iu search (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2)

Recherche dans lintervalle [deacutebut_1 fin_1) la premiegravere occurrence dune

seacutequence deacuteleacutements identique (==) agrave celle de lintervalle [deacutebut_2 fin_2)

Fournit un iteacuterateur sur le premier eacuteleacutement si cette occurrence si elle existe la

fin fin_1 sinon Complexiteacute au maximum N1 N2 comparaisons

Iu search (Iu deacutebut_1 Iu fin_1 Iu deacutebut_2 Iu fin_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de search avec cette diffeacuterence que

la comparaison de deux eacuteleacutements de chacune des deux seacutequences se fait par le

preacutedicat binaire preacutedicat_b au lieu de se faire par eacutegaliteacute Complexiteacute au

maximum N1 N2 appels du preacutedicat

SEARCH_N Iu search_n (Iudeacutebut Iu fin NbFois valeur)

Recherche dans lintervalle [deacutebut fin) une seacutequence de NbFois eacuteleacutements

eacutegaux (au sens de ==) agrave valeur Fournit un iteacuterateur sur le premier eacuteleacutement si

une telle seacutequence existe la valeur fin sinon Complexiteacute au maximum N

comparaisons

Iu search_n (Iudeacutebut Iu fin NbFois valeur preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la com-

paraison entre un eacuteleacutement et valeur se fait par le preacutedicat binaire preacutedicat_b au

lieu de se faire par eacutegaliteacute Complexiteacute au maximum N applications du preacutedi-

cat

3 - Algorithmes de transformation dune seacutequence561

MAX_ELEMENT

Iu max_element (Iu deacutebut Iu fin)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) qui ne soit

infeacuterieur (lt) agrave aucun des autres eacuteleacutements de lintervalle Complexiteacute exacte-

ment N-1 comparaisons

Iu max_element (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de max_element mais en utilisant le

preacutedicat binaire preacutedicat_b en lieu et place de lopeacuterateur lt Complexiteacute

exactement N-1 appels du preacutedicat

MIN_ELEMENT

Iu min_element (Iu deacutebut Iu fin)

Fournit un iteacuterateur sur le premier eacuteleacutement de lintervalle [deacutebut fin) tel

quaucun des autres eacuteleacutements de lintervalle ne lui soit infeacuterieur (lt)

Complexiteacute exactement N-1 comparaisons

Iu min_element (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente de min_element mais en utilisant le

preacutedicat binaire preacutedicat_b en lieu et place de lopeacuterateur lt Complexiteacute

exactement N-1 appels du preacutedicat

3 Algorithmes de transformation dune seacutequence

REVERSE void reverse (Ib deacutebut Ib fin)

Inverse le contenu de lintervalle [deacutebut fin) Complexiteacute exactement N2

eacutechanges

REVERSE_COPY Is reverse_copy (Ib deacutebut Ib fin Is position)

Copie lintervalle [deacutebut fin) dans lordre inverse agrave partir de position les

emplacements correspondants doivent exister attention ici position deacutesigne

donc lemplacement de la premiegravere copie et aussi le deacutebut de lintervalle ren-

voie un iteacuterateur sur la fin de lintervalle ougrave sest faite la copie Les deux inter-

valles ne doivent pas se chevaucher Complexiteacute exactement N affectations

Les algorithmes standardANNEXE G

562

REPLACE void replace (Iu deacutebut Iu fin anc_valeur nouv_valeur)

Remplace dans lintervalle [deacutebut fin) tous les eacuteleacutements eacutegaux (==) agrave

anc_valeur par nouv_valeur Complexiteacute exactement N comparaisons

REPLACE_IF void replace_if (Iu deacutebut Iu fin preacutedicat_u nouv_valeur)

Remplace dans lintervalle [deacutebut fin) tous les eacuteleacutements satisfaisant au preacutedi-

cat unaire preacutedicat_u par nouv_valeur Complexiteacute exactement N applica-

tions du preacutedicat

REPLACE_COPY

Is replace_copy (Ie deacutebut Ie fin Is position anc_valeur nouv_valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position en remplaccedilant tous les eacuteleacute-

ments eacutegaux (==) agrave anc_valeur par nouv_valeur les emplacements correspon-

dants doivent exister Fournit un iteacuterateur sur la fin de lintervalle ougrave sest faite

la copie Les deux intervalles ne doivent pas se chevaucher Complexiteacute

exactement N comparaisons

REPLACE_COPY_IF

Is replace_copy_if (Ie deacutebut Ie fin Is position preacutedicat_u nouv_valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position en remplaccedilant tous les eacuteleacute-

ments satisfaisant au preacutedicat unaire preacutedicat_u par nouv_valeur les emplace-

ments correspondants doivent exister Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Les deux intervalles ne doivent pas se chev-

aucher Complexiteacute exactement N applications du preacutedicat

ROTATE void rotate (Iu deacutebut Iu milieu Iu fin)

Effectue une permutation circulaire (vers la gauche) des eacuteleacutements de linter-

valle [deacutebut fin) dont lampleur est telle que apregraves permutation leacuteleacutement

deacutesigneacute par milieu soit venu en deacutebut Complexiteacute au maximum N eacutechanges

ROTATE_COPY Is rotate_copy (Iu deacutebut Iu milieu Iu fin Is position)

Recopie agrave partir de position les eacuteleacutements de lintervalle [deacutebut fin) affecteacutes

dune permutation circulaire deacutefinie de la mecircme faccedilon que pour rotate les

emplacements correspondants doivent exister Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Complexiteacute au maximum N affectations

3 - Algorithmes de transformation dune seacutequence563

PARTITION Ib partition (Ib deacutebut Ib fin Preacutedicat_u)

Effectue une partition de lintervalle [deacutebut fin) en se fondant sur le preacutedicat

unaire preacutedicat_u il sagit dune reacuteorganisation telle que tous les eacuteleacutements sat-

isfaisant au preacutedicat arrivent avant tous les autres Fournit un iteacuterateur it tel que

les eacuteleacutements de lintervalle [deacutebut it) satisfont au preacutedicat tandis que les eacuteleacute-

ments de lintervalle [it fin) ny satisfont pas Complexiteacute au maximum N2

eacutechanges et exactement N appels du preacutedicat

STABLE_PARTITION Ib stable_partition (Ib deacutebut Ib fin Preacutedicat_u)

Fonctionne comme partition avec cette diffeacuterence que les positions relatives

des diffeacuterents eacuteleacutements agrave linteacuterieur de chacune des deux parties soient

preacuteserveacutees Complexiteacute exactement N appels du preacutedicat et au maximum

N Log N eacutechanges (et mecircme k N si lon dispose de suffisamment de meacutemoire)

NEXT_PERMUTATION

bool next_permutation (Ib deacutebut Ib fin)

Cet algorithme reacutealise ce que lon nomme la permutation suivante des eacuteleacute-

ments de lintervalle [deacutebut fin) Il suppose que lensemble des permutations

possibles est ordonneacute agrave partir de lopeacuterateur lt dune maniegravere lexicographique

On considegravere que la permutation suivant la derniegravere possible nest rien dautre

que la premiegravere Fournit la valeur true sil existait bien une permutation suiva-

nte et la valeur false dans le cas ougrave lon est revenu agrave la premiegravere permutation

possible Complexiteacute au maximum N2 eacutechanges

bool next_permutation (Ib deacutebut Ib fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette seule diffeacuterence que

lensemble des permutations possibles et ordonneacute agrave partir du preacutedicat binaire

preacutedicat_b Complexiteacute au maximum N2 eacutechanges

PREV_PERMUTATION

bool prev_permutation (Ib deacutebut Ib fin)

bool prev_permutation (Ib deacutebut Ib fin preacutedicat_b)

Ces deux algorithmes fonctionnent comme next_permutation en inversant

simplement lordre des permutations possibles

Les algorithmes standardANNEXE G

564

RANDOM_SHUFFLE

void random_shuffle (Ia deacutebut Ia fin)

Reacutepartit au hasard les eacuteleacutements de lintervalle [deacutebut fin) Complexiteacute exact-

ement N-1 eacutechanges

void random_shuffle (Ia deacutebut Ia fin geacuteneacuterateur)

Mecircme chose que random_shuffle mais en utilisant la fonction geacuteneacuterateur pour

geacuteneacuterer des nombres au hasard Cette fonction doit fournir une valeur apparte-

nant agrave lintervalle [0 n) n eacutetant une valeur fournie en argument Complexiteacute

exactement N-1 eacutechanges

TRANSFORM

Is transform (Ie deacutebut Ie fin Is position opeacuteration_u)

Place agrave partir de position (les eacuteleacutements correspondants doivent exister) les

valeurs obtenues en appliquant la fonction unaire (agrave un argument) opeacuteration_u

agrave chacune des valeurs de lintervalle [deacutebut fin) Fournit un iteacuterateur sur la fin

de lintervalle ainsi rempli

Is transform (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Is position opeacuteration_b)

Place agrave partir de position (les eacuteleacutements correspondants doivent exister) les

valeurs obtenues en appliquant la fonction binaire (agrave deux arguments)

opeacuteration_b agrave chacune des valeurs de mecircme rang de lintervalle [deacutebut_1

fin_1) et de lintervalle de mecircme taille commenccedilant en deacutebut_2 Fournit un

iteacuterateur sur la fin de lintervalle ainsi rempli

4 Algorithmes de suppression REMOVE Iu remove (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur it tel que lintervalle [deacutebut it) contienne toutes les valeurs

initialement preacutesentes dans lintervalle [deacutebut fin) deacutebarrasseacutees de celles qui

sont eacutegales (==) agrave valeur Attention aucun eacuteleacutement nest deacutetruit tout au plus

peut-il avoir changeacute de valeur Lalgorithme est stable crsquoest-agrave-dire que les

valeurs non eacutelimineacutees conservent leur ordre relatif Complexiteacute exactement N

comparaisons

4 - Algorithmes de suppression565

REMOVE_IF Iu remove_if (Iu deacutebut Iu fin preacutedicat_u)

Fonctionne comme remove avec cette diffeacuterence que la condition deacutelimina-

tion est fournie sous forme dun preacutedicat unaire preacutedicat_u Complexiteacute

exactement N appels du preacutedicat

REMOVE_COPY Is remove_copy (Ie deacutebut Ie fin Is position valeur)

Recopie lintervalle [deacutebut fin) agrave partir de position (les eacuteleacutements correspon-

dants doivent exister) en supprimant les eacuteleacutements eacutegaux (==) agrave valeur Fournit

un iteacuterateur sur la fin de lintervalle ougrave sest faite la copie Les deux intervalles

ne doivent pas se chevaucher Comme remove lalgorithme est stable Com-

plexiteacute exactement N comparaisons

REMOVE_COPY_IF Is remove_if (Ie deacutebut Ie fin Is position preacutedicat_u)

Fonctionne comme remove_copy avec cette diffeacuterence que la condition deacutelim-

ination est fournie sous forme dun preacutedicat unaire preacutedicat_u Complexiteacute

exactement N appels du preacutedicat

UNIQUE Iu unique (Iu deacutebut Iu fin)

Fournit un iteacuterateur it tel que lintervalle [deacutebut it) corresponde agrave lintervalle

[deacutebut fin) dans lequel les seacutequences de plusieurs valeurs conseacutecutives eacutegales

(==) sont remplaceacutees par la premiegravere Attention aucun eacuteleacutement nest deacutetruit

tout au plus peut-il avoir changeacute de place et de valeur Complexiteacute exacte-

ment N comparaisons

Iu unique (Iu deacutebut Iu fin preacutedicat_b)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que la condi-

tion de reacutepeacutetition est fournie sous forme dun preacutedicat binaire preacutedicat_b

Complexiteacute exactement N appels du preacutedicat

UNIQUE_COPY

Is unique_copy (Ie deacutebut Ie fin Is position)

Recopie lintervalle [deacutebut fin) agrave partir de position (les eacuteleacutements correspon-

dants doivent exister) en ne conservant que la premiegravere valeur des seacutequences

de plusieurs valeurs conseacutecutives eacutegales (==) Fournit un iteacuterateur sur la fin de

lintervalle ougrave sest faite la copie Les deux intervalles ne doivent pas se chev-

aucher Complexiteacute exactement N comparaisons

Les algorithmes standardANNEXE G

566

Is unique_copy (Ie deacutebut Ie fin Is position preacutedicat_b)

Fonctionne comme unique_copy avec cette diffeacuterence que la condition de

reacutepeacutetition de deux valeurs est fournie sous forme dun preacutedicat binaire

preacutedicat_u On notera que la deacutecision deacutelimination dune valeur se fait tou-

jours par comparaison avec la preacuteceacutedente et non avec la premiegravere dune

seacutequence cette remarque na en fait dimportance quau cas ougrave le preacutedicat

fourni ne serait pas transitif Complexiteacute exactement N appels du preacutedicat

5 Algorithmes de tri SORT void sort (Ia deacutebut Ia fin)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se fondant sur lopeacuterateur lt

Lalgorithme nest pas stable crsquoest-agrave-dire que lordre relatif des eacuteleacutements

eacutequivalents (au sens de lt) nest pas neacutecessairement respecteacute Complexiteacute en

moyenne N Log N comparaisons

void sort (Ia deacutebut Ia fin fct_comp)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se fondant sur le preacutedicat

binaire fct_comp Complexiteacute en moyenne N Log N appels du preacutedicat

STABLE_SORT

void stable_sort (Ia deacutebut Ia fin)

Trie les eacuteleacutements de lintervalle [deacutebut fin) en se basant sur lopeacuterateur lt

Contrairement agrave sort cet algorithme est stable Complexiteacute au maximum

N (Log N)2 comparaisons si limpleacutementation dispose dassez de meacutemoire on

peut descendre agrave N Log N comparaisons

void stable_sort (Ia deacutebut Ia fin fct_comp)

Mecircme chose que stable_sort en se basant sur le preacutedicat binaire fct_comp qui

doit correspondre agrave une relation dordre faible strict Complexiteacute au maximum

N (Log N)2 applications du preacutedicat si limpleacutementation dispose dassez de

meacutemoire on peut descendre agrave N Log N appels

PARTIAL_SORT

void partial_sort (Ia deacutebut Ia milieu Ia fin)

Reacutealise un tri partiel des eacuteleacutements de lintervalle [deacutebut fin) en se basant sur

lopeacuterateur lt et en placcedilant les premiers eacuteleacutements convenablement trieacutes dans

5 - Algorithmes de tri567

lintervalle [deacutebut milieu) (cest la taille de cet intervalle qui deacutefinit lampleur

du tri) Les eacuteleacutements de lintervalle [milieu fin) sont placeacutes dans un ordre

quelconque Aucune contrainte de stabiliteacute nest imposeacutee Complexiteacute envi-

ron N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

void partial_sort (Ia deacutebut Ia milieu Ia fin fct_comp)

Fonctionne comme partial_sort avec cette diffeacuterence quau lieu de se fonder

sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire fct_comp qui

doit correspondre agrave une relation dordre faible strict Complexiteacute environ

N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

PARTIAL_SORT_COPY

Ia partial_sort_copy (Ie deacutebut Ie fin Ia pos_deacutebut Ia pos_fin)

Place dans lintervalle [pos_deacutebut pos_fin) le reacutesultat du tri partiel ou total des

eacuteleacutements de lintervalle [deacutebut fin) Si lintervalle de destination comporte plus

deacuteleacutements que lintervalle de deacutepart ses derniers eacuteleacutements ne seront pas util-

iseacutes Fournit un iteacuterateur sur la fin de lintervalle de destination (pos_fin lor-

sque ce dernier est de taille infeacuterieure ou eacutegale agrave lintervalle dorigine) Les

deux intervalles ne doivent pas se chevaucher Complexiteacute environ N Log N

comparaisons N eacutetant le nombre deacuteleacutements effectivement trieacutes

Ia partial_sort_copy (Ie deacutebut Ie fin Ia pos_deacutebut Ia pos_fin fct_comp)

Fonctionne comme partial_sort_copy avec cette diffeacuterence quau lieu de se

fonder sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire

fct_comp qui doit correspondre agrave une relation dordre faible strict Complexiteacute

environ N Log N comparaisons N eacutetant le nombre deacuteleacutements trieacutes

NTH_ELEMENT

void nth_element (Ia deacutebut Ia position Ia fin)

Place dans lemplacement deacutesigneacute par position ndash qui doit donc appartenir agrave

lintervalle [deacutebut fin) ndash leacuteleacutement de lintervalle [deacutebut fin) qui se trouverait

lagrave agrave la suite dun tri Les autres eacuteleacutements de lintervalle peuvent changer de

place Complexiteacute en moyenne N comparaisons

void nth_element (Ia deacutebut Ia position Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence quau lieu de se

fonder sur lopeacuterateur lt cet algorithme se fonde sur le preacutedicat binaire

fct_comp qui doit correspondre agrave une relation dordre faible strict Complexiteacute

en moyenne N applications du preacutedicat

Les algorithmes standardANNEXE G

568

6 Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees

NB Tous ces algorithmes peuvent fonctionner avec de simples iteacuterateurs unidirectionnels

Mais lorsque lon dispose diteacuterateurs agrave accegraves direct on peut augmenter leacutegegraverement les per-

formances dans la mesure ougrave certaines seacuteries de p increacutementations de la forme it++ peuvent

ecirctre remplaceacutees par une seule it+=p plus preacuteciseacutement on passe de O(N) agrave O(Log N) increacute-

mentations

LOWER_BOUND

Iu lower_bound (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur sur la premiegravere position ougrave valeur peut ecirctre inseacutereacutee

compte tenu de lordre induit par lopeacuterateur lt Complexiteacute au maximum

Log N+1 comparaisons

Iu lower_bound (Iu deacutebut Iu fin valeur fct_comp)

Fournit un iteacuterateur sur la premiegravere position ougrave valeur peut ecirctre inseacutereacutee

compte tenu de lordre induit par le preacutedicat binaire fct_comp Complexiteacute au

maximum Log N+1 comparaisons

UPPER_BOUND

Iu upper_bound (Iu deacutebut Iu fin valeur)

Fournit un iteacuterateur sur la derniegravere position ougrave valeur peut ecirctre inseacutereacutee compte

tenu de lordre induit par lopeacuterateur lt Complexiteacute au maximum Log N+1

comparaisons

Iu upper_bound (Iu deacutebut Iu fin valeur fct_comp)

Fournit un iteacuterateur sur la derniegravere position ougrave valeur peut ecirctre inseacutereacutee compte

tenu de lordre induit par le preacutedicat binaire fct_comp Complexiteacute au maxi-

mum Log N+1 comparaisons

EQUAL_RANGE

pair ltIu Iugt equal_range (Iu deacutebut Iu fin valeur)

Fournit le plus grand intervalle [it1 it2) tel que valeur puisse ecirctre inseacutereacutee en

nimporte quel point de cet intervalle compte tenu de lordre induit par lopeacutera-

teur lt Complexiteacute au maximum 2 Log N+1 comparaisons

6 - Algorithmes de recherche et de fusions sur des seacutequences ordonneacutees569

pair ltIu Iugt equal_range (Iu deacutebut Iu fin valeur fct_comp)

Fonctionne comme la version preacuteceacutedente en se basant sur lordre induit par le

preacutedicat binaire fct_comp au lieu de lopeacuterateur lt

BINARY_SEARCH

bool binary_search (Iu deacutebut Iu fin valeur)

Fournit la valeur true sil existe dans lintervalle [deacutebut fin) un eacuteleacutement eacutequiv-

alent agrave valeur et la valeur false dans le cas contraire Complexiteacute au plus Log

N+2 comparaisons

bool binary_search (Iu deacutebut Iu fin valeur fct_comp)

Fournit la valeur true sil existe dans lintervalle [deacutebut fin) un eacuteleacutement eacutequiv-

alent agrave valeur (au sens de la relation induite par le preacutedicat fct_comp) et la

valeur false dans le cas contraire Complexiteacute au plus Log N+2 appels du

preacutedicat

MERGE Is merge (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Fusionne les deux intervalles [deacutebut_1 fin_1) et [deacutebut_2 fin_2) agrave partir de

position (les eacuteleacutements correspondants doivent exister) en se fondant sur lordre

induit par lopeacuterateur lt Lalgorithme est stable lordre relatif deacuteleacutements

eacutequivalents dans lun des intervalles dorigine est respecteacute dans lintervalle

darriveacutee si des eacuteleacutements eacutequivalents apparaissent dans les intervalles agrave

fusionner ceux du premier intervalle apparaissent toujours avant ceux du sec-

ond Lintervalle darriveacutee ne doit pas se chevaucher avec les intervalles dorig-

ine (en revanche rien ninterdit que les deux intervalles dorigine se

chevauchent) Complexiteacute au plus N1+N2-1 comparaisons

Is merge (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que lon se base

sur lordre induit par le preacutedicat binaire fct_comp Complexiteacute au plus

N1+N2-1 appels du preacutedicat

INPLACE_MERGE

void inplace_merge (Ib deacutebut Ib milieu Ib fin)

Fusionne les deux intervalles [deacutebut milieu) et [milieu fin) dans lintervalle

[deacutebut fin) en se basant sur lordre induit par lopeacuterateur lt Complexiteacute N-1

comparaisons si lon dispose de suffisamment de meacutemoire N Log N comparai-

sons sinon

Les algorithmes standardANNEXE G

570

void inplace_merge (Ib deacutebut Ib milieu Ib fin fct_comp)

Fonctionne comme la version preacuteceacutedente avec cette diffeacuterence que lon se base

sur lordre induit par le preacutedicat binaire fct_comp Complexiteacute N-1 appels du

preacutedicat si lon dispose de suffisamment de meacutemoire N Log N appels sinon

7 Algorithmes agrave caractegravere numeacuterique ACCUMULATE

valeur accumulate (Ie debut Ie fin val_init)

Fournit la valeur obtenue en ajoutant (opeacuterateur +) agrave la valeur initiale val_init

la valeur de chacun des eacuteleacutements de lintervalle [deacutebut fin)

valeur accumulate (Ie debut Ie fin val_initiale fct_cumul)

Fonctionne comme la version preacuteceacutedente en la geacuteneacuteralisant lopeacuteration appli-

queacutee neacutetant plus deacutefinie par lopeacuterateur + mais par la fonction fct_cumul rece-

vant deux arguments du type des eacuteleacutements concerneacutes et fournissant un reacutesultat

de ce mecircme type (la valeur accumuleacutee courante est fournie en premier argu-

ment celle de leacuteleacutement courant en second)

INNER_PRODUCT

valeur inner_product (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 val_init)

Fournit le produit scalaire de la seacutequence des valeurs de lintervalle [deacutebut_1

fin_2) et de la seacutequence de valeurs de mecircme longueur deacutebutant en deacutebut_2

augmenteacute de la valeur initiale val_init

valeur inner_product (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 val_init

fct_cumul fct_prod)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de cumul

(+) par lappel de la fonction fct_cumul (la valeur cumuleacutee est fournie en pre-

mier argument) et lopeacuteration de produit par lappel de la fonction fct_prod (la

valeur courante du premier intervalle eacutetant fournie en premier argument)

PARTIAL_SUM

Is partial_sum (Ie deacutebut Ie fin Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) un

intervalle de mecircme taille que lintervalle [deacutebut fin) contenant les sommes

partielles du premier intervalle le premier eacuteleacutement correspond agrave la premiegravere

8 - Algorithmes agrave caractegravere ensembliste571

valeur de [deacutebut fin) le second eacuteleacutement agrave la somme des deux premiegraveres

valeurs et ainsi de suite Fournit un iteacuterateur sur la fin de lintervalle creacuteeacute

Is partial_sum (Ie deacutebut Ie fin Is position fct_cumul)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de som-

mation (+) par lappel de la fonction fct_cumul (la valeur cumuleacutee est fournie

en premier argument)

ADJACENT_DIFFERENCE

Is adjacent_difference (Ie deacutebut Ie fin Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) un

intervalle de mecircme taille que lintervalle [deacutebut fin) contenant les diffeacuterences

entre deux eacuteleacutements conseacutecutifs de ce premier intervalle leacuteleacutement de rang i

hormis le premier sobtient en faisant la diffeacuterence (opeacuterateur -) entre leacuteleacutement

de rang i et celui de rang i-1 Le premier eacuteleacutement reste inchangeacute Fournit un

iteacuterateur sur la fin de lintervalle creacuteeacute

Is adjacent_difference (Ie deacutebut Ie fin Is position fct_diff)

Fonctionne comme la version preacuteceacutedente en remplaccedilant lopeacuteration de dif-

feacuterence (-) par lappel de la fonction fct_diff

8 Algorithmes agrave caractegravere ensembliste INCLUDES bool includes (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2)

Fournit la valeur true si agrave toute valeur appartenant agrave lintervalle [deacutebut_1

fin_1) correspond une valeur eacutegale (==) dans lintervalle [deacutebut_2 fin_2)

avec la mecircme pluraliteacute autrement dit (si une valeur figure n fois dans le pre-

mier intervalle elle devra figurer au moins n fois dans le second intervalle)

Complexiteacute au maximum 2 N1N2-1 comparaisons

bool includes (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Complexiteacute au maximum

2 N1N2-1 appels du preacutedicat

Les algorithmes standardANNEXE G

572

SET_UNION

Is set_union (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant au moins agrave lun des deux intervalles

[deacutebut_1 fin_1) [deacutebut_2 fin_2) avec la pluraliteacute maximale si un eacuteleacutement

apparaicirct n fois dans le premier intervalle et n fois dans le second il apparaicirctra

max(n n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme

relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes

deacutequivalence de R Les deux intervalles ne doivent pas se chevaucher Fournit

un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-

1 comparaisons

Is set_union (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

SET_INTERSECTION

Is set_intersection (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant simultaneacutement aux deux intervalles

[deacutebut_1 fin_1) [deacutebut_2 fin_2) avec la pluraliteacute minimale si un eacuteleacutement

apparaicirct n fois dans le premier intervalle et n fois dans le second il apparaicirctra

min(n n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme

relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes

deacutequivalence de R Les deux intervalles ne doivent pas se chevaucher Fournit

un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-

1 comparaisons

Is set_intersection (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

8 - Algorithmes agrave caractegravere ensembliste573

SET_DIFFERENCE

Is set_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant agrave lintervalle [deacutebut_1 fin_1) sans

appartenir agrave lintervalle [deacutebut_2 fin_2) on tient compte de la pluraliteacute si un

eacuteleacutement apparaicirct n fois dans le premier intervalle et n fois dans le second il

apparaicirctra max(0 n-n) fois dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes sui-

vant la mecircme relation R et leacutegaliteacute de deux eacuteleacutements (==) devra correspondre

aux classes deacutequivalence de R Les deux intervalles ne doivent pas se chev-

aucher Fournit un iteacuterateur sur la fin de lintervalle creacuteeacute Complexiteacute au max-

imum 2N1N2-1 comparaisons

Is set_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is position

fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

SET_SYMMETRIC_DIFFERENCE

Is set_symetric_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is

position)

Creacutee agrave partir de position (les eacuteleacutements correspondants doivent exister) une

seacutequence formeacutee des eacuteleacutements appartenant agrave lintervalle [deacutebut_1 fin_1) sans

appartenir agrave lintervalle [deacutebut_2 fin_2) ou appartenant au second sans

appartenir au premir on tient compte de la pluraliteacute si un eacuteleacutement apparaicirct n

fois dans le premier intervalle et n fois dans le second il apparaicirctra |n-n| fois

dans le reacutesultat Les eacuteleacutements doivent ecirctre trieacutes suivant la mecircme relation R et

leacutegaliteacute de deux eacuteleacutements (==) devra correspondre aux classes deacutequivalence

de R Les deux intervalles ne doivent pas se chevaucher Fournit un iteacuterateur

sur la fin de lintervalle creacuteeacute Complexiteacute au maximum 2N1N2-1 comparai-

sons

Is set_symetric_difference (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 Ie fin_2 Is

position fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour deacutecider de leacutegaliteacute de deux valeurs Lagrave encore ce dernier doit

correspondre aux classes deacutequivalence de la relation ayant servi agrave ordonner les

deux intervalles Complexiteacute au maximum 2N1N2-1 appels du preacutedicat

Les algorithmes standardANNEXE G

574

9 Algorithmes de manipulation de tasMAKE_HEAP

void make_heap (Ia deacutebut Ia fin)

Transforme lrsquointervalle [deacutebut fin) en un tas en se fondant sur lrsquoopeacuterateur lt

Complexiteacute au maximum 3N comparaisons

void make_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum 3N comparaisons

PUSH_HEAP

void push_heap (Ia deacutebut Ia fin)

La seacutequence [debut fin-1) doit ecirctre initialement un tas valide En se fondant

sur lrsquoopeacuterateur lt lrsquoalgorithme ajoute lrsquoeacuteleacutement deacutesigneacute par fin-1 de faccedilon que

[debut fin) soit un tas Complexiteacute au maximum Log N comparaisons

void push_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum Log N comparai-

sons

SORT_HEAP

void sort_heap (Ia deacutebut Ia fin)

Transforme le tas deacutefini par lrsquointervalle [debut fin) en une seacutequence ordonneacutee

par valeurs croissantes Lrsquoalgorithme nrsquoest pas stable crsquoest-agrave-dire que lrsquoordre

relatif des eacuteleacutements eacutequivalents (au sens de lt) nrsquoest pas neacutecessairement

respecteacute Complexiteacute au maximum N Log N comparaisons

void sort_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner les valeurs Complexiteacute au maximum N Log N com-

paraisons

10 - Algorithmes divers575

POP_HEAP

void pop_heap (Ia deacutebut Ia fin)

La seacutequence [debut fin) doit ecirctre initialement un tas valide Lrsquoalgorithme

eacutechange les eacuteleacutements deacutesigneacutes par debut et fin-1 et en se fondant sur lrsquoopeacutera-

teur lt fait en sorte que [debut fin-1) soit un tas Complexiteacute au maximum 2

Log N comparaisons

void pop_heap (Ia deacutebut Ia fin fct_comp)

Fonctionne comme la version preacuteceacutedente mais en utilisant le preacutedicat binaire

fct_comp pour ordonner le tas Complexiteacute au maximum 2 Log N comparai-

sons

10 Algorithmes divers COUNT nombre count (Ie deacutebut Ie fin valeur)

Fournit le nombre de valeurs de lintervalle [deacutebut fin) eacutegales agrave valeur (au sens

de ==)

COUNT_IF nombre count_if (Ie deacutebut Ie fin preacutedicat_u)

Fournit le nombre de valeurs de lintervalle [deacutebut fin) satisfaisant au preacutedicat

unaire preacutedicat_u

FOR_EACH fct for_each (Ie deacutebut Ie fin fct)

Applique la fonction fct agrave chacun des eacuteleacutements de lintervalle [deacutebut fin)

fournit fct en reacutesultat

EQUAL bool equal (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2)

Fournit la valeur true si tous les eacuteleacutements de lintervalle [deacutebut_1 fin_2) sont

eacutegaux (au sens de ==) aux eacuteleacutements correspondants de lintervalle de mecircme

taille commenccedilant en deacutebut_2

bool equal (Ie deacutebut_1 Ie fin_1 Ie deacutebut_2 preacutedicat_b)

Fonctionne comme la version preacuteceacutedente en utilisant le preacutedicat binaire

preacutedicat_b agrave la place de lopeacuterateur ==

ITER_SWAP void iter_swap (Iu pos1 Iu pos2)

Echange les valeurs des eacuteleacutements deacutesigneacutes par les deux iteacuterateurs pos1 et pos2

Les algorithmes standardANNEXE G

576

LEXICOGRAPHICAL_COMPARE

bool lexicographical_compare (Ie deacutebut_1 Ie fin-1 Ie deacutebut_2 Ie fin_2)

Effectue une comparaison lexicographique (analogue agrave la comparaison de

deux mots dans un dictionnaire) entre les deux seacutequences [deacutebut_1 fin_1) et

[deacutebut_2 fin_2) en se basant sur lrsquoopeacuterateur lt Fournit la valeur true si la

premiegravere seacutequence apparaicirct avant la seconde Complexiteacute au plus N1N2

comparaisons

bool lexicographical_compare (Ie deacutebut_1 Ie fin-1 Ie deacutebut_2 Ie fin_2

preacutedicat_b)

Fonctionne comme la version preacuteceacutedente en utilisant le preacutedicat binaire

preacutedicat_b agrave la place de lopeacuterateur lt Complexiteacute au plus N1N2 comparai-

sons

MAX valeur max (valeur_1 valeur_2)

Fournit la plus grande des deux valeurs valeur_1 et valeur_2 (qui doivent ecirctre

drsquoun mecircme type) en se fondant sur lrsquoopeacuterateur lt

MIN valeur min (valeur_1 valeur_2)

Fournit la plus petite des deux valeurs valeur_1 et valeur_2 (qui doivent ecirctre

drsquoun mecircme type) en se fondant sur lrsquoopeacuterateur lt

Correction des exercices

Voici la correction des exercices dont leacutenonceacute est preacuteceacutedeacute de lindication (C) Bien entendu

les programmes proposeacutes doivent ecirctre consideacutereacutes comme une solution parmi dautres

Chapitre 5

Exercice 52

include ltiostreamgtusing namespace std deacuteclaration de la classe vecteur class vecteur double x y z public void initialise (double double double) void homothetie (double) void affiche () deacutefinition des fonctions membres de la classe vecteur void vecteurinitialise (double a double b double c) x = a y = b z = c

void vecteurhomothetie (double coeff) x = x coeff y = y coeff z = z coeff void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

Correction des exercices578

programme de test de la classe vecteur main() vecteur v1 v2 v1initialise (10 25 58) v1affiche () v2initialise (125 38 00) v2affiche () v1homothetie (35) v1affiche () v2 = v1 v2affiche ()

Exercice 53

include ltiostreamgtusing namespace std deacuteclaration de la classe vecteur class vecteur double x y z public vecteur (double double double) constructeur void homothetie (double) void affiche () deacutefinition des fonctions membres de la classe vecteur vecteurvecteur (double a double b double c) attention pas de void x = a y = b z = c void vecteurhomothetie (double coeff) x = x coeff y = y coeff z = z coeff void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n programme de test de la classe vecteur main() vecteur v1(10 25 58) vecteur v1 serait ici invalide vecteur v2(125 38 00) v1affiche () v2affiche () v1homothetie (35) v1affiche () v2 = v1 v2affiche ()

Chapitre 6579

Chapitre 6

Exercice 61

a) Avec des fonctions membres indeacutependantes

include ltiostreamgt

using namespace std

deacuteclaration de la classe vecteur

class vecteur

double x y z

public

vecteur () constructeur 1

vecteur (double double double) constructeur 2

void affiche ()

deacutefinition des fonctions membres de la classe vecteur

vecteurvecteur ()

x=0 y=0 z=0

vecteurvecteur (double a double b double c)

x = a y = b z = c

void vecteuraffiche ()

cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt 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

reacutesultat de type vecteur

vecteur v2(125 38 00)

ces deacuteclarations seraient ici invalides

vecteur v3 (5) vecteur v4 (25 4)

v1affiche ()

v2affiche ()

Correction des exercices580

b) Avec des fonctions membres en ligne

include ltiostreamgtusing namespace std deacuteclaration 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 ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

programme de test de la classe vecteur main() vecteur v1 v2(345) v1affiche () v2affiche ()

Exercice 62

include ltiostreamgtusing namespace std deacuteclaration 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)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c

Chapitre 6581

void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur v) return (x vx + y vy + z vz) main() programme de test de la classe vecteur vecteur v1 (123) vecteur v2 (543) v1affiche () v2affiche () int ps ps = v1prod_scal (v2) cout ltlt V1V2 = ltlt ps ltlt n ps = v2prod_scal (v1) cout ltlt V2V1 = ltlt ps ltlt n cout ltlt V1V1 = ltlt v1prod_scal (v1) ltlt n cout ltlt V2V2 = ltlt v2prod_scal (v2) ltlt n

Exercice 63

include ltiostreamgtusing namespace std

deacuteclaration 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)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur v) return (x vx + y vy + z vz)

Correction des exercices582

vecteur vecteursomme (vecteur v) vecteur res resx = x + vx resy = y + vy resz = z + vz return res

programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (v2) v3affiche () v3 = v2somme (v1) v3affiche ()

Exercice 64

a) Transmission par adresse des valeurs de type vecteur

include ltiostreamgtusing namespace std deacuteclaration 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 ) deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n int vecteurprod_scal (vecteur adv) return (x adv-gtx + y adv-gty + z adv-gtz) on pourrait eacutecrire de faccedilon plus symeacutetrique return (this-gtx adv-gtx + this-gty adv-gty + this-gtz adv-gt z

Chapitre 6583

vecteur vecteursomme (vecteur adv) vecteur res resx = x + adv-gtx resy = y + adv-gty resz = z + adv-gtz ou pour conserver la symeacutetrie resx = this-gtx + adv-gt x return res attention on ne peut pas transmettre ladresse de res car il sagit dune variable automatique programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (ampv2) v3affiche () v3 = v2somme (ampv1) v3affiche ()

b) Transmission par reacutefeacuterence des valeurs de type vecteur

include ltiostreamgtusing namespace std deacuteclaration 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 amp) vecteur somme (vecteur amp)

deacutefinition des fonctions membres de la classe vecteur vecteurvecteur () x=0 y=0 z=0 vecteurvecteur (double a double b double c) x = a y = b z = c void vecteuraffiche () cout ltlt Vecteur de coordonnees ltlt x ltlt ltlt y ltlt ltlt z ltlt n

Correction des exercices584

int vecteurprod_scal (vecteur amp v) return (x vx + y vy + z vz) vecteur vecteursomme (vecteur amp v) vecteur res resx = x + vx resy = y + vy resz = z + vz return res attention on ne peut pas transmettre ladresse de res car il sagit dune variable automatique programme de test de la classe vecteur main() vecteur v1 (123) vecteur v2 (543) vecteur v3 v1affiche () v2affiche () v3affiche () v3 = v1somme (v2) v3affiche () v3 = v2somme (v1) v3affiche ()

Chapitre 7

Exercice 75

include ltiostreamgtusing namespace std deacuteclaration (et deacutefinition) de la classe pile_entier ici toutes les fonctions membres sont inline const int Max = 20 class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes 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 lt dim) adr[nelem++] = p

Chapitre 7585

int depile () if (nelem gt 0) return adr[--nelem] else return 0 faute de mieux int pleine () return (nelem == dim) int vide () return (nelem == 0 )

Exercice 76

programme dessai de la classe pile_entier main() int i exemples dutilisation de piles automatiques pile_entier a(3) une pile de 3 entiers b une pile de 20 entiers (par deacutefaut) cout ltlt a pleine ltlt apleine () ltlt n cout ltlt a vide ltlt avide () ltlt n aempile (3) aempile (9) aempile (11) cout ltlt Contenu de a for (i=0 ilt3 i++) cout ltlt adepile () ltlt cout ltlt n for (i=0 ilt30 i++) bempile (10i) cout ltlt Contenu de b for (i=0 ilt30 i++) if ( bvide() ) cout ltlt bdepile () ltlt cout ltlt n

exemple dutilisation dune pile dynamique pile_entier adp = new pile_entier (5) pointeur sur une pile de 5 entiers cout ltlt pile dynamique vide ltlt adp-gtvide () ltlt n for (i=0 ilt10 i++) adp-gtempile (10i) cout ltlt Contenu de la pile dynamique for (i=0 ilt10 i++) if ( adp-gtvide() ) cout ltlt adp-gtdepile () ltlt

Exercice 78

include ltiostreamgtusing namespace std deacuteclaration (et deacutefinition) de la classe pile_entiers const int Max = 20

Correction des exercices586

class pile_entier

int dim nombre maximal dentiers de la pile

int adr adresse emplacement des dim entiers

int nelem nombre dentiers actuellement empileacutes

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 lt dim) adr[nelem++] = p

int depile ()

if (nelem gt 0) return adr[--nelem]

else return 0 faute de mieux

int pleine ()

return (nelem == dim)

int vide ()

return (nelem == 0 )

pile_entier (pile_entier amp) constructeur de recopie

pile_entierpile_entier (pile_entier amp p)

adr = new int [dim = pdim]

nelem = pnelem

int i

for (i=0 iltnelem i++) adr[i] = padr[i]

programme dessai de la classe pile_entier

main()

int i

pile_entier a(3) une pile a de 3 entiers

aempile (5) aempile (12)

pile_entier b = a une pile b eacutegale agrave a

cout ltlt Contenu de b

for (i=0 ilt3 i++) if ( bvide() ) cout ltlt bdepile () ltlt

cout ltlt n

Chapitre 9587

Chapitre 9

Exercice 93

a) Avec une fonction membre

include ltiostreamgtusing namespace std classe point avec surdeacutefinition de == comme fonction membre class point int x y public point (int abs=0 int ord=0) x=abs y=ord int operator == (point amp p) on pourrait ne pas transmettre par reacutefeacuterence return ( (px == x) ampamp (py == y) ) programme de test de la classe point main() point a(23) b(1) c(23) cout ltlt a == b ltlt (a == b) ltlt n attention parenthegraveses cout ltlt b == a ltlt (b == a) ltlt n indispensables compte tenu cout ltlt a == c ltlt (a == c) ltlt n des prioriteacutes relatives de cout ltlt c == a ltlt (c == a) ltlt n de == et de ltlt

b) Avec une fonction amie1

include ltiostreamgtusing namespace std classe point avec surdeacutefinition de == comme fonction amie class point int x y public point (int abs=0 int ord=0) x=abs y=ord friend int operator == (point amp point amp) int operator == (point amp p point amp q) return ( (px == qx) ampamp (py == qy) )

1 Avec certains environnements il faut preacutefixer le nom de operator == de std dans son en-tecircte

Correction des exercices588

programme de test de la classe point main() point a(23) b(1) c(23) cout ltlt a == b ltlt (a == b) ltlt n attention parenthegraveses cout ltlt b == a ltlt (b == a) ltlt n indispensables compte tenu cout ltlt a == c ltlt (a == c) ltlt n des prioriteacutes relatives de cout ltlt c == a ltlt (c == a) ltlt n de == et de ltlt

Exercice 94

a) Avec des fonctions membres

include ltiostreamgtusing namespace std

la classe pile_entiers avec surdeacutefinition des opeacuterateurs lt et gt comme fonctions membre class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes

public pile_entier (int n) constructeur adr = new int [dim=n] nelem = 0 ~pile_entier () destructeur delete adr void operator lt (int n) if (nelem lt dim) adr[nelem++] = n void operator gt (int amp n ) attention amp indispensable ici if (nelem gt 0) n = adr[--nelem] programme dessai de la classe pile_entier main() int i n pile_entier a(3) a lt 3 a lt 9 a lt 11 cout ltlt Contenu de a for (i=0 ilt3 i++) a gt n cout ltlt n ltlt cout ltlt n

Chapitre 9589

b) Avec des fonctions amies

include ltiostreamgtusing namespace std la classe pile_entiers avec surdeacutefinition des opeacuterateurs lt et gt comme fonctions amies class pile_entier int dim nombre maximal dentiers de la pile int adr adresse emplacement des dim entiers int nelem nombre dentiers actuellement empileacutes public pile_entier (int n) constructeur adr = new int [dim=n] nelem = 0 ~pile_entier () destructeur delete adr friend void operator lt (pile_entier amp int) amp non indispensable friend void operator gt (pile_entier amp int amp) int amp indispensable ici void operator lt (pile_entier amp p int n) if (pnelem lt pdim) padr[pnelem++] = n void operator gt (pile_entier amp p int amp n) if (pnelem gt 0) n = padr[--pnelem]

programme dessai de la classe pile_entier main() int i n pile_entier a(3) a lt 3 a lt 9 a lt 11 cout ltlt Contenu de a for (i=0 ilt3 i++) a gt n cout ltlt n ltlt cout ltlt n

Exercice 96

include ltiostreamgtusing namespace std

class chaine int lg longueur actuelle de la chaicircne char adr adresse zone contenant la chaicircne

Correction des exercices590

public chaine () constructeur I chaine (char ) constructeur II chaine (const chaine amp) constructeur III (par recopie) ~chaine () destructeur (inline) delete adr void affiche () chaine amp operator = (const chaine amp) int operator == (chaine amp) chaine operator + (chaine amp) char amp operator [] (int)

chainechaine () constructeur I lg = 0 adr=0 chainechaine (char adc) constructeur II (agrave partir dune chaicircne C) char ad = adc lg = 0 while (ad++) lg++ calcul longueur chaicircne C adr = new char [lg] for (int i=0 iltlg i++) recopie chaicircne C adr[i] = adc[i] chainechaine (const chaine amp ch) constructeur III (par recopie) adr = new char [lg = chlg] for (int i=0 iltlg i++) adr[i] = chadr[i] void chaineaffiche () for (int i=0 iltlg i++) cout ltlt adr[i] en version lt 20 utilisez printf chaine amp chaineoperator = (const chaine amp ch) if (this = amp ch) on ne fait rien pour a=a delete adr adr = new char [lg = chlg] for (int i=0 iltlg i++) adr[i] = chadr[i] return this pour pouvoir utiliser la valeur de a=b int chaineoperator == (chaine amp ch) for (int i=0 iltlg i++) if (adr[i] = chadr[i]) return 0 return 1

Chapitre 9591

chaine chaineoperator + (chaine amp ch) attention la valeur de retour

chaine res est agrave transmettre par valeur

resadr = new char [reslg = lg + chlg]

int i

for (i=0 iltlg i++) resadr[i] = adr[i]

for (i=0 iltchlg i++) resadr[i+lg] = chadr[i]

return res

char amp chaineoperator [] (int i)

return adr[i] ici on na pas preacutevu de

veacuterification de la valeur de i

main()

chaine a cout ltlt chaine a aaffiche () cout ltlt n

chaine b(bonjour) cout ltlt chaine b baffiche () cout ltlt n

chaine c=b cout ltlt chaine c caffiche () cout ltlt n

chaine d(hello)

a = b = d

cout ltlt chaine b baffiche () cout ltlt n

cout ltlt chaine a aaffiche () cout ltlt n

cout ltlt a == b ltlt (a == b) ltlt n

chaine x(salut ) y(chegravere ) z(madame)

a = x + y + z

cout ltlt chaine a aaffiche () cout ltlt n

a = a

cout ltlt chaine a aaffiche () cout ltlt n

chaine e(xxxxxxxxxx)

for (char cr=a i=0 crltf cr++ i++ ) e[i] = cr

cout ltlt chaine e eaffiche () cout ltlt n

Exemple drsquoexeacutecution

chaine a

chaine b bonjour

chaine c bonjour

chaine b hello

chaine a hello

a == b 1

chaine a salut ch_re madame

chaine a salut ch_re madame

chaine e abcdexxxxx

Index

Aabort 385

abs 499

accegraves direct 365

iteacuterateur agrave ~ 456

accumulate (algorithme) 478 570

acos 500

acquisition de ressources 540

adaptateur

de conteneur 432

adjacent_difference (algorithme) 478 571

adjacent_find (algorithme) 466 560

adjustfield 357

affectation 162

drsquoobjets 71

de conteneur 414

et heacuteritage 273

virtuelle 316

algorithme 399

drsquoinitialisation 462 558

de copie 462

de fusion 476 568

de geacuteneacuteration de valeurs 463

de minimum ou de maximum 467

de partition 472

de permutation 469 470

de recherche 466 476 559 568

de remplacement 469

de suppression 472 564

de transformation 561

de transformation de seacutequence 468

de tri 475 566

ensembliste 479 571

numeacuterique 478 570

standard 455

alias 524

allocation dynamique 49 111 116

app 367

apply 503

arg 500

argument

adresse drsquoun objet 99

de type classe 97 99

par deacutefaut 39 94

reacutefeacuterence 31

reacutefeacuterence agrave un objet 101

asin 500

assign 414 487

at 419 486

atan 500

auto_ptr 542

C++ pour programmeurs C594

Bback 420 424 426 433

bad 349

bad_alloc 52

bad_cast 330

badbit 348

base 358

base de numeacuteration (en sortie) 338

basefield 357

basic_string 485

beg 365

begin 397 486

bibliothegraveque standard 395

bidirectionnel (iteacuterateur) 456

binary 367

binary_search (algorithme) 476 569

bits derreur 348

bitset 507

bloc try 375

bool 57

boolalpha 339 358

Ccapacity 421 486

caractegravere

de remplissage 356

deacutelimiteur 343

espace blanc 343

fin de ligne 368

invalide 22 25

seacuteparateur 23

cast 57 184 198

catch 375 378 384

cateacutegories

drsquoiteacuterateurs 457

de conteneurs 401

cerr 336

chaicircne de caractegraveres 485

champ 62

cin 21 333

class 67

classe 3 61 67 87

abstraite 317

canonique 170

fonction 404 405

fonction preacutedeacutefinie 406

forme canonique 277

virtuelle 297

virtuelle et constructeurs 298

classe amie

et patrons de fonctions 239

classe drsquoallocation

automatique 111

statique 111

classe deacuteriveacutee 247 248

conversion 265

classe patron 231

identiteacute de ~ 239

cleacute 438

clear 349 415

clog 336

commentaire 28

comparaison

de conteneurs 415

lexicographique 415

compatibiliteacute classe de base et deacuteriveacutee 264

compilation

conditionnelle 85

seacutepareacutee 83

complex 499

compteur de reacutefeacuterences 547

concateacutenation 488

conj 500

const 14 106

const_cast 57

constructeur 73 113

conversion par ~ 199

de recopie 119 132 402

de recopie et heacuteritage 270

de recopie par deacutefaut 119

en cas drsquoobjet membre 129

et classes virtuelles 298

et conversion 191

et fonction virtuelle 315

et heacuteritage 254 255

et heacuteritage multiple 293

explicit 197

priveacute 79

construction

drsquoun conteneur 402

drsquoun conteneur seacutequentiel 412

Index595

conteneur 396 400

adaptateur de ~ 432

affectation de ~ 414

associatif 401 437

cateacutegories de ~ 401

comparaison de ~ 415

construction 402

et relation drsquoordre 407

insertion drsquoeacuteleacutements 416

seacutequentiel 401 411

suppression drsquoeacuteleacutements 417

controcircle des accegraves 248 258

conversion

drsquoun type deacuteriveacute en un type de base 265

drsquoune classe en une autre 198

de pointeurs 266

deacutefinie par lrsquoutilisateur 182 532

en chaicircne 189 193

explicite 181

interdiction par explicit 197

par cast 184 185 198

par constructeur 191 199

standard 531

copie (algorithme) 462

copy (algorithme) 462 558

copy_backward (algorithme) 558

correspondance exacte 530

cos 500

cosh 500

count 447 448

count (algorithme) 575

count_if 575

cout 18 333

cshift 503

cur 365

Ddec 339 357 358

deacuteclaration

drsquoamitieacute 142

drsquoamitieacute et classes patron 239

drsquoune classe 87

en C++ 28

deacutefinition

drsquoune fonction membre 64 68

delete 49 50 117

surdeacutefinition 175

deacutelimiteur 343

deque 412 424

deacuterivation

priveacutee 262

proteacutegeacutee 263

publique 261

destructeur 73

en cas drsquoobjet membre 129

priveacute 79

virtuel 315

divides 407

dynamic_cast 329

dynamique (allocation) 111

Eefficaciteacute 403

empty 432 433 434

encapsulation 3 141

end 365 397 486

endl 359

ends 359

ensemble

algorithme 571

entreacutee standard 333

entreacutees-sorties

conversationnelles 17

eof 349

eofbit 348

equal (algorithme) 575

equal_range 447 449

equal_range (algorithme) 568

equal_to 406

erase 417 446 448 491

espace blanc 22 343

espaces

anonymes 524

de noms 56 511

exception 374

gestionnaire drsquo~ 375 380 383

standard 390

exit 380

exp 500

explicit 197

C++ pour programmeurs C596

exponentielle

notation 341

export 210 229

extern 48

Ffail 349

failbit 348

false 57

fichier

accegraves direct 365

binaire 368

connexion drsquoun flot agrave un ~ 362

modes drsquoouverture 367

pointeur 365

texte 368

fill 361 558

fill (algorithme) 465 558

fill_n (algorithme) 558

fin de ligne 368

find 444 448 489

find (algorithme) 466 559

find_end (algorithme) 559

find_first_not_of 489

find_first_of 489

find_first_of (algorithme) 466 559

find_if (algorithme) 466 559

find_last_not_of 489

find_last_of 489

first 439

fixed 341 357 358

flip 424

flot 18 21 333

connexion agrave un fichier 362

preacutedeacutefini 336

statut drsquoerreur 348

statut de formatage 356

flottante (notation) 341

flush 359

fonction

agrave arguments variables 532

assembleur 48

C 48

choix drsquoune ~ surdeacutefinie 43 46

classe ~ 406

de rappel 405

deacuteclaration de ~ 11

deacutefinition de ~ 10

en ligne 54

membre 63

objet ~ 405

patron de ~ 206

prototype drsquoune ~ 11

reacutedeacutefinition drsquoune ~ virtuelle 312

sans arguments 14

sans valeur de retour 14

surdeacutefinition drsquoune ~ 42 530

surdeacutefinition drsquoune ~ membre 91

surdeacutefinition drsquoune ~ virtuelle 313

virtuelle 305 311

virtuelle pure 318

fonction amie 142

de plusieurs classes 146

deacuteclaration 142

et classes patron 239

et espaces de noms 525

exploitation 150

indeacutependante 142 144

membre drsquoune classe 145

surdeacutefinition drsquoopeacuterateur par ~ 153

fonction membre

amie 145

arguments par deacutefaut 94

constante 107

deacutefinition 68

en ligne 95

heacuteritage 247

patron de ~ 238

pointeur sur une ~ 551

speacutecialisation 236

statique 104

surdeacutefinition 91 533

volatile 108

fonction patron 207

speacutecialisation 220

fonction virtuelle

et construteur 315

restrictions 314

fopen 367

for_each (algorithme) 575

Index597

formatage 338 356

en meacutemoire 368 493

mot drsquoeacutetat 360

statut de ~ drsquoun flot 356

forme canonique

et heacuteritage 277

free 49

freeze 369

friend 142

front 424 426 433

fseek 365

fstream 362

functional 406

fusion

algorithme 476 568

de listes 429

Ggabarit 356

gabarit de lrsquoinformation (en sortie) 339

gcount 346

generate (algorithme) 463

generate_n (algorithme) 465 558

geacuteneacuterateur drsquoopeacuterateur 409

geacuteneacuteration (algorithme) 463

gestionnaire drsquoexception 375 383

get 345

getline 346

good 349

goodbit 348

greater_equal 406

gslice 506

Hheacuteritage 3 245

appel des constructeurs 254

controcircle des accegraves 248 258

et affectation 273

et constructeur de recopie 270

et conversion de pointeurs 266

et conversions 265

et fonctions virtuelles 311

et forme canonique 277

et patron de classes 284

et typage statique 266

membre proteacutegeacute 259

multiple 291

multiple et constructeurs 293

hex 339 357 358

Iidentification de type 326

identiteacute

de classes patron 239

ifstream 364

imag 500

in 367

includes (algorithme) 571

inclusion multiple 85

initialisation

drsquoun membre donneacutee 88

drsquoun membre donneacutee statique 81

drsquoun objet 127

drsquoun tableau drsquoobjets 134

de reacutefeacuterence 38

des variables de type standard 213

par recopie 119

initialisation (algorithme) 462 558

inline 54 95

inner_product (algorithme) 478 570

inplace_merge (algorithme) 476 569

insert 417 445 490

insertion

iteacuterateur drsquo~ 458

instance 3 69

interdire

lrsquoaffectation 169

la copie 120

internal 357 358

intervalle drsquoiteacuterateur 398 457

invalidation

drsquoiteacuterateur 421

ios

adjustfield 357

app 367

basefield 357

beg 365

binary 367

cur 365

C++ pour programmeurs C598

end 365

floatfield 357

in 367

out 367

trunc 367

iostream 20 334

istream 334 343 360

istrstream 370

iter_swap (algorithme) 575

iteacuterateur 396

agrave accegraves direct 418 456

bidirectionnel 456

cateacutegories drsquo~ 456 457

drsquoinsertion 458

de flot 456 460 461

en entreacutee 456

en sortie 456

et pointeur 400

intervalle drsquo~ 457

unidirectionnel 456

iterator 397 419 426 486

Kkey_comp 442

Llrsquointervalle (algorithme) 558

left 357 358

less 406

less_equa 406

lexicographical_compare 576

ligature dynamique 305 308

list 412 426

fusion 429

tri 428

log 500

logical_and 407

logical_not 407

logical_or 407

lower_bound 447 448 449

lower_bound (algorithme) 568

Mmacro 55

make_heap 574

malloc 49

manipulateur 339 358

parameacutetrique 359

map 438

masque 504

max 503 576

max_element (algorithme) 467 561

max_size 422 424 430

maximum(recherche de ~) 467

membre

donneacutee 65

donneacutee statique 80 86

fonction 63

objet ~ 129

priveacute 68

proteacutegeacute 258

public 68

merge 429

merge (algorithme) 476 569

message 3

meacutethode 61

min 503 576

min_element (algorithme) 467 561

minimum(recherche de ~) 467

minus 407

mode drsquoouverture drsquoun fichier 367

modulus 407

multimap 448

multiset 452

Nname 326

namespace 56 512

new 49 50 117

surdeacutefinition 175

new (opeacuterateur) 175

new(nothrow) 51

next_permutation (algorithme) 470 563

noboolalpha 339 358

noshowbase 358

noshowpoint 358

Index599

noshowpos 358

noskipws 358

not_equal_to 406

notation

exponentielle 341

flottante 341

nothrow 51

nouppercase 358

nth_element (algorithme) 475 567

numeacuterique (algorithme) 570

Oobjet 2

affectation drsquo~ 71

automatique 112 539

construction 75 113

destruction 75

dynamique 116

en argument 97

en valeur de retour 102

fonction 405

initialisation 127

instance drsquo~ 69

membre 129

recopie 119

statique 112

tableau drsquo~ 133

temporaire 136

oct 339 357 358

ofstream 362

opeacuterateur

-- 161

349

() 173 349

++ 160

ltlt 334 335 352

= 162 163 316

= et heacuteritage 273

gtgt 334 343 352

de cast 184 198

delete 175

geacuteneacuterateur drsquo~ 409

new 175

surdeacutefinition 42

operator 153 154

ostream 334 360

ostrstream 369

out 367

PPOO (Programmation Orienteacutee Objet) 2

pair 439 440

paramegravetres de type

drsquoun patron de classes 231

drsquoun patron de fonctions 211 216

paramegravetres expressions

drsquoun patron de classes 233

drsquoun patron de fonctions 215 219

paramegravetres par deacutefaut

drsquoun patron de classes 238

partial_sort (algorithme) 475 566

partial_sort_copy (algorithme) 567

partial_sum (algorithme) 478 570

partition 472

partition (algorithme) 472 563

patron de classes 225

creacuteation 226

et deacuteclaration drsquoamitieacute 239

et heacuteritage 284

paramegravetres de type 231

paramegravetres expressions 233

paramegravetres par deacutefaut 238

speacutecialisation 235 237

utilisation 228

patron de fonctions

creacuteation 206

limitations 214

paramegravetres de type 211

paramegravetres expressions 215 219

speacutecialisation 220

surdeacutefinition 216

utilisation 207

pattern singleton 79

peek 347

permutation

algorithme 469 470

plus 407

pointeur

de fichier 365

et iteacuterateur 400

C++ pour programmeurs C600

intelligent 542

sur des fonctions membres 551 554

polar 500

polymorphisme 4 305 316

pop 432 433 434

pop_back 418 420 425 427

pop_front 425 427

pop_heap 575

precision 361

preacutecision

de lrsquoinformation eacutecrite 341

preacutecision numeacuterique 356

preacutedicat 405

binaire 405

en argument 405

unaire 405

prev_permutation (algorithme) 470 563

priority_queue 434

private 68

programmation structureacutee 2

protected 258

prototype 11

public 68

push 432 433 434

push_back 418 420 427

push_front 425 427

push_heap 574

put 337

putback 347

Qqueue 433

RRAII 541

random_shuffle (algorithme) 471 564

rbegin 486

rdstate 349

read 347

real 500

recherche

algorithme 466 476 559 568

dans une chaicircne 488

recopie

drsquoun objet drsquoune classe deacuteriveacutee 271

redeacutefinition

drsquoune fonction virtuelle 312

reacutefeacuterence 30 101 156

initialisation 38

reinterpret_cast 58

relation drsquoordre 407 408

remove 427

remove (algorithme) 473 564

remove_copy (algorithme) 565

remove_copy_if (algorithme) 473

remove_if 427

remove_if (algorithme) 473 565

remplacement

algorithme 469

rend 486

replace 492

replace (algorithme) 469 562

replace_copy (algorithme) 562

replace_copy_if (algorithme) 562

replace_if (algorithme) 469 562

reserve 421 486

resetiosflags 359

resize 422 486 502

reverse (algorithme) 561

reverse_copy (algorithme) 561

reverse_iterator 419 426 486

rfind 489

right 357

rotate (algorithme) 469 562

rotate_copy (algorithme) 562

Sscientific 357 358

search (algorithme) 466 560

search_n (algorithme) 466 560

second 439

section de vecteur 505

seekg 365

seekp 365

seacuteparateur 23

seacutequence 457

set 451

set_difference (algorithme) 480 573

set_intersection (algorithme) 480 572

Index601

set_new_handler 52

set_symetric_difference (algorithme) 573

set_symmetric_difference (algorithme) 480

set_terminate 385 387

set_union (algorithme) 480 572

setbase 359

setf 360

setfill 359

setiosflags 359

setprecision 359

setw 356 359

shift 503

showbase 357 358

showpoint 357 358

showpos 357 358

sin 500

singleton (motif de conception) 79

sinh 500

size 421 424 430 432 433 434 486

skipws 357 358

slice 505

sort 428

sort (algorithme) 566

sort_heap 574

sortie standard 333

speacutecialisation

drsquoun patron de classes 235

drsquoune classe 237

drsquoune fonction membre 236

de fonctions patrons 220

partielle drsquoun patron de fonctions 221

splice 430

stable_partition 472

stable_partition (algorithme) 563

stable_sort (algorithme) 475 566

stack 432

static 80 105 112

static_cast 58

statique

classe ~ 111

fonction membre 104

membre donneacutee 80

objet 112

statique (typage des objets) 266

statut drsquoerreur

drsquoun flot 348

std 56

stderr 336

stdin 333

stdio 357

stdout 333

STL 395

str 369

string 336 344 485 486

Stroustrup 1

struct 62

structure 61 67

dynamique 115

suppression (algorithme) 472 564

surdeacutefinition

drsquoopeacuterateurs 42

drsquoune fonction virtuelle 313

de fonctions 42 530

de fonctions membres 91 533

de lrsquoaffactation 162

de lrsquoopeacuterateur -- 161

de lrsquoopeacuterateur 349

de lrsquoopeacuterateur () 173 349

de lrsquoopeacuterateur ltlt 335 352

de lrsquoopeacuterateur = 163 273

de lrsquoopeacuterateur gtgt 343 352

de lrsquoopeacuterateur delete 175

de lrsquoopeacuterateur new 175

de patrons de fonctions 216

et espaces de noms 521

par fonction amie 153

par fonction membre 154

swap 415 447 487

swap_ranges (algorithme) 558

Ttableau drsquoobjets 133

tan 500

tanh 500

tas 574

tellg 365

tellp 365

terminate 385 387

this 103

throw 374 378 383

times 407

C++ pour programmeurs C602

top 432 434

transform (algorithme) 564

transformation

algorithme 561

transformation(algorithme) 468

tri

algorithme 475 566

drsquoune liste 428

true 57

trunc 367

try (bloc) 375

typage dynamique 305

typage statique 266

type

bool 57

deacutefini par lrsquoutilisateur 61

structure 61

type_info 326

typeid 326

Uunexpected 387

unidirectionnel (iteacuterateur) 456

unions 87

unique 428

unique (algorithme) 473 565

unique_copy (algorithme) 565

unitbuf 357

unsetf 360

upper__bound 449

upper_bound 447

upper_bound (algorithme) 568

uppercase 357 358

using 20 56

using (deacuteclaration) 516

using (directive) 519 523

Vval_array 499

valarray 501

value_comp 442

vecteur drsquoindice 506

vector 412 424

virtual 297 306

volatile 108

Wwidth 361

Wirth (eacutequation de ~) 2

write 337

ws 359

  • Table des matiegraveres
  • Avant-propos
  • 1 Geacuteneacuteraliteacutes concernant C++
    • 1 La Programmation Orienteacutee Objet
      • 11 Probleacutematique de la programmation
      • 12 La programmation structureacutee
      • 13 Les apports de la Programmation Orienteacutee Objet
        • 131 Objet
        • 132 Encapsulation
        • 133 Classe
        • 134 Heacuteritage
        • 135 Polymorphisme
          • 14 POO et langages
            • 2 C++ C ANSI et POO
            • 3 Les speacutecificiteacutes de C++
            • 4 C++ et la programmation orienteacutee objet
              • 2 Les incompatibiliteacutes entre C++ et C
                • 1 Les deacutefinitions de fonctions en C++
                • 2 Les prototypes en C++
                • 3 Arguments et valeur de retour drsquoune fonction
                  • 31 Points communs agrave C et C++
                  • 32 Diffeacuterences entre C et C++
                    • 321 Fonctions sans arguments
                    • 322 Fonctions sans valeur de retour
                        • 4 Le qualificatif const
                          • 41 Porteacutee
                          • 42 Utilisation dans une expression
                            • 5 Compatibiliteacute entre le type void et les autres pointeurs
                              • 3 Les entreacutees-sorties conversationnelles du C++
                                • 1 Geacuteneacuteraliteacutes
                                • 2 Affichage agrave lrsquoeacutecran
                                  • 21 Quelques exemples
                                  • 22 Le fichier en-tecircte iostream
                                  • 23 Les possibiliteacutes drsquoeacutecriture sur cout
                                    • 3 Lecture au clavier
                                      • 31 Introduction
                                      • 32 Les diffeacuterentes possibiliteacutes de lecture sur cin
                                      • 33 Exemple classique drsquoutilisation des seacuteparateurs
                                      • 34 Lecture drsquoune suite de caractegraveres
                                      • 35 Les risques induits par la lecture au clavier
                                        • 351 Manque de synchronisme entre clavier et eacutecran
                                        • 352 Blocage de la lecture
                                        • 353 Boucle infinie sur un caractegravere invalide
                                          • 4 Les speacutecificiteacutes du C++
                                            • 1 Le commentaire de fin de ligne
                                            • 2 Deacuteclarations et initialisations
                                              • 21 Regravegles geacuteneacuterales
                                              • 22 Cas des instructions structureacutees
                                                • 3 La notion de reacutefeacuterence
                                                  • 31 Transmission des arguments en C
                                                  • 32 Exemple de transmission drsquoargument par reacutefeacuterence
                                                  • 33 Proprieacuteteacutes de la transmission par reacutefeacuterence drsquoun argument
                                                    • 331 Induction de risques indirects
                                                    • 332 Absence de conversion
                                                    • 333 Cas drsquoun argument effectif constant
                                                    • 334 Cas drsquoun argument muet constant
                                                      • 34 Transmission par reacutefeacuterence drsquoune valeur de retour
                                                        • 341 Introduction
                                                        • 342 On obtient une lvalue
                                                        • 343 Conversion
                                                        • 344 Valeur de retour et constance
                                                          • 35 La reacutefeacuterence dune maniegravere geacuteneacuterale
                                                            • 351 La notion de reacutefeacuterence est plus geacuteneacuterale que celle drsquoargument
                                                            • 352 Initialisation de reacutefeacuterence
                                                                • 4 Les arguments par deacutefaut
                                                                  • 41 Exemples
                                                                  • 42 Les proprieacuteteacutes des arguments par deacutefaut
                                                                    • 5 Surdeacutefinition de fonctions
                                                                      • 51 Mise en oeuvre de la surdeacutefinition de fonctions
                                                                      • 52 Exemples de choix dune fonction surdeacutefinie
                                                                      • 53 Regravegles de recherche dune fonction surdeacutefinie
                                                                        • 531 Cas des fonctions agrave un argument
                                                                        • 532 Cas des fonctions agrave plusieurs arguments
                                                                        • 533 Le meacutecanisme de la surdeacutefinition de fonctions
                                                                            • 6 Les opeacuterateurs new et delete
                                                                              • 61 Exemples dutilisation de new
                                                                              • 62 Syntaxe et rocircle de new
                                                                              • 63 Exemples dutilisation de lopeacuterateur delete
                                                                              • 64 Syntaxe et rocircle de lopeacuterateur delete
                                                                              • 65 Lrsquoopeacuterateur new (nothrow)
                                                                              • 66 Gestion des deacutebordements de meacutemoire avec set_new_handler
                                                                                • 7 La speacutecification inline
                                                                                  • 71 Rappels concernant les macros et les fonctions
                                                                                  • 72 Utilisation de fonctions en ligne
                                                                                    • 8 Les espaces de noms
                                                                                    • 9 Le type bool
                                                                                    • 10 Les nouveaux opeacuterateurs de cast
                                                                                      • 5 Classes et objets
                                                                                        • 1 Les structures en C++
                                                                                          • 11 Rappel les structures en C
                                                                                          • 12 Deacuteclaration dune structure comportant des fonctions membres
                                                                                          • 13 Deacutefinition des fonctions membres
                                                                                          • 14 Utilisation dune structure comportant des fonctions membres
                                                                                          • 15 Exemple reacutecapitulatif
                                                                                            • 2 Notion de classe
                                                                                            • 3 Affectation drsquoobjets
                                                                                            • 4 Notions de constructeur et de destructeur
                                                                                              • 41 Introduction
                                                                                              • 42 Exemple de classe comportant un constructeur
                                                                                              • 43 Construction et destruction des objets
                                                                                              • 44 Rocircles du constructeur et du destructeur
                                                                                              • 45 Quelques regravegles
                                                                                                • 5 Les membres donneacutees statiques
                                                                                                  • 51 Le qualificatif static pour un membre donneacutee
                                                                                                  • 52 Initialisation des membres donneacutees statiques
                                                                                                  • 53 Exemple
                                                                                                    • 6 Exploitation drsquoune classe
                                                                                                      • 61 La classe comme composant logiciel
                                                                                                      • 62 Protection contre les inclusions multiples
                                                                                                      • 63 Cas des membres donneacutees statiques
                                                                                                      • 64 En cas de modification drsquoune classe
                                                                                                        • 641 La deacuteclaration des membres publics nrsquoa pas changeacute
                                                                                                        • 642 La deacuteclaration des membres publics a changeacute
                                                                                                            • 7 Les classes en geacuteneacuteral
                                                                                                              • 71 Les autres sortes de classes en C++
                                                                                                              • 72 Ce quon peut trouver dans la deacuteclaration dune classe
                                                                                                              • 73 Deacuteclaration dune classe
                                                                                                                • Exercices
                                                                                                                  • 6 Les proprieacuteteacutes des fonctions membres
                                                                                                                    • 1 Surdeacutefinition des fonctions membres
                                                                                                                      • 11 Exemple
                                                                                                                      • 12 Incidence du statut public ou priveacute drsquoune fonction membre
                                                                                                                        • 3 Les fonctions membres en ligne
                                                                                                                        • 2 Arguments par deacutefaut
                                                                                                                        • 4 Cas des objets transmis en argument drsquoune fonction membre
                                                                                                                        • 5 Mode de transmission des objets en argument
                                                                                                                          • 51 Transmission de ladresse dun objet
                                                                                                                          • 52 Transmission par reacutefeacuterence
                                                                                                                          • 53 Les problegravemes poseacutes par la transmission par valeur
                                                                                                                            • 6 Lorsqursquoune fonction renvoie un objet
                                                                                                                            • 7 Autoreacutefeacuterence le mot cleacute this
                                                                                                                            • 8 Les fonctions membres statiques
                                                                                                                            • 9 Les fonctions membres constantes
                                                                                                                              • 91 Rappels sur lrsquoutilisation de const en C
                                                                                                                              • 92 Deacutefinition drsquoune fonction membre constante
                                                                                                                              • 93 Proprieacuteteacutes drsquoune fonction membre constante
                                                                                                                                • 10 Les membres mutables
                                                                                                                                • Exercices
                                                                                                                                  • 7Construction destruction et initialisation des objets
                                                                                                                                    • 1 Les objets automatiques et statiques
                                                                                                                                      • 11 Dureacutee de vie
                                                                                                                                      • 12 Appel des constructeurs et des destructeurs
                                                                                                                                      • 13 Exemple
                                                                                                                                        • 2 Les objets dynamiques
                                                                                                                                          • 21 Les structures dynamiques
                                                                                                                                          • 22 Les objets dynamiques
                                                                                                                                            • 221 Points communs avec les structures dynamiques
                                                                                                                                            • 222 Les nouvelles possibiliteacutes des opeacuterateurs new et delete
                                                                                                                                            • 223 Exemple
                                                                                                                                                • 3 Le constructeur de recopie
                                                                                                                                                  • 31 Preacutesentation
                                                                                                                                                    • 311 Il nexiste pas de constructeur approprieacute
                                                                                                                                                    • 312 Il existe un constructeur approprieacute
                                                                                                                                                    • 313 Lorsqursquoon souhaite interdire la contruction par recopie
                                                                                                                                                      • 32 Exemple 1 objet transmis par valeur
                                                                                                                                                        • 321 Emploi du constructeur de recopie par deacutefaut
                                                                                                                                                        • 322 Deacutefinition dun constructeur de recopie
                                                                                                                                                          • 33 Exemple 2 objet en valeur de retour dune fonction
                                                                                                                                                            • 4 Initialisation dun objet lors de sa deacuteclaration
                                                                                                                                                            • 5 Objets membres
                                                                                                                                                              • 51 Introduction
                                                                                                                                                              • 52 Mise en oeuvre des constructeurs et des destructeurs
                                                                                                                                                              • 53 Le constructeur de recopie
                                                                                                                                                                • 6 Initialisation de membres dans lrsquoen-tecircte drsquoun constructeur
                                                                                                                                                                • 7 Les tableaux drsquoobjets
                                                                                                                                                                  • 71 Notations
                                                                                                                                                                  • 72 Constructeurs et initialiseurs
                                                                                                                                                                  • 73 Cas des tableaux dynamiques dobjets
                                                                                                                                                                    • 8 Les objets temporaires
                                                                                                                                                                    • Exercices
                                                                                                                                                                      • 8 Les fonctions amies
                                                                                                                                                                        • 1 Exemple de fonction indeacutependante amiedrsquoune classe
                                                                                                                                                                          • 2 Les diffeacuterentes situations drsquoamitieacute
                                                                                                                                                                            • 21 Fonction membre dune classe amie dune autre classe
                                                                                                                                                                            • 22 Fonction amie de plusieurs classes
                                                                                                                                                                            • 23 Toutes les fonctions dune classe amies dune autre classe
                                                                                                                                                                              • 3 Exemple
                                                                                                                                                                                • 31 Fonction amie indeacutependante
                                                                                                                                                                                • 32 Fonction amie membre dune classe
                                                                                                                                                                                  • 4 Exploitation de classes disposant de fonctions amies
                                                                                                                                                                                      • 9 La surdeacutefinition drsquoopeacuterateurs
                                                                                                                                                                                        • 1 Le meacutecanisme de la surdeacutefinitiondrsquoopeacuterateurs
                                                                                                                                                                                          • 11 Surdeacutefinition dopeacuterateur avec une fonction amie
                                                                                                                                                                                          • 12 Surdeacutefinition dopeacuterateur avec une fonction membre
                                                                                                                                                                                          • 13 Opeacuterateurs et transmission par reacutefeacuterence
                                                                                                                                                                                            • 2 La surdeacutefinition drsquoopeacuterateurs en geacuteneacuteral
                                                                                                                                                                                              • 21 Se limiter aux opeacuterateurs existants
                                                                                                                                                                                              • 22 Se placer dans un contexte de classe
                                                                                                                                                                                              • 23 Eviter les hypothegraveses sur le rocircle drsquoun opeacuterateur
                                                                                                                                                                                              • 24 Cas des opeacuterateurs ++ et --
                                                                                                                                                                                              • 25 Les opeacuterateurs = et amp ont une signification preacutedeacutefinie
                                                                                                                                                                                              • 26 Les conversions
                                                                                                                                                                                              • 27 Choix entre fonction membre et fonction amie
                                                                                                                                                                                                • 3 Exemple de surdeacutefinition de lrsquoopeacuterateur =
                                                                                                                                                                                                  • 31 Rappels concernant le constructeur par recopie
                                                                                                                                                                                                  • 32 Cas de lrsquoaffectation
                                                                                                                                                                                                  • 33 Algorithme proposeacute
                                                                                                                                                                                                  • 34 Valeur de retour
                                                                                                                                                                                                  • 35 En deacutefinitive
                                                                                                                                                                                                  • 36 Exemple de programme complet
                                                                                                                                                                                                  • 37 Lorsqursquoon souhaite interdire lrsquoaffectation
                                                                                                                                                                                                    • 4 La forme canonique dune classe
                                                                                                                                                                                                    • 5 Exemple de surdeacutefinition de lopeacuterateur [ ]
                                                                                                                                                                                                    • 6 Surdeacutefinition de lopeacuterateur ()
                                                                                                                                                                                                    • 7 Surdeacutefinition des opeacuterateurs new et delete
                                                                                                                                                                                                      • 71 Surdeacutefinition de new et delete pour une classe donneacutee
                                                                                                                                                                                                      • 72 Exemple
                                                                                                                                                                                                      • 73 Drsquoune maniegravere geacuteneacuterale
                                                                                                                                                                                                        • Exercices
                                                                                                                                                                                                          • 10 Les conversions de type deacutefinies par lrsquoutilisateur
                                                                                                                                                                                                            • 1 Les diffeacuterentes sortes de conversionsdeacutefinies par lrsquoutilisateur
                                                                                                                                                                                                            • 2 Lopeacuterateur de cast pour la conversion typeclasse ndashgt type de base
                                                                                                                                                                                                              • 21 Deacutefinition de lopeacuterateur de cast
                                                                                                                                                                                                              • 22 Exemple dutilisation
                                                                                                                                                                                                              • 23 Appel implicite de lopeacuterateur de cast lors drsquoun appel de fonction
                                                                                                                                                                                                              • 24 Appel implicite de lopeacuterateur de cast dans leacutevaluationdune expression
                                                                                                                                                                                                              • 25 Conversions en chaicircne
                                                                                                                                                                                                              • 26 En cas dambiguiumlteacute
                                                                                                                                                                                                                • 3 Le constructeur pour la conversion typede base -gt type classe
                                                                                                                                                                                                                  • 31 Exemple
                                                                                                                                                                                                                  • 32 Le constructeur dans une chaicircne de conversions
                                                                                                                                                                                                                  • 33 Choix entre constructeur ou opeacuterateur daffectation
                                                                                                                                                                                                                  • 34 Emploi dun constructeur pour eacutelargir la signification dun opeacuterateur
                                                                                                                                                                                                                  • 35 Interdire les conversions implicites par le constructeur le rocircle drsquoexplicit
                                                                                                                                                                                                                    • 4 Les conversions drsquoun type classe en un autretype classe
                                                                                                                                                                                                                      • 41 Exemple simple dopeacuterateur de cast
                                                                                                                                                                                                                      • 42 Exemple de conversion par un constructeur
                                                                                                                                                                                                                      • 43 Pour donner une signification agrave un opeacuterateur deacutefini dans uneautre classe
                                                                                                                                                                                                                        • 5 Quelques conseils
                                                                                                                                                                                                                          • 11 Les patrons de fonctions
                                                                                                                                                                                                                            • 1 Exemple de creacuteation et drsquoutilisationdrsquoun patron de fonctions
                                                                                                                                                                                                                              • 11 Creacuteation dun patron de fonctions
                                                                                                                                                                                                                              • 12 Premiegraveres utilisations du patron de fonctions
                                                                                                                                                                                                                              • 13 Autres utilisations du patron de fonctions
                                                                                                                                                                                                                                • 131 Application au type char
                                                                                                                                                                                                                                • 132 Application agrave un type classe
                                                                                                                                                                                                                                  • 14 Contraintes drsquoutilisation drsquoun patron
                                                                                                                                                                                                                                    • 2 Les paramegravetres de type drsquoun patronde fonctions
                                                                                                                                                                                                                                      • 21 Utilisation des paramegravetres de type dans la deacutefinitiondun patron
                                                                                                                                                                                                                                      • 22 Identification des paramegravetres de type dune fonction patron
                                                                                                                                                                                                                                      • 23 Nouvelle syntaxe dinitialisation des variables des types standard
                                                                                                                                                                                                                                      • 24 Limitations des patrons de fonctions
                                                                                                                                                                                                                                        • 3 Les paramegravetres expressions drsquoun patron de fonctions
                                                                                                                                                                                                                                        • 4 Surdeacutefinition de patrons
                                                                                                                                                                                                                                          • 41 Exemples ne comportant que des paramegravetres de type
                                                                                                                                                                                                                                          • 42 Exemples comportant des paramegravetres expressions
                                                                                                                                                                                                                                            • 5 Speacutecialisation de fonctions de patron
                                                                                                                                                                                                                                              • 51 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                              • 52 Les speacutecialisations partielles
                                                                                                                                                                                                                                                • 6 Algorithme drsquoinstanciation drsquounefonction patron
                                                                                                                                                                                                                                                  • 12 Les patrons de classes
                                                                                                                                                                                                                                                    • 1 Exemple de creacuteation et drsquoutilisation dun patron de classes
                                                                                                                                                                                                                                                      • 11 Creacuteation dun patron de classes
                                                                                                                                                                                                                                                      • 12 Utilisation dun patron de classes
                                                                                                                                                                                                                                                      • 13 Contraintes drsquoutilisation drsquoun patron de classes
                                                                                                                                                                                                                                                      • 14 Exemple reacutecapitulatif
                                                                                                                                                                                                                                                        • 2 Les paramegravetres de type drsquoun patron de classes
                                                                                                                                                                                                                                                          • 21 Les paramegravetres de type dans la creacuteation dun patron de classes
                                                                                                                                                                                                                                                          • 22 Instanciation dune classe patron
                                                                                                                                                                                                                                                            • 3 Les paramegravetres expressions drsquoun patron de classes
                                                                                                                                                                                                                                                              • 31 Exemple
                                                                                                                                                                                                                                                              • 32 Les proprieacuteteacutes des paramegravetres expressions
                                                                                                                                                                                                                                                                • 4 Speacutecialisation drsquoun patron de classes
                                                                                                                                                                                                                                                                  • 41 Exemple de speacutecialisation dune fonction membre
                                                                                                                                                                                                                                                                  • 42 Les diffeacuterentes possibiliteacutes de speacutecialisation
                                                                                                                                                                                                                                                                    • 421 On peut speacutecialiser une fonction membre pour tous les paramegravetres
                                                                                                                                                                                                                                                                    • 422 On peut speacutecialiser une fonction membre ou une classe
                                                                                                                                                                                                                                                                    • 423 On peut preacutevoir des speacutecialisations partielles de patrons de classes
                                                                                                                                                                                                                                                                        • 5 Paramegravetres par deacutefaut
                                                                                                                                                                                                                                                                        • 6 Patrons de fonctions membres
                                                                                                                                                                                                                                                                        • 7 Identiteacute de classes patrons
                                                                                                                                                                                                                                                                        • 8 Classes patrons et deacuteclarations drsquoamitieacute
                                                                                                                                                                                                                                                                          • 81 Deacuteclaration de classes ou fonctions ordinaires amies
                                                                                                                                                                                                                                                                          • 82 Deacuteclaration dinstances particuliegraveres de classes patrons ou de fonctions patrons
                                                                                                                                                                                                                                                                          • 83 Deacuteclaration drsquoun autre patron de fonctions ou de classes
                                                                                                                                                                                                                                                                            • 9 Exemple de classe tableau agrave deux indices
                                                                                                                                                                                                                                                                              • 13 Lrsquoheacuteritage simple
                                                                                                                                                                                                                                                                                • 1 La notion drsquoheacuteritage
                                                                                                                                                                                                                                                                                • 2 Utilisation des membres de la classe de base dans une classe deacuteriveacutee
                                                                                                                                                                                                                                                                                • 3 Redeacutefinition des membres dune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 31 Redeacutefinition des fonctions membres drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 32 Redeacutefinition des membres donneacutees drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                  • 33 Redeacutefinition et surdeacutefinition
                                                                                                                                                                                                                                                                                    • 4 Appel des constructeurs et des destructeurs
                                                                                                                                                                                                                                                                                      • 41 Rappels
                                                                                                                                                                                                                                                                                      • 42 La hieacuterarchisation des appels
                                                                                                                                                                                                                                                                                      • 43 Transmission dinformations entre constructeurs
                                                                                                                                                                                                                                                                                      • 44 Exemple
                                                                                                                                                                                                                                                                                      • 45 Compleacutements
                                                                                                                                                                                                                                                                                        • 5 Controcircle des accegraves
                                                                                                                                                                                                                                                                                          • 51 Les membres proteacutegeacutes
                                                                                                                                                                                                                                                                                          • 52 Exemple
                                                                                                                                                                                                                                                                                          • 53 Inteacuterecirct du statut proteacutegeacute
                                                                                                                                                                                                                                                                                          • 54 Deacuterivation publique et deacuterivation priveacutee
                                                                                                                                                                                                                                                                                            • 541 Rappels concernant la deacuterivation publique
                                                                                                                                                                                                                                                                                            • 542 Deacuterivation priveacutee
                                                                                                                                                                                                                                                                                              • 55 Les possibiliteacutes de deacuterivation proteacutegeacutee
                                                                                                                                                                                                                                                                                              • 56 Reacutecapitulation
                                                                                                                                                                                                                                                                                                • 6 Compatibiliteacute entre classe de base et classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                  • 61 Conversion dun type deacuteriveacute en un type de base
                                                                                                                                                                                                                                                                                                  • 62 Conversion de pointeurs
                                                                                                                                                                                                                                                                                                  • 63 Limitations lieacutees au typage statique des objets
                                                                                                                                                                                                                                                                                                  • 64 Les risques de violation des protections de la classe de base
                                                                                                                                                                                                                                                                                                    • 7 Le constructeur de recopie et lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                      • 71 La classe deacuteriveacutee ne deacutefinit pas de constructeur de recopie
                                                                                                                                                                                                                                                                                                      • 72 La classe deacuteriveacutee deacutefinit un constructeur de recopie
                                                                                                                                                                                                                                                                                                        • 8 Lrsquoopeacuterateur drsquoaffectation et lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                          • 81 La classe deacuteriveacutee ne surdeacutefinit pas lopeacuterateur =
                                                                                                                                                                                                                                                                                                          • 82 La classe deacuteriveacutee surdeacutefinit lopeacuterateur =
                                                                                                                                                                                                                                                                                                            • 9 Heacuteritage et forme canonique dune classe
                                                                                                                                                                                                                                                                                                            • 10 Lrsquoheacuteritage et ses limites
                                                                                                                                                                                                                                                                                                              • 101 La situation dheacuteritage
                                                                                                                                                                                                                                                                                                                • 1011 Le type du reacutesultat de lappel
                                                                                                                                                                                                                                                                                                                • 1012 Le type des arguments de f
                                                                                                                                                                                                                                                                                                                  • 102 Exemples
                                                                                                                                                                                                                                                                                                                    • 1021 Heacuteritage dans pointcol dun opeacuterateur + deacutefini dans point
                                                                                                                                                                                                                                                                                                                    • 1022 Heacuteritage dans pointcol de la fonction coincide de point
                                                                                                                                                                                                                                                                                                                        • 11 Exemple de classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                                        • 12 Patrons de classes et heacuteritage
                                                                                                                                                                                                                                                                                                                          • 121Classe ordinaire deacuterivant dune classe patron
                                                                                                                                                                                                                                                                                                                          • 122Deacuterivation de patrons avec les mecircmes paramegravetres
                                                                                                                                                                                                                                                                                                                          • 123Deacuterivation de patrons avec introduction dun nouveau paramegravetre
                                                                                                                                                                                                                                                                                                                            • 13 Lrsquoheacuteritage en pratique
                                                                                                                                                                                                                                                                                                                              • 131Deacuterivations successives
                                                                                                                                                                                                                                                                                                                              • 132Diffeacuterentes utilisations de lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                                              • 133 Exploitation drsquoune classe deacuteriveacutee
                                                                                                                                                                                                                                                                                                                                  • 14 Lheacuteritage multiple
                                                                                                                                                                                                                                                                                                                                    • 1 Mise en oeuvre de lheacuteritage multiple
                                                                                                                                                                                                                                                                                                                                    • 2 Pour reacutegler les eacuteventuels conflits les classes virtuelles
                                                                                                                                                                                                                                                                                                                                    • 3 Appels des constructeurs et des destructeurs cas des classes virtuelles
                                                                                                                                                                                                                                                                                                                                    • 4 Exemple drsquoutilisation de lrsquoheacuteritage multiple et de la deacuterivation virtuelle
                                                                                                                                                                                                                                                                                                                                      • 15 Les fonctions virtuelles et le polymorphisme
                                                                                                                                                                                                                                                                                                                                        • 1 Rappel drsquoune situation ougrave le typage dynamique est neacutecessaire
                                                                                                                                                                                                                                                                                                                                        • 2 Le meacutecanisme des fonctions virtuelles
                                                                                                                                                                                                                                                                                                                                        • 3 Autre situation ougrave la ligature dynamique est indispensable
                                                                                                                                                                                                                                                                                                                                        • 4 Les proprieacuteteacutes des fonctions virtuelles
                                                                                                                                                                                                                                                                                                                                          • 41 Leurs limitations sont celles de lrsquoheacuteritage
                                                                                                                                                                                                                                                                                                                                          • 42 La redeacutefinition dune fonction virtuelle nest pas obligatoire
                                                                                                                                                                                                                                                                                                                                          • 43 Fonctions virtuelles et surdeacutefinition
                                                                                                                                                                                                                                                                                                                                          • 44 Le type de retour drsquoune fonction virtuelle redeacutefinie
                                                                                                                                                                                                                                                                                                                                          • 45 On peut deacuteclarer une fonction virtuelle dans nimporte quelle classe
                                                                                                                                                                                                                                                                                                                                          • 46 Quelques restrictions et conseils
                                                                                                                                                                                                                                                                                                                                            • 461 Seule une fonction membre peut ecirctre virtuelle
                                                                                                                                                                                                                                                                                                                                            • 462 Un constructeur ne peut pas ecirctre virtuel
                                                                                                                                                                                                                                                                                                                                            • 463 Un destructeur peut ecirctre virtuel
                                                                                                                                                                                                                                                                                                                                            • 464 Cas particulier de lrsquoopeacuterateur drsquoaffectation
                                                                                                                                                                                                                                                                                                                                                • 5 Les fonctions virtuelles pures pour la creacuteation de classes abstraites
                                                                                                                                                                                                                                                                                                                                                • 6 Exemple drsquoutilisation de fonctions virtuelles liste heacuteteacuterogegravene
                                                                                                                                                                                                                                                                                                                                                • 7 Le meacutecanisme drsquoidentification dynamique des objets
                                                                                                                                                                                                                                                                                                                                                • 8 Identification de type agrave lexeacutecution
                                                                                                                                                                                                                                                                                                                                                  • 81 Utilisation du champ name de type_info
                                                                                                                                                                                                                                                                                                                                                  • 82 Utilisation des opeacuterateurs de comparaison de type_info
                                                                                                                                                                                                                                                                                                                                                  • 83 Exemple avec des reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                    • 9 Les cast dynamiques
                                                                                                                                                                                                                                                                                                                                                      • 16 Les flots
                                                                                                                                                                                                                                                                                                                                                        • 1 Preacutesentation geacuteneacuterale de la classe ostream
                                                                                                                                                                                                                                                                                                                                                          • 11 Lopeacuterateur ltlt
                                                                                                                                                                                                                                                                                                                                                          • 12 Les flots preacutedeacutefinis
                                                                                                                                                                                                                                                                                                                                                          • 13 La fonction put
                                                                                                                                                                                                                                                                                                                                                          • 14 La fonction write
                                                                                                                                                                                                                                                                                                                                                            • 141 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                            • 142 Autres cas
                                                                                                                                                                                                                                                                                                                                                              • 15 Quelques possibiliteacutes de formatage avec ltlt
                                                                                                                                                                                                                                                                                                                                                                • 151 Action sur la base de numeacuteration
                                                                                                                                                                                                                                                                                                                                                                • 152 Action sur le gabarit de linformation eacutecrite
                                                                                                                                                                                                                                                                                                                                                                • 153 Action sur la preacutecision de lrsquoinformation eacutecrite
                                                                                                                                                                                                                                                                                                                                                                • 154 Choix entre notation flottante ou exponentielle
                                                                                                                                                                                                                                                                                                                                                                    • 2 Preacutesentation geacuteneacuterale de la classe istream
                                                                                                                                                                                                                                                                                                                                                                      • 21 Lrsquoopeacuterateur gtgt
                                                                                                                                                                                                                                                                                                                                                                        • 211 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                                        • 212 Cas des chaicircnes de caractegraveres
                                                                                                                                                                                                                                                                                                                                                                        • 213 Les types accepteacutes par gtgt
                                                                                                                                                                                                                                                                                                                                                                          • 22 La fonction get
                                                                                                                                                                                                                                                                                                                                                                          • 23 Les fonctions getline et gcount
                                                                                                                                                                                                                                                                                                                                                                          • 24 La fonction read
                                                                                                                                                                                                                                                                                                                                                                            • 241 Cas des caractegraveres
                                                                                                                                                                                                                                                                                                                                                                            • 242 Autres cas
                                                                                                                                                                                                                                                                                                                                                                              • 25 Quelques autres fonctions
                                                                                                                                                                                                                                                                                                                                                                                • 3 Statut drsquoerreur drsquoun flot
                                                                                                                                                                                                                                                                                                                                                                                  • 31 Les bits derreur
                                                                                                                                                                                                                                                                                                                                                                                  • 32 Actions concernant les bits derreur
                                                                                                                                                                                                                                                                                                                                                                                    • 321 Accegraves aux bits derreur
                                                                                                                                                                                                                                                                                                                                                                                    • 322 Modification du statut derreur
                                                                                                                                                                                                                                                                                                                                                                                      • 33 Surdeacutefinition des opeacuterateurs () et
                                                                                                                                                                                                                                                                                                                                                                                      • 34 Exemples
                                                                                                                                                                                                                                                                                                                                                                                        • 4 Surdeacutefinition de ltlt et gtgt pour les types deacutefinis par lrsquoutilisateur
                                                                                                                                                                                                                                                                                                                                                                                          • 41 Meacutethode
                                                                                                                                                                                                                                                                                                                                                                                          • 42 Exemple
                                                                                                                                                                                                                                                                                                                                                                                            • 5 Gestion du formatage
                                                                                                                                                                                                                                                                                                                                                                                              • 51 Le statut de formatage dun flot
                                                                                                                                                                                                                                                                                                                                                                                              • 52 Description du mot deacutetat du statut de formatage
                                                                                                                                                                                                                                                                                                                                                                                              • 53 Action sur le statut de formatage
                                                                                                                                                                                                                                                                                                                                                                                                • 531 Les manipulateurs non parameacutetriques
                                                                                                                                                                                                                                                                                                                                                                                                • 532 Les manipulateurs parameacutetriques
                                                                                                                                                                                                                                                                                                                                                                                                • 533 Les fonctions membres
                                                                                                                                                                                                                                                                                                                                                                                                    • 6 Connexion drsquoun flot agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 61 Connexion dun flot de sortie agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 62 Connexion dun flot dentreacutee agrave un fichier
                                                                                                                                                                                                                                                                                                                                                                                                      • 63 Les possibiliteacutes daccegraves direct
                                                                                                                                                                                                                                                                                                                                                                                                      • 64 Les diffeacuterents modes douverture dun fichier
                                                                                                                                                                                                                                                                                                                                                                                                        • 7 Les anciennes possibiliteacutes de formatage en meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                          • 71 La classe ostrstream
                                                                                                                                                                                                                                                                                                                                                                                                          • 72 La classe istrstream
                                                                                                                                                                                                                                                                                                                                                                                                              • 17 La gestion des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                • 1 Premier exemple drsquoexception
                                                                                                                                                                                                                                                                                                                                                                                                                  • 11 Comment lancer une exception linstruction throw
                                                                                                                                                                                                                                                                                                                                                                                                                  • 12 Utilisation dun gestionnaire dexception
                                                                                                                                                                                                                                                                                                                                                                                                                  • 13 Reacutecapitulatif
                                                                                                                                                                                                                                                                                                                                                                                                                    • 2 Second exemple
                                                                                                                                                                                                                                                                                                                                                                                                                    • 3 Le meacutecanisme de gestion des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                      • 31 Poursuite de lexeacutecution du programme
                                                                                                                                                                                                                                                                                                                                                                                                                      • 32 Prise en compte des sorties de blocs
                                                                                                                                                                                                                                                                                                                                                                                                                        • 4 Choix du gestionnaire
                                                                                                                                                                                                                                                                                                                                                                                                                          • 41 Le gestionnaire reccediloit toujours une copie
                                                                                                                                                                                                                                                                                                                                                                                                                          • 42 Regravegles de choix drsquoun gestionnaire drsquoexception
                                                                                                                                                                                                                                                                                                                                                                                                                          • 43 Le cheminement des exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                          • 44 Redeacuteclenchement drsquoune exception
                                                                                                                                                                                                                                                                                                                                                                                                                            • 5 Speacutecification dinterface la fonction unexpected
                                                                                                                                                                                                                                                                                                                                                                                                                            • 6 Les exceptions standard
                                                                                                                                                                                                                                                                                                                                                                                                                              • 61 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                              • 62 Les exceptions deacuteclencheacutees par la bibliothegraveque standard
                                                                                                                                                                                                                                                                                                                                                                                                                              • 63 Les exceptions utilisables dans un programme
                                                                                                                                                                                                                                                                                                                                                                                                                              • 64 Creacuteation drsquoexceptions deacuteriveacutees de la classe exception
                                                                                                                                                                                                                                                                                                                                                                                                                                • 641 Exemple 1
                                                                                                                                                                                                                                                                                                                                                                                                                                • 642 Exemple 2
                                                                                                                                                                                                                                                                                                                                                                                                                                  • 18 Geacuteneacuteraliteacutes sur la bibliothegraveque standard
                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Notions de conteneur diteacuterateur et dalgorithme
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Notion de conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 12 Notion diteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                      • 13 Parcours dun conteneur avec un iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                        • 131 Parcours direct
                                                                                                                                                                                                                                                                                                                                                                                                                                        • 132 Parcours inverse
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 14 Intervalle diteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 15 Notion dalgorithme
                                                                                                                                                                                                                                                                                                                                                                                                                                          • 16 Iteacuterateurs et pointeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Les diffeacuterentes sortes de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Conteneurs et structures de donneacutees classiques
                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Les diffeacuterentes cateacutegories de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Les conteneurs dont les eacuteleacutements sont des objets
                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 31 Construction copie et affectation
                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 32 Autres opeacuterations
                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 4 Efficaciteacute des opeacuterations sur des conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Fonctions preacutedicats et classes fonctions
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 51 Fonction unaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 52 Preacutedicats
                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 53 Classes et objets fonctions
                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 531 Utilisation dobjet fonction comme fonction de rappel
                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 532 Classes fonction preacutedeacutefinies
                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 6 Conteneurs algorithmes et relation dordre
                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 61 Introduction
                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 62 Proprieacuteteacutes agrave respecter
                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 7 Les geacuteneacuterateurs dopeacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 19 Les conteneurs seacutequentiels
                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Fonctionnaliteacutes communes aux conteneurs vector list et deque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Construction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 111 Construction dun conteneur vide
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 112 Construction avec un nombre donneacute deacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 113 Construction avec un nombre donneacute deacuteleacutements initialiseacutes agrave une valeur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 114 Construction agrave partir dune seacutequence
                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 115 Construction agrave partir dun autre conteneur de mecircme type
                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 12 Modifications globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 121 Opeacuterateur daffectation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 122 La fonction membre assign
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 123 La fonction clear
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 124 La fonction swap
                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Comparaison de conteneurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 131 Lopeacuterateur ==
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 132 Lopeacuterateur lt
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 133 Exemples
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 14 Insertion ou suppression deacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 141 Insertion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 142 Suppression
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 143 Cas des insertionssuppressions en fin pop_back et push_back
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 2 Le conteneur vector
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 21 Accegraves aux eacuteleacutements existants
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 211 Accegraves par iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 212 Accegraves par indice
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 213 Cas de laccegraves au dernier eacuteleacutement
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 23 Gestion de lemplacement meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 231 Introduction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 232 Invalidation diteacuterateurs ou de reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 233 Outils de gestion de lemplacement meacutemoire dun vecteur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 24 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 25 Cas particulier des vecteurs de booleacuteens
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 3 Le conteneur deque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 31 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 32 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 4 Le conteneur list
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 41 Accegraves aux eacuteleacutements existants
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 42 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 421 Suppression des eacuteleacutements de valeur donneacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 422 Suppression des eacuteleacutements reacutepondant agrave une condition
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 43 Opeacuterations globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 431 Tri dune liste
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 432 Suppression des eacuteleacutements en double
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 433 Fusion de deux listes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 434 Transfert dune partie de liste dans une autre
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 44 Gestion de lemplacement meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 45 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Les adaptateurs de conteneur queue stack et priority_queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 51 Ladaptateur stack
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 52 Ladaptateur queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 53 Ladaptateur priority_queue
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 20 Les conteneurs associatifs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 Le conteneur map
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 11 Exemple introductif
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 12 Le patron de classes pair
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Construction dun conteneur de type map
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 131 Constructions utilisant la relation dordre par deacutefaut
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 132 Choix de lordre intrinsegraveque du conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 133 Pour connaicirctre la relation dordre utiliseacutee par un conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 134 Conseacutequences du choix de lordre dun conteneur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 14 Accegraves aux eacuteleacutements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 141 Accegraves par lopeacuterateur [ ]
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 142 Accegraves par iteacuterateur
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 143 Recherche par la fonction membre find
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 15 Insertions et suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 151 Insertions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 152 Suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 16 Gestion meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 17 Autres possibiliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 18 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Le conteneur multimap
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Le conteneur set
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 31 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 32 Exemple
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 33 Le conteneur set et lensemble matheacutematique
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 4 Le conteneur multiset
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Conteneurs associatifs et algorithmes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 21 Les algorithmes standard
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 1 Notions geacuteneacuterales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 11 Algorithmes et iteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 12 Les cateacutegories diteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 121 Iteacuterateur en entreacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 122 Iteacuterateur en sortie
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 123 Hieacuterarchie des cateacutegories diteacuterateurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 13 Algorithmes et seacutequences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 14 Iteacuterateur dinsertion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 15 Iteacuterateur de flot
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 151 Iteacuterateur de flot de sortie
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 152 Iteacuterateur de flot dentreacutee
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 2 Algorithmes dinitialisation de seacutequences existantes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 21 Copie dune seacutequence dans une autre
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 22 Geacuteneacuteration de valeurs par une fonction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 3 Algorithmes de recherche
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 31 Algorithmes fondeacutes sur une eacutegaliteacute ou un preacutedicat unaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 32 Algorithmes de recherche de maximum ou de minimum
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 4 Algorithmes de transformation dune seacutequence
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 41 Remplacement de valeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 42 Permutations de valeurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 421 Rotation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 422 Geacuteneacuteration de permutations
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 423 Permutations aleacuteatoires
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 43 Partitions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 5 Algorithmes dits de suppression
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 6 Algorithmes de tris
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 7 Algorithmes de recherche et de fusion sur des seacutequences ordonneacutees
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 71 Algorithmes de recherche binaire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 72 Algorithmes de fusion
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 8 Algorithmes agrave caractegravere numeacuterique
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 9 Algorithmes agrave caractegravere ensembliste
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 10 Algorithmes de manipulation de tas
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 22 La classe string
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 Geacuteneacuteraliteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 Construction
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 3 Opeacuterations globales
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 4 Concateacutenation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 5 Recherche dans une chaicircne
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 51 Recherche dune chaicircne ou dun caractegravere
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 52 Recherche dun caractegravere preacutesent ou absent dune suite
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 6 Insertions suppressions et remplacements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 61 Insertions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 62 Suppressions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 63 Remplacements
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 7 Les possibiliteacutes de formatage en meacutemoire
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 71 La classe ostringstream
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 72 La classe istringstream
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 721 Preacutesentation
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 722 Utilisation pour fiabiliser les lectures au clavier
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 23 Les outils numeacuteriques
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 1 La classe complex
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 2 La classe valarray et les classes associeacutees
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 21 Constructeurs des classes valarray
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 Lrsquoopeacuterateur []
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 23 Affectation et changement de taille
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 24 Calcul vectoriel
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 25 Seacutelection de valeurs par masque
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 26 Sections de vecteurs
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 27 Vecteurs drsquoindices
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 La classe bitset
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • 24 Les espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • 1 Creacuteation drsquoespaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 11 Exemple de creacuteation drsquoun nouvel espace de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 12 Exemple avec deux espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 13 Espace de noms et fichier en-tecircte
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 14 Instructions figurant dans un espace de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • 15 Creacuteation increacutementale drsquoespaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        • 2 Les instructions using
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          • 21 La deacuteclaration using pour les symboles
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 211 Preacutesentation geacuteneacuterale
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            • 212 Masquage et ambiguiumlteacutes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              • 22 La directive using pour les espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 3 Espaces de noms et surdeacutefinition
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 4 Imbrication des espaces de noms
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 5 Transitiviteacute de la directive using
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 6 Les alias
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 7 Les espaces anonymes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                • 8 Espaces de noms et deacuteclaration drsquoamitieacute
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  • Annexes
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe A Mise en correspondance darguments
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe B Utilisation de code eacutecrit en C
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe C Compleacutements sur les exceptions
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe D Les diffeacuterentes sortes de fonctions en C++
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe E Comptage de reacutefeacuterences
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe F Les pointeurs sur des membres
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    • Annexe G Les algorithmes standard
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • Correction des exercices
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      • Index
Page 3: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 4: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 5: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 6: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 7: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 8: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 9: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 10: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 11: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 12: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 13: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 14: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 15: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 16: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 17: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 18: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 19: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 20: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 21: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 22: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 23: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 24: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 25: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 26: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 27: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 28: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 29: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 30: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 31: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 32: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 33: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 34: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 35: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 36: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 37: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 38: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 39: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 40: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 41: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 42: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 43: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 44: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 45: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 46: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 47: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 48: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 49: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 50: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 51: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 52: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 53: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 54: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 55: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 56: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 57: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 58: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 59: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 60: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 61: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 62: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 63: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 64: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 65: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 66: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 67: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 68: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 69: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 70: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 71: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 72: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 73: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 74: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 75: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 76: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 77: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 78: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 79: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 80: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 81: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 82: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 83: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 84: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 85: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 86: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 87: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 88: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 89: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 90: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 91: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 92: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 93: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 94: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 95: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 96: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 97: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 98: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 99: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 100: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 101: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 102: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 103: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 104: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 105: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 106: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 107: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 108: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 109: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 110: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 111: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 112: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 113: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 114: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 115: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 116: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 117: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 118: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 119: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 120: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 121: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 122: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 123: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 124: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 125: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 126: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 127: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 128: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 129: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 130: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 131: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 132: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 133: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 134: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 135: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 136: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 137: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 138: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 139: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 140: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 141: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 142: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 143: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 144: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 145: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 146: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 147: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 148: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 149: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 150: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 151: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 152: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 153: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 154: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 155: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 156: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 157: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 158: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 159: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 160: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 161: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 162: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 163: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 164: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 165: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 166: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 167: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 168: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 169: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 170: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 171: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 172: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 173: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 174: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 175: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 176: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 177: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 178: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 179: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 180: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 181: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 182: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 183: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 184: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 185: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 186: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 187: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 188: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 189: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 190: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 191: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 192: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 193: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 194: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 195: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 196: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 197: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 198: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 199: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 200: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 201: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 202: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 203: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 204: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 205: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 206: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 207: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 208: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 209: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 210: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 211: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 212: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 213: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 214: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 215: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 216: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 217: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 218: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 219: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 220: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 221: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 222: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 223: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 224: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 225: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 226: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 227: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 228: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 229: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 230: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 231: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 232: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 233: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 234: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 235: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 236: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 237: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 238: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 239: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 240: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 241: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 242: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 243: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 244: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 245: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 246: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 247: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 248: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 249: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 250: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 251: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 252: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 253: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 254: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 255: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 256: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 257: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 258: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 259: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 260: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 261: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 262: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 263: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 264: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 265: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 266: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 267: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 268: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 269: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 270: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 271: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 272: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 273: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 274: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 275: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 276: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 277: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 278: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 279: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 280: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 281: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 282: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 283: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 284: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 285: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 286: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 287: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 288: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 289: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 290: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 291: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 292: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 293: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 294: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 295: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 296: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 297: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 298: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 299: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 300: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 301: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 302: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 303: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 304: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 305: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 306: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 307: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 308: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 309: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 310: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 311: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 312: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 313: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 314: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 315: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 316: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 317: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 318: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 319: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 320: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 321: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 322: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 323: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 324: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 325: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 326: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 327: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 328: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 329: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 330: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 331: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 332: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 333: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 334: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 335: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 336: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 337: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 338: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 339: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 340: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 341: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 342: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 343: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 344: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 345: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 346: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 347: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 348: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 349: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 350: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 351: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 352: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 353: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 354: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 355: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 356: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 357: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 358: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 359: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 360: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 361: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 362: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 363: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 364: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 365: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 366: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 367: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 368: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 369: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 370: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 371: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 372: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 373: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 374: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 375: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 376: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 377: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 378: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 379: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 380: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 381: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 382: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 383: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 384: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 385: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 386: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 387: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 388: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 389: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 390: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 391: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 392: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 393: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 394: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 395: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 396: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 397: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 398: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 399: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 400: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 401: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 402: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 403: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 404: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 405: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 406: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 407: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 408: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 409: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 410: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 411: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 412: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 413: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 414: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 415: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 416: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 417: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 418: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 419: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 420: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 421: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 422: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 423: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 424: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 425: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 426: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 427: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 428: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 429: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 430: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 431: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 432: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 433: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 434: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 435: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 436: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 437: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 438: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 439: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 440: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 441: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 442: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 443: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 444: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 445: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 446: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 447: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 448: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 449: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 450: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 451: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 452: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 453: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 454: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 455: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 456: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 457: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 458: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 459: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 460: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 461: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 462: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 463: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 464: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 465: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 466: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 467: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 468: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 469: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 470: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 471: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 472: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 473: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 474: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 475: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 476: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 477: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 478: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 479: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 480: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 481: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 482: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 483: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 484: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 485: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 486: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 487: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 488: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 489: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 490: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 491: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 492: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 493: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 494: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 495: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 496: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 497: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 498: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 499: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 500: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 501: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 502: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 503: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 504: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 505: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 506: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 507: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 508: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 509: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 510: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 511: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 512: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 513: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 514: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 515: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 516: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 517: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 518: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 519: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 520: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 521: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 522: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 523: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 524: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 525: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 526: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 527: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 528: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 529: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 530: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 531: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 532: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 533: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 534: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 535: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 536: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 537: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 538: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 539: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 540: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 541: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 542: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 543: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 544: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 545: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 546: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 547: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 548: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 549: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 550: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 551: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 552: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 553: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 554: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 555: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 556: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 557: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 558: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 559: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 560: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 561: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 562: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 563: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 564: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 565: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 566: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 567: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 568: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 569: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 570: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 571: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 572: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 573: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 574: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 575: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 576: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 577: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 578: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 579: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 580: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 581: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 582: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 583: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 584: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 585: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 586: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 587: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 588: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 589: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 590: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 591: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 592: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 593: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 594: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 595: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 596: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 597: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 598: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 599: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 600: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 601: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 602: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 603: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 604: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 605: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 606: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 607: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 608: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 609: C++ pour les programmeurs C - bibliotheque.pssfp.net
Page 610: C++ pour les programmeurs C - bibliotheque.pssfp.net