Vous êtes sur la page 1sur 79

Le langage C++

Introduction  la programmation oriente objets,


a
e
prsentation du langage C++
e

Ce guide est une introduction la conception oriente objets, principes, concepts,


vocabulaire, et la mise en oeuvre via le langage de programmation C++.
Comme son nom lindique, C++ est un surensemble du langage C et les deux partagent donc un important noyau commun. Ce guide ne traite que des spcicits de
C++ par rapport C. Il sadresse donc un lectorat ayant dj la pratique (ou au
moins une connaissance syntaxique raisonnable) du langage C.
Un autre guide, Une introduction au langage C (mme auteur, mme collection), est
disponible.

dition
Auteur

2.0
Jean-Franois Rabasse

Copyright c 1996-2005,Jean-Franois Rabasse


Ce manuel a t rdig des ns denseignement
et son utilisation est limite ce cadre.
En particulier il ne saurait remplacer les manuels
de rfrences et normes des langages.
Contact :
jean-francois.rabasse@lra.ens.fr
http://www.lra.ens.fr/

Sommaire
1

Introduction

1.1
1.2

Mise en oeuvre

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3

Compatibilits

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.4

Spcicits du langage

1.5

Extensions par rapport C

1.6

Le langage

Notes commentaires

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . .

Objets et classes
Lobjet logiciel

2.2

Classes et instances

2.3

Mcanismes de spcication

2.4

Interface de classe

2.5

Instanciations

2.6

Implmentation de classe

2.7

Visibilits

2.8

Cycle de vie

2.9

Gestion des objets

. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .

7
7

. . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . .

10

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .

12
14

17

Appels et surcharges
3.1

Mthodes de classes

3.2

Surcharges de slection

3.3

Arguments optionnels

3.4

. . . . . . . . . . . . . . . . . . . . .

2.1

Notes commentaires

. . . . . . . . . . . . . . . . . . . . . . . . .

17

. . . . . . . . . . . . . . . . . . . . . . .

17

. . . . . . . . . . . . . . . . . . . . . . . .

18

. . . . . . . . . . . . . . . . . . . . . . . . .

19

Hritage

21

4.1

Comportement gnrique

. . . . . . . . . . . . . . . . . . . . . .

21

4.2

Classe de base

. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

4.3

Spcialisation par drivation

4.4

Exploitation de lhritage

. . . . . . . . . . . . . . . . . . . .

23

. . . . . . . . . . . . . . . . . . . . . .

25
i

Introduction au langage C++

4.5
4.6

Objets composites

4.7

Accs privilgis

. . . . . . . . . . . . . . . . . . . . . . . . . . .

26

. . . . . . . . . . . . . . . . . . . . . . . . . .

26

Notes commentaires

. . . . . . . . . . . . . . . . . . . . . . . . .

27

29

Accs, protections
5.1

. . . . . . . . . . . . . . . . . . . . . . . .

29

5.2

Protection en criture

. . . . . . . . . . . . . . . . . . . . . . . .

30

5.3

Codage en ligne

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

5.4

Touche mon pote !

5.5

Passages darguments

Conclusion

. . . . . . . . . . . . . . . . . . . . . . . . .

34

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

34

Polymorphisme

37

6.1
6.2

Mthodes virtuelles

6.3

Classes abstraites

6.4

Compatibilit hirarchique

. . . . . . . . . . . . . . . . . . . . .

37

. . . . . . . . . . . . . . . . . . . . . . . . .

38

. . . . . . . . . . . . . . . . . . . . . . . . . . .

40

Familles polymorphiques

. . . . . . . . . . . . . . . . . . . . . .

41

43

Complments
A.1

Membres statiques

A.2

Rsolution de porte

A.3

Qui suis-je ?

A.4

Structures

A.5

Gestion des dclarations

. . . . . . . . . . . . . . . . . . . . . . . . . .

43

. . . . . . . . . . . . . . . . . . . . . . . . .

45

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

46

. . . . . . . . . . . . . . . . . . . . . . .

47

49

Points dentre

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

49

B.2

Compatibilit C/C++
B.1

Interface objets

. . . . . . . . . . . . . . . . . . . . . . . . . . . .

52

55

Surcharges doprateurs
C.1

. . . . . . . . . . . . . . . . . . . . . . .

55

C.2

Oprateurs sur la classe

. . . . . . . . . . . . . . . . . . . . . . .

57

C.3

Associativit

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

57

C.4

Surcharge de slection

C.5

Objets temporaires

C.6

Remarques

C.7

ii

Arithmtique complexe

Notes commentaires

. . . . . . . . . . . . . . . . . . . . . . . .

58

. . . . . . . . . . . . . . . . . . . . . . . . . .

59

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

. . . . . . . . . . . . . . . . . . . . . . . . .

62

1 - Sommaire

iii

Les streams

63

Les patrons

65

Exceptions

69

Index

71

iii

Introduction au langage C++

iv

Introduction
Ce manuel veut se donner un double objectif : prsenter les principes de la conception oriente objets1 et toutes les notions affrentes, et dautre part dtailler la mise
en oeuvre laide du langage C++.
En toute rigueur, ces deux points sont indpendants lun de lautre. La conception
oriente objets est un cadre de programmation, une nouvelle manire de penser les
applications informatiques, alors que C++ nest quun outil de mise en oeuvre parmi
dautres langages orients objets, SmallTalk, Java...
Ceci tant, il est souvent malcommode dexposer des concepts sans sappuyer sur
un matriel exemplaire. Ce manuel se voulant essentiellement pratique, les notions
objets seront donc illustres au fur et mesure par leur expression syntaxique en
C++ (voir note [ 1.1 ] page 4 en n de chapitre).
Il appartiendra au lecteur de sparer mentalement les deux aspects, concepts dune
part, programmation dautre part, pour pouvoir terme mettre en oeuvre un autre
outil de programmation (Java par exemple).
La structure de ce manuel va dailleurs dans ce sens. Tous les chapitres, partir du
chapitre 2 page 7, dtaillent les grands concepts de la programmation objets illustrs
par leur mise en oeuvre avec C++. Les annexes, elles, prsentent un certain nombre de fonctionnalits C++, utiles ou indispensables, mais quon ne retrouvera pas
ncessairement (ou pas sous la mme forme) dans dautres langages objets.

1.1

Le langage
Le langage C++, invent par Bjarne Stroustrup vers 1983 et dcrit par louvrage The
C++ Programming Language, est une volution oriente objets du langage C de Brian
Kernighan et Denis Ritchie.
Il sest enrichi, au cours de la dcennie 1980, paralllement la stabilisation et la
normalisation de C (norme C-Ansi de 1989).
C++ est actuellement en cours de normalisation, la rfrence syntaxique et fonctionnelle du langage tant louvrage de Stroustrup remis hauteur en 1992, The C++
Programming Language, 2nd edition.
Cet ouvrage est un "pav", relativement indigeste mais exhaustif et de qualit. Le
prsent manuel tant une initiation, il est loin de comporter toutes les nesses et
subtilits2 de la programmation en C++, louvrage de Stroustrup reste LA rfrence.

(1) ou COO. En anglais OOD, Objects Oriented Design.


(2) Oui ! C++ est subtil, nen dplaise aux mcrants !

Introduction au langage C++

1.2

Mise en oeuvre
Il nexiste pas de standard universel pour dsigner les noms de chiers source C++.
Un certain nombre dextensions de noms existent : .cxx, .cc, .C, .cpp, .c++, ...,
selon les plateformes et compilateurs utiliss.
Lextension la plus universelle est .cxx et cest celle qui sera utilise dans tout ce
guide (voir note [ 1.2 ] page 4).
Les commandes de compilation les plus courantes sont :
DEC C++ sur machines VAX/VMS
cxx toto.cxx
DEC C++ sur machines Alpha/DEC-Unix

cxx -c toto.cxx
Sun C++ sur machines Sun/Solaris

CC -c toto.cxx
GNU C/C++ sur toutes machines Alpha, Sun, Linux

g++ -c toto.cxx
Voir galement la note [ 1.3 ] page 4.
Ldition de liens du ou des modules objets se fait de manire classique :
Linker VMS
link/exec=toto.exe toto.obj
Linkers Unix, selon plateforme

cxx -o toto toto.o


CC

-o toto toto.o

g++ -o toto toto.o


NB : on se souviendra que, sous Unix, les minuscules et majuscules sont diffrenties
dans les lignes de commandes. Ainsi, avec les outils Sun, cc lance une compilation
C et CC lance une compilation C++ !

1.3

Compatibilits
e
On remarquera que, contrairement la compilation de sources C, la compilation en
C++ nutilise pas doptions Ansi ou autres.
La syntaxe de lAnsi relative aux dclarations, prototypes de fonctions et autres, est
obligatoire en C++. Un compilateur C++ est capable de compiler un code source
crit en C-Ansi pur3.
(3)

Mais linverse est videmment faux.

1 - Introduction

Certains compilateurs, cest le cas du GNU C/C++, sont capables de traiter les deux
dialectes, sur dtection de lextension de nom du chier source (ou, parfois, via une
option spcique, cest le cas du Turbo-C/C++ de Borland).
Il y a donc compatibilit ascendante, C vers C++, au niveau de lcriture. Il nest par
contre pas possible de mlanger sans prcautions, au sein dun mme programme,
des modules objet compils en C et en C++ (voir lannexe B page 49).

1.4

Spci cits du langage


e
e
Le langage C++ est un surensemble de C et repose sur les mmes mcanismes
dcriture et de gnration :
Dclarations pralables et obligatoires.
Prototypages des fonctions, selon les conventions de lAnsi, obligatoires.
Exploitation de toutes les fonctionnalits du prprocesseur C pour les inclusions
de chiers, code conditionnel, macro dnitions, etc.
De fait, une connaissance pratique de C est indispensable pour aborder le C++. Si
C++ apporte, par rapport C, des notions nouvelles et fondamentales, la syntaxe
elle est trs peu diffrente.
La syntaxe du C++ est 95 % de C et 5 % dajouts, et ce guide ne traite que des
notions nouvelles (et des 5 % syntaxiques). En particulier, on ne reviendra pas sur
"comment crire une boucle, un test", "comment coder un calcul", "comment ouvrir
un chier", etc. Tout ceci est conforme au langage C.

1.5

Extensions par rapport  C


a
Ce paragraphe sadresse aux lecteurs pratiquant dj le C et peut tre saut en
premire lecture.

1.5.1 Nouveaux concepts


C++ ajoute C trois notions importantes et quelques amliorations, moins fondamentales mais intressantes :
Classes et objets : notion fondamentale et qui est le coeur mme de la programmation oriente objets. Cette notion est dveloppe aux chapitres 2 page 7 et 3
page 17.
Surcharge de slection : cest la possibilit de dnir des traitements (fonctions)
un niveau conceptuel plus lev quen programmation classique, en reportant
sur le compilateur le maximum de dtails de mise en oeuvre, en particulier
les traitements associs aux types des arguments dappel. Cette notion est
dveloppe en section 3.2 page 17.
Hritages : cest la possibilit de construire de nouveaux objets par rutilisation
(drivation) et modication dobjets existants (surcharge fonctionnelle). Cette
notion est dveloppe aux chapitres 4 page 21 et 6 page 37.
Surcharges doprateurs : cest une extension des rgles dcritures arithmtiques classiques des objets non scalaires. Le principe est illustr en annexe C
3

Introduction au langage C++

page 55.
Entres/sorties par streams : cest une amlioration lgante des mcanismes de
lecture/criture de donnes. Lannexe D page 63 documente ces mcanismes.
Classe ou fonctions patrons (templates). Il sagit dun mcanisme daide
lcriture des codes C++, permettant de dnir, sous une forme semi-symbolique, des traitements similaires. Cette possibilit nest disponible que depuis
peu de temps dans les compilateurs C++. Elle est illustre en annexe E page 65.
Gestion derreurs et exceptions : C++ a introduit, tout rcemment, des principes
sophistiqus de gestion des erreurs et problmes en excution. Ces mcanismes
ne seront pas traits dans ce guide4.


1.5.2 Evolutions syntaxiques
Si la conception de programmes, en C++, na plus grand chose voir avec la conception en C, la syntaxe elle est trs peu modie par rapport au C-Ansi. Les diffrences
portent sur :
Introduction dun commentaire "jusqu n de ligne", symbolis par // :
int mini; // Valeur mini
en plus du commentaire "bloc" de C /* ... */, toujours reconnu.
Introduction de nouveaux mots-cls correspondant aux nouvelles fonctionnalits : class, public, private, protected, friend, virtual, this,
template, operator, new, delete, et au support derreurs quand il est
disponible : try, throw, rethrow, catch.
Modication ou extension de la smantique de certains mots-cls du C : extern, static, et de certains oprateurs : &, >>, <<. Cest sur ces derniers
points que les habitu(e)s de C devront se mer.

1.6

Notes commentaires

Le choix de C++, pour une introduction la conception objets, est du au fait que
cest aujourdhui LE langage de dveloppement orient objets.
Des langages antrieurs, comme SmallTalk, sont trop peu rpandus pour justier
un investissement. Dautres, comme le rcent langage Java, sont plus spcialiss et
prennent donc tout leur intrt dans des environnements bien particuliers (Internet).
[ 1.2 ] En tout tat de cause, il est fortement dconseill dutiliser des extensions par trop
spciques une plateforme. Des chiers source C, toto.c, et C++, toto.C, valides
sur une plateforme Unix vont provoquer des collisions de noms en cas de migration
vers un systme qui ne distingue pas la casse des noms de chiers (VMS, MS-DOS) !
[ 1.3 ] Le compilateur GNU est un compilateur mixte C/C++. On pourra compiler des
sources C++ en utilisant lune ou lautre des commandes gcc ou g++.
Pour ldition de liens, par contre, linvocation de g++ permet de congurer correctement toutes les options ncessaires au linker. En particulier, lorsquon utilise
des packages spciques C++, iostreams, nombres complexes, etc., les librairies seront

[ 1.1 ]

(4)

lheure actuelle tous les compilateurs ne supportent pas encore ces fonctionnalits.

1 - Introduction

invoques implicitement. Avec la commande gcc, seule la librairie standard C est


mise en oeuvre.

Introduction au langage C++

Objets et classes
Le concept objet est lessence mme de la programmation oriente objets5. La vision
du monde (informatique) qua une application se ramne la construction et la manipulation dun ensemble dobjets. Partant du principe que tout, dans lunivers, peut
tre reprsent par un ou des objets6 la partie principale dune application objets se
rsoud : construire "lobjet application" (lequel met en oeuvre autant de sous-objets
que ncessaire) et le faire vivre jusqu la n du programme.

2.1

L'objet logiciel
Un objet est une entit informatique, autonome et modulaire, disposant de son propre
code de manipulation, les mthodes, et enfermant ses propres donnes, les attributs.
On parle galement de fonctions membres et donnes membres.
Les mthodes traduisent le : "que sait faire lobjet ?", les attributs traduisent le : "que
connait lobjet ?".
Lanalogie avec un objet concret, par exemple un tlviseur, est immdiate : un
tlviseur dispose de mthodes (boutons de face avant) permettant de lutiliser, "mise
en marche", "changement de canal", "rglage de volume", etc., et comporte en interne
les attributs (composants lectroniques) ncessaires son fonctionnement.
On remarquera, et cest galement vrai pour lobjet informatique, que lutilisation
dun objet suppose de savoir sen servir mais ne ncessite pas la connaissance intime
de son fonctionnement interne.
De plus, dans le cadre dun dveloppement (informatique ou industriel), la priorit
est donne la spcication des mthodes, ce que lobjet "doit pouvoir faire", sans
forcment savoir a priori comment le faire. Limplmentation interne sera ensuite la
mise en oeuvre des spcications.

2.2

Classes et instances
Dans la terminologie objets, on appelle classe la famille, le type, la nature de lobjet.
On appelle instance une occurence, une ralisation dun objet de classe donne.
"Mon tlviseur" (instance) nest pas le mme objet physique que celui (autre instance) de mon voisin. Et ceci mme si les deux appareils sont exactement du mme
modle (mme classe).
En programmation traditionnelle, ces notions existent sous les appellations type et

(5)
(6)

On sen doutait un peu !


Seul Dieu chappe sans doute cette rgle

Introduction au langage C++

variable. Ainsi, en Fortran :


real
x, y
integer n
on dclare deux instances, nommes x et y, de la classe numrique rel et une
instance, nomme n, de la classe numrique entier.

2.3

Mcanismes de spci cation


e
e
A titre dexemple (minimaliste) on dsire, dans le cadre dune application gomtrique, disposer dobjets Cercle.
Lutilisateur potentiel de lobjet va spcier les mthodes requises (ces mthodes sont
des fonctions informatiques classiques, avec nom, arguments dappel, type retour) :
une mthode Move, appele avec deux arguments rels, permet de dplacer
lobjet en relatif.
une mthode Zoom, appele avec un argument rel, permet dappliquer un
facteur dchelle lobjet.
une mthode Area, sans arguments, retourne la surface de lobjet.
A partir de ces spcications, le dveloppeur dobjet va choisir dimplmenter trois
attributs numriques, la position X du centre et le rayon du cercle.
NB : dans une bonne conception objet, tout attribut doit pouvoir tre justi relativement la mise en oeuvre dune ou plusieurs mthodes. Cest pourquoi cette tape
seffectue dans un deuxime temps.

2.4

Interface de classe
En C++, une interface de classe est une description symbolique de lobjet, destine au
compilateur. A ce titre, elle comporte la dnition publique de la classe, mthodes utilisateurs, et limplmentation prive des attributs (et/ou mthodes internes) ncessaires
au fonctionnement.
Traditionnellement, une interface est crite dans un chier header spar, portant le
nom de la classe.

2 - Objets et classes

Par exemple, ici, cercle.h


class Cercle
{
// Methodes utilisateurs
public:
void
Move(float deltax, float deltay);
void
Zoom(float scale);
float
Area();
// Attributs implantation
private:
float
cX, cY;
// Position centre
float
cR;
// Rayon
};
NB : cet exemple est volontairement rduit son strict minimum et va tre complt
au cours de ce chapitre.

2.5

Instanciations
Le programme application dsirant utiliser une classe doit inclure dans son code
source le chier interface, puis dclarer une ou plusieurs instances de cette classe et
les manipuler :
int main()
{
float S;
Cercle toto;

// Variable locale
// Instance de cercle

/* Deplace toto */
toto.Move(150, 0);
/* Affiche sa surface */
S = toto.Area();
printf("Surface = %f\n", S);
/* Zoom et reaffiche */
toto.Zoom(1.5);
S = toto.Area();
printf("Surface apres zoom = %f\n", S);
return 0;
}
On remarquera la syntaxe des appels de mthodes. Le nom de la mthode est insufsant par lui-mme, il faut spcier lobjet auquel on veut lappliquer, i.e. le nom
de linstance.

Introduction au langage C++

On pourrait vouloir manipuler deux cercles :


Cercle c1, c2;
c1.Zoom(3);
c2.Zoom(0.5);
float S1, S2;
S1 = c1.Area();
S2 = c2.Area();
auquel cas la surface de c1 na aucune raison dtre la mme que la surface de c2.
Cest le travail du compilateur dassurer que les mthodes seront appeles sur les
objets ad-hoc.
NB : contrairement C, C++ autorise les dclarations, scalaires ou objets, nimporte
quel endroit du code et non plus uniquement en en-tte de fonction. Cf. ci-dessus la
dclaration de S1 et S2.

2.6

Implmentation de classe
e
Lexemple ci-dessus montre que lon est capable dcrire du code source utilisant des
objets sans se proccuper de limplantation. (On peut savoir utiliser un tlviseur
sans tre lectronicien, sans savoir le construire !) Linterface et la connaissance de ce
que font les mthodes est sufsante.
Pratiquement, il faudra tout de mme assurer limplmentation de lobjet et lcriture
effective du code des mthodes. Traditionnellement, un objet est encod dans un
chier source portant le nom de la classe.
Par exemple, ici, cercle.cxx
/* Deplacement */
void Cercle::Move(float deltax, float deltay)
{
cX += deltax;
cY += deltay;
}
/* Echelle */
void Cercle::Zoom(float scale)
{
cR *= scale;
}
/* Surface */
float Cercle::Area()
{
return 3.14159 * cR * cR;
}
Lexemple est sufsament simpliste7 pour que la programmation nappelle pas de
(7)

10

Pour ne pas dire : bbte !

2 - Objets et classes

11

commentaire particulier.
mthode :

On notera simplement la syntaxe de dnition dune

NomClasse::NomMethode
Dans le code des mthodes, les attributs sont invoqus sous leur nom symbolique,
tel que dni dans la dclaration dinterface. En pratique, chaque instance dune
classe dispose de son propre jeu dattributs et cest au compilateur C++ de faire en
sorte que les donnes convenables soient manipules.
Ainsi, lorsquun code utilisateur manipule plusieurs instances :
Cercle c1, c2;
c1.Zoom(3.0);
c2.Zoom(0.5);
cest bien lattribut cR de linstance c1 qui sera multipli par 3, et lattribut cR de
linstance c2 qui sera divis par 2.
Le code dimplmentation dun objet est donc une programmation gnrique, se
rfrant "lobjet courant pour lappel".
Cest MAGIQUE !
Ou presque, voir le paragraphe A.3 page 45 en annexe.

2.7

Visibilits
e
On aura remarqu, dans la description dune interface de classe, paragraphe 2.4
page 8, la prsente de deux attributs de visibilit, public et private.
Pour des raisons lies limplmentation des compilateurs C++, une interface de
classe doit comporter la description exhaustive de lobjet, mthodes publiques mais
aussi tous les attributs et mthodes prives. Les attributs de visibilit ont pour rle
de signaler au compilateur les invocations autorises ou interdites :
le code interne lobjet, i.e. la programmation des mthodes de classe, a accs
tout, public ou priv !
le code externe, en gnral le code utilisateur, na accs quaux invocations
publiques. Laccs explicite un attribut priv nest pas autoris :
Cercle c1;
c1.Zoom(2.0);
c1.cR *= 2.0;

// Ok, methode publique


// Erreur en compilation !

Ce mcanisme, appel aussi encapsulation des donnes, est l pour obliger le code
utilisateur passer par les mthodes prvues par le concepteur. Ce nest pas une
contrainte mais plutt une scurit.
Dune part, le concepteur de lobjet qui assure la maintenance des chiers relatifs
lobjet, chier interface machin.h et chier source machin.cxx, reste libre de
modier limplmentation interne, de changer des noms dattributs, den ajouter,
den supprimer. Le code utilisateur reste valide ( une recompilation prs) tant que
linterface publique est stable (et, en principe, elle doit ltre puisquelle rsulte dune
spcication initiale).
Dautre part, et cest souvent le cas en pratique, un objet important exige une cer11

Introduction au langage C++

taine cohrence sur ses attributs. Parfois, une simple modication de valeur peut
ncessiter un recalcul dautres attributs. En obligeant le code utilisateur passer par
des "guichets", le concepteur est assur de pouvoir maintenir un objet consistant.
Par dfaut, dans une classe C++, tout est priv. Ces attributs sont placer aux
endroits ad-hoc de la dnition de classe, on peut les alterner, la visibilit est valide
pour "tout ce qui suit" jusquau prochain attribut.
NB : dautres mcanismes de protection existent, voir le chapitre 5 page 29.

2.8

Cycle de vie
Un objet logiciel a une vie et une mort8.
Le langage offre la possibilit dimplmenter deux mthodes de classe particulires,
le constructeur et le destructeur. La compilation assure que le constructeur, sil est
spci, sera appel lors de la cration dune instance et avant la toute premire utilisation, et que le destructeur, sil est spci, sera appel juste avant la destruction
physique de lobjet.
Ainsi, dans lexemple ci-dessus, on ne sait pas, lorsquon instancie un objet cercle,
ce que valent ses attributs. Le rle typique dun constructeur est dassurer une
initialisation par dfaut qui soit convenable.
Ces mthodes se dclarent sans type et avec un nom impos, NomClasse pour un
constructeur, ~NomClasse pour un destructeur.
Linterface de classe (chier cercle.h) deviendrait :
class Cercle
{
// Constructeur, destructeur
public:
Cercle();
Cercle();
// Methodes utilisateurs
public:
void
Move(float deltax, float deltay);
etc...

(8)

12

On en est tous l !

2 - Objets et classes

13

et limplmentation (chier cercle.cxx) comporterait :


/* Constructeur */
Cercle::Cercle()
{
cX = cY = 0.0;
cR = 1.0;
}

// A lorigine par defaut


// Rayon unite

/* Destructeur */
Cercle:: Cercle()
{
// Rien a faire de special !
}
Le mcanisme dinitialisation par constructeur est, en pratique, indispensable, cest
le moyen dassurer que tout objet commence sa vie avec une conguration plausible.
Dans un environnement objets bien conu, les mcanismes dinstanciation doivent
toujours produire des objets utilisables en ltat et le code utilisateur ne devrait avoir
recongurer que lorsque les valeurs par dfaut sont inacceptables.
Un autre mcanisme trs intressant est la possibilit qua le concepteur dobjet de
proposer diffrents constructeurs de classe. Par exemple, on pourrait proposer un
constructeur de cercles prenant une valeur initiale de rayon en argument.
Interface de classe :
class Cercle
{
// Constructeurs, destructeur
public:
Cercle();
Cercle(float rayon);
Cercle();
...
Implmentation :
/* Constructeur par defaut */
Cercle::Cercle()
{
cX = cY = 0.0;
// A lorigine par defaut
cR = 1.0;
// Rayon unite
}
/* Constructeur avec rayon */
Cercle::Cercle(float rayon)
{
cX = cY = 0.0;
// A lorigine par defaut
cR = rayon;
// Rayon utilisateur
}
Le code utilisateur pourra ensuite instancier des cercles en spciant tel ou tel con-

13

Introduction au langage C++

structeur :
Cercle c1;

// Construction par defaut, rayon 1.0

Cercle c2(5.5); // Construction avec argument rayon


Lappel correct de tel ou tel constructeur sera effectu par le compilateur C++, en
fonction du contexte de dclaration et ce, de manire transparente pour le code
utilisateur. On nappelle jamais explicitement un constructeur ou un destructeur :
Cercle c1;

// Le constructeur est appele ici

c1.Cercle();

// Non !

Limplantation dun destructeur (qui lui, ne peut tre multiple ni comporter darguments) est moins frquente. Dans lexemple ci-dessus elle est inutile puisquon ne
fait rien. Elle se justie lorsquun objet ncessite des tches de "mnage" lors de sa
destruction : fermeture dun chier qui aurait t ouvert par lobjet, libration dune
zone mmoire alloue, etc. Comme le destructeur est galement appel automatiquement, on est ainsi sr de ne rien oublier.

2.9

Gestion des objets


Le langage C dispose de trois mcanismes de dure de vie des donnes :
statique ou global : la dure de vie des donnes est celle du programme.
automatique ou local : la dure de vie est limite un contexte { ... } de
programme.
dynamique : les donnes sont cres (malloc()) et dtruites explicitement
(free()), leur manipulation seffectue via un pointeur.
Les mmes mcanismes sont utilisables en C++, pour les variables classiques et, a
fortiori, pour des objets.

2.9.1 Gestion directe


Cercle c1;
void toto()
{
Cercle c2;
...
if( ... ) {
Cercle c3;
...
...
}
...
}

// Global, statique

// Local
// Nouveau contexte
// Local

// Fin de contexte, c3 est detruit


// Fin de fonction, c2 est detruit

Un objet est cr (i.e. la mmoire est alloue puis le constructeur est appel) lors
de sa dclaration. Un objet global (c1 dans lexemple ci-dessus) est construit au
lancement du programme.
14

2 - Objets et classes

15

Un objet est dtruit (i.e. le destructeur est appel puis la mmoire est libre) lorsque
quil devient hors de porte, lorsque lon quitte le contexte qui le dclarait. Un objet
global est dtruit en n de programme.
NB : on voit ici toute la puissance apporte par la possibilit de programmer un
destructeur lorsquun objet ncessite des tches de "mnage", libration de ressources
et autres : un simple return, nimporte o dans une fonction, fera quitter le contexte et invoquera implicitement toutes les oprations de nettoyage sur tous les objets
locaux existants.

2.9.2 Gestion indirecte


La gestion de variables par pointeurs, familire aux programmeurs C, seffectue de
manire identique en C++ :
dclaration dun pointeur typ
allocation dune donne
manipulation classique via loprateur -> ou loprateur dindirection *, cf.
exemple ci-dessous
enn, destruction explicite
float S;
Cercle *pc;

// Pointeur de Cercle

pc = new Cercle;

// Allocation

pc->Zoom(3.5);

// Appel methode

(*pc).Zoom(5.0);

// Autre syntaxe possible

S = pc->Area();
...
delete pc;

// Appel methode
// Liberation

La diffrence porte sur la mise en oeuvre des allocations et librations. En C++ on


nutilise JAMAIS les appels malloc() et free() !
Loprateur new effectue lallocation mmoire pour lobjet ET lappel du constructeur.
Loprateur delete effectue lappel du destructeur puis la libration mmoire. Dans
le cas de constructeurs multiples, cest la syntaxe de cration qui lve les ambiguts :
Cercle *pc1, *pc2;
*pc1 = new Cercle;
*pc2 = new Cercle(5.0);

// Constructeur par defaut


// Constructeur "avec rayon"

A noter que ces oprateurs sont galement utilisables sur des variables simples et

15

Introduction au langage C++

existent sous une forme "tableaux" :


int
*pi;
float *pf;
pi = new int;
pf = new float[50];
...
delete pi;
delete[] pf;

// Allocation scalaire
// Allocation tableau
// Liberation scalaire
// Liberation tableau

Remarquer la notation delete[] pour dtruire un tableau. On peut manipuler


des tableaux de scalaires mais aussi des tableaux dobjets. Dans le cas de tableaux
dobjets, les appels des constructeurs et destructeurs sont effectus sur tous les
lments du tableau.
NB : tout comme en C, un pointeur dclar dans une fonction est dtruit (en tant
que variable pointeur) lorsquon quitte le contexte, mais la mmoire ventuellement
associe nest pas libre !
En C++, en cas de cration dobjets par new, on devra assurer la destruction explicite
par delete, un moment ou un autre de lexcution : destruction avant de quitter
le contexte, ou sauvegarde du pointeur avant retour pour destruction ultrieure.

16

3
3.1

Appels et surcharges
Mthodes de classes
e
Contrairement aux autres langages de programmation o la porte dun identicateur est unique pour une application donne, une et une seule fonction ou routine
peut sappeler toto pour tout un programme, en C++ la porte dun identicateur
dpend du contexte dappel.
Imaginons un autre type dobjet gomtrique, le rectangle, qui disposerait des mmes
mthodes que le cercle :
class Rectangle
{
// Methodes utilisateurs
public:
void
Move(float deltax, float deltay);
void
Zoom(float scale);
float
Area();
etc.
Dans le code utilisateur suivant :
Cercle c1;
Rectangle r1;
c1.Zoom(3.5);
r1.Zoom(4.0);
le compilateur lve les ambiguts de nom selon le contexte dappel, lcriture
c1.Zoom dsigne la mthode Zoom de la classe Cercle, applique lobjet c1, alors
que r1.Zoom dsigne la mthode Zoom de la classe Rectangle, applique r1.
La syntaxe dimplmentation des mthodes de classes (cf. 2.6 page 10), est dailleurs
parlante, les points dentre sont Cercle::Zoom ou Rectangle::Zoom.

3.2

Surcharges de slection
e
(Lappelation surcharge de slection est propre ce guide, voir la note [ 3.1 ] page 19
en n de chapitre.)
Un second mcanisme, trs puissant, permet dimplanter dans une mme classe
plusieurs mthodes de mme nom, ds linstant que la liste darguments dappel,
nombre et nature, peut lever lambigut.

17

Introduction au langage C++

Par exemple :
class Machin
{
void Calcul(int);
// Interface 1 entier, Ci
void Calcul(int, int);
// Interface 2 entiers, Cii
void Calcul(float, float); // Interface 2 reels, Cff
...
Lors de lutilisation, cest le compilateur qui va choisir lappel correct en fonction du
contexte :
int n;
float x, y;
Machin M;
M.Calcul(n,
M.Calcul(x,
M.Calcul(x,
M.Calcul(x,

3);
y);
1);
n);

//
//
//
//

Appel
Appel
Appel
Appel

Cii
Cff
Cff, conversion 1 -> 1.0
Cff avec cast (float)n

M.Calcul(5);
// Appel Ci
M.Calcul(x);
// ERREUR !
M.Calcul((int)x); // Cast explicite, appel Ci
Contrairement dautres langages o la mme fonction peut exister sous tout un
tas de noms diffrents selon les types darguments (voir en Fortran les sin, dsin,
imod, jmod, amod, etc.), en C++, et sous rserve davoir prvu diffrentes congurations opratoires, on invoque tel ou tel traitement sous une appelation fonctionnelle
gnrique en laissant au compilateur le soin de traiter les dtails dintendance !
Ce mcanisme a dj t utilis, sans explications, dans le cas du cercle et ses deux
constructeurs, Cercle() et Cercle(float). Cest exactement une mise en oeuvre
de ce mcanisme de slection.

3.3

Arguments optionnels
Un dernier mcanisme permet de dclarer des mthodes avec des arguments optionnels et valeurs par dfaut sils ne sont pas fournis lors de lappel.
Dans lexemple du cercle, on aurait pu nimplanter quun seul constructeur, celui avec
un argument rayon optionnel. Si largument nest pas fourni lappel, le compilateur
utilisera la valeur par dfaut.
Linterface est la suivante :
class Cercle
{
Cercle(float rayon = 1.0);
...

18

3 - Appels et surcharges

19

et limplmentation ne comporte quun constructeur :


/* Constructeur avec rayon */
Cercle::Cercle(float rayon)
{
cX = cY = 0.0;
// A lorigine par defaut
cR = rayon;
// Rayon utilisateur
}
A lutilisation, le compilateur compltera lappel automatiquement :
Cercle c1(5.0);
Cercle c2;

// Rayon initial 5.0 explicite


// c2(1.0) implicite

Dans cet exemple, lintrt est une simplication de limplmentation, une seule
mthode au lieu de deux.
Un autre type dutilisation, trs utile en pratique, concerne lvolution de dveloppements C++. Supposons quun jour la librairie dobjets gomtriques, Cercle,
Rectangle, etc., volue vers une version 3D.
La classe Cercle devra tre revue, avec trois attributs coordonnes du centre, cX,
cY, cZ. La mthode effectuant un dplacement relatif deviendra :
void Move(float dx, float dy, float dz);
Doit-on remettre hauteur toutes les applications 2D existantes ? Pas ncessairement,
on peut dcider que les anciennes applications 2D travailleront dans le plan Z = 0;
il suft alors dimplanter linterface ainsi :
void Move(float dx, float dy, float dz = 0.0);
pour que tous les codes existants utilisant lancienne interface, deux arguments :
Cercle c1;
float dx, dy;
...
c1.Move(dx, dy);
restent recompilables en ltat !

3.4
[ 3.1 ]

Notes commentaires
Il existe une grosse ambigut lexicale, dans la terminologie franaise C++. La
terminologie anglo-saxonne utilise deux vocables : overstrike, traduit en franais par
surcharge, et overload, traduit en franais par ... surcharge !
Sans vouloir relancer les ternelles polmiques sur la dfense de la langue franaise
(dont je suis un fervent partisan), il nest pas acceptable de laisser en ltat de
telles dgradations smantiques. Cest pourquoi ce guide a choisi, arbitrairement,
dutiliser lappelation surcharge de slection pour la surcharge overstrike, prsente ici
et consistant dnir des homonymes parmi lesquels le compilateur fera son choix.
La surcharge overload, prsente plus loin dans ce manuel, consistant rednir par
hritage une mthode dune classe anctre, sera appele surcharge fonctionnelle.

19

Introduction au langage C++

20

Hritage
e
Aprs le concept de classe le concept dhritage est la seconde grande notion en
programmation oriente objets.
Il sagit, dans le cadre de dveloppements importants, de construire des ensembles
de classes, selon une structure arborescente qui rappelle les mcanismes de taxinomie
quon trouve en sciences de la nature : les chevaux sont des onguls qui sont des
mammifres qui sont des vertbrs qui sont des animaux. A chaque niveau, la classe
apporte ses spcicits un hritage commun, on parlera de ses classes anctres.
Pratiquement, la conception informatique dune arborescence dobjets est loin dtre
un exercice trivial. La rexion et lintuition jouent un rle important mais on chappe
rarement un processus itratif consistant dtecter, en cours de dveloppement,
un oubli de conception.
Cela na rien de tragique, cest mme le lot commun du concepteur, et on arrive
rectier une conception relativement facilement. Un cas de gure trs frquent est la
dtection, aprs coup, dun anctre commun :

4.1

Comportement gnrique
e e
Dans le cadre de la conception dune petite librairie de gures gomtriques,
reprenons lexemple du Cercle et ajoutons une classe Rectangle, disposant des
mmes mthodes application, savoir Move, Zoom et Area.
Limplmentation interne devra, elle, comporter deux attributs de dimensions, largeur
et hauteur, la place du rayon.
La programmation nave, analogique, conduit dnir linterface suivante (chier
rectangle.h) :
class Rectangle
{
// Methodes utilisateurs
public:
void
Move(float deltax, float deltay);
void
Zoom(float scale);
float
Area();
// Attributs implantation
private:
float
cX, cY;
// Position centre
float
cL, cH;
// Largeur, hauteur
};

21

Introduction au langage C++

et limplmentation suivante (chier rectangle.cxx) :


/* Deplacement */
void Rectangle::Move(float deltax, float deltay)
{
cX += deltax;
cY += deltay;
}
/* Echelle */
void Rectangle::Zoom(float scale)
{
cL *= scale;
cH *= scale;
}
/* Surface */
float Rectangle::Area()
{
return cL * cH;
}

4.2

(On ajouterait un ou plusieurs constructeurs pour assurer linitialisation des attributs.)


La chose importante remarquer, si lon compare les classes Cercle et Rectangle,
est que le support relatif la position est strictement le mme : deux attributs cX,
cY, pour la position cartsienne, implantation identique de la mthode Move.
Une rgle incontournable, en programmation objets comme en programmation classique, voulant quon nait jamais de code identique en plusieurs exemplaires (programmer nest pas copier/coller), on se trouve devant un cas de dtection a posteriori
danctre commun9 !
Un tel oubli est rarement une fatalit mais rsulte plutt dun manque de vigilance,
les rponses sont souvent enfouies dans le vocabulaire de la spcication. Cest le
cas ici, lintroduction de ce paragraphe parle de la conception dune petite librairie
de gures gomtriques (sic).
De fait, avant de sattacher des notions prcises comme cercle ou rectangle (ou
triangle, trapze, etc.), il est utile de sintresser ce quest une gure gomtrique.

Classe de base
On construira une classe, disposant de tout le support gomtrique souhait (ici 2D),
sans prjuger de laspect exact de cette gure. On pourra imaginer un constructeur
permettant de xer la position initiale.

(9)

22

Ou, en langue vulgaire : "Enfer ! on a du oublier quelquechose !"

4 - Hritage
e

23

Interface (chier figure.h) :


class Figure
{
public:
// Constructeurs
Figure();
Figure(float xpos, float ypos);
// Methode(s) utilisateurs
void
Move(float deltax, float deltay);
// Attributs implantation
private:
float
cX, cY;
// Position
};
Implmentation (chier figure.cxx) :
/* Constructeur par defaut */
Figure::Figure()
{
cX = cY = 0.0;
}
/* Constructeur avec position initiale */
Figure::Figure(float xpos, float ypos)
{
cX = xpos;
cY = ypos;
}
/* Deplacement */
void Figure::Move(float deltax, float deltay)
{
cX += deltax;
cY += deltay;
}

4.3

Spcialisation par drivation


e
e
On construira ensuite des classes drives, hritant de tout le support position et
ajoutant simplement leur spcicits de forme.

23

Introduction au langage C++

Ainsi, linterface cercle (chier cercle.h) devient :


class Cercle : public Figure
// Declaration dheritage
{
public:
// Constructeurs
Cercle();
Cercle(float xpos, float ypos, float rayon = 1.0);
// Methodes utilisateurs
void
Zoom(float scale);
float
Area();
// Attributs implantation
private:
float
cR;
// Rayon
};
On remarque que cette nouvelle classe ne comporte plus rien qui soit relatif la
position gomtrique, le seul attribut est le rayon.
Dans la dclaration dhritage gure un attribut de visibilit, ici public. Par dfaut,
en C++,
class Cercle : Figure
{
...
le mcanisme dhritage "privatise" tout ce qui vient des anctres, mme ce qui tait
public dans la classe anctre. Cest une scurit, C++ pousse la paranoa trs loin.
Par contre, le fait de dclarer lhritage public ne rend pas public ce qui est private dans la classe anctre, mais se borne conserver les visibilits en ltat. Il sagit
dune combinaison logique des visibilits, pas dune rednition.
La terminologie objets utilise les mots superclasse
et sousclasse . Comme le mcanisme est arborescent, ici Figure est LA superclasse de
Cercle, alors que Cercle est UNE sousclasse de Figure (Rectangle pourra aussi
tre une autre sousclasse de Figure).
Limplmentation (chier cercle.cxx) devient :
/* Constructeur par defaut */
Cercle::Cercle()
: Figure()
{
cR = 1.0;
// Rayon par defaut
}
/* Constructeur avec position et rayon */
Cercle::Cercle(float xpos, float ypos, float rayon)
: Figure(xpos, ypos)
{
cR = rayon; // Rayon specifie
}
...

24

4 - Hritage
e

4.4

25

(Les autres mthodes, Zoom et Area, sont strictement identiques la premire


implmentation, voir 2.6 page 10.)
On remarquera la syntaxe particulire des constructions. La rfrence au constructeur
de la superclasse gure avant laccolade ouvrante du corps de fonction.
La notation est parlante : puisquun Cercle est, au minimum, une Figure, plus
des spcicits, la construction dun Cercle consiste dabord construire la partie
Figure, ensuite congurer les spcicits. La construction est donc effectue du
haut vers le bas.
Enn, dans le cas de constructeurs multiples, chaque constructeur de sousclasse peut
choisir celui des constructeurs superclasse utiliser, en "routant" si besoin est certains
des arguments. Cest le cas ici, pour les arguments de position initiale.
NB : lorsque les classes implmentent des destructeurs, optionnels, aucun mcanisme
de chanage nest spcier. Cest le compilateur seul qui assurera lappel des destructeurs ventuels et dans lordre inverse de la construction, sousclasses avant
superclasses.
NB : la compilation correcte dune classe drive suppose que le compilateur ait la
connaissance de la classe et tous ses anctres. On doit donc inclure tous les chiers
interface ncessaires ! Ceci peut tre fait, au choix, dans les chiers sources ou dans
les chiers headers; dans le cas dinclusions dans les headers, il conviendra de se
protger des inclusions multiples, frquentes en C++. Les techniques sont les mmes
quen C, voir en annexe le paragraphe A.5 page 47.

Exploitation de l'hritage
e
Si lhritage est pris en compte explicitement, pour le travail de dveloppements
dobjets, il est par contre transparent au code utilisateur :
Cercle c1;
c1.Zoom(3.5);
c1.Move(10, 2);

// Methode propre a la classe


// Methode heritee

Si lon compare aux exemples 2.5 page 9, on voit que la mise en oeuvre est inchange. Bien que la classe Cercle ne dispose pas explicitement dune mthode
Move, le simple fait quun cercle soit dabord une gure fait que Cercle hrite de
la fonctionnalit Figure::Move.
Autrement dit, une sousclasse sait faire, au minimum, tout ce que savent faire ses
anctres. On dispose l dun mcanisme remarquablement puissant et concis (au prix
de compilateurs remarquablement complexes10).
De la mme manire, on pourra driver de Figure, des sousclasses Rectangle,
Triangle, etc., toutes exploitant les mcanismes de position qui sont, on le rappelle,
crits une seule fois dans un seul chier source, figure.cxx.
Cette architecture se prte merveille aux volutions dun dveloppement : Lorsque
lon souhaitera, un jour, ajouter ce petit environnement exemple du code graphique,
il faudra implanter dans chaque classe une mthode de dessin spcique, un Draw()
pour un cercle est diffrent dun Draw() pour un rectangle. Par contre, tout le
code support dattributs graphiques (couleur, paisseur de trait, type de trait, plein,
(10)

Tant pis pour eux ! Quils bossent !

25

Introduction au langage C++

pointill, etc.) pourra tre implant, une fois et une seule, dans la classe Figure.
Enn, ce mcanisme peut se rpter indniment. Toute sousclasse est utilisable
comme superclasse pour une drivation. Dans notre exemple il aurait t plus
rigoureux (mathmatiquement parlant) de driver de Figure une classe Ellipse
deux attributs, cA et cB, puis de driver de celle-ci la classe Cercle. Cette dernire
se bornerait assurer lgalit des demi-axes la construction, cA = cB = R.
Mme remarque pour une drivation de Rectangle en Carre.

4.5

Accs privilgis
e
e e
Les mcanismes de protection daccs (cf 2.7 page 11), grs en tout ou rien par les
attributs de visibilit public ou private, manquent un peu de souplesse.
En particulier, il peut arriver que pour lcriture dune classe drive, on ait besoin
daccder des attributs ou mthodes non publics de la superclasse (ou dune anctre
de la superclasse).
La rvision C++ de 1992 a introduit un troisime attribut de visibilit, protected,
qui est un intermdiaire entre les deux autres et qui rend accessible tout code dune
mthode de classe drive tout en verrouillant laccs depuis du code extrieur.
On pourra ainsi moduler assez nement ce qui est en accs public, dans une classe,
ce qui est strictement priv, ce qui nest pas public mais utile certaines classes
drives. Voir note [ 4.1 ] page 27 en n de chapitre.

4.6

Objets composites
Un objet peut tout fait contenir, parmi ses attributs, dautres objets. Par exemple,
on pourrait imaginer une gure composite comportant deux cercles concentriques :
class Machin : public Figure
{
public:
Machin(float xpos, float ypos);
private:
Cercle aC1;
Cercle aC2;
...
};
Par dfaut, la construction dun objet composite, tous les sous-objets sont construits
avec leur constructeur par dfaut (i.e. sans arguments) sil existe :
Machin::Machin(float xpos, float ypos)
: Figure(xpos, ypos)
{
...
}
Dans cet exemple, les instances de cercle aC1 et aC2 sont initialiss via le constructeur

26

4 - Hritage
e

27

Cercle().
On peut spcier un constructeur diffrent, par exemple avec des arguments, avant
le corps de fonction :
Machin::Machin(float xpos, float ypos)
: Figure(xpos, ypos),
aC1(xpos, ypos, 2.0), aC2(xpos, ypos, 0.5)
{
...
}
On notera la diffrence dcriture : le constructeur superclasse est invoqu par son
nom gnrique, Figure, alors que les constructions des attributs, ou objets membres,
utilisent le nom spcique des instances.
Une alternative consiste laisser les constructions par dfaut puis congurer les
sous-objets explicitement :
Machin::Machin(float xpos, float ypos)
: Figure(xpos, ypos)
{
aC1.Move(xpos, ypos);
aC1.Zoom(2.0);
aC2.Move(xpos, ypos);
aC2.Zoom(0.5);
}
Pour les destructeurs, on na strictement rien faire, le compilateur C++ gnre le
code ncessaire pour que les destructeurs des sous-objets soient invoqus lors de la
destruction de lobjet principal.

4.7
[ 4.1 ]

Notes commentaires
En rgle gnrale, au cours dun dveloppement, il est conseill de jouer la "scurit
maximale" (le mode par dfaut, en C++) en dclarant private tout ce qui ne
concerne pas strictement linterface publique telle que spcie.
Par la suite, on modiera au cas par cas les visibilits en fonction des besoins de
telle ou telle classe drive et en choisissant le meilleur mcanisme (voir galement
le paragraphe 5.3 page 32).
Surtout pour des dveloppements importants, cest toujours une faute de dclarer
a priori tout public, uniquement pour "ne plus avoir sembter ensuite avec les
protections" !

27

Introduction au langage C++

28

Accs, protections
e
Le bug est la plaie de linformatique ! Les causes de bugs11 sont multiples, proportionnelles aux capacits dimagination de ltre humain.
Cela dit, une des causes majeures est due aux effets de bords et pollutions de
donnes. Laphorisme sous-jacent est que moins on touche aux donnes, dans un
programme, moins on risque de les modier par inadvertance.
Le niveau de abilit dun langage de programmation est directement li aux capacits du-dit langage cacher le plus de choses possibles et tous les langages
invents depuis quarante ans ont cherch dvelopper ces mcanismes, ce qui fait
que le classement du moins able au plus able suit peu prs lordre historique :
Fortran, C, Pascal, C-Ansi, C++

5.1

Passages d'arguments
Comme C, C++ passe les arguments dappels par valeur (i.e. copie locale au code
appel de la valeur dappel). Si largument dappel est une variable, celle-ci nest
donc jamais modie dans le contexte appelant, quelles que soient les avanies que
peut subir largument dans le code appel.
Il existe toujours des cas de programmation o lon a besoin de passer une variable
de retour, pratiquement ds quun traitement doit fournir plus dun rsultat et que
donc la fonction informatique, avec sa valeur de retour unique, nest pas sufsante.
Le langage C, disposant de pointeurs de donnes, rsoud ce problme en utilisant
des adresses explicites :
void toto(int* arg)
{
*arg = 10;
}
...
/* Appel */
int var;
toto(&var);
C++ dispose des mmes mcanismes mais galement, et cest nouveau par rapport
C, dun passage par rfrence, analogue ce que fait Fortran en standard, utilisant la

(11)

Dsol pour les puristes, je ne sais pas me rsoudre crire : bogue comme le voudrait notre Druon
national...

29

Introduction au langage C++

syntaxe suivante :
void toto(int& arg)
{
arg = 10;
// Et non pas :
}

*arg !

...
/* Appel */
int var;
toto(var);

// Et non pas : &var !

Leffet est analogue au passage explicite dadresses, mais on est affranchi des critures
dindirection, l encore cest le compilateur qui se dbrouille.
La seule obligation se situe au niveau du prototype de lappel. La coexistence dun
double mcanisme, par valeur ou par rfrence, suppose une dclaration explicite,
utilisant le symbole & :
void toto(int val, int& ref);
NB : les Pascaliennes et Pascaliens reconnatront :
procedure toto(val : integer, var ref : integer);

Attention : une donne passe par rfrence nest pas un pointeur sur donne mais
se manipule, syntaxiquement, comme une donne locale :
void toto(Cercle& a, Cercle* b)
{
a.Zoom(10);
// Invocation directe
b->Zoom(10);
// Invocation via pointeur
}
// Appel
Cercle c1;
Cercle c2;
toto(c1, &c2);
Mme si, au nal, le rsultat est le mme, la syntaxe est diffrente.

5.2

Protection en criture
e
Un mcanisme de protection, introduit dans le C-Ansi, utilise un qualieur const
pour indiquer que quelque chose est consultable mais ne peut tre modi.

30

5 - Acc`s, protections
e

31

Par exemple :
void toto(int *p1, const int *p2)
{
int a;
a =
a =
*p1
*p2

*p1;
*p2;
= 0;
= 0;

//
//
//
//

Correct
Correct
Correct
ERREUR !

En dveloppement, on devrait toujours utiliser ce mcanisme chaque fois que cest


possible. Cela permet dliminer, ds la phase de compilation, un certain nombre
dcritures errones ou suspectes.
C++ a tendu ce mcanisme aux passages par rfrences. On peut dclarer des
fonctions ainsi :
void toto(const int& arg);
Pour des arguments scalaires, cest sans aucun intrt, si lon veut passer une donne
non modiable, on la passe par valeur, cest le dfaut en C, C++.
Par contre, dans le cas darguments objets, seuls les passages par pointeur ou par
rfrence sont utilisables, avec toutes les consquences, bonnes ou mauvaises, que
cela implique ! On pourra alors scuriser du code en utilisant des pointeurs ou des
rfrences const, non modiables par le code appel.
Par exemple :
void toto(const Cercle& arg)
{
...
Le dfaut de ce mcanisme est que, part utiliser largument tel quel pour un autre
appel, en gnral le code appel ne pourra rien faire avec lobjet en question. Le
compilateur, ne voulant pas prendre le risque de modier quoi que ce soit de lobjet
interdira toute invocation de mthode !
Sauf ...
Sauf si lobjet a t soigneusement conu. Et cest le rle du concepteur de lobjet de
distinguer les mthodes qui peuvent modier lobjet de celles qui sont sres.
Dans lexemple de la classe Cercle, la mthode Zoom modie lattribut cR, le rayon,
alors que la mthode Area se borne faire un calcul utilisant des donnes de lobjet
mais sans le modier. Cette mthode peut donc tre utilise sans risques sur un objet
constant.
On introduira le qualieur const dans linterface :
class Cercle : public Figure
{
...
float
Area() const;

31

Introduction au langage C++

et galement dans limplmentation :


float Cercle::Area() const
{
return 3.14159 * cR * cR;
}
Moyennant quoi, on pourra alors concevoir du code recevant en argument des
rfrences non modiables :
void toto(const Cercle& arg)
{
float S;
S = arg.Area();
arg.Zoom(5.0);
...

5.3

// Autorise, methode const


// ERREUR !

Codage en ligne
Les volutions des architectures processeurs, pipeline, superscalaire, ont conduit les
compilateurs implanter des mcanismes de codage en ligne, consistant compiler
non plus des appels des fonctions, mais rpliquer sur place, lendroit de lappel,
le code de ces fonctions. Le but est de faciliter au maximum une excution en
squence, sans branchements, sans droutages.
Les langages ont suivi le mouvement et le C-Ansi a introduit un qualieur inline
permettant dcrire des fonctions en spciant un codage en ligne.
En C++, on pourra ainsi implanter, directement dans le chier interface (et non plus
dans le chier source, la dnition en ligne doit tre disponible lors de la compilation
de tous les modules application), des mthodes (courtes) :
class Cercle : public Figure
{
...
void Zoom(float scale);
...
};
inline void Cercle::Zoom(float scale)
{
cR *= scale;
}
On peut faire mieux, par convention du C++, toute mthode encode directement
dans la dclaration de classe est inline !
class Cercle : public Figure
{
...
void Zoom(float scale) { cR *= scale; }
...
};

32

5 - Acc`s, protections
e

33

On conserve ainsi une interface "propre", de type fonction, tout en ayant les avantages
en performances dun codage direct.
Ce mcanisme est utilis intensivement pour implanter ce quon appelle des accesseurs, savoir des mthodes permettant la manipulation des attributs dun objet.
Par exemple, on ajoute notre petite librairie un support graphique utilisant un
attribut "couleur de la gure". Cet attribut est un code numrique, index dans une
palette par exemple.
Le code application doit pouvoir dnir lindex et accder sa valeur courante :
class Figure
{
...
// Support couleur
private:
int
iColor;
public:
void SetColor(int color)
int
GetColor() const
};

{ iColor = color; }
{ return iColor; }

On a dj signal lintrt dencapsuler les donnes, au paragraphe 2.7 page 11,


laccs inline permet dinterdire quiconque la manipulation explicite de lattribut,
dclar private, tout en ayant les mmes performances en excution.
Il nexiste AUCUNE (mauvaise) raison dimplanter des attributs publics !
Le jour o, pour telle ou telle raison, la modication du code couleur ncessitera
des traitements auxiliaires (reconguration faire au niveau de linterface graphique
utilise), il sufra de remplacer la mthode en ligne SetColor par une mthode
encode de manire classique, dans le chier source figure.cxx et effectuant tout
le travail ncessaire.
Vu de lextrieur, les codes applicatifs qui utilisent la mthode SetColor seront
inchangs ( une recompilation prs).
NB : on notera la prsence du qualieur const sur la mthode GetColor. Celle-ci
ne modiant pas lobjet, pourra donc tre utilise partir dune rfrence constante.
Enn, ce mcanisme permet de moduler trs subtilement les accs. On peut imaginer
une classe, comportant un attribut consultable par tout le monde mais modiable
uniquement par la classe ou les classes drives, mais non par du code externe :
class Machin
{
// On ne touche pas !
private:
int iTruc;
// Tout le monde peut lire !
public:
int GetTruc() const
{ return iTruc; }
// Les sousclasses seules peuvent modifier
protected:
void SetTruc(int truc) { iTruc = truc; }

33

Introduction au langage C++

5.4

Touche  mon pote !


a
Dans certains cas, on pourra avoir besoin daccder des membres ou mthodes
privs ou protgs dune classe, depuis une autre classe (non drive, sinon lattribut
protected suft) ou depuis une fonction externe.
On dclarera alors, dans linterface de classe, telle ou telle classe amie ou telle ou
telle fonction amie :
class Truc
{
friend class Pote;
friend void toto(Truc& arg);

// Classe amie
// Fonction amie

private:
int mon_attrib;
};
Moyennant quoi, tous les accs sont possibles, sur des objets de la la classe Truc,
depuis le code de la fonction toto :
void toto(Truc& arg)
{
arg.mon_attrib = 0;
...
}

// Attribut prive !

ou depuis nimporte quelle mthode de la classe Pote, puisque lensemble de la


classe est amie.
Ce mcanisme casse TOUS les autres types de protection ! Il ne doit donc tre utilis
que dans certains cas bien prcis et pour contourner certaines rigidits dimplantation.
Un exemple de tels cas est prsent en annexe C page 55, paragraphe C.5 page 60.
NB : la dclaration amie doit gurer obligatoirement dans linterface de classe. Cest
voulu ! Le concepteur dune classe est seul responsable de sa scurit et les chiers
source et header lui appartiennent. Cest le concepteur et lui seul qui dcide des
visibilits, des amis.

5.5

Conclusion
Ce chapitre avait pour but de dtailler tous les mcanismes de protection disponibles
en C++.
Il faut casser un mythe : tout cela nest pas QUE du dtail !
Cest sans aucun intrt tant que lon se limite la programmation dun "Hello
world !", et lorsquun dveloppement, commenc tout petit, ni par devenir norme
(plusieurs dizaines ou centaines de classes, imbriques dans des arborescences complexes, possdant chacune des dizaines de mthodes) il est trop tard pour "commencer
penser la abilit du code" !

34

5 - Acc`s, protections
e

35

Un concepteur de classe doit cultiver sa paranoa, une bonne charte de dveloppement pourrait tre :
a priori, tout est verrouill, private, attributs et mthodes.
toute mthode qui laisse lobjet intact est dclare const
laccs un attribut se fera par un accesseur de type GetXXX, qui est toujours
const
le positionnement dun attribut se fera par un accesseur de type SetXXX.
les visibilits des mthodes (ou accesseurs) seront public uniquement si elles
font partie de linterface de spcication de la classe, sinon private
on assouplira la rgle prcdente en changeant la visibilit private en protected pour les mthodes qui savrent ncessaires limplantation de classes
drives
Pour tre honnte, il faut dire que le zro bug nexiste pas, mais cest une asymptote
et tout doit tre tent pour sen rapprocher, au moins en ce qui concerne les effets de
bords et les pollutions. Pour les bugs caractre algorithmique, il nexiste pas daide
spcique langage.

35

Introduction au langage C++

36

Polymorphisme
Le polymorphisme est le troisime grand concept de la programmation objets. Lide
de base est de pouvoir manipuler des objets dont on ne connait pas la nature exacte,
plus prcisement dont on connait simplement un anctre rel, on parlera de classe
support, ou un anctre thorique, sans existence informatique12, on parlera alors de
classe abstraite.
En poussant plus loin, ce concept permet dcrire aujourdhui du code qui manipule
des objets connus et des objets inconnus, qui ne seront dvelopps que dans le futur,
et ce sans mme avoir recompiler le code en question.
On peut poser le problme sur lexemple suivant, utilisant une petite librairie de
gures gomtriques13.
On se propose de grer un groupe de plusieurs gures, des cercles, des rectangles, et
pouvoir effectuer des oprations densemble : dplacer tout le monde, zoomer tout
le monde, calculer un barycentre partir des surfaces, etc.
De plus, on souhaite que le travail en question reste valide, lorsque dans quelques
mois, la librairie se sera enrichie dautres gures, triangles, trapzes, et tout ce qui
aura t imagin dici l et quon ignore aujourdhui.
La technique la plus classique, pour implanter un groupe quelconque, passe par une
table de pointeurs dobjets quon cre dynamiquement et quon remplira ensuite :
int
total = 20;
XXX** table;
table = new (XXX*)[total];
remplir(table, total);

//
//
//
//

Nombre dobjets
Table des pointeurs
Allocation
Remplissage, ouf !

Tout cela est bel et bon, un dtail prs : XXX ? Une table de pointeurs de quoi ?

6.1

Compatibilit hirarchique
e e
C++ assure une compatibilit ascendante des objets, savoir que tout objet, connu
par pointeur ou par rfrence, est utilisable en lieu et place dun de ses anctres,
puisque tout objet est une de ses superclasses.
Si une classe Cercle drive dune classe Figure, on peut crire des choses comme :
Figure* PF = new Cercle;
Linverse est videmment faux :
Cercle* PC = new Figure;

(12)
(13)

Cest un must informatique que dcrire des programmes qui manipulent des choses qui nont pas
dexistence informatique !
a alors ! On sy attendait si peu...

37

Introduction au langage C++

Le compilateur C++ rejettera une telle criture, et mme si lon voulait tricher en
utilisant un cast :
Cercle* PC = (Cercle*)(new Figure);
la sanction sera immdiate en excution14.
Ceci nous permet donc de manipuler tout ce qui drive dun anctre commun, ici
des Figure :
int
total = 20;
Figure** table;

// Nombre dobjets
// Table des pointeurs

table = new (Figure*)[total];


remplir(table, total);

// Allocation
// Remplissage, ouf !

et le code de remplissage pourra placer ce quil veut :


void remplir(Figure** table, int total)
{
table[0] = new Cercle;
table[1] = new Rectangle;
table[2] = new Machin;
...
(Machin est une Figure, cf. 4.6 page 26 !)
Disposant dune table de pointeurs dobjets, on est maintenant capable de dplacer
lensemble des gures, par une simple boucle :
int ii;
for(ii = 0; ii < total; ii++)
table[ii]->Move(150, 10);
Ceci exploite le fait que le dplacement est un hritage de la superclasse Figure,
laquelle dispose de la mthode Move, mme si, dans les faits, nos pointeurs sont des
pointeurs de Cercle ou de Rectangle, ou de...
Par contre, la mme technique nest plus utilisable si lon souhaite appliquer un
facteur dchelle au groupe : la classe Figure ne dispose pas de mthode Zoom, et
pour cause, la description gomtrique dune gure est indnie.

6.2

Mthodes virtuelles
e
La premire technique consiste implanter une mthode virtuelle dans la superclasse :
class Figure
{
...
virtual void Zoom(float scale);
...

(14)

38

"Mettez un lapin la peau dun chacal, vous ne ferez pas croire que cest un chacal un autre
chacal !" (Proverbe touareg).

6 - Polymorphisme

39

Cette mthode pourra tre code dans le module source dimplmentation :


void Figure::Zoom(float scale)
{
}
ou mieux (vu le volume de code mis en oeuvre !), implante en ligne dans linterface :
class Figure
{
...
virtual void Zoom(float scale) { }
...
Une mthode virtuelle, i.e. dclare avec un qualieur virtual, est une mthode
de classe qui pourra tre remplace compltement, surcharge, par toute mthode
de mme nom et mme interface dappel (arguments) dune classe drive. Ce
mcanisme de remplacement se fait lors de la cration de la classe drive.
Cette seconde surcharge, overload en anglais, que nous appelons surcharge fonctionnelle ici, est trs diffrente de la surcharge de slection, dtaille au paragraphe 3.2
page 17. La premire consistait proposer au compilateur diverses variantes dune
mthode, en fonction des types darguments.
Ici, si lon crit maintenant une boucle de zoom :
int ii;
for(ii = 0; ii < total; ii++) table[ii]->Zoom(8);
le compilateur ne connait quune mthode Zoom dans la classe Figure. Il nempche
que, si le pointeur de Figure en table[0] est en ralit un pointeur de Cercle,
cest bien le code Cercle::Zoom qui sera excut. Si table[1] est en ralit un
pointeur de Rectangle, cest le code Rectangle::Zoom qui sera excut.
On dispose l dun mcanisme puissant permettant, une sousclasse de remplacer,
lors de sa construction, une mthode dune de ses classes anctres, par une autre
mieux adapte sa nature. Les seules contraintes sont que la classe anctre, qui
devient ainsi une classe support (support de surcharge), autorise le remplacement en
dclarant sa mthode virtual, et que la mthode de classe drive ait strictement
la mme interface.
En effet, une classe drivant de Figure, qui dclarerait une mthode :
void Zoom(int scale);
crerait une surcharge de slection, et non plus une surcharge fonctionnelle.
NB : il est inutile de redclarer virtual la mthode surcharge dans les classes
drives, la dclaration dans la classe de base suft pour toutes les drivations
possibles.
NB : limplantation ci-dessus, si elle est correcte, nest pas des plus heureuses : on
dclare une mthode ctive, sans objet sur la classe en question, et on limplante par
un code vide pour ensuite la remplacer par autre chose de plus intelligent !
De plus, et si par exemple la fonction de remplissage voulait samuser crer des

39

Introduction au langage C++

Figure :
void remplir(Figure** table, int total)
{
table[0] = new Cercle;
table[1] = new Figure;
...
Rien ne linterdit et on aura un fonctionnement stupide !
Pratiquement, la surcharge fonctionnelle sert implanter dans une classe de base
des algorithmes gnraux, utilisables tels quels dans la majorit des cas. charge
pour une classe drive particulire, qui ncessite un traitement non standard, de
surcharger avec son propre algorithme spcialis.
De plus, il est possible dans une surcharge dutiliser le code de la mthode originale
de la classe anctre, sil prsente un intrt :
class Parent
{
...
virtual void Hello(int world);
...
class Enfant : public Parent
{
...
void Hello(int world);
...

// Methode virtuelle

// Heritage

// Surcharge

Si lon appelle la mthode Hello sur un objet Enfant, ou mme, par polymorphisme, partir dun pointeur de Parent qui est en ralit un Enfant, cest bien la
mthode Enfant::Hello qui est invoque.
Cette mthode peut utiliser explicitement le code de sa superclasse :
void Enfant::Hello(int world)
{
Parent::Hello(world); // Appel explicite
...
// Complements
}
La syntaxe Parent::Hello sappelle rsolution de porte. En effet, par dfaut, un
identicateur de mthode ou dattribut sapplique la classe courante et crire un
appel Hello dans la mthode Enfant::Hello va provoquer un appel rcursif
inni vite suivi du dsagrable :
Bus error !

6.3

Classes abstraites
Notre problme peut se traiter de manire plus lgante, et plus rjouissante intellectuellement parlant !
On veut disposer dune mthode Zoom dans la classe Figure pour pouvoir zoomer
nos objets, connus par pointeurs, comme si ctait des Figure. Donc mthode

40

6 - Polymorphisme

41

virtuelle.
Mais on sait quil sagit dun artice puisquune Figure ne se zoome pas. Un
Cercle oui, un Rectangle oui, mais pas une Figure. On va alors prciser que
la classe Figure possde bien une mthode Zoom, mais quen fait, cette mthode
nexiste pas15 !
Ce qui, en langue C++, se dit :
class Figure
{
...
virtual void Zoom(float scale) = 0;
...
La syntaxe est rude, mthode = 0, aucun doute le C++ est bien un digne hritier de
C ! Elle nexiste pas, ce qui ne lempche pas dtre virtual16.
On vient de crer une classe abstraite. Une classe abstraite sait faire (potentiellement)
tout un tas de choses, possde telle ou telle mthode, mais si une au moins des
mthodes de la classe nexiste pas, la classe toute entire ne peut avoir dexistence
lgale.
On ne pourra jamais instancier, directement ou indirectement, une telle classe :
Figure F1;
Figure* PF;
PF = new Figure;

// ERREUR
// ERREUR

Par contre, on peut la driver, et si la ou les mthodes vides sont virtuelles, et


surcharges par les sousclasses, ces sousclasses deviennent tout fait instanciables.
Grce ce mcanisme, on na plus, comme dans la premire implantation, encoder
une mthode qui ne fait rien, on ne court plus le risque dutiliser un objet Figure
puisque toute cration est devenue impossible, et on conserve lintrt de manipuler
nos objets sous une interface banalise, le pointeur de Figure.
Enn, lors de lajout de nouveaux objets gures, dans la librairie, il faudra videmment remettre hauteur le code de la fonction de remplissage si lon souhaite crer
aussi des Triangle ou autres, mais le code de manipulation de la table, boucles
Move, Zoom, et autres, restera inchang et mme, sil a t cod dans un module
spar, naura mme pas tre recompil !

6.4

Familles polymorphiques
Les mcanismes de surcharges fonctionnelle et dabstraction sont gnralisables sur
toute une arborescence. La conception de grosses applications nest pas un exercice
trivial et dborde du cadre de ce manuel dintroduction.
Certaines applications peuvent ncessiter la conception dune classe anctre, abstraite.
Cette classe est ensuite drive en sousclasses qui commencent implanter telles ou
telles mthodes virtuelles, tout en restant elles-mmes abstraites. La rgle de base,
pour pouvoir instancier une classe, est que toutes les mthodes de cette classe et de
tous ses anctres existent bel et bien.
(15)
(16)

Jusque l, tout le monde suit ?


Tout le monde suit toujours ?

41

Introduction au langage C++

Il faut toutefois signaler un petit problme potentiel lors de la destruction dobjets


polymorphiques. Par exemple, en reprenant notre exemple ci-dessus, on veut en n
dexcution dtruire la table et tout ses objets :
int ii;
// Destruction des objets
for(ii = 0; ii < total; ii++) delete table[ii];
// Destruction de la table elle-meme
delete[] table;

Le problme est que le compilateur va dtruire des objets connus via des pointeurs
de Figure. Il na aucun moyen de savoir quen ralit il sagit de Cercle, de
Rectangle, ou mme de classes qui ont t cres par la suite et qui nexistaient pas
au moment de la compilation.
Si une classe drive a besoin de faire un traitement spcique dans son destructeur,
celui-ci ne sera jamais appel.
Sauf... si lon utilise le mcanisme de surcharge fonctionnelle pour le destructeur17 !
Une rgle, trs gnrale, est que toute classe destine servir de support polymorphique doit implmenter un destructeur virtuel, mme vide ! Ceci garanti un
fonctionnement correct lors de la destruction de classes drives :
class Figure
{
public:
// Constructeurs
Figure();
Figure(float xpos, float ypos);
// Destructeur vide, en ligne
virtual Figure() { }
NB : certains compilateurs sympathiques (gcc en particulier) pousseront la courtoisie
jusqu signaler par un warning que telle classe possde des mthodes virtuelles mais
que son destructeur ne lest pas.

(17)

42

Bon sang ! Mais cest bien sr !

Annexe A

Complments
e

Cette annexe prsente, un peu ple-mle, un certain nombre de particularits C++.


Ces points nont pas t voqus dans les chapitres prcdents pour ne pas encombrer
une premire lecture, mais il faut les connaitre, on en a parfois besoin.

A.1 Membres statiques

Contrairement un membre de classe, attribut ou mthode, qui na de sens que relativement une instance ralise de cette classe, un membre statique existe toujours,
en un seul exemplaire dans le cas dun attribut, mme en labsence totale dinstances
de cette classe.
Il sagit, en quelque sorte, dun patrimoine commun toutes les instances de cette
classe.
Pour illustrer ceci, imaginons dimplanter dans une classe un systme de comptage
dinstances. Le code application souhaite pouvoir connatre, tout moment, le nombre dobjets raliss de cette classe. Ce compteur doit tre unique, bien sr, et non
dupliqu dans chaque instance. Dautre part il doit exister et tre accessible mme
si aucune instance de la classe nest disponible (on voudra savoir sil nexiste, un
moment donn, aucune instance).
Dans linterface de classe, on implantera un compteur statique, et un accesseur public,
galement statique :
class Truc
{
// Constructeur, destructeur
public:
Truc();
Truc();
// Comptage
private:
static unsigned
public:
static unsigned
...

iTotal;
GetTotal()

{ return iTotal; }

ATTENTION : le qualieur static, dans un tel contexte C++, na aucun rapport


avec le static du langage C ! Une bonne ide aurait t dinventer un autre motcl, cela na pas t fait.

43

Introduction au langage C++

Implmentation :
/* Attribut(s) statique(s) */
unsigned Truc::iTotal = 0;
/* Constructeur */
Truc::Truc()
{
...
iTotal++;
}
/* Destructeur */
Truc:: Truc()
{
iTotal--;
}
On remarquera que, contrairement un attribut "normal", un attribut statique
simplmente explicitement. Cest, en fait, une variable globale dont la dure de vie
est celle du programme et qui DOIT tre initialise correctement la dclaration.
Les mthodes statiques, elles, simplantent de la manire classique, codage explicite
dans limplmentation ou codage en ligne dans la dclaration (cest le cas ici).
Le mcanisme ci-dessus est parfaitement sr. La variable est prive, et ne peut tre
modie que par cration ou destruction dune instance de cette classe (ou dune
classe drive). (Ne pas oublier, si lon implante plusieurs variantes de constructeurs,
dincrmenter le compteur dans chaque constructeur !)
Laccs public peut se faire de deux manires. Si lon dispose dune instance "sous la
main", on effectue une invocation classique :
Truc t1;
...
unsigned total = t1.GetTotal();
printf("Il existe %u Trucs !\n", total);
Sinon, on peut utiliser le mcanisme dj signal de rsolution de porte :
unsigned total = Truc::GetTotal();
NB : cet exemple est assez souvent mis en oeuvre, au moins lors de dveloppements
importants. Lorsquune application manipule des objets par centaines, en gestion
dynamique travers new et delete, une bonne ide est de vrier, juste en n de
programme, quon na pas oubli des delete ici ou l !
Ce nest pas gnant en soi puisque, lors de larrt dun processus, toute la mmoire
est libre, mais cest le symptme dune programmation malpropre quelque part ou
dune erreur de conception.

44

7 - Complments
e

45

A.2 Rsolution de porte


e
e
La rsolution de porte a une dernire utilisation, pour lever des ambiguts.
Imaginons une classe comportant une mthode nomme sqrt :
class Toto
{
...
double
double

sqrt(double x);
calcul(double x);

Que se passe-t-il si, dans une mthode de cette classe, par exemple la mthode calcul, on veut utiliser la fonction racine carre de la librairie C ? On peut dabord
considrer que cest bien fait pour nous, on navait qu rchir et choisir un autre
nom pour notre mthode !
On peut aussi utiliser la rsolution de porte, sans nom de classe, puisque sqrt de
la librairie mathmatique C nest pas une mthode de classe :
double Toto::calcul(double x)
{
double y;
y = sqrt(x);
// Appelle notre methode
y = :$_:sqrt(x);
// Appelle LA sqrt de la libm C
}

A.3 Qui suis-je ?


Nous avons signal, cf. 2.6 page 10, que dans une mthode de classe, par exemple :
void Cercle::Zoom(float scale)
{
cR *= scale;
}
la rfrence au nom dun attribut ou dune mthode se rapporte "lobjet courant
pour cet appel".
Cet objet courant existe bel et bien, sous la forme dun pointeur sur linstance appel :
this (mot rserv en C++).
Ce pointeur sert peu, en pratique, puisque implicitement, crire :
cR *= scale;
revient crire :
this->cR *= scale;
Il faut toutefois savoir quil existe, on lutilise dans certains cas o depuis le code
dune mthode, on aurait besoin dappeler "sur nous" une fonction externe la classe,
prenant un pointeur dobjet en argument. Un autre cas dutilisation est signal dans
lannexe C page 55, paragraphe C.3 page 58.
45

Introduction au langage C++

A.4 Structures
Pour des raisons de compatibilit indispensable, C++ supporte les structures de
donnes du langage C.
Comme les structures, au sens du C, nont aucun intrt dans un langage objets, en
C++ les structures sont en fait des classes !
Syntaxiquement, cela se traduit par le fait quon peut dclarer des donnes de type
structure comme on instancie des classes, le dclarateur struct est facultatif :
struct Toto {
int a;
int b;
};

// Definition structure C

struct Toto S1; // Declaration avec "look" C


Toto S2;
// Declaration avec "look" classe C++
En fait, en C++, une structure est une classe o tous les champs, les membres, sont
accessibles.
On aurait le mme effet avec :
class Toto
{
public:
int a;
int b;
};
Toto S1;
S1.a = 0;
S1.b = 1;

(On rappelle que, par dfaut, dans une classe et sans spcication de visibilit tout
est private.)
Comme il sagit en fait de classes, il devrait donc tre possible dimplanter dans des
structures des mthodes, un constructeur, etc. :
struct Toto {
Toto() { a = b = 0; }
int a;
int b;
};

// Constructeur en ligne

En effet, cest possible. Lcriture ci-dessus est tout fait valide. Et a na AUCUN
INTRT !
Ou bien on porte du code C existant dans une application C++, auquel cas on laisse
ce qui existe dj et le code C nutilisait srement pas de mthodes de structures, ou
alors on fait un nouveau dveloppement C++ et on utilise des classes, uniquement.
La structure, en C++, est un outil de compatibilit, pas un outil de dveloppement.

46

7 - Complments
e

47

A.5 Gestion des dclarations


e
A.5.1 Prdclarations
e e
Assez souvent, dans un dveloppement important, on se trouve confront des
problmes dimbrications de dclarations.
Par exemple, une classe Toto possde des attributs qui sont des pointeurs de classe
Truc, et la classe Truc possde des pointeurs de Toto. Pour pouvoir compiler
correctement, C++ autorise des prdclarations de classes (forward declarations dans la
terminologie anglaise).
Fichier interface toto.h :
class Truc;
class Toto
{
private:
Truc* monTruc;
};

// Forward

// Attribut pointeur

Fichier interface truc.h :


class Toto;
class Truc
{
private:
Toto* monToto;
};

// Forward

// Attribut pointeur

On peut remarquer que, lors de linclusion des headers dans un module source qui a
besoin des deux interfaces de classes :
#include "toto.h"
#include "truc.h"
lune des prdclarations devient en fait une postdclaration. Cest tolr, savoir
que le compilateur ignore une prdclaration sil a dj vu linterface de classe.

A.5.2 Inclusions multiples


Dans un gros dveloppement, plusieurs dizaines de classes, on se trouve vite la
tte de multiples chiers headers (au minimum un par classe, parfois plus).
Souvent des modules sources ont besoin dinclure de multiples chiers, lequels peuvent comporter aussi des directives #include nest pas rare quun mme chier
puisse se trouver inclus plusieurs fois (indirectement).
a, par contre, cest strictement interdit, en C++ comme en C ! Il faut donc
systmatiquement protger tous les chiers headers contre linclusion multiple. La
technique est classique, chaque chier dnit un symbole en rapport avec son nom,

47

Introduction au langage C++

et nimplante son code que si cest la premire lecture. Exemple toto.h :


#ifndef TOTO_H

// TOTO_H nexiste pas, 1ere fois

class Toto
{
...
};
#define TOTO_H
#endif

48

// Il existera la prochaine fois

Annexe B

Compatibilit C/C++
e

Le langage C++ est une extension, oriente objets, du C-Ansi. Les deux dialectes sont
sufsament proches pour que beaucoup de compilateurs soient capable de traiter les
deux. On parle de compilateurs mixtes, C/C++.
On dira que C++ est un surensemble du C-Ansi dans la mesure o toute la syntaxe
du C-Ansi est valide en C++. Et donc, tout programme crit en C-Ansi peut tre
compil avec un compilateur C++. Le C-Ansi est impratif, la syntaxe ancienne du
C-K&R, sans prototypes de fonctions, est rejette en C++.
Linverse est videmment faux, un source C++ ne sera pas, en gnral, compilable
par un compilateur C. Sera rejett tout ce qui concerne les classes, mais galement,
dans des critures de fonctions classiques, les passages par rfrences inconnus en C
et les surcharges de slection : C nautorise pas plusieurs fonctions de mme nom,
mme si les arguments dappel diffrent.

B.1 Points d'entre


e
Un premier problme va apparatre lorsque lon voudra mlanger, pour un mme
programme, des modules crits et compils en C avec des modules crits et compils
en C++.
En C (comme en Fortran ou Pascal), le nom dune fonction est un identiant global
pour tout un programme :
void toto(int n);
Au moment de ldition des liens, une et une seule fonction toto doit exister dans
lensemble des modules objets.
C++ supporte la surcharge de slection :
void toto(int n);
void toto(int i, int j);
void toto(float x, float y);

49

Introduction au langage C++

et les mthodes de classes :


class Machin
{
public:
void toto(int a);
...
class Truc
{
public:
void toto(int a);
void toto(float x, float y);
...
De fait, la porte symbolique dun identicateur C++ est propre au contexte dinvocation. Pour implmenter cela, les compilateurs disposent dun algorithme interne
de gnration de noms (appel name mangling dans la terminologie anglaise). Les
points dentre dexcution, i.e. les noms qui seront utiliss ldition de liens pour
rsoudre les appels, sont entirement reconstruits.
Un mcanisme classique consiste prendre le nom de la fonction ou de la mthode,
prcd du nom de la classe si cest une mthode, et suivi de codes symboliques
dcrivant les arguments dappel. Par exemple, tous les toto ci-dessus pourraient
tre renomms en interne :
_toto_i
_toto_ii
_toto_ff
Machin_toto_i
Truc_toto_i
Truc_toto_ff
Cet algorithme est ensuite utilis lors de la compilation des fonctions ou mthodes,
mais galement lors des appels :
Machin M;
Truc T;
float x, y;
...
toto(x, y);
// Appel _toto_ff(x, y)
M.toto(3);
// Appel Machin_toto_i(3)
T.toto(1.5, 0.0); // Appel Truc_toto_ff(1.5, 0.0)
En conclusion, rien de magique, tout cela nest quune cuisine interne de compilation.
Deux problmes potentiels existent :
1. lalgorithme dencodage de noms est propre aux compilateurs, rien nest standardis aujourdhui ! Et donc, une mme mthode de classe, crite en syntaxe
C++ :
void Truc::toto(int a);
pourra conduire un encodage interne :
Truc_toto_i

50

8 - Compatibilit C/C++
e

51

avec tel compilateur, ou :


_DEC$CXX$Truc$toto$I
avec tel autre.
Il est donc fortement dconseill de lier, dans une mme application, des modules objets compils avec des compilateurs C++ diffrents ! On en choisi un,
sur une plateforme, et on sy tient !
2. il est en gnral impossible dappeler une fonction crite en C depuis du code
C++, ou inversement. Par exemple on veut, dans du code C++, utiliser une ou
des fonctions de la librairie mathmatique C :
double sqrt(double); // Prototype
double x;
x = sqrt(4.0);
// Appel _sqrt_f(4.0) !
et ldition de liens, le linker ne va pas trouver le point dentre _sqrt_f
et pour cause, dans la librairie mathmatique, compile en C, lentre sappelle
sqrt !
Ce second problme est rel et pour cela, C++ permet dinhiber lencodage des noms
et de compiler avec des points dentre aux normes du C. On peut inhiber le name
mangling fonction par fonction :
extern "C" void toto(int a);
extern "C" float truc(float x, float y);
ou pour tout un groupe de prototypes :
extern "C" {
void toto(int a);
float truc(float x, float y);
}
Il faut connaitre et utiliser ce mcanisme, trs important. Depuis dj une dizaine
dannes, avec le dploiement de C++, toutes les librairies C sous Unix sont
disponibles pour C++ et donc les headers, stdio.h, stdlib.h, math.h, etc.,
comportent ces dclarations extern "C".
Quiconque dveloppe en C, utilitaires, librairies, devrait fournir des chiers de prototypes conformes cette rgle. Dtail, la dclaration extern "C" est du C++ et
sera rejette par un compilateur C. Cest pourquoi TOUT chier header prototypant
du C doit respecter les critures suivantes :
#ifdef __cplusplus
extern "C" {
#endif
/* Prototypes C */
void toto(int a);
...
#ifdef __cplusplus
}
#endif
Le symbole __cplusplus, standard, est prdni par tous les compilateurs C++.
51

Introduction au langage C++

Moyennant cette prcaution, le header est compatible C-Ansi, C++.


De plus, on sinterdira lutilisation du commentaire ligne //, spcique C++, dans
des headers mixtes.

B.2 Interface objets


Il est donc possible dcrire des fonctions C++, appelables depuis du code C, sous
rserve dutiliser la dclaration extern "C" prsente ci-dessus.
Il nest pas possible dinterfacer directement des objets, C ntant pas un langage
objets. Par contre, C manipulant des pointeurs, il est tout fait possible dimaginer
une interface par pointeurs.
A titre dillustration, on se propose dinterfacer notre petite librairie de gures
gomtriques, dans sa version polymorphique (chapitre 6 page 37), avec du code C.
On utilisera un type gnrique "pointeur de gure", dni diffremment selon le
langage cible (cf. ci-dessous) et, pour la cration, des codes symboliques spciant la
nature de lobjet crer.

B.2.1 Header interface


Fichier libfig.h
#ifdef __cplusplus
typedef Figure* figure; /* Pointeur de figure C++ */
extern "C" {
#else
typedef void* figure;
#endif
/* Types figures */
#define FIG_CERCLE
#define FIG_RECTANGLE
... etc

/* Pointeur quelconque C */

1
2

/* Interface */
figure figCreate(int type);
void
figDelete(figure F);
/* Methodes */
void figMove(figure F, float dx, float dy);
void figZoom(figure F, float scale);
float figArea(figure F);
#ifdef __cplusplus
}
#endif

52

8 - Compatibilit C/C++
e

53

B.2.2 Source interface


Fichier libfig.cxx
#include "figure.h"
#include "cercle.h"
#include "rectangle.h"

// Classes

#include "libfig.h"

// Interface C

/* Constructeur */
figure figCreate(int type)
{
switch( type ) {
case FIG_CERCLE
: return new Cercle;
case FIG_RECTANGLE : return new Rectangle;
default : return (Figure*)0;
}
}
/* Destructeur */
void figDelete(figure F)
{
delete F;
}
/* Methodes */
void figMove(figure F, float dx, float dy)
{
F->Move(dx, dy);
}
void figZoom(figure F, float scale)
{
F->Zoom(scale);
}
float figArea(figure F)
{
return F->Area();
}
Comme on peut le constater, cest un petit travail simple, mme sil na rien de
passionnant. On notera galement toute la puissance du polymorphisme qui permet
de ne sintresser la nature exacte des objets que lors de la construction. Tout le
reste du code est gnrique, pointeur de gure quelconque.
NB : cest parce que toutes les fonctions de ce module sont dclares extern "C",
dans le chier header, quelle pourront tre lies aux appels venant du code C.

53

Introduction au langage C++

54

Annexe C

Surcharges d'oprateurs
e

Quiconque a dj programm, en Fortran, en Pascal, en C, connait la notion


doprateur. Il sagit dune notation symbolique spciant une opration faire, un
traitement, dont la nature peut varier en fonction des arguments ou oprandes.
Ainsi, dans tous les langages, lcriture 10 / 3 spcie une division entire dont
le rsultat sera 3, alors que 10.0 / 3 spcie une division relle, rsultat 3.3333.
Cest le compilateur qui va, partir dun mme symbole opratoire et selon la nature
des oprandes, dterminer le traitement effectuer.
C++ permet de dnir des oprations spciques, utilisant les notations symboliques
du langage, sur des oprandes a priori inconnus des compilateurs, des objets par
exemple. Le terme consacr, surcharge doprateur, est sans doute un peu abusif. On
devrait plutt parler de dnition doprateur puisque cela sapplique des oprations
inconnues.
Les domaines dapplication sont essentiellement mathmatiques, calculs en complexes, algbre linaire, etc.

C.1 Arithmtique complexe


e
On se propose de dvelopper cette notion, en construisant une classe dobjets nombres
complexes, lesquels nexistent pas en standard en C ou C++ (voir note [ 9.1 ] page 62
en n dannexe).
On construit des objets deux attributs, parties relle et imaginaire. On va choisir
dimplanter trois constructeurs :
un constructeur par dfaut, classique
un constructeur avec initialisateurs
un constructeur dit de copie, permettant de crer un objet par clonage dun
autre, pass par rfrence.
Interface (chier complex.h) :
class complex
{
// Constructeurs
public:
complex();
complex(float real, float imag);
complex(complex& model);
// Attributs
private:
float pR, pI;
};

55

Introduction au langage C++

Implmentation (chier complex.cxx) :


#include "complex.h"
/* Constructeur par defaut */
complex::complex()
{
pR = pI = 0.0;
}
/* Constructeur initialisateur */
complex::complex(float real, float imag)
{
pR = real;
pI = imag;
}
/* Constructeur cloneur */
complex::complex(complex& model)
{
pR = model.pR;
pI = model.pI;
}
On dispose donc dune base qui va permettre dinstancier des objets de diffrentes
manires :
complex c1;
complex c2(3.5, 0);
complex c3(c2);
...

// Avec initialisation
// Clonage sur c2

Que peut-on faire maintenant, de ces objets ? Pas grand chose en fait ! On peut
vouloir accder aux attributs, privs, donc par un mcanisme daccesseurs (cf. 5.3
page 32), SetReal, SetImag, GetReal, GetImag.
La technique manque un peu dlgance et on va trs vite se trouver face du code
comme :
// Affectation : c1 = c3
c1.SetReal(c3.GetReal());
c1.SetImag(c3.GetImag());
// Somme composite : c1 += c2
c1.SetReal(c1.GetReal() + c2.GetReal());
c1.SetImag(c1.GetImag() + c2.GetImag());
Tout ce quon peut dire de la monstruosit prcdente est que cela fonctionne !

56

9 - Surcharges doprateurs
e

57

C.2 Oprateurs sur la classe


e
Heureusement, C++ permet de dnir des oprateurs =, ou +=, valables pour des
objets de la classe complex. On ajoutera dans linterface :
class complex
{
...
// Operations
public:
void operator=(complex& arg);
void operator+=(complex& arg);
et, dans limplmentation :
/* Affectation */
void complex::operator=(complex& arg)
{
pR = arg.pR;
pI = arg.pI;
}
/* Somme composite */
void complex::operator+=(complex& arg)
{
pR += arg.pR;
pI += arg.pI;
}
On dispose maintenant doutils propres, permettant dcrire du code qui ressemble
de larithmtique en C :
complex c1(1, 0);
complex c2(2.5, -1);
c2 += c1;
c1 = c2;
...

C.3 Associativit
e
En C++ comme en C, certains oprateurs sont associatifs, en particulier laffectation,
ce qui permet dcrire des choses telles que :
int i, j, k;
i = j = k = 3;
Cela fonctionne parce que laffectation est une opration qui retourne son oprande
de droite. Syntaxiquement, le rsultat dune affectation est donc un oprande et peut
gurer dans une expression.
57

Introduction au langage C++

Modions donc notre oprateur daffection pour quil retourne son oprande de
droite, savoir une rfrence sur un objet. Linterface devient :
class complex
{
...
complex& operator=(complex& arg);
et limplmentation :
complex& complex::operator=(complex& arg)
{
pR = arg.pR;
pI = arg.pI;
return arg;
}
Maintenant, des critures telles que :
complex c1, c2;
complex c3(2.5, -1);
c1 = c2 = c3;
sont licites18.
NB : dans lcriture de loprateur =, on retourne loprande de droite. Si lon a
besoin, dans un oprateur, de retourner loprande de gauche, cest dire lobjet
courant, on se souviendra du pointeur this (cf. A.3 page 45).
Attention, this est un pointeur sur nous, mais ce nest pas nous ! Nous, cest lobjet
point par this, et donc :
complex& complex::operator=(complex& arg)
{
pR = arg.pR;
pI = arg.pI;
return *this;
// Mais oui !
}

C.4 Surcharge de slection


e
Encore mieux19, la surcharge permettant au compilateur de choisir telle ou telle
mthode en fonction des arguments est applicable aux oprateurs.
Implantons donc la multiplication composite, *=, entre complexes ou entre complexe
et scalaire.

(18)
(19)

58

Isnt it great ?
Mais o cela va-t-il sarrter ?

9 - Surcharges doprateurs
e

59

On ajoute dans linterface :


class complex
{
...
void operator*=(float arg);
void operator*=(complex& arg);
et on code, dans limplmentation :
void complex::operator*=(float arg)
{
pR *= arg;
pI *= arg;
}
void complex::operator*=(complex& arg)
{
float R = pR * arg.pR - pI * arg.pI;
float I = pR * arg.pI + pI * arg.pR;
pR = R;
pI = I;
}
On peut maintenant crire :
complex c1(1, 1);
complex c2(5, 0);
c2 *= c1;
c2 *= 0.5;
et le compilateur choisira lopration ad-hoc en fonction des oprandes exactement
comme dans le cas de larithmtique scalaire.

C.5 Objets temporaires


Dans les exemples prcdents, on a sournoisement contourn un problme en implantant des oprateurs composs, += ou *=, mais pas des oprateurs simples, + ou
*.
Que se passe-t-il dans une expression arithmtique :
int i, j, k;
i = 3 + j + k;
En pratique, le compilateur utilise une ou plusieurs variables intermdiaires, anonymes (le plus souvent des registres du CPU), pour conserver les rsultats partiels des
oprations et les utiliser comme oprandes pour les oprations suivantes.

59

Introduction au langage C++

Lexpression ci-dessus est traite, en interne, comme :


int i, j, k;
int __1, __2;

// Temporaires

__1 = 3 + j;
__2 = __1 + k;
i = __2;
On utilisera le mme principe en crant, dans les oprateurs, un objet temporaire
rsultat. Par contre, on ne devra plus implanter des oprateurs internes la classe,
utilisant lobjet courant, mais des oprateurs externes deux oprandes. Pour quils
puissent tout de mme accder aux attributs, ils seront dclars friend.
Ajoutons une addition dans linterface :
class complex
{
...
friend complex operator+(complex& a, complex& b);
et dans limplmentation :
complex operator+(complex& a, complex& b)
{
float R = a.pR + b.pR;
float I = a.pI + b.pI;
complex result(R, I);
// Nouvel objet
return result;
}
NB : le type retour est bien un objet, complex, et non une rfrence, complex&.
Le compilateur doit tre prvenu que lopration a cr une instance, temporaire, et
quelle devra tre dtruite aprs utilisation, donc en n de traitement de lexpression.
On dispose maintenant dune vritable addition (voir note [ 9.2 ] page 62) :
complex
complex
complex
complex
c4 = c1

c1(1, 0);
c2(1, 1);
c3(c2);
c4;
+ c2 + c3;

Ce mcanisme ne supportant pas, a priori, la commutativit que le compilateur ne


peut pas deviner, dans le cas doprations hybrides on devra implanter les diffrentes
variantes. Par exemple, pour la multiplication :
complex operator*(complex& a, float b);
et :
complex operator*(float a, complex& b);
La variante commutative peut dailleurs simplanter en ligne en utilisant loprateur
dj disponible :
inline complex operator*(float a, complex& b)
{ return b * a; }
60

9 - Surcharges doprateurs
e

61

C.6 Remarques
Les exemples prcdents illustraient les principes de la surcharge, ou rednition
doprateurs.
Tous les oprateurs de C peuvent tre rednis, arithmtiques mais aussi boolens.
On pourrait comparer des nombres complexes, par des critures telles que :
complex c1, c2;
...
if( c1 == c2 ) ...
en implantant des oprateurs ==, ~!=, etc.
Il est conseill de conserver un minimum de bon sens. Mme si C++ le permet, ce
nest PAS une bonne ide dimplanter une addition de complexes sur loprateur *
et une multiplication sur loprateur +, dautant que les priorits dvaluation restent
celles de larithmtique :
(a + b * c)

svalue selon (a + (b * c))


Il peut arriver quon ait besoin doprations qui nexistent pas sous forme scalaire. Par
exemple, dans une application dalgbre linraire implmentant une classe vecteur,
on aimerait disposer de deux oprations de multiplication, les produits scalaire et
vectoriel.
Les notations symboliques, pour un mathmaticien, sont V 1.V 2 pour le produit
scalaire et V 1 V 2 pour le produit vectoriel. Le . en C, C++, est rserv laccs
aux membres de structures ou dobjets et est donc inutilisable.
Un choix convenable consisterait implanter le produit scalaire sur loprateur *, et
le produit vectoriel sur loprateur ^, le xor binaire de C, lequel na aucun intrt
dans un contexte vecteurs. On aura alors des critures informatiques lisibles, dfaut
dtre rigoureuses :
vecteur V1, V2, V3;
float sc;
...
V1 = V2 ^ V3;
sc = V1 * V2;

Enn, ne pas oublier que C++ ne sert pas qu construire des objets mais quon peut
aussi crire des fonctions. Le mcanisme de surcharge de slection permettant de
lever les ambiguts de nom partir de la nature des arguments dappel, on pourra,
pour les besoins dun module comme celui de ce chapitre, rimplanter des fonctions
existantes en version scalaire :
complex sqrt(complex& arg);
et autres...

61

Introduction au langage C++

C.7 Notes commentaires


En fait, cest faux ! Les complexes en C++, sils ne sont pas supports en standard
par le langage, sont disponibles sous forme dun petit package.
Cela existe parce que cest utile et assez rapide crire, et cest parce que cest rapide
crire que nous lutilisons comme illustration du principe.
Ce nest quune illustration, volontairement simplie. En particulier on a omis tout
le support daccs en lecture seule, const, qui doit normalement gurer dans tous
les oprateurs !
[ 9.2 ] Derrire llgance apparente dcritures comme :

[ 9.1 ]

c4 = c1 + c2 + c3;
il ne faut pas perdre de vue que se cache un traitement assez important : instanciations dobjets, appels des constructeurs, appels de mthodes oprateurs, calculs,
destruction !
Dans le cas dobjets assez consquents, par exemple une implantation dalgbre
linaire avec toutes les oprations ncessaires implantes sur vecteurs, matrices, on
peut aboutir de vritables monstres arithmtiques.
Cest pourquoi, trs souvent, on favorise les oprateurs daffectation compose, plus
simples crire et excuter.
Ainsi, on trouvera du calcul matriciel encod comme suit :
matrice M1, M2, M3, M4;
...
M4 = M1;
M4 += M2;
M4 *= M3;
plutt que :
M4 = (M1 + M2) * M3;
mme si la seconde criture est plus jolie !

62

Annexe D

Les streams

Deux oprateurs standards de C, >> et <<, oprateurs de dcalages de bits, jouent


un rle particulier en C++.
Comme ils sont assez peu utiliss, et en tout tat de cause limits des oprandes
entiers, ils ont t rednis (voir lannexe C page 55) pour un tout autre usage :
manipuler des entres/sorties !
En plus de la librairie C dentres/sorties, stdio.h, C++ dispose dune librairie,
iostream.h, permettant des entres/sorties plus sophistiques. En particulier, la
gestion des formatages darguments a t intgre, et ces objets entres/sorties sont
interfacs par des oprateurs de transfert.
Exemple, la sortie standard, qui en C est une structure stdout, est un objet C++
cout :
#include <stdio.h>
#include <iostream.h>

// E/S du C
// E/S du C++

float x;
x = 3.14159;
// Affichage a la mode C
fprintf(stdout, "x = %g\n", x);
// Affichage a la mode C++
cout << "x = " << x << \n;
On apprciera llgance de la syntaxe, on "vide20" vers le stream une suite dentits,
chane de caractres, rel, caractre de contrle, etc. En particulier, la spcication de
format a disparu.
Le but de cette annexe nest pas de dtailler la librairie iostream mais dexpliciter
le mcanisme pour pouvoir ladapter nos propres besoins.
Cette librairie repose sur des classes, istream pour les entres, ostream pour les
sorties. La classe istream surcharge loprateur >>, la classe ostream surcharge
loprateur <<.
Par surcharge de slection, ces oprateurs sont implants pour tous les types
darguments de base (les oprations de formatage en fonction de la nature, entier,
rel, chane, ..., sont donc internes loprateur) et, pour permettre lcriture associative, ces oprateurs retournent leur oprande de gauche qui est une rfrence sur un
ostream (dans le cas des sorties).
On peut complter lexemple de lannexe C page 55, construisant une classe de nombres complexes, en ajoutant par exemple un oprateur dafchage de complexe. On
peut imaginer dimprimer les parties relle et imaginaire, entre parenthses, spares
par une virgule.

(20)

Cest la raison du choix de ces oprateurs. Aucun rapport avec des dcalages de bits, mais leffet
visuel est vocateur !

63

Introduction au langage C++

On ajoutera, dans linterface :


class complex
{
...
friend ostream& operator<<(ostream& out, complex& c);
et dans limplmentation :
ostream& operator<<(ostream& out, complex& c)
{
out << ( << c.pR << , << << c.pI << );
return out;
}
On utilise des types oprandes, caractres, rels, dj existants dans la classe ostream.
Ensuite :
complex c1(3.5, 0.5);
cout << "c1 = " << c1 << \n;
afchera :
c1 = (3.5, 0.5)
Joli non ?
NB : ce nest pas la meilleure programmation. Pour pouvoir accder aux attributs du
complexe, on doit dclarer loprateur friend ce qui oblige adapter linterface de
classe. En pratique il serait prfrable dutiliser des accesseurs, GetReal, GetImag,
disponibles dans la classe.
Ainsi, et sans devoir toucher au chier interface de classe, nimporte quel code
utilisateur pourrait implanter son oprateur de sortie personnel :
ostream& operator<<(ostream& out, complex& c)
{
out << ( << c.GetReal() << ", " << c.GetImag() << );
return out;
}

64

Annexe E

Les patrons

Le dernier gros apport de C++, par rapport C, concerne la possibilit de dnir des
patrons (templates en anglais) ou modles. Il ny a rien de conceptuel, cest simplement
un outil de programmation mais trs puissant.
Lide est dviter de devoir crire et recrire du code presque identique, et donc de
donner au compilateur les informations ncessaires pour gnrer automatiquement
du code. Un patron C++ est, en quelque sorte, du code source paramtr.
Lutilisation intensive de patrons est un vaste sujet, cette annexe se borne prsenter
le principe.
Dans lannexe C page 55, on avait initi le dveloppement dune petite classe de
nombres complexes. Ceux-ci comportaient des attributs parties entire et imaginaire,
encods en rels simple prcision, float
Si lon dsire galement travailler avec des complexes en double prcision, il faudrait
reconstruire une classe analogue, dupliquer les chiers, remplacer les types float
par des types double, etc. Bref, un abominable travail qui nest plus de la programmation. Quant la maintenance, ajout de nouvelles oprations, nen parlons
pas.
La solution cest le patron de classe. On va dcrire, non plus une interface de classe
C++ mais un modle pour construire des classes C++, le type des attributs tant un
paramtre symbolique que lon appellera : VERB (ou TOTO si lon prfre).

E.1

Interface
Nouveau chier interface, complex.h, avec le maximum de code en ligne (on
prcisera pourquoi ensuite) :
template<class VERB>
class complex
{
// Constructeurs
public:
complex()
{ pR = pI = (VERB)0; }
complex(VERB real, VERB imag)
{ pR = real; pI = imag; }
complex(complex<VERB>& model)
{ pR = model.pR; pI = model.pI; }
// Attributs
private:
VERB pR, pI;

65

Introduction au langage C++

// Operateurs
public:
complex<VERB>& operator=(complex<VERB>& arg)
{ pR = arg.pR; pI = arg.pI; return arg; }
void
operator+=(complex<VERB>& arg)
{ pR += arg.pR; pI += arg.pI; }
... etc
};
Lcriture est similaire, quelques dtails prs. Les attributs sont typs par le type
symbolique VERB, les rfrences une classe patron scrivent, ici, complex<VERB>
et non plus simplement complex. En fait, le nom de classe lui-mme est paramtr.
Lutilisation dune classe patron est immdiate, sous rserve de rsoudre le paramtrage :
complex<float> c1; // Un complexe simple precision
complex<double> c2; // et un autre, double precision
et cest tout ! Le compilateur a tout ce quil faut pour implanter une "vraie" classe
de complexes attributs float et une attributs double.
NB : si lon trouve la notation un peu disgracieuse, on peut la contourner facilement :
typedef complex<float> acomplex;
typedef complex<double> dcomplex;
acomplex c1;
dcomplex c2;

E.2

// Un complexe simple precision


// et un autre, double precision

Implmentation
e
On peut, bien sr, implmenter du code de patron de manire classique, dans un
chier source spar, moyennant quelques petites prcautions syntaxiques, lcriture
est un peu plus lourde que pour du codage de mthodes classique :
/* Constructeur initialisation */
template<class VERB>
complex<VERB>(VERB real, VERB imag)
{
pR = real;
pI = imag;
}
/* Somme composee */
template<class VERB>
void complex<VERB>::operator+=(complex<VERB>& arg)
{
pR += arg.pR;
pI += arg.pI;
}
Lintrt de la gnration en ligne, quand elle est envisageable (quelques lignes de
code), est que dune part le compilateur gnre le code sur place, et dautre part
nutilise le patron que par fragments, selon les besoins.

66

11 - Les patrons

67

Une classe comme celle de notre exemple, des complexes, pourrait comporter
plusieurs dizaines doprateurs, avec diffrents types darguments. Si le code application nen utilise que deux ou trois, les autres nauront mme jamais exist dans le
programme !
Enn, si tout le codage est possible en ligne, seul le chier de dclaration, complex.h, existe. Plus de chier source, plus ddition de liens avec tel ou tel module
librairie pour le code utilisateur.

E.3

Remarques
La puissance de cet outil est assez remarquable ! On se borne dcrire comment
construire des classes, de tel ou tel type. Cest un peu un mcanisme dapprentissage,
ensuite le compilateur se dbrouille (en gnral bien, et toujours mieux quun humain
qui fait du copier/coller et du cherche/remplace lditeur de texte) !
De plus, il est possible de dnir des patrons plusieurs paramtres :
template<class P1, class P2>
class machin
{
...
et on pourra ensuite instancier par :
machin<float, float> m1;
machin<int, double> m2;
...

(Voir le nombre de copier/coller vits, avec un patron simplement 2 paramtres


pouvant chacun tre substitu par 3 ou 4 types diffrents ! Et que penser dun patron
10 paramtres...)
Ce mcanisme est trs utilis pour implanter du code gnrique, par exemple des
algorithmes de gestion de listes dobjets, ajout, insertion, recherche, etc.
On construit un patron list<TRUC>, pour grer une liste de nimporte quoi, et on
instancie au fur et mesure des besoins :
list<int>
L1; // Liste dentiers
list<dcomplex> L2; // Liste de complexes double

L, on quitte le domaine du trivial, mais le travail est intressant et surtout rutilisable


un haut degr.
Il faut signaler que les patrons sont un outil C++ rcent et que la mise en oeuvre nest
pas totalement stabilise. En particulier, lorsquon commence scarter des utilisations simples, comme prsent ici, il peut y avoir des variantes de comportement
dun compilateur lautre.
Le gcc, par exemple, comporte des directives spcialises pour la gestion des patrons,
#pragma interface, #pragma implementation.
Certains compilateurs C++, cest le cas du CC de Sun, crent mme des bases de
donnes de patrons dans les rpertoires de dveloppement (sous rpertoire Templates.DB pour Sun).
Dans tous les cas, la documentation du compilateur utilis savre indispensable.

67

Introduction au langage C++

68

Annexe F

Exceptions

C++ a introduit rcemment un mcanisme de gestion derreurs par exceptions logicielles. Ce mcanisme nest pas encore stabilis, tous les compilateurs C++ nen
disposent pas, ou sur options, ou avec des variantes.
Ce manuel ne traite pas le sujet ! Si ncessaire, se rfrer au manuel de B. Stroustrup
et tudier la documentation du compilateur utilis.

69

Introduction au langage C++

70

Index
@

superclasse 25
__cplusplus 51
cxx 2

delete 15, 16
Destructeur 12
virtuel 42
Dynamique,
instance 15
Drive,
classe 23

& 30
<< 63
>> 63

D
Abstraite,
classe 40
Accesseur 33
Ami,
membre 34
oprateur 63
Attribut 7
de visibilit 11, 26

E
B

Base,
classe de

dition de liens 2
Entres/sorties 63
extern "C" 51

22

C
catch 69
CC 2
class 8
Classe 7
abstraite 40
de base 22
drive 23
forward 47
implmentation 10
instance 9
interface 8
mthode 17
oprateur 57
patron 65
structure 46
support 38
Cloneur,
constructeur 55
Code en ligne 32
Compilation 2
options 2
const 30
Constructeur 12
cloneur 55
d objets membres 27

F
Fichier,
implmentation 10
inclusion 47
interface 8, 47
Fonctionnelle,
surcharge 38
Forward,
classe 47
friend 34

G
gcc 2

H
Hritage 21
public 23

71

Introduction au langage C++

L
Locale,
instance 14

N
50

O
Objets membres,
constructeur d 27
operator 57
Options,
compilation 2
Oprateur,
ami 63
classe 57
surcharge 55, 63
overload 38
overstrike 17

72

rethrow 69
Rfrence 30
Rsolution de porte 40, 44,
45

Membre 7
ami 34
statique 43
Mthode 7
classe 17
virtuelle 38

Name mangling
new 15

P
Patron 65
classe 65
Pointeur 15
Polymorphisme 37
private 8, 11
protected 26
Prdclaration 47
public 8, 11, 23
hritage 23

Implmentation,
classe 10
chier 10
Inclusion,
chier 47
inline 32
Instance 7
classe 9
dynamique 15
locale 14
temporaire 59
Interface,
classe 8
chier 8, 47

Sousclasse 23, 24
static 43
Statique,
membre 43
struct 46
Structure,
classe 46
Superclasse 22, 24
constructeur 25
Support,
classe 38
Surcharge,
fonctionnelle 38
oprateur 55, 63
de slection 17
Slection,
surcharge de 17

T
template 65
Temporaire,
instance 59
this 45
throw 69
try 69

13 - Index

73

73

Vous aimerez peut-être aussi