Vous êtes sur la page 1sur 0

Cours de Programmation

Introduction
C++
Laurent Henocque
Matre de Confrences
Ecole Suprieure dIngnieurs de Luminy
Universit de la Mditerrane Aix-Marseille II
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 1
Cours de programmation
Introduction C++
Utilisation avance du langage
Manuel de rfrence sommaire
ESIL / ES2I
Universit de la Mditerrane
par Laurent Henocque
(henocque@esil.univ-mrs.fr)
(http://www.esil.univ-mrs.fr/Staff/Prof/henocque/)
version 1.2 en date du 8 octobre 1996
Ce document peut tre librement reproduit dans son intgralit pourvu que la prsente mention de copyright ainsi que
celles prsentes en tte et en pied de page y restent attaches. Toute autre forme de copie est interdite.
Auteur Laurent Henocque, matre de confrences.
Ce document est un cours de l
Ecole Suprieure dIngnieurs de Luminy,
dpartement Etudes Suprieures en Ingnierie Informatique,
163 Avenue de Luminy, case 925, 13288 Marseille Cedex 9
(http://www.esil.univ-mrs.fr)
0. Introduction et plan
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 2
Ce cours voque les notions fondamentales du langages C++ telles quexposes dans louvrage C++ Seconde Edition,
par lauteur du langage C++ : Bjarne Stroustrup. Ce livre constitue un document de rfrence irremplaable. Nous en
reprenons ici de nombreux exemples, et une partie de la structure.
Lobjectif du cours est de servir de rfrence pour ltudiant soucieux dexploiter le plus possible les qualits du langage,
et envisage donc les diffrentes constructions dans un assez grand dtail.
Voici le plan de ce cours :
1. A LA DECOUVERTE DE C++ 1
1.1. introduction1
1.2. paradigmes de programmation 1
1.3. "Un meilleur C" 4
1.4. C++ apporte un support pour les abstractions de donn es 6
1.5. C++ apporte un support pour la programmation par objets 9
2. FONCTIONS ET FICHIERS 12
2.1. introduction12
2.2. porte d'dition 12
2.3. porte d'dition 12
2.4. fichiers d' en tte .h 13
2.5. ditions de liens avec du code non C++ 14
2.6. comment construire les bibliothques15
2.7. les fonctions 15
2.8. macros 21
2.9. macros 21
2.10. exercices 24
3. CLASSES 26
3.1. classes et membres 26
3.2. interfaces et mise en oeuvre 29
3.3. autres caractristiques des classes 30
3.4. construction et destruction 34
3.5. exercices 36
3.6. 37
4. HERITAGE 38
4.1. introduction et tour d'horizon 38
4.2. hritage : classes drives 38
4.3. classes abstraites 38
4.4. hritage multiple 39
4.5. hritage virtuel 39
4.6. contrle d'accs 39
4.7. mmoire dynamique39
5. DECLARATIONS ET CONSTANTES 41
5.1. dclarations 41
5.2. les noms 43
5.3. les types 43
5.4. les littraux 50
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 3
5.5. les constantes nommes 51
5.6. les champs de bits et unions 53
5.7. exercices 54
6. EXPRESSIONS ET INSTRUCTIONS 56
6.1. sommaire des oprateurs 56
6.2. les instructions 65
6.3. commentaires et indentation67
6.4. exercices 67
7. SURCHARGE D'OPERATEUR 70
7.1. introduction70
7.2. fonctions oprateurs 70
7.3. conversions de types dfinis par le programmeur 71
7.4. littraux 73
7.5. gros objets 73
7.6. affectation et initialisation 73
7.7. indexation 73
7.8. oprateur dappel de fonction 73
7.9. indirections 73
7.10. incrmentation et dcrmentation 74
7.11. une classe chane de caractres 74
7.12. amies et membres 75
7.13. avertissement 76
8. TEMPLATES 77
8.1. introduction77
8.2. un patron simple : patron de classe 77
8.3. listes gnriques 77
8.4. fonctions gnriques globales81
8.5. rsolution de la surcharge des fonctions gnriques 82
8.6. arguments de template 82
8.7. drivation et templates 83
8.8. un tableau associatif 83
9. GESTION DES EXCEPTIONS 85
9.1. gestion des erreurs 85
9.2. discrimination et nommage des exceptions 85
9.3. acquisition de ressources 87
9.4. exceptions qui ne sont pas des erreurs 89
9.5. spcification d'interface 89
9.6. exceptions non interceptes 90
9.7. alternatives la gestion des erreurs 90
9.8. 90
10. FLOTS 91
10.1. introduction91
10.2. sorties 91
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 4
10.3. entres 91
10.4. mise en forme 93
10.5. fichiers et flots 98
10.6. entres/sorties C 99
11. NOTES RAPIDES AU PROGRAMMEUR C 100
11.1. rgles empiriques de base pour la conception d'objets100
11.2. notes aux programmeurs C 100
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 1
1. A la dcouverte de C++
1.1. introduction
C++ est une tentative d'amliorerC
C++ supporte labstraction de donnes
C++ permet la programmation objet
1.2. paradigmes de programmation
1.2.1. la programmation procdurale : algorithmie
choisir les procdures, implanter les meilleurs algorithmes
double sqrt(double) {
// calcule result avec le meilleur algorithme possible
return result;
}
1.2.2. la programmation modulaire
choisir les modules, masquer les donnes (exemple de la pile)
#include "stack.h"
static char v[stack_size]
static char * p=v;
void push(char c){/*vrification de dbordement et empilement*/}
char pop(){/*vrification de taille 0 et pop*/}
avantages : l'utilisateur ne connat que les fonctions, et la reprsentation interne peut changer
C++ supporte ce type de programmation par compatibilit avec C, et l'tend grce aux classes
1.2.3. l'abstraction de donnesdans un langage classique (C)
pour chaque type de donne, on donne un ensemble complet d'oprations : notamment des fonctions de construction et
de destruction et de copie, comme il en existe pour les types fondamentaux, mais aussi toutes les fonctions correspondant aux
services offerts par la classe
c'est ncessaire par exemple si l'on doit pouvoir utiliser deux piles simultanment, ce qui n'est pas permis par la
programmation modulaire ( cause de l'utilisation de variables globales)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 2
/*class*/ struct stack_id {};
stack_id create_stack();
void delete_stack(stack_id);
void push (stack_id, char);
char pop (stack_id);
les types ainsi conus par des classes sont diffrents des types pr dfinisdans leur utilisation
le compilateur (C) reste incapable de dtecter certaines erreurs. Dans l'exemple ci dessous, s2 est utilis et dtruit sans
avoir t initialis.
main(){
stack_id s1,s2;
s1 = create_stack();
push (s1,'a');
char c = pop(s1);
push (s2,'b');
delete_stack(s2);
}
1.2.4. ... abstraction de donnes
C++ amliore cette situation. On dispose du mot clef "class". La classe est une unit d'encapsulation pour les fonctions
qui implmentent les services rendus, et pour les donnes ncessaires. Le langage interdit d'utiliser un objet non initialis, et
le compilateur devient capable d'effectuer certains contrles.
class complex {
double re,im;
public:
complex (double r, double im){re = r; im = i;}
complex (double r){re = r; im = 0;}// conversion
friend complex operator+(complex,complex);
friend complex operator-(complex,complex);
friend complex operator-(complex);
friend complex operator*(complex,complex);
friend complex operator/(complex,complex);

};
complex operator+(complex c1, complex c2){
return complex(a1.re+a2.re,a1.im+a2.im);
}
void main(){
complex a = 2.3;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 3
complex b = 1/a;
complex c = a+b*complex(5,7.3);
c = c-a*b+2;
}
Dans l'exemple ci dessus, les fonctions de construction de la classe "complex" sont appeles automatiquement, et la
dfinition des oprateurs pour ce nouveau type permet de l'utiliser "comme" un type prdfini. C'est du C++.
1.2.5. difficults lies l'abstraction (quand on n'a pas de notion d'objet!)
il peut tre impossible d'adapter un type pour de nouvelles utilisations sauf en modifiant sa dfinition. En
programmtion classique, on doit souvent recourir des tests (au moyen de "switch" par exemple) que C++ rend inutiles,
facilitant ainsi considrablement la rutilisabilit des programmes.
class point {};
enum shapeType {circle, triangle, square};
class shape{
point center;
shapeType type;
public :
point where (){return center;}
void draw();
void rotate(float);

};
void shape::draw(){
switch (type){
case circle : break;
case triangle : break;
case square : break;
}
}
dans l'exemple ci dessus, chaque nouvelle forme ajoute impose de toucher le code de toutes les fonctions importantes
dfinies pour letype "forme"
1.2.6. la programmation par objets
le problme rencontr auparavant vient de ce que le langage ne permet pas de distinguer entre les proprits gnrales
des "shape" et celles qui sont spcifiques de chaque sorte de "shape"
l'hritage permet de rsoudre ce problme
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 4
class shape {
point center;
public:
point where () { return center;}
void move (point to) {undraw(); center = point; draw();}
virtual void draw();
virtual void rotate(float);
};
les fonctions dont l'interface d'appel peut tre dclare, mais ne peut pas tre dfinie, ont t dclares virtual
de telles fonctions sont dites constituer le protocole de la classe abstraite shape.
une fonction virtuelle est lie dynamiquement : la bonne fonction est appele automatiquement sur un objet, mme
quand son type exact est inconnu
shape *tab[50];
void draw_all(float){
for (int i=0; i<50;i++){ tab[i]->rotate();}
}
1.2.7. la programmation par objets
chaque forme particulire est alors dclare comme une forme (via l'hritage, dclar par la syntaxe ":" ci dessous),
dont les caractristiques spcifiques peuvent tre prcises
class circle : public shape {
float radius;
public:
void draw(){};
void rotate(float){/*rien a faire*/}
};
le processus de dveloppement consiste alors
choisir les classes,
partager par hritage ce qui est commun,
implanter les fonctions spcifiques chacun des types
1.3. Comment C++ amliore le langage C
C++ apporte fonctions, arithmtique, instructions de branchement et constructions itratives comme en C
les entres sorties sont accessibles au travers d'une bibliothque , diffrente de celle connue en C
les constructions lmentaires et les pointeurs sont issus de C
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 5
la compilation spare apporte une notion minimale de module , comme en C
on ne dispose toujours pas d'une notion de package qui fournirait un espace de nommage isol
1.3.1. le plus petit programme C++du monde
int main(){return 0;}
1.3.2. le programme "hello world"
#include <iostream.h>
int main(){
cout << "bonjour tout le monde\n";
return 0;
}
1.3.3. les entres sorties
#include <iostream.h>
int a;
cin >> a; // charge dans la variable a l'entier qui est frapp au clavier
cout << 2*a << endl; // affiche sur la console le double de a, et fin de ligne
1.3.4. variables et arithmtique
types fondamentaux : char, short, int, long, float, double, long double
oprateurs arithmtiques : + - * / %
oprateurs de comparaison : == != < > <= >=
C++ permet la conversion automatique entre les types de base, garantie sans perte d'information si possible (c'est
assur dl lors que le type origine est converti en un type dont la reprsentation est au moins aussi grande en nombre
d'octets).
double d;
int i = 2.0;//float vers int
short s;
d = d+i;//int vers double
i=s*i;//short vers int
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 6
1.3.5. pointeurs et tableaux
les types X tab[] et X* tab sont comparables de mme qu'en C (un tableau n'est jamais copi). Un tableau est
strictement identique un pointeur vers son premier lment.
char v[20]; // un pointeur vers 20 caractres conscutifs
char *p, *q; // deux pointeurs vers un caractre
q=v; // ok
p=&v[3]; // l'adresse du quatrime char est un pointeur
1.3.6. tests et itrations
if, switch, while, for comme en C
on peut dclarer une variable au moment de sa premire utilisation, aprs des instructions, mme dans une instruction
"for" : for (int i=8; i>= 0; i--){}
la norme C++ prvoitmaintenant que la variable ainsi dclare soit locale la boucle, mais attention, de nombreux
compilateurs ne sont pas encore la norme.
1.3.7. fonctions
les types des arguments sont contrls lors de l'appel et ventuellement convertis dans le type attendu
la signature d'une fonction(on dit aussi son "prototype") est constitue de :
son nom
les types de ses arguments dans l'ordre ou ils se prsentent
le type retourn par la fonction n'est pas indiffrent, mais n'est pas traditionnellement en C++ considr dans sa
signature.
deux fonctions diffrentes peuvent porter le mme nom : int f(int); int f(float). On parle alors de surcharge, ou de
polymorphisme. Le compilateur a l'intelligence de savoir quelle fonction appeler en fonction des types des arguments qui
sont proposs.
le passage d'argument par rfrence est possible comme en Pascal (passage VAR). En C, le mme mcanisme requiert
l'utilisation explicite de pointeurs.
void swap (int& i, int&j){ // permute les valeurs de deux variables
int aux = j;
j = i;
i = aux;
}
int main (){
int a = 1;
int b = 2;
cout << a << " " << b << endl;
swap(a,b);
cout << a << " " << b << endl;
return 0;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 7
}
1.3.8. la ralisation de modules et de bibliothques
C++ permet l'dition de liens avec des fonctions crites en d'autres langages , condition d'informer le
compilateur des conventions de passage des arguments
extern "C" double sqrt(double);
extern ostream cout;
extern permet de spcifier le type deconvention de passage des arguments (fortran et pascal sont comme "C")
on peut rpartir la programmation dans des fichiers spars avec rfrences externes
// header.h
extern char *chaine;
// chainedef.cc
#include "header.h"
char *chaine = "hello world\n";
//chainedisp.cc
#include "header.h"
#include <iostream.h>
main(){
cout << chaine;
return 0;
}
//compilation
les deux fichiers .cc sont alors compils par la commande :
CC chainedef.cc chainedisp.cc -o prog
ou encore:
CC -c chainedef.cc #genere chainedef.o
CC -c chainedisp.cc #genere chainedisp.o
CC chainedef.o chanedisp.o -o prog
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 8
1.4. C++ apporte un support pour les abstractions de donnes
1.4.1. initialisation et destruction
les classes comportent des mthodes de construction d'objet, et de destruction
on veut viter de sparer l'allocation de l'espace requis pourun objet et son initialisation (source d'oublis facheux)
un constructeur est une fonction qui porte le meme nom que la classe. Il y en a toujours plusieurs
le destructeur porte le nom de la classe prcd du caractre "~" (tilde)
class vector{
int _s;
int *_t;
public:
vector (int s){ // cette fonction est un constructeur de vector
assert(s>0);
_s=s;
_t=new int [s];
}
vector ():_s(0),_t(0){} // un autre constructeur, qui initialise tout 0
~vector () {delete []t;} // cette fonction est LE destructeur de vector
int operator[](int i){return _t[i];}
};
Le compilateur appelle automatiquement les constructeurs correspondant aux arguments fournis en mme temps que la
dclaration, et les destructeurs des variables locales
main(){
vector v(5); // appelle le constructeur un argument
vector w = 8; // appelle egalement ce constructeur
vector x; // appelle le constructeur sans argument.
...
} // appelle le destructeur de vector pour x, puis pour w puis pour v
1.4.2. affectation et initialisation
on doit galement contrler les oprations de copie, dans deux cas : l'initialisation d'un objet avec un autre du mme
type pour argument (on parle alors de construction par copie), ou l'affectation d'un objet sur un autre.
par dfaut, la copie C++ est a copie champ champ de la structure C, en gnral non satisfaisante :
void main(){
vector v1(100); //initialisation classique
vector v2 = v1; //initialisation par copie
v1 = v2; //copie simple lors d'affectation
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 9
}
la classe vector peut tre compltecomme suit :
class vector{

void operator=(const vector&); // affectation


vector (const vector&); // initialisation par copie
};
question : pourqoui la copie par dfaut des champs des objets n'est elle pas satisfaisante?
question : comment programmer ces deux fonctions afin de remdier ce problme?
1.4.3. patrons
en C++, on peut galement dfinir des types gnriques, comme un "vecteur "de n'importe quoi". Dans l'exemple ci
dessous, le symbole T est un type paramtre pour le template VectorOf :
template<class T> class VectorOf {
T* v;
int sz;
public:
VectorOf (int s) { v = new T[sz = s]; }
};
void f() {
VectorOf<int> v1(100);
VectorOf<complex> v2(100);
}
1.4.4. gestion des exceptions
en C, les exceptions ne sont pas prises en charge par le langage. Habituellement on utilise setjump et longjump (des
fonctions de libc) pour transfrer rapidement le contrle d'execution d'un programme lors de situations exceptionnelles sans
avoir prvoir de codes d'erreur en valeurs de retour des fonctions.
C++ apporte des constructions spcifiques pour le traitement des exceptions :
on dclare un type quelconque (notre sempiternel vector par exemple), et une (ou plusieurs) classe d'exception pour ce
type : ici "range" qui sera leve lors de dpassement des bornes du tableau :
class vector {
class range {};
...};
on lance le contrle tout programme susceptible de traiter l' exception par l'intruction "throw"
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 10
int vector::operator[](int i) {
if (i<0 sz<=i) throw range();
return v[i];
}
on peut alors intercepter l'erreur dans un blocspcialis de type "try {} catch{}"
void f(int i) {
try {
vector v[i];
v[i+1000] = 12; // exception assure
// programmes pouvant aussi provoquer une exception
} catch (vector::range){
error ("attention : bornes de tableau dpasses");
}
}
1.4.5. conversions de types
C++ est un langage trs fortement typ statiquement. Le dfaut d'un tel langage est que le compilateur refuse de
prendre des vessies pour des lanternes : on doit parfois convertir (on dit "caster") des pointeurs d'un type vers un autre. En
C++ le programmeur peut dfinir des convertisseurs pour ses objets dans d'autres types, ce qui peut viter ces fameux cast, et
mme programmer des conversions d'un type vers un autre par forcment trs proche (un objet converti en entier qui indique
son tat par exemple)
les convertisseurs peuvent tre appels explicitement ou laisss aux bons soins du compilateur quand il en est capable
(lors d'un appel de fonction notamment)
complex a = complex(1); // explicite
complex b = 1; // implicite
a = b + complex(2); // explicite
a = b + 2; // implicite
les convertisseurs permettent aussi de rduire la complexit des interfaces de programmation : une seule fonction
complex operator+ (complex,complex) traite trois situations ds lors qu'il existe une convertion de int vers
complex
1.4.6. C++ permet de multiplier les implantations
on peut dfinir une superclasse abstraite de plusieurs implantations distinctes du mme type
par exemple : une pile dclare de faon abstraite puis implante sous les deux formes de tableau et de liste
template <class type> class stack {
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 11
public:
virtual void push(T) = 0; // pure virtuelle
virtual T pop(void) = 0; // pure virtuelle
};
on ne peut pas utiliser d'instances d'une classe abstraite
stack<vtt> S; // erreur
void f(stack<car>& sc, car mercedes){ //ok
sc.push(mercedes);
car aux = sc.pop();
}
1.4.7. C++ permet de multiplier les implantations
on peut dfinir plusieurs sous types de piles, l'interface ne change pas
ex : avec un tableau
template <class T> class astack : public stack<T>{
// un tableau
public:
astack(int s);
~astack();
void push(T);
T pop(void);
}
ex : avec une liste :
template <class T> class lstack : public stack<T>{
// une liste
public:
lstack(void);
~lstack();
void push(T);
T pop(void);
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 12
1.5. C++ apporte un support pour la programmation par objets
1.5.1. mcanismes d'appel
appel de fonction membre par les oprateurs -> et .
class shape{
virtual void rotate(int);
};
void main(){
shape *p;

p->rotate();
}
dtermination statique de la fonction membre
c'est le cas lorsqu'elle n'est pas dclare virtuelle : le compilateur choisit celle qui est dfinie pour la classe connue de
l'objet
dtermination du membre dynamique
lorsqu'elle est virtuelle : le compilateur appelle la fonction indirectement, au travers d'un champ appel vtbl
cet appel est aussi efficace qu'un appel normal de fonction
Shape
center
color

&?::draw()
&?::rotate()
Circle
vtbl
&Circle::draw()
&Circle::rotate()
vtbl
1.5.2. vrification de type
les types des arguments des fonctions sont contrls par le compilateur, ce qui permet une dtection prcoce des erreurs
la vrification statique associe au mcanisme de fonctions virtuelles est trs performante compare la vrification de
type dynamique de certains langages (Smalltalk)
les erreurs sont par ailleurs dtectes avant l'excution
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 13
ex smalltalk:
Stack s; // pile fourre tout
void main(){
s.push (new Peugeot(309));
s.push (new Boeing(727));
s.pop()->takeoff();
s.pop()->takeoff(); // erreur excution : une 309 ne vole pas
ex C++:
Stack s<plane>; // pile d'avions
void main(){
s.push (new Boeing(727)); // ok
s.push (new Peugeot(309)); // erreur compilation
s.pop()->takeoff();
Smalltalk permet de dfinir pour une classe un ensemble minimal d'oprations, l'utilisateur tant libre d'(essayer d')
appeler une fonction non dfinie la base
C++ permet de dfinir une interface exacte, toute erreur tant dtecte ds la compilation
1.5.3. hritage multiple
C++ permet de dfinir des classes qui hritent de plusieurs super classes
ce mcanisme est prcieux car il offre une flexibilit qui ne peut tre atteinte sinon
class task {};
class printableObj {};
class taskPrintable : public task, public printableObj{};
class mytask : public task {};
class myprintable : public printable {};
class mytaskPrintable : public taskPrintable {};
sans l'hritage multiple, deux seulement des trois choix ci dessus sont accessibles
C++ ne tient aucun compte de l'ordre de l'hritage pour rsoudre les ambiguts, et demande une dsambiguation
explicite
1.5.4. un exemple d'hritage multiple
class A {void f();};
class B {void f();};
class C : public A, public B {/*f non redfini*/};
class D : public A, public B {
void f() {
A::f(); // appel explicite de f pour la classe A;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 14
B::f(); // appel explicite de f pour la classe B
}
};
main(){
C c;
c.f();// erreur : ambigu
c.A::f(); // OK
D d;
D.f();// ok
}
1.5.5. l'encapsulation
les fonctions oprant sur un objet sont encapsules dans la classe.
l'unit d'encapsulation est la classe, et non l'objet : un objet d'une classe possde tous les droits sur un autre objet de la
mme classe
en particulier, une classe C++ n'est pas un objet C++ : la classe n'est pas une entit palpable, mais une abstraction utile
seulement lors de la compilation
C++ permet de restreindre l'accs aux membres des classes, donnes ou fonctions, sans distinguer entre les
autorisations de lecture et d'criture pour les donnes membres
public donne l'accs tout programme
private interdit l'accs tout programme, y compris un membre d'une classequi en hrite
protected donne l'accs aux seuls membres de s (futures) sous classes
le mot clef friend permet de donner l'accs de faon explicite (toutes les fonctions d') une classe, o une fonction
dsigne explicitement
l'accs une fois possible l'est en lecture et en criture pour les champs
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 15
2. Fonctions et fichiers
2.1. introduction
le fichier a un rle unique : dfinir la porte de fichier pour :
les fonctions static,
les fonctions inline,
les variables globales static et
les variables globales const
cest aussi habituellement une unit de stockage et de compilation
2.2. La porte d'dition
un nom qui nest pas local une fonction ou une classe doit dsigner un objet du mme type dans tous les fichiers
dun programme compil en plusieurs units
donc un nom de fonction ou de variable n'apparat qu'une seule fois dans un programme (on entend ici programme
excutable)
// fic1.cc
int a = 1;
int f() {/* du code ici */}
//fic2.cc
extern int a; // la variable a de fic1.cc
int f(); // la fonction f de fic1.cc
void g() { a = f();} // g dfinie ici appelle f dfini dans fic1.cc
un objet doit tre dfini une seule fois dans un programme
il peut tre dclar plusieurs fois, de faon identique, notamment dans diffrents fichiers combins pour produire le
programme excutable
// fic1.cc
int a = 1; // dclaration ET dfinition
int b = 1; // id
extern int c; // dclaration seule
//fic2.cc
int a; // erreur, signifie int a = 0; les globales sontinitialises
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 16
extern double b; // erreur type diffrent
extern int c; // erreur, dclaration mais pas de dfinition
2.3. porte d'dition
on peut faire empcher la publication d'un symbole dans tout le programme par une dclaration interne explicite
utilisant static (porte de fichier)
la porte static facilite la comprhension des programmes
les noms de classe doivent tre uniques tout le programme, et rfrer des descriptions identiques
// fic1.cc
struct S {int a; char b;};
extern int f(S*);
//fic2.cc
struct S {char a; int b;}; // diffre de S dans fic1
int f(S*p){/*your code here*/}
// (certains compilateurs ne verront pas lerreur)
habituellement, les dfinitions de classes sont dcrites dans des fichiers d'en tte inclus par tous les fichiers qui les
utilisent
les fonctions inline ont une porte ddition interne
les constantes (const) aussi
les typedef sont locaux leur fichier galement. Attention, en C++ typedef ne sert pas dfinir un type mais dfinir
un nouveau nom pour un type, ou un nom de type composite.
on a la possibilit de dclarer des constantes externes explicites
extern const int a;
const int a = 1;
2.4. fichiers d' en tte .h
leur suffixe est habituellement .h
ils sont inclus dans les fichiers sources .cc
#include monfic.h // cherche d'abord dans le rpertoire courant puis comme <>
#include <libfic.h> // dans les rpertoires dinclude standard et utilisateur
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 17
2.4.1. contenu normal d'un fichier .h
dfinitions de types struct list{};
patrons template <class T> class A {T f();};
dclarations de fonctions extern void g();
dclarations de fonctions inline inline max(int a,int b) {}
dclarations de variables extern char calu;
dclarations de constantes const int MAXINT = 10000;
dclarations d'numrations enum codes {NUL, BCD, WKL}
dclarations de noms struct list;
inclusions #include
dfinitions de macros #define ONDEBUG(prog) {prog}
commentaires // et /* */
2.4.2. ce quil ne faut pas y mettre
dfinition de fonctions normales, void g(){};
dfinition de donnes int maglobale; //initialise
dfinition d'agrgats de constantes const tab[] = {1,3,5};
2.4.3. le projet fichier en tte unique
on dfinit un unique fichier .h pour un projet, qui permet la dclaration des lments communs tous les fichiers
compiler
utile sur un petit projet que l'on veut compiler par parties
2.4.4. le projet fichiers en tte multiples
utile lorsque des parties peuvent tre utilises sparment
ncessaire sur les grands projets pour viter que tous les programmes soient compils avec toutes les dclarations, ce
qui ralentit la compilation
on dcrit souvent linterface publique de programmation dun fichier .c dans un .h de mme nom
2.5. ditions de liens avec du code non C++
2.5.1. extern "C" {}
sert dire au compilateur que les conventions d'dition de liens sont celle de "C" pour un ensemble de fonctions ou de
variables
n'affecte pas la porte, la smantique, ni les ordres d'appels
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 18
fortran et assembleur ont les mmes conventions que C
possibilit d'utiliser le symbole __cplusplus dfini par le prprocesseur du compilateur
extern C char * strcpy(char *, const chat *);
ou encore
extern C {
char * strcpy(char *, const char *);
char * strcmp(const char *, const char *);

}
2.5.2. extern "C" {}
pour utiliser un fichier de dclarations dune bibliothque standard C :
extern C {
#include <string.h>
}
pour crire un fichier .h compatible entre C et C++:
#ifdef __cplusplus
extern C {
#endif
char * strcpy(char *, const char *);
char * strcmp(const char *, const char *);

#ifdef __cplusplus
}
#endif
Note : la directive extern C spcifie la convention ddition de liens, mais le programme compil doit rester du C++,
qui est plus rigoureux que C, notamment sur lutilisation effective des arguments des fonctions
2.6. comment construire les bibliothques
2.6.1. gnration d'objets
CC -c prog.cc
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 19
2.6.2. construction de bibliothques
ar rv prog1.o, prog2.o malib.a
ranlib malib.a
2.6.3. compilation d'excutables
CC main.cc -o main malib.a
2.7. les fonctions
pas d'appel possible avant la dclaration(en C, une fonction non dclare tait sense retourner un int).
2.7.1. dclarations
une dclaration de fonction mentionne les types de la valeur de retour et des arguments et le nom de la fonction
une fonction est soit globale (comme une fonction C) soit membre d'une classe donne. On y accde alors avec les
oprateurs . et -> comme dans le cas des donnes membres.
class StackOfInt {
// ...
void push (int data);
int pop ();
};
// ...
main(){
StackOfInt s;
s.push(5);
(&s)->pop();
}
le passage d'argument est comparable linitialisation : les types sont vrifis et les conversions ncessaires qui sont
possibles sont ralises
les arguments peuvent tre nomms lors de la dclaration : cela rend les fichiers .h plus lisibles, car le nom d'un
argument claire souvent plus que son type sur son rle.
on peut fournir des valeurs par dfaut aux derniers arguments fournis dans la dclaration. Ces arguments sont alors
optionnels.
int fonction (int a, char* s = "", float f=2.0);
fonction(12); // ok : fonction(12,"",2.0);
fonction(12,"aze"); // ok : fonction(12,"aze",2.0);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 20
fonction(12,3.4); // non : les arguments doivent tre renseigns dans l'ordre
fonction(12,"ert",5.6); // ok
on peut donner le type d'une fonction qui attend un nombre variable d'arguments.
int printf (char* format ...); // un char * puis autant d'arguments que voulu
2.7.2. dfinition de fonction
toute fonction appele doit tre dfinie quelque part dans le programme avant son appel
une dfinition de fonction est une dclaration plus un corps entre accolades
int double (int a) {return 2*a;}
des arguments peuvent rester inutiliss : il suffit de ne pas les nommerpour obtenir le calme du compilateur
une fonction peut tre dclare inline
inline int double (int a) {return 2*a;}
dans ce cas, le compilateur insre le code (assembleur si on veut) de la fonction chaque appel, et sait parfois mme
faire mieux :
inline int fact (int n) {return n<2 ? 1 : n*fact(n-1);}
int i=fact(5); // gnre i=120;
un trs bon compilateur doit savoir calculer la valeur de i ci dessus la compilation
2.7.3. passage d'arguments
pour le passage d'arguments, de la mmoire est rserve dans la pile d'excution, et les arguments rels sont initialiss
par copie
C++ permet le passage par rfrence, utile pour le passage de gros objets. Un argument pass par rfrence est
comparable un argument VAR en Pascal. La rfrence s'emploie comme un paramtre copi, mais se comporte comme un
pointeur.
void f(const large& arg); // const permet que l'original ne soit pas modifi
il faut utiliser const autant que possible, mme pour les passages d'arguments par pointeur, lorsque la fonction ne doit
pas modifier l'objet point
int strlen (const char *); // strlen ne modifie pas le contenu de la chane
un littral, une constante, ou un argument qui demande une conversion peuvent tre passs comme argument d'une
fonction qui attend const&(une rfrence un objet const) , mais pas d'une fonction qui attend une rfrence non const
float fortran_sqrt(const float&);
void f(double d){
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 21
float r;
fortran_sqrt(2.0f); // rf tmp= 2.0f (erreur si non const)
fortran_sqrt(r); // rf r, ok dans tous les cas
fortran_sqrt(d); // rfrence tmp= float(d) (erreur si non const)
}
c'est normal car l'original pass en argument rfrence non const est susceptible d'tre modifi par la fonction appele.
Ce n'est pas possible pour la constante 2.0f ci dessus, ni pour la temporaire de conversion de "d" en float : la conversion
inverse n'existe pas.
2.7.4. valeur de retour
une fonction non void doit retourner une valeur, indique par return
une instruction de retour est considre comme initialisant une variable du type retourn
toutes les conversions licites peuvent avoir lieu dans ce cadre
double f(){

return 1; // converti en double(1)


}
on ne peut retourner ni une rfrence, ni un pointeur vers une variable locale ou une constante locale :
int * f(){
int aux;
return &aux;//erreur
}
int & f(){
int aux;
return aux;//erreur
}
int & f() {return 1;} // erreur
2.7.5. arguments de type tableaux
un tableau est pass comme pointeur vers son premier lment
un argument de type T[] est converti en T*
un tableau ne peut pastre pass par valeur (c'est le seul cas en C++)
la taille d'un tableau est inconnue pour la fonction appele
dans le cas des tableaux multidimensionnels, le compilateur a besoin de connatre les dimensions du tableau pour
gnrer le code d'indexation. Une seule dimension du tableau peut tre ignore, sauf implanter lsoi mme l'indexation (sans
perte de performance cela dit, voir exemple ci dessous).
void print_m34(int m[3][4]){ //cas idal
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 22
for (int i = 0 ; i<3 ; i++)
for (int j = 0 ; j<4 ; j++)
cout <<"lment i,j :" << m[i][j]<< endl;
}
void print_mi4(int m[][4], int dim1){ //cas moins idal mais OK
for (int i = 0 ; i<dim1 ; i++)
for (int j = 0 ; j<4 ; j++)
cout <<"lment i,j :" << m[i][j]<< endl;
}
void print_mij(int m[][], int dim1, int dim2); //impossible
void print_mij(int **m, int dim1, int dim2){ // la solution OK
for (int i = 0 ; i<dim1 ; i++)
for (int j = 0 ; j<dim2 ; j++)
cout << "elt i,j :" << ((int*)m)[i*dim2+j] << endl;
}
le code prcdent est le mme que celui gnr par le compilateur
2.7.6. surcharge de noms de fonctions
C++ permet de donner le mme nom des fonctions qui diffrent par leurs seuls arguments
la signature d'une fonction ne prend pas en compte le type de la valeur de retour
un appel de fonction donn choisit la fonction qui est dans la porte pour laquelle un ensemble de conversions existe
qui permettrait de l'appeler, est qui correspond le mieux possibleaux arguments rels.
la fonction choisie est celle qui dcrit une correspondance meilleure que tout autre pour au moins un argument. Dans
tout autre cas, il y a ambigut, et une erreur de compilation
void print(double);
void print(long);
f(){
print (1L); //ok 1L est un int de type long (L)
print (1.0); //ok 1.0 est une constante de type flottant
print (1); //erreur, ambigu car les deux conversion existent
}
ou encore, de faon plus vicieuse :
void print(char *);
void print(long);
f(){
print (1L); //ok
print ("toto"); //ok
print (0); //erreur, ambigu : zro ou pointeur nul?
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 23
}
dans ce dernier cas, noter que zro est un int : lambigut nat ici de ce qu'il existe deux conversions possibles
2.7.7. surcharge de noms de fonctions
les fonctions n arguments optionnels sont considres comme n+1 fonctions
si un membre d'une classe X est explicitement appel sur un pointeur en utilisant l'oprateur ->, cet argument
supplmentaire est suppos avoir le type const X* pour les membres const, volatile X* pour les membres volatile et X* pour
les autres.
si un membre d'une classe X est explicitement appel sur un objet en utilisant l'oprateur ., ou si la fonction est
invoque sur le premier oprande d'un oprateur surcharg, cet argument supplmentaire est rput avoir le type const X&
pour les membres const, volatile X& pour les membres volatile et X& pour les autres.
aucune squence de conversions contenant plus de une conversion dfinie par l'utilisateur, ou pouvant tre raccourcie
n'est examine.
la squence de correspondance la plus courte pour construire d'un type un autre s'appelle squence de meilleure
correspondance
les points de suspension correspondent tout argument rel de n'importe quel type. Dans ce cas le compilateur
n'effectue pas de conversion des arguments. Toutefois les arguments fournis dont la taille est infrieure celle d'un int sont
convertis en int.
2.7.8. conversions triviales
Les conversions triviales ci dessous n'affectent pas laquelle de deux conversions est la meilleure.
T T&
T& T
T[] T*
T(args) T(*)(args)
T const T
T volatile T
T* const T*
T* volatile T*
2.7.9. les conversions standard
promotions d'entiers (automatique des petits entiers vers int ou unsigned suivant l'implantation)
conversions d'entiers (vers unsigned, ou vers un type sign plus petit)
float et double (l'un vers l'autre, avec des pertes)
float et entier (perte de la partie dcimale)
conversions arithmtiques (pour harmoniser les types de oprandes arithmtiques, vers le type du plus grand)
conversions de pointeurs : de 0 vers ptr, de prt non const ni volatile vers void*, de fonction vers void* si assez grand,
de classe vers classe de base, de tableau vers ptr, de fonction vers adresse de fonction (sauf adresse explicite ou appel)
conversions de rfrences : d'une classe vers classe de base accessible
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 24
pointeurs sur membres : d'une classe vers une classe drive
Note : dans le cas des pointeurs sur membre, la conversion est inverse par rapport aux pointeurs normaux. Ce ne sont
pas de vrais pointeurs, et ils ne peuvent d'ailleurs pas tre convertis vers void *
2.7.10. rgles de priorit pour les correspondances
1 : correspondance exacte
les squences de zro ou plus conversions triviales sont meilleures que toute autre squence.
celles qui ne convertissent pas vers const ou volatile sont meilleures que toutes les autres.
2 : correspondance avec les promotions
les squences qui ne contiennent que des promotions d'entiers, des conversions de float en double, et des triviales sont
meilleures que toutes les autres
3 : correspondance avec les conversions standard
les squences qui ne contiennent que des conversions standard et triviales sont meilleures que toutes les autres
4 : correspondance avec les conversions dfinies par l'utilisateur
5 : correspondance avec les points de suspension dans la dclaration
si deux correspondances existent au mme niveau de priorit, l'appel est ambigu et rejet
2.7.11. arguments par dfaut
on peut spcifier des valeurs par dfaut aux arguments d'une fonction. L'argument absent lors d'un appel effectif sera
remplac par cette valeur
ce n'est possible que pour les derniers arguments de la fonction
cela doit tre fait la dfinition de la fonction
void print (int d , int base=10);
f(){
print (3);// print(3,10);
print (4,16);
}
on peut simuler ce mcanisme par surcharge (et l'tendre aux autres arguments)
void error (char *text, int code);
inline void error (int code) { error ("no text here", code);}
2.7.12. arguments de nombre et type inconnus la dclaration
on utilise dans ce cas les points de suspension, qui permettent au compilateur d'accepter des arguments
supplmentaires, utiliss ou non par la fonction lors de l'appel
extern "C" int printf(const char * ...);
extern "C" int fprintf(FILE*, const char * ...);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 25
extern "C" int execl(const char * ...);
le fichier stdarg.h dcrit des macros permettant de concevoir de telles fonctions
node * buildnode(node *first ...){
va_list ap; //ap pour Argument Pointer
va_start(ap,first); //initialise
node *child; //auxiliaire
// on cree un noeud ici
for (child = first ; child != 0 ; child = va_arg(ap,node*)){
// bravo un fils on l'ajoute a son pre
// on sarrte zro
}
va_end(ap); //ncessaire
}
f(){
node *n=buildnode(new node(), new node(), (node*)0);
}
noter que 0 est un int, et que sizeof int est potentiellement diffrent de sizeof (node *), do le cast
2.7.13. pointeur de fonction
on peut soit appeler une fonction soit prendre son adresse
void error(char*);
void (*errpt) (char*);//une variable
typedef void (*errpttype) (char*);//un type pour ces variables
f(){
errpt = &error;
errpttype aux = &error;
(*errpt)("test");
(*aux)("test");
}
lors d'une affectation un pointeur de fonction, le type de l'argument doit correspondre exactement, y compris pour sa
valeur de retour
les rgles de l'appel direct s'appliquent aux pointeurs de fonction sans changement
on peut dfinir un type pointeur de fonction pour rendre plus aise la manipulation (cf. signal.h)
ces pointeurs sont utiles pour :
paramtrer la dynamique d'un systme (actions correspondant des menus par exemple)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 26
raliser des procdures polymorphiques (comme la fonction "map" de lisp) : on passe l'adresse d'une fonction en
paramtre une autre pour effectuer un traitement global (tri d'un tableau d'objets inconnus pour lequel on mentionne un
fonction de comparaison exemple de qsort dans libC)
on peut prendre l'adresse d'une fonction inline, ou d'une fonction surcharge
2.8. macros
elles sont d'un usage plus limit en C++ qu'en C, cause de "template", "inline", et "const"
elles sont parfois utiles
les compilateurs et dbuggers sont largus, parce que les macros gnrent du code sur une seule ligne, et le
prprocesseur est invoqu avant la compilation proprement dite
#define ma_macro du texte a qui mieux mieux
#define le texte p enrob
donnent l'utilisation :
ma_macro fada
-> du texte a qui mieux mieux fada
avec_param(qui suit est)
-> le texte qui suit est enrob
partout ou C++ offre une construction quivalente il faut l'utiliser
const int MAXINT = 32768;
template <class type>
inline type max(type a, type b){return (a<b) ? b : a;}
les macros rcursives sont interdites (tentation de factorielle)
2.9. macros
lorsqu'un argument d'une macro intervient dans une expression, la macro doit le parenthser
lorsqu'un argument d'une macro est une squence d'instructions, la macro doit le mettre entre accolades
dans une macro, utiliser les commentaires /* */ la C
les mentions de noms globaux dans une macro doivent tre prfixes de "::", afin de ne pas subir de masquage local
intempestif
lorsque le rsultat de la substitution est une squence d'instructions, la macro doit la mettre entre accolades.
Par exemple :
#define carre(a) a*a
#define fonc(prog) if () prog else exit(); validate();
devraient tre crites :
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 27
#define carre(a) (a)*(a)
#define fonc(prog) {if () {prog} else exit(); validate();}
2.9.1. tapes
le pr processeur ralise les oprations suivantes :
des caractres de passage la ligne sont introduits pour remplacer les indicateurs de fin de ligne dpendant du systme
(ainsi que toute autre traduction dpendant du systme). les squences trigraphes sont remplaces (voir ci dessous)
la paire du caractre \ suivi d'un passage la ligne est efface
le source est dcompos en symboles de pr traitement et squences d'espaces. Chaque commentaire est remplac par un
unique espace
les directives sont excutes et les macros sont gnres
les squences d'chappement dans les chanes sont remplaces par leur quivalent
les littraux chaine adjacents sont concatns
la compilation peut enfin avoir lieu
2.9.2. squence trigraphe
les squences suivantes sont substitues avant toute chose
??= # ??/ \ ??' ^
??( [ ??) ] ??! |
??< { ??> } ??- ~
2.9.3. oprateur #
suivi d'un paramtre de macro, les deux sont remplacs par la chaine de caractres fournie en argument rel de la
macro
2.9.4. oprateur ##
il permet de concatner un symbole et un paramtre de macro, en supprimant les espaces
cela permet de crer de nouveaux symboles
2.9.5. analyses successives
une chaine produite par une macro est ranalyse jusqu' ce que plus aucune substitution ne soit possible
une macro en cours de gnration ne peut pas tre gnre rcursivement (factorielle)
2.9.6. porte des noms de macros et #undef
une macro est active ds sa dfinition jusqu' la fin du fichier obtenu par tous les #include ou jusqu' la rencontre de
#undef
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 28
un #undef abusif est ignor
2.9.7. inclusion de fichiers
#include <nom> provoque une recherche de nom dans les rpertoires d'include standard et ceux spcifis par
lutilisateur
#include "nom" provoque la recherche de nom dans le rpertoire courant, et en cas d'chec continue comme pour
#include <nom>
2.9.8. compilation conditionnelle
#if expression-constante-entire
defined value 1 si le symbole est dfini, ou zro
#ifdef symb quivalent #if defined (symb)
#ifndef symb quivalent #if ! defined (symb)
#else
#elsif
2.9.9. contrle des lignes
#line constante "nom_fichier"
opt
cette directive modifie la valeur des macros pr dfinies __LINE__ et __FILE__
2.9.10. directive d'erreur
#error chaine-symbole
provoque la gnration d'un message d'erreur
2.9.11. pragmas
#pragma chaine-symbole
provoque un comportement dpendant de la mise en oeuvre (voir la doc du compilateur)
#pragma once fait enregistrer le nom du fichier de sorte qu'il ne sera plus rinclu dans le mme programme
2.9.12. directive nulle
#
n'a aucun effet
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 29
2.9.13. noms pr dfinis
__LINE__
__FILE__
__DATE__
__TIME__
__cplusplus
__STDC__ est dfini par certains compilateurs
les compilateurs dfinissent normalement de nombreux symboles qui permettent de rendre du code dpendant du
systme, de la machine, du niveau de respect du standard C++
2.10. exercices
2.10.1. exercice
crire des dclarations de fonctions prenant des pointeurs de fonctions en arguments et retournant de tels pointeurs
2.10.2. exercice
que signifie typedef int (&rifii)(int,int);
2.10.3. exercice
crire un programme qui affiche Hello suivi de tous les arguments de la ligne de commande
2.10.4. exercice
crire le programme cat, qui lit les fichiers nomms sur la ligne de commande et les crit sur sa sortie standard
2.10.5. exercice
programmer une fonction de tri "sort" prenant une fonction de comparaison en argument
2.10.6. exercice
dcrire une structure de terme acceptant plusieurs fils
crire une fonction qui construise un tel terme dont les fils sont passs en arguments, de sorte que l'arbre puisse tre
exprim presque comme s'il tait interprt
2.10.7. exercice
programmer itoa
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 30
2.10.8. exercice
lire les fichiers .h prsents dans /usr/include et /usr/include/CC
2.10.9. exercice
crire une fonction qui inverse u tableau deux dimensions
2.10.10. exercice
crire un programme de cryptage qui utilise une clef passe en paramtre dont les caractres sont combins de faon
itrative aux caractres du fichier traduit
2.10.11. exercice
crire la fonction printf
2.10.12. exercice
dfinir des rgles typographiques pour marquer la diffrence entre les diffrentes entits nommes par vos programmes
(fonctions, pointeurs vers, variables locales, globales, etc)
2.10.13. exercice
crire un processeur de macros qui traite des macros simples
2.10.14. exercice
crire un programme qui appelle une fonction (sqrt par exemple) de la bibliothque C standard (sans include <math.h>)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 31
3. Classes
3.1. classes et membres
les classes sont des types dfinis par l'utilisateur
aucun type de base de C++ n'est une classe
3.1.1. fonctions membres
une classe est une structure laquelle s'appliquent un certain nombre de fonctions
ces fonctions sont encapsules dans la classe, et ne peuvent s'appliquer qu' des objets instances de la classe
des structures distinctes peuvent avoir des fonctions membres de mme nom
struct individu {
char *nom;
int age;
void set (char *nom,int age);//une fonction membre
void print();//une autre
};
3.1.2. classes
le type "class" permet la restriction des appels : seules des fonctions "autorises" pourront invoquer une fonction
membre, ou bien agir sur un membre (lire o modifier)
cela permet une localisation plus facile des erreurs : tout tat erron est le fait des seules fonctions membres
class individu {
char *nom;
int age;
public:
void set (char *nom,int age);
void print();
};
3.1.3. auto rfrence
une fonction membre est invoque sur une instance d'une classe
un pointeur vers l'objet qui porte l'appel est pass implicitement en paramtre lors de l'appel
on peut obtenir ce pointeur avec la variable fictive this
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 32
on ne peut pas assigner this, mais on peut modifier l'objet point. Pour une classe X, le type de this dans les fonctions
membres est :
X *const this;
utiliser this pour dsigner l'objet n'est pas ncessaire : les membres d'une classe sont accessibles directement par les
fonctions membres d'un objet
class X {
int _a;
void f(int a) {_a = a;} // signifie this->_a = a;
};
3.1.4. auto rfrence
quand on veut un membre ne pouvant pas modifier l'objet on mentionne const aprs les arguments
class X {
int _a;
public :
int get_a() const {return _a;} //ne modifie pas l'objet point
};
un membre const peut tre invoqu sur un objet const, une fonction ordinaire ne peut pas
noter que le compilateur ne dtecte pas seul les tentatives de modification d'un objet const : il est essentiel de faire
figurer ce type dans la dclaration des fonctions
le type de this dans un membre const de la classe X est
const X *const
en cas de besoin, il y a possibilit de coercition explicite pour passer outre ce const :
void X::f() const { ((X*)this)->compteur++;}
C'est utile pour modifier physiquement un objet dont l'tat logique n'est cependant pas affect par l'opration : par
exemple pour implanter un compteur d'accs l'objet (cas ci dessus). On distingue la constance logique de la constance
physique.
3.1.5. initialisation
dans une classe X, on peut dfinir des fonctions membres d'initialisation qui portent le nom X
class individu {
char * _nom;
int _age;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 33
individu();//pour initialiser un individu
};
individu::individu(char *nom, int age):_nom(nom),_age(age){}
lors de la cration d'objets d'une classe donne, on doit fournir les argument attendus par le constructeur utilis :
main(){
individu bob("bob",34);
individu *paulptr = new individu("paul",23);
}
un constructeur est invoqu dans les condition suivantes :
lors de la cration d'une variable automatique (le cas de bob ci dessus)
lors de la cration d'un objet allou sur le tas
pour passer un paramtre rel
pour passer une valeur retourne
lors d'une conversion dans le type correspondant
3.1.6. initialisation
on dfinit en gnral de multiples constructeurs, avec des arguments par dfaut
individu::individu(char *nom="", int age=0):_nom(nom),_age(age){}
un constructeur particulier est le constructeur de copie, de type :
X::X(const X&);
la copie par dfaut est une copie champ champ (chaque champ est copi avec son propre constructeur de copie s'il
existe
si aucun constructeur de copie n'existe, pour la classe comme pour les donnes membres, la copie par dfaut est celle
de la structure : recopie bit bit
on peut crer un tableau d'instances d'un classe condition que cette classe dfinisse un constructeur sans paramtre.
On ne peut pas passer de paramtre au constructeur pour initialiser tous les objets d'un tableau
Attention : un constructeur un seul argument peut tre appel automatiquement par le compilateur pour convertir un
argument lors d'un appel de fonction. Pour l'empcher, on utilise le mot clef explicit dans la dclaration du constructeur.
3.1.7. destruction
en gnral, les objets qui ont t crs doivent faire un peu de mnage quand on les jette
cela se produit automatiquement la sortie du bloc de porte pour les variables automatiques, et explicitement par
appel de delete pour les objet allous
C++ garantit l'appel automatique des destructeurs des objets crs dans ces deux situations, dans l'ordre inverse des
appels de constructeurs correspondants
le destructeur pour une classe X porte le nom ~X
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 34
individu::individu(char *nom):_age(0){
_nom = new char [1+strlen(nom)];//acquisition de mmoire
strcpy(_nom,nom);
}
individu::~individu(){
delete[] _nom;//libration dans le destructeur
}
il ne prend aucun paramtre
il est unique, et peut tre virtuel (il doit souvent ltre)
le rle d'un destructeur est de librer les ressources acquises lors de la construction ou de la vie de l'objet
pour dtecter un ventuel accs un objet dj dtruit, un constructeur peut (mais ne doit pas) mettre les donnes
membres de l'objet dans un tat incorrect mais reconnaissable
3.1.8. fonctions inline
les classes implantent souvent de nombreuses petites fonctions, qu'il est utile de programmer "en ligne"
notamment, l'accs au donnes est souvent interfac par de petites fonctions d'accs, qui permettent notamment le
mode "lecture seule"
l'appel d'un fonction est normalement plus coteux que l'accs une donne membre : ce n'est pas le cas des fonctions
d'accs "inline"
// file individu.h
class individu {
char * _nom;//private
int _age;//private
public:
const char *getnom(){return _nom;} //inline car dans la classe
int getage();
};
inline int individu::getage(){return _age;} //inline explicite hors classe
cela sert un objectif de performance : pas de surcot la dfinition d'une classe "propre"
les fonctions membres dfinies au sein de la dfinition de la classe sont automatiquement inline
elles peuvent tre dclares hors de la classe
3.2. interfaces et mise en oeuvre
brivement ici, on peut dire qu'une bonne classe est une boite noire, prestataire de services, dont les modalits
d'utilisation ne sont pas sensibles aux modalits d'implantation. Le cours de conception oriente objet complte et raffine ces
notions.
ex : objets containers
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 35
3.2.1. modification de mise en oeuvre
modifier l'implantation d'une classe est sans effet pour ses utilisateurs tant que la partie publique reste inchange, ainsi
que les dclarations des fonctions membres
les utilisateurs doivent recompiler aprs modification de la partie prive, notamment cause du changement possible
de la taille de la structure, ou la transformation de certaines fonctions en virtuelles
on doit permettre que des fonctions inline puissent atteindre les champs privs d'un objet
un bon compilateur peut dterminer quels fichiers doivent absolument tre recompils lors du changement d'une
interface
on doit gnralement garantir la compatibilit ascendante d'une bibliothque : les programmes crits avec une
ancienne version doivent compiler et tourner sans changement avec la nouvelle
si la nouvelle implantation de fonctions (constructeurs) requiert plus de paramtres, des valeurs par dfaut permettent
de garder l'ancienne version
une fonction qui attend un paramtre de type X peut tre transforme pour accepter un paramtre de type const X&
sans changement pour ses utilisateurs
3.2.2. un exemple de classe
programmer avec des classes demande plus de rflexion priori qu'avant, notamment car chaque classe dcrit un type
de donnes dont il faut prvoir toutes les utilisations ralistes, et dvelopper en permettant au minimum la rusabilit et la
scurit
class intset {
int _cursize;
int _maxsize;
int *_array;
public:
intset (int m, int n);//au moins m entiers dans 1..n
~intset();
int hasmember(int t)const;// t est il un membre
void add(int t);//ajouter t
//itration
void start(int&v)const{v=0;}
int isnotfinished(int&v)const{return v<_cursize;}
void next(int&v)const{v++;}
int getvalue(int&v)const{return _array[v];}
};
int intset::intset(int m, int n){/*alloue et initialise*/}
int intset::hasmember(int t)const{/*dichotomique ds tab tri*/
void intset::add (int t){/*insertion ds l'ordre avec dcalage*/}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 36
3.2.3. un exemple de classe
les fonctionnalits d'itration permettent un programme d'utiliser la classe malgr un changement de reprsentation
interne : on n'accde jamais aux donnes membres
main(){
intset is(15,15);
is.add(1);
is.add(7);
int num;
for (is.start(num) ; is.isnotfinished(num) ; is.next()){
cout << "num : "<< num <<" val : "<< is.getvalue(num);
cout << endl;
}
3.3. autres caractristiques des classes
3.3.1. fonctions amies
dans une classe, la dclaration "friend" permet d'accorder l'accs au membres privs ou protected des fonctions
isoles, ou toutes les fonctions d'une classe
cela sert notamment quand une opration requiert des donne membres de deux ou plusieurs classes : par exemple
pour multiplier un vecteur par une matrice
class vector {
friend vector mult(const vector&,const matrix&);
};
class matrix {
friend vector mult(const vector&,const matrix&);
};
une fonction amie peut tre elle mme une mthode
class Y{
friend void X::f();
};
ou bien tre n'importe quelle fonction d'une classe donne
class X{
friend class Y;
};
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 37
une fonction amie fait partie de l'interface de programmation d'une classe
3.3.2. qualification des noms de membre
dans certaines situations on doit dsigner explicitement le nom de la classe d'un membre
on utilise l'oprateur de rsolution de porte"::"
class X{
int m;
public:
int getm()const{return m;}
void setm (int m) {X::m=m;} //le paramtre masque le nom du membre
};
on peut aussi accder des symboles globaux masqus par un symbole local
class MyFile {
void open(){

::open();//appelle la fonction globale "open"

}
};
3.3.3. classes embotes
une classe peut tre dclare dans une autre, ce qui rduit les symboles globaux en circulation
class X{
struct Y{
int i;
Y():_i(0){}
};
Y* head;
public:
X():head(0){}
};
cela sert en cas de besoin reconnu, pour des classes embotes simples. Le mcanisme utile (accs par la seule classe
englobante) peut tre obtenu par l'utilisation de classes amies :
class Y{ friend class X;
int i;
Y():_i(0){}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 38
};
class X{
Y* head;
public:
X():head(new Y()){}
};
Un type embot peut tre atteint directement par qualification de porte : X::Y. Une classe imbrique possde le mme
statut que tout autre classe. Un membre qui retourne une valeur d'un type embot se dclare ainsi :
T1::T2 T1::f();
3.3.4. membres statiques
il est parfois ncessaire de stocker des informations relatives un classe (compter les instances, maintenir une liste des
instances cres )
exemple : la bibliothque iostream compte le nombre d'instances de cout cres puis dtruites afin de savoir quand
fermer le fichier de sortie standard
cela se fait en dclarant des membres statiques dans la classe
class obj {
static obj * listeDesObj; // liste des obj est une variable globale
};
un membre statique est une donne globale, dont la visibilit et restreinte la classe, sauf s'il est public
une fonction membre statique n'est visible que dans le fichier qui la dfinit
Attention : il y a ncessit de dfinir et initialiser les membres statiques dans le fichier .cc, car leur dclaration "static"
dans la classe n'est qu'une dclaration
3.3.5. pointeurs sur fonctions membres
on peut prendre l'adresse de membres, que ce soient des fonctions ou des donnes
ce mcanisme ncessaire en C est moins souvent utile en C++ grce aux fonctions virtuelles
struct cl {
char *v;
void print (int x){cout << v <<< x << endl;}
cl(char *_v):v(_v){}
};
typedef void (cl::*PMFI)(int);
int main() {
cl z1("z1");
cl z2("z2");
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 39
cl * p = &z2;
PMFI pf = &cl::print;
z1.print(1)
(z1.*pf)(2);//parenthses obligatoires
z2->print (3);
(z2->*pf)(4);//parenthses obligatoires
}
3.3.6. structures et unions
une structure est une classe publique par dfaut(et une classe est une struct, prive par dfaut)
struct S {}; quivaut class S {public:};
une union nomme est une struct dont chaque membre possde la mme adresse, utile dans le cas rarissime o l'on sait
qu'un seul membre d'une structure est utis un moment donn. Une programme C++ avec des unions est en gnral un
mauvais programme C++
union token {
char *p;
char v[8];
long i;
double d;
token(const char*);//pb : p ou v ? : dcid par programme par ex
token (long _i):i(_i){}
token (double _d):d(_d){}
};
le compilateur ne sait pas quelle est la donne valide un moment donn : pas de vrification
on peut utiliser des constructeurs surchargs pour initialiser une union
on a un problme de vrification de conformit au type : on encapsule souvent l'union dans une classe qui mmorise le
type, ne serait-ce que pendant les phases de dveloppement et de tests, afin d'viter de douloureuses msaventures.
struct Token {
enum Type {Double, Long, StringPtr, StringArray};
private:
Type type;
union token {
char *p;
char v[8];
long i;
double d;
};
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 40
public:
Token(char *pp);
Token(long ii):i(ii),type(Long){}
Token(double dd):d(dd),type(Double){}
long& ival(){assert(type==Long);return i;}
long& dval(){assert(type==Double);return d;}
long& sval(){assert(type==StringPtr);return s;}
long& aval(){assert(type==StringArray);return v;}
};
de tel classes unions type maintenu fournissent une solution lgante pour dcrire des fonctions arguments
variables scurises
extern Token NOTHING;
void message(const char * pattern, Token a1=NOTHING, Token a2=NOTHING, Token
a3=NOTHING);
les constructeurs permettent alors la conversion lors de l'appel en passant des arguments normaux, qui sont
rceptionns en toute scurit aprs l'appel
3.4. construction et destruction
quand une classe possde un constructeur (toujours!) il est appel chaque cration d'objet :
automatique (variable locale, conversion dans une expression, paramtre formel)
statique (variable globale)
dynamique (allou par new)
membre (d'une classe ou d'un tableau)
retourn par une fonction
et galement lors de tout appel explicite du constructeur (locale muette)
3.4.1. variables locales
le constructeur est appel chaque passage du flux de contrle sur la dclaration
les destructeurs sont appels en ordre inverse des constructeurs
on a gnralement un problme avec la copie
table t1(100);
table t2 = t1; //constructeur par copie
table t3(200);
t3 = t2; //oprateur d'affectation
le destructeur est appel pour t2, mais pas le constructeur, et le t3 original pas dsallou
pour viter ces problmes il faut dfinir le constructeur par copie et l'affectation
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 41
3.4.2. mmoire statique
les objets statiques et globaux sont allous dans l'ordre de leur dfinitions et dsallous dans l'ordre inverse
ils permettent de faire excuter du code avant et aprs main
un appel de exit() appelle les destructeurs de globales avant de sortir (et peut donc boucler), ce qui n'est pas le cas de
abort()
parfois, il est pratique dans une librairie de dfinir un type ayant pour seul but d'initialiser la librairie par son
constructeur
la bibliothque iostream utilise ces mcanismes pour ouvrir et fermer les fichiers standard (cout, cin et cerr sont des
variables statiques)
3.4.3. mmoire dynamique
un objet dynamique est allou avec l'oprateur new doit tre libr par delete. Si c'est un tableau, il doit tre libr par
delete[].
class A{};
A* ptr = new A; // pointeur vers un seul A
A* tab = new A[25]; // pointeur vers 25 A conscutifs
delete ptr; // ok
delete tab; // erreur
delete[] tab; // ok
on ne peut allouer un tableau d'instances d'une classe que si elle possde un constructeur sans argument
oublier d' appeler delete perd dfinitivement de la mmoire
appeler delete deux fois sur un mme pointeur est probablement fatal
3.4.4. objets membres d'autres objets
les membres d'une classe doivent tre initialiss par tous les constructeurs
les arguments du constructeur de membre sont placs dans la dfinition, entre la parti e dclaration et les accolades
les membres sont initialiss dans l'ordre de leur dclaration dans la classe, et seront dtruits dans l'ordre inverse
class A {
int i;
A(int ii):i(ii){}
};
class B {
int j;
A a;
B(int i, int jj);
};
B::B(int i, int jj) : a(i),j(jj){/*des acquisitions de ressources/}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 42
3.4.5. tableaux d'objets
la dclaration d'un tableau d'objets d'une classe ayant un constructeur ncessite que la classe ait un constructeur ne
prenant pas de paramtre
C++ ne permet pas de passer de paramtres pour la construction de tous les objets d'un tableau
on contourne cette difficult en stockant des valeurs par dfaut d'initialisation dans des variables statiques de la classe
le destructeur doit tre appel sur chaque objet du tableau : il faut utiliser delete[] et non delete
delete[] utilise une information de taille stocke ct de la zone alloue
3.4.6. allocation de petits objets
l'allocateur standard peut tre inefficace si l'on doit allouer et dsallouer de trs nombreux petits objets
on peut avoir de meilleures stratgies d'allocation quand on traite des objets d'un seul type
il est possible de dfinir des oprateurs new et delete pour une classe, appels en priorit s'ils existent
class X{
void *operator new (size_t);
void operator delete(void*, size_t);
};
l'oprateur new global reste accessible si besoin est par ::new, sauf s'il a t lui mme masqu, ce qui est trs
dsagrable
si l'on implante un allocateur pour un besoin spcifique, il est bon de pas masquer pour la classe l'oprateur new
habituel : on surcharge donc new en mentionnant un argument supplmentaire
typedef HEAP ;
class X{
void *operator new (size_t,HEAP);//spcifique
void *operator new (size_t){return ::new char[size_t];};//standard
void operator delete(void*, size_t);
};
noter que si l'on a plusieurs "new" on a un seul delete, ce qui peut poser quelques problmes
enfin, si l'on alloue des blocs de taille constante, on peut ignorer l'argument taille de new, et utiliser une version de
delete sans argument taille
on peut jusqu' doubler la vitesse d'un programme en allouant bien les petit blocs beaucoup utiliss (maillons de liste
chaine par exemple)
3.5. exercices
3.5.1. exercice
concevoir une structure Noeud d'arbre binaire avec des constructeurs et destructeurs
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 43
3.5.2. exercice
modifier la classe intset pour en faire un ensemble de Noeuds, un ensemble de chanes
3.5.3. exercice
dfinir une classe pour l'analyse, la mmorisation et l'valuation d'expressions arithmtiques entires simples (le
constructeur reoit la chaine de caractres qui reprsente l'expression)
3.5.4. exercice
concevoir une classe table des symboles, et une classe "entre de table des symboles"
3.5.5. exercice
utiliser la construction d'un objet global pour afficher du texte avant le main et aprs
3.6.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 44
4. Hritage
4.1. introduction et tour d'horizon
l'hritage permet de dcrire une hirarchie entre les diffrents types de donnes manipuls par un programme. La
relation fondatrice de cette hirarchie est la relation "est une sorte de". Cette relation logique est celle qui doit guider la
dcision d'untiliser l'hritage autant que possible.
les classes hrites permettent de dcrire des points communs entre diffrentes classes
l'hritage multiple permet de combiner des caractristiques issues de plusieurs super classes soit par ajout simple (on
parle alors de mixin - pour mixing in -) soit pour hriter d'une part d'une implmentation, d'autre part d'une interface de
programmation. Cess notions sont dtailles dans le cours de programmation objet.
4.2. hritage : classes drives
Exemple si nous disposons d'une classe employ et d'une classe manager, il est probable que manager hrite de
employ. Un manager est une sorte de employ, avec certaines prrogatives.
class employ {};
class manager : public employ {};
C++ permet la conversion implicite de la classe drive vers la classe de base ,
et la conversion explicite (cast) de la classe de base vers la classe drive sans qu'aucune vrification ne soit possible
par le compilateur dans ce deuxime cas
4.2.1. fonctions membres
un membre priv de la classe de base ne peut pas tre accd par un membre de la classe drive.
si on dsire permettre cette possibilit, on utilisele spcificateur d'accs protected au lieu de private
4.2.2. constructeurs et destructeurs
la classe de base est vue exactement comme un membre de la classe drive. Le constructeur de chaque classe hrite
doit tre appel comme les constructeurs des membres
class B : public A {
int i;
B():A(),i(0){} // la construction de B requiert celle de A et de i
};
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 45
4.2.3. hirarchies de classes
Pour savoir quel type rel appartient un objet dont on connat la classe de base, il y a trois solutions :
garantir que l'on ne peut pointer que sur des objets d'un seul type
utiliser un champ de type
utiliser des fonction virtuelles
4.2.4. champs de type
une information de type peut tre fournie par une classe au moyen d'une variable statique (globale) dclare dans la
classe, et dont la valeur (ou simplement l'adresse) permet de savoir quel classe appartient un objet.
on peut mme construire automatiquement l'arbre des classes d'un programme ce qui permet de savoir si un objet
appartient une "sous classe" d'une classe donne. (Exercice !)
4.2.5. fonctions virtuelles
une fonction virtuelle est lie dynamiquement par le compilateur : la fonction appele sur un objet dont le type n'est
pas connu avec prcision (car son pointeur est manipul au travers d'un pointeur vers une super classe) est celle qui
correspond sa classe de cration. En C++ le liage par dfaut est statique : la fonction appele est celle dfinie pour la classe
identifie par le type du pointeur utilis (elle peut bien sr tre hrite), mme s'il y a eu un cast. Dans le doute, une fonction
memebre est virtuelle.
une fonction virtuelle est marque par le qualificateur virtual.
elle peut tre dfinie dans la classe ou elle est dclare : la classe de base est capable de fournir une implantation par
dfaut, masque par les futures sous classes ventuellement
ou alors elle est virtuelle pure, dfinie par 0
class Z {
virtual f()=0; // virtuelle pure
};
l'ensemble des fonctions virtuelles d'une classe dfinissent son protocole.
4.3. classes abstraites
il s'agit de classes qui groupent des fonctionnalits et des donnes utilises par plusieurs classes drives, mais dont
aucun objet rel ne peut tre issu. Toute classe qui comporte au moins une virtuelle pure est abstraite d'office : le compilateur
refuse d'en crer des instances, mme si l'on n'utilise pas les fonctions non dfinies.
exemple : la classe forme dans un systme graphique est abstraite. On en drive les classes concrtes carr, rond,
triangle, qui pour lesquelles les fonctions dessine, efface, pivote du protocole de forme peuvent recevoir une implantation.
les classes abstraites permettent de fournir une interface sans exposer les dtails de ralisation.
une classe abstraite ne peut tre utilise comme type d'argument, de valeur de retour, ou comme type d'une conversion
explicite. Par contre, dans tous ces cas, on peut utiliser un pointeur vers la classe abstraite.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 46
4.4. hritage multiple
C++ permet l'hritage multiple. Le problme de conflit potentiel lors de l'hritage de plusieurs classes qui possdent
des membres de mme signature doit tre rgl par le programmeur en spcifiant explicitement quelle est la classe de la
fonction appele. On crit A::f() ou B::f() si on parle du f de A ou du f de B
on peut dfinir une nouvelle fonction f() dans la classe drive qui appelle celle qui convient ou les deux si ncessaire.
il reste un problme li la mention explicite du type de la classe de base : si on insre une classe dans la hirarchie de
classes, on doit modifier les programmes des classes drives (le nom de la super classe change). Une solution est de dfinir
un type local appel inherited, ou superclasspour identifier la classe d'hritage principal par exemple :
class manager : public worker, public A, public Z {
typedef manager inherited;
void f(){ inherited::f()}
}
4.5. hritage virtuel
Il arrive que des classes soeurs aient besoin de partager de l'information. Cela peut tre obtenu par l'hritage commun
d'une classe de base hrite virtuellement.Un tel exemple de partage est le nom de l'objet dans un systme objets nomms.
dans toute instance d'une classe donne, on trouve une seule instance de chaque classe hrite virtuellement
class B : public virtual A {}
class C : public virtual A {}
class D : public C, public B {} // un seul A dans D
quand une classe hrite virtuellement, une fonction virtuelle de la classe de base peut tre effectivement implante par
une classe soeur.
l'hritage virtuel est implant au travers de pointeurs internes l'objet et prsente un cout non nul (compens par la
non rptition)
4.6. contrle d'accs
private : la classe seulement et les amies
protected : la classe et toutes ses filles venir et les amies
public : tout le monde
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 47
4.7. mmoire dynamique
4.7.1. surcharge de new et delete
une classe de base peut redfinir new et delete
void * operator new (size_t);
void operator delete (void *, size_t);
tant que le type rel est le type de l'objet spcifi, le compilateur connat la taille de l'objet dtruire.
dans le cas contraire, on doit utiliser un destructeur virtuel. Attention, il est toujours prfrable d'utiliser des
destructeurs virtuels !!!
4.7.2. constructeurs virtuels
on a parfois besoin de fonctions de clonage de structures, pouvant tre apparentes des constructeurs virtuels (par
dfinition un constructeur ne peut pas tre virtuel car on dsigne le nom de la classe instancier). On dfinit un systme de
clonage ainsi :
virtual base * new_base () { return new base()};
et dans une classe drive :
base * new_base () {return new drive ()};
4.7.3. oprateur de placement
On peut vouloir allouer des objets dans un espace prdtermin (placement explicite):
void * operator new(size_t, void *p);
char buffer[sizeof(X)];
X*p = new(buffer) X(i);
On peut vouloir placer dans un espace de stockage particulier, ce qui est utile pour faire du backtracking, ou stocker
des donnes en diffrents espaces (rmanents, partags, etc.) :
class storage {
virtual void * alloc(size_t);
virtual void free(void *, size_t);
};
void *operator new(size_t s, storage & loc) {
return loc.alloc ( s );
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 48
storage maPileDobjets (1024);
X* p = new(maPileDobjets) (args);
Lors de la destruction, il faut appeler explicitement le destructeur (qui doit donc tre virtuel si l'opration est faite par
free soi mme), et ensuite prvenir le systme de stockage:
p->~X(); maPileDobjets.free(p);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 49
5. Dclarations et constantes
5.1. dclarations
en C++ un nom doit tre dclar
la dclaration stipule le type de l'objet
syntaxe : nom de type + nom de variable [ + "=" + valeur];
quand il y a valeur, c'est une dclaration et une dfinition.
Exemples : dterminer les dfinitions :
char ch;
int count =1;
char * name;
struct complex {float re, im};
complex cvar;
extern complex sqrt(complex);
extern int error_number;
typedef complex point;
float real(complex *p) { return p->re;};
const double pi = 3.1415926...;
struct user;
template<class T> abs(T a) {return a<0 ? -a : a; }
enum car {peugeot, citroen, volvo};
certains types ont une valeur initiale permanente : structures, fonctions
toute dclaration prcisant une valeur est une dfinition
5.1.1. porte des symboles
une dclaration introduit un nom (symbole) dans une porte
deux dclarations dans le mme bloc sont impossibles
une dclaration dans un bloc englob peut masquer une dclaration plus globale
cette facilit doit tre utilise avec prcautions : un bon moyen est de donner des noms longs aux variables (viter i, z,
t, x etc)
espaces de porte en C++:
bloc { }
classe class { } ;
fonction T f() { }
fichier static
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 50
programme extern
5.1.2. porte des symboles
oprateur de rsolution de porte ::
int x;
main(){
int x= 1;
x = x + ::x;
}
il n'y a aucun moyen d'utiliser un nom local masqu
la porte commence ds que le nom est connu:
int x = x;
la porte commence ds la dclaration
int x;
main(){
int y = x+1; // x global
int x = 2;
y = x+1; // x local
}
5.1.3. objets et l_values
un objet est une rgion de la mmoire
une l_value est un objet ou une fonction
en C++ les l_values const ne peuvent tre affectes (places gauche du signe =)
une l_value qui n'est pas dclare const est dite modifiable
5.1.4. dure de vie
un objet est normalement dtruit quand le flux de contrle sort de la zone de porte
sauf s'il est static
dans ce cas, il est initialis la premire fois que le flux de contrle passe par lui
int a = 1;
void f() {
int b = 1;
static int c = a;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 51
a++, b++, c++;
cout << a << " " << b << " " << c << " " << endl;
}
main(){
while (a<4) {f();}
}
5.2. les noms
le premier caractre doit tre une lettre
soulign "_" est une lettre
l'analyse considre le nom le plus long possible
certains caractres ($) rendent les programmes non portables
les mots clef ne sont pas des noms
majuscules et minuscules sont distinctes
5.3. les types
tout nom est associ un type
le nom du type dtermine les oprations possibles sur le symbole associ
un nom de type est normalement utilis pour spcifier le type d'un autre nom
deux oprations particulires s'appliquent aux seuls noms de type :
sizeof - pour connatre la taille d'une structure en multiples de la taille d'un char
new - pour allouer dynamiquement une instance du type
int main() {
int * p = new int;
cout << sizeof(int) << endl; // taille d'un int
cout << sizeof(p) << endl; // taille d'un pointeur
cout <<sizeof(*p) << endl; // taille d'un int
un nom de type peut aussi tre utilis pour spcifier une conversion explicite d'un type vers un autre
char *p;
long l = long(p); // convertit de pointeur vers long
5.3.1. types fondamentaux
char, short int, int, long int (signed, unsigned)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 52
float, double, long double
tout type manquant est considr comme int
tout type est sign par dfaut (sauf char)
char, unsigned char et signed char sont trois types distincts, mais ont la mme taille
char est suffisamment grand pour contenir un caractre du jeu standard, et est sign ou non sign suivant les
caractristiques de la machine (critre de performance)
signed char est donc un entier de la mme taille
unsigned char est plus portable, mais peut tre considrablement moins efficace
int est optionnel dans les combinaisons ("unsigned" au lieu de "unsigned int")
5.3.2. tailles des types
les tailles des types respectent les rgles suivantes :
sizeof(char) == 1
char < short < int < long
float < long < double
T == signed T == unsigned T
char >= 8, short >= 16, long >= 32
on est garanti qu'un char contiendra les entiers de 0 127 ; supposer plus est non portable
donner le type unsigned n'empche pas de copier une valeur ngative : cela n'agit que sur les rgles de l'arithmtique
unsigned int bitmask = -1; // warning peut tre
unsigned int bitmask2 = ~0; // meilleur
5.3.3. la conversion implicite
lors de la conversion d'un type en un autre, si possible, l'information de dpart est conserve
ds que l'on perd des bits, on a des problmes :
int i = 256+255;
char c = i; //c = 255
int j = c;
// j vaut 255 sur une machine ou le char est non sign (68XXX)
// j vaut -1 sur une machine o le char est sign (VAX)
5.3.4. les types drivs
partir de type(s) de base, on peut dfinir des types drivs :
* pointeur,
& rfrence,
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 53
[] tableau,
() fonction,
struct structure
exemples :
int* a;
float v[10];
chat-r *p[20];
void f(int);
struct str{int a; char *s;};
les parenthses peuvent tre utilises dans les cas o la prcdence des oprateurs n'est pas celle souhaite
int *v[10]; // tableau de 10 pointeurs vers des int
int (*p) [10]; // pointeur vers un tableau de 10 int
on peut dclarer plusieurs noms ensemble spars par une virgule (mais il faut viter de le faire)
int *p, q; // q n'est pas un pointeur
5.3.5. les types void et void*
type fondamental, ne peut servir que comme lment d'un type driv
un pointeur de n'importe quel type peut tre affect une variable de type void *
utile pour les fonctions qui ne sont pas autorises faire d'hypothse sur le type de la donne qu'elles manipulent
exemple de malloc :
void * malloc(size_t);
void free (void *);
main(){
int * s = (int *) malloc(10*sizeof(int));

free (s);
}
5.3.6. pointeurs
pour la plupart des types T, la dclaration d'un pointeur sur T est noteT*
int * pi;
char **ps; //pointeur vers pointeur
int (*vp)[10]; //pointeur sur un tableau de 10 int
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 54
int (*f) (char, float); // pointeur sur fonction
la drfrence (ou encore indirection) est note *V
l'arithmtique des pointeurs est possible
exemple : strlen version 1
int strlen(char *p){
int i = 0;
while (*p++) i++;
return i;
}
ou encore
int strlen(char *p){
char * q = p;
while (*q++);
return q-p-1;
}
5.3.7. tableaux
dclaration T[taille];
les lments sont indexs de 0 taille - 1;
pas de virgule pour les dimensions suprieures a un
int tab[2][5]; //un tableau de deux tableaux de cinq entiers
initialisation statique
char t[]="abcdefghijkl";
char v[2][5] = {{1,2,3,4,5},{'a','b','c','d','e'}};
utilisation
main (){
for (int i=0; i<2 ; i++)
for (int j = 0; j<5 ; j++)
cout << v[i][j] << endl;
}
l'affectation un tableau est impossible, il faut faire une copie lment par lment
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 55
5.3.8. pointeurs et tableaux
un tableau est toujours assimilable son premier lment, et rciproquement
les arguments de fonctions de type tableau sont toujours passs sous la forme d'un pointeur vers leur premier lment
il n'y a aucun moyen de provoquer une copie de tableau lors d'un appel de fonction
dans une structure, un tableau diffre d'un pointeur car il est intgr dans la structure (le tableau intgr dans la
structure sera donc copi lors d'une copie bit bit de la structure)
arithmtique :
on peut soustraire deux pointeurs: le rsultat est entier
on peut ajouter ou soustraire un entier un pointeur : le rsultat est un pointeur
le seul type entier qui est garanti de contenir un pointeur converti est "long"
le compilateur ne fait aucun contrle sur la validit d'un pointeur obtenu par calcul
5.3.9. structures
on appelle structure un agrgat arbitraire d'objets de types quelconques
struct adresse {
char * nom;
int numro;
char * rue;
int code;
char * pays;
}; // noter le point virgule final
l'accs aux membres des structures se fait par les oprateurs "" et " ->"
adresse add;
add.nom = "James Bond";
add.number = 007;
adresse *padd = &add;
cout << padd->nom << " " << padd->number << endl;
l'initialisation statique est possible comme pour les tableaux
adresse A={"Pernod",45,"rue des vagues", 13004, "Marseille"};
les comparaisons == et != sont non dfinies (mais dfinissables par le programmeur)
l'affectation d'une structure une autre fait une copie bit bit
5.3.10. structures
le nom d'un type est utilisable ds qu'il a t vu, pourvu que son emploi ne ncessite pas de connatre la taille de la
structure
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 56
struct maillon {
maillon *suivant;

};
et encore :
class S;
extern S a;
S f();
void g(S);
par contre :
void h(){
S a; //erreur S inconnu
f(); //id
g(a);//id
}
on ne peut dclarer une instance d'un type structure avant que la dfinition du type n'ait t vue entirement
struct mauvaise {
mauvaise elem; // refus
};
5.3.11. structures
la gestion des rfrences croises (list de links qui pointent sur la liste) se fait par des dclarations pralables :
struct link; //dclaration pralable
struct list {
link *l;
};
struct link {
link *next;
list *pere
};
5.3.12. quivalences de types
deux types sont diffrents mmes s'ils ont les mmes membres et ne sont pas interchangeables
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 57
struct s1 {int a;};
struct s2 {int a;};
s1 x;
s2 y = x; //impossible
int i =x; //impossible
on utilise typedef pour dfinir de nouveaux (noms de) types partir d'existants
typedef char * String;
String p1, p2;
char * q1,q2; //attention ici q2 est char !
5.3.13. rfrences
une rfrence est un nom alternatif un objet : les oprateurs agissent sur l'objet rfrenc au travers de la rfrence
int i = 0;
int& j = i;
j++; //i vaut maintenant 1
l'initialiseur d'une rfrence doit donc tre une l_value (sauf cas particulier ci aprs)
les rfrences servent essentiellement pour
le passage d'arguments par adresse
les valeurs de retour de fonction
les dfinitions d'oprateurs
une rfrence est un alias : on ne peut prendre une double rfrence
int i = 0;
int& j = i;
int&& k = j; // impossible
5.3.14. rfrences
une rfrence est un pointeur masqu (constant)
le type de la rfrence et de l'objet rfrenc doivent tre strictement compatibles
on peut prendre une rfrence une constante ; dans ce cas, linitialiseur peut ne pas tre une l_value, ni mme tre du
type demand : des convertisseurs sont appels automatiquement pour initialiser une variable temporaire
double& cd1=1; //impossible
const double& cdr = 1; //ok
les rfrences permettent l'utilisation d'un appel de fonction en l_value ( gauche du signe =)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 58
struct assoc {
char *nom;
int value;
};
int&value(char*nom){
assoc *courant;
//recherche de nom
return courant->value;
}
main(){
char buf[80];
while (cin>>buf) {
value(buf)++;
}
}
5.3.15. rfrences
les rfrences permettent de faire voluer une interface fonctionnelle qui copie des structures (petites) vers une
interface qui copie des pointeurs sans modifier les programmes qui utilisent cette interface
struct data {};
//version 1
data f(){}
main(){
data res=f();
}
//version 2
const data& f(){}
main(){
data res=f(); // cet appel ne change pas
}
5.4. les littraux
5.4.1. constantes entires
dcimales :0, 123, 213546887778984
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 59
octales (commencent par un zro) : 077, 0732,
hexadcimales (commencent par un zro et un x) : 0x1a6f
les suffixes U et L identifient des constantes non signes ou long : 3U, 3L
5.4.2. constantes virgule flottante
type double par dfaut
1.3, .23, 1.2e-15,
le suffixe f identifie les constantes de type float : 1.56e4f
5.4.3. constantes caractres
'a', '\n', '\a', '\0'
ce sont des constantes symboliques pour les valeurs entires du jeu de caractre de la machine
caractres spciaux:
passage la ligne NL(LF) \n
tabulation horizontale HT \t
tabulation verticale VT \v
effacement BS \b
retour chariot CR \r
saut de page FF \f
alerte BEL \a
anti slash \ \\
caractre ? \?
caractre ' \'
caractre " \"
caractre valant 0 NUL \0
caractre en octal ooo \ooo (1,2,3 chiffres)
caractre en hexa hhh \xhhh (autant que l'on veut)
utiliser des constantes explicites (octales ou hexa) rend les programmes non portables entre machines ayant des jeux de
caractres diffrents
une constante octale ou hexa se termine au premier caractre non octal ou non hexa
char *s="voici un caractre idiot \x8E345AB insr dans une chane";
5.4.4. littraux chanes
texte entre guillemets, caractre nul terminal
sizeof donne la longueur de la chane + 1
strlen donne la longueur de la chane
le passage a la ligne dans une chane est interdit
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 60
la concatnation est automatique
il est conseill de toujours utiliser trois chiffres pour les caractres en octal
s= "cette chaine provoque
une erreur";
char s[]= "ca fait " "bien plaisir "
"par rapport a C";
char s[]= "parlez aprs le bip\007\n";
char s[]= "la fin disparat\000imbecile";
char s[]= "a\xOfah\0129"; //'a' '\xfa' 'h' '\12' '9'
char s[]= "a\xfah\129"; //'a' '\xfa' 'h' '\12' '9'
char s[]= "a\xfad\127"; //'a' '\xfad' '\127'
5.4.5. zro
c'est un int utilisable comme constante de tout type entier, pointeur, ou flottant.
void f(int);
void f(char *);
main(){
f(0); // le compilateur refuse cet appel : ambigu
f(int(0)); //ok
f((int)0); //ok, coercition a la C
f((char *)0);//ok
}
gnralement, quand c'est possible, il correspond un mot dont les bits sont tous a zro
unsigned bitmask = ~0; // bits tous a un
C++ recommande d'utiliser 0 pour dsigner le pointeur nul plutt que la macro NULL habituellement dfinie dans des
fichiers include de l'utilisateur ou des bibliothques
5.5. les constantes nommes
5.5.1. le mot clef const
le mot clef const ajout a un type permet de transformer l'objet correspondant en constante plutt qu'en variable
une donne const ne peut pas tre modifie dans tout l'espace de sa porte
une constante doit tre initialiseds sa dclaration
const int tailleTab =4;
const int tab[]={1,2,3,4};
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 61
const est un modifieur de type : il dcrit comment une donne doit tre utilise
const char * peek(int i) {
return tab[i]; //l'appelant ne peut pas changer tab[i]
}
void f(const char *);
void f(char *); //une autre fonction f
5.5.2. le mot clef const
utilisations de const :
const char *s1="123456789";
s1++; //ok
s1[3]='e'; //interdit
char *const s2="123456789";
s2++; //interdit
s2[3]='e'; //ok
const char *const s3="123456789";
s3++; //interdit
s3[3]='e'; //interdit
void f1(const char *); //appel possible sur s1, s2, s3
void f2(char *); //appel possible sur s2
void f3(const char *&); //appel possible sur s1 et s2
void f4(char *&); //appel impossible dans tous les cas
5.5.3. numrations
pour dclarer des constantes, on peut galement utiliser enum
enum {ASM, AUTO, BREAK}; // dclare trois valeurs
forme quivalente :
const int ASM =0;
const int AUTO =1;
const int BREAK =2;
une numration peut tre nomme. Attention, il ne faut pas utiliser la syntaxe "typedef enum" comme en C.
enum motclef {ASM, AUTO, BREAK}; // motclef devient un type
on a la possibilit de valeurs explicites
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 62
enum data {a=123,b=-78,c=0};
la conversion d'enum vers int est automatique mais la conversion inverse doit tre rendue explicite, ce qui rend souvent
les numrs assez dsagrables utiliser
int i = ASM; // ok
motclef var1 = 2; // rejet
int j = 1;
motclef var = motclef(i); ok
les enumrations sont parfois meilleures que les int correspondants : elles permettent au compilateur de gnrer des
messages si l'un des cas est oubli dans un switch.
5.6. les champs de bits et unions
objectif : gain d'espace mmoire. C'est du HACK rarement utilis sauf dans des programmes de communication.
L'accs un bit est d'ailleurs plus cher que l'accs un int.
on peut obtenir de la place en mettant plusieurs objets de petite taille dans un octet, ou en utilisant le mme espace
des fins diffrentes suivant les cas
c'est rarement immdiatement portable
5.6.1. champs de bits
struct registre {
unsigned int enable :1; //un bit
unsigned int error : 2; //deux bits
unsigned int :2; //deux bits inutiliss
unsigned int mode : 3;

};
gain hypothtique (la taille du programme et le cot des accs augmente)
utiliss surtout pour accder de faon nomme des parties d' octet
5.6.2. unions
on veut utiliser la mme structure pour stocker des donnes diffrentes suivant les moments
exemple : table des symboles, dont une entre contient nom et valeur, de type entier ou chane.
struct entre {
char type;
char *nom;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 63
union {char* valeurChaine; int valeurInt;};
};
sur certaines machines, int et pointeur n'auront pas la mme taille : ce n'est pas une simple conversion
certains programmeurs les utilisent pour convertir sans que le compilateur ne rechigne (c'est vilain : mauvaise
utilisation du concept)
struct cast {
union baduse{ //on peut la nommer
int i;
int *p;
};
};
main(){
cast c;
c.i = 12;
int *p=c.p; //a vomir
}
5.7. exercices
5.7.1. exercice
crire un programme qui affiche les tailles de tous les types fondamentaux, et de types pointeurs vers, tableaux et
structures qui en drivent.
5.7.2. exercice
crire un programme qui affiche sous forme d'entiers les adresses relatives de champs de structures
5.7.3. exercice
crire une fonction qui permute deux entiers
5.7.4. exercice
afficher la configuration de bits du pointeur 0 sur votre machine
5.7.5. exercice
afficher tous les caractres utiles et leurs valeurs comme entiers
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 64
5.7.6. exercice
dfinir un fichier de dfinitions pour des types de base de taille connue avec exactitude. (pour la portabilit).
5.7.7. exercice
crire des dclarations pour
un pointeur sur un caractre
un tableau de 10 entiers
un pointeur sur un tableau de chanes de caractres
un pointeur sur un pointeur de caractre
une constante entire
un pointeur sur une constante entire
un pointeur constant sur une constante de type entier
crire les initialisations et compiler
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 65
6. Expressions et instructions
6.1. sommaire des oprateurs
6.1.1. oprateurs
voici un tableau synoptique des oprateurs du langage C++, avec les conventions suivantes :
les oprateurs sont prsents par ordre de prcdence dcroissant
dans la mme boite, la prcdence est la mme
objet est une expression donnant une instance d'une classe et l_value est une expression reprsentant un objet non
constant
:: rsolution de porte classe::membre
:: global ::nom
. slection de membre objet.membre
-> slection de membre objet->membre
[] indexation pointeur[expression]
() appel de fonction expression(liste
dexpression)
() construction de valeur type(liste dexpression)
sizeof taille d'un objet sizeof expression
sizeof taille d'un type sizeof (type)
6.1.2. oprateurs
++ pr et post incrmentation ++lvalue et lvalue++
-- pr et post dcrmentation --l_value et l_value--
~ complment 2 ~expr
! non !expression
-,+ moins et plus unaires -expression, +expr
& adresse de &lvalue
* drfrence *pointeur
new crer new type
delete dtruire delete pointeur
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 66
delete[] dtruire tableau delete[] pointeur
() coercition (conversion) (type) expression
.* section de membre objet.ptr_de_membre
->* section de membre ptr->ptr_de_membre
*, /, % fois, divise, modulo expression op expression
+, - plus, moins expression op expression
<<, >> dcalage expression op expression
<, <=, >, >= comparaisons expression op expression
==, != gal diffrent expression op expression
& et bit bit expression op expression
6.1.3. oprateurs
^ ou exclusif bit bit expression op expression
| ou bit bit expression op expression
&& et logique expression op expression
|| ou logique expression op expression
? : expression conditionnelle expression ? expression :
expression
= affectation simple l_value = expression
op= op et affectation l_value op= expression
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 67
(op peut valoir +,-,*,/,%,<<,>>,&,|,^)
, virgule (squence) expr,expr
6.1.4. associativit
les oprateurs unaires et d'affectation sont associatifs droite
tous les autres associent gauche, y compris les oprateurs postfixs
a=b=c signifie (a=(b=c))
*p++ signifie (*(p++))
a<b<c signifie ((a<b)<c) et non (a<b && b<c)
6.1.5. parenthses
les parenthses permettent de contrler l'associativit, et l'ordre d'valuation en partie du fait de la prcdence des
oprateurs
6.1.6. ordre d'valuation
il n'est pas garanti sauf pour les oprateurs &&, ||, "," qui valuent d'abord la gauche
int i=1;
v[i]=i++; //v[1]=1 ou v[2]=1;
i=v[i++]; //valeur de i indfinie
les parenthses peuvent imposer un ordre d'valuation
x*y/z value en (x*y)/z
(x*y)/z diffre en gnral de x*(y/z) (virgule flottante)
6.1.7. expressions primaires
primaire :
littral
this
:: identificateur
:: operator operateur
:: nom_classe_qualifi::nom (permet A::B::C::size)
( expression )
nom
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 68
nom:
identificateur
operator operateur
nom_fonction_conversion
~nom_classe
nom_classe_qualifi::nom
6.1.8. indexation
a[b] est identique par dfinition *((a)+(b))
ce n'est plus vrai pour l'oprateur [] quand il est dfini pour un type utilisateur videment
6.1.9. appel de fonction
avant l'appel, chaque argument formel est initialis avec l'argument rel
la fonction peut changer la valeur de ses arguments formels non constants
les arguments rels sont intouchs sauf rfrences non const
l'ordre d'valuation des arguments est non dfini
les appels rcursifs sont permis
un appel de fonction dont le type retourn est une rfrence non const est une l_value
une fonction peut tre dclare pour accepter moins d'arguments rels (valeurs par dfaut) ou plus (notation )
dans le cas (pas d'argument formel disponible)
un argument float est converti en double
un char, short, champ de bit ou enum est converti en int ou unsigned int par promotion d'entiers (int de prfrence si la
valeur passe peut tre dcrite par un int)
un objet de classe est pass comme une struct (sinon un appel au constructeur de copie est ralis)
6.1.10. conversion de type explicite type(liste_expr)
construit une valeur du type partir des arguments
s'il y a plusieurs paramtres, le type doit tre une classe avec un constructeur disponible et non ambigu pour ces
arguments rels
s'il n'y a aucun argument, soit un constructeur existe, soit le rsultat est une donne de valeur indfinie pour le type
void f(int){}
main(){
f(int());//passe un int arbitraire
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 69
6.1.11. accs un membre et ->
l'expression est une l_value ssi le membre en est une
a->nom quivaut strictement (*a).nom
6.1.12. oprateurs d'incrmentation et de dcrmentation
leur effet sur les pointeurs est celui de l'arithmtique des pointeurs (qu'ils soient prfixes ou postfixes)
char * strcpy (char *p, const char *q) {
while(*p++ = *q++);
return p;
}
6.1.13. sizeof
sizeof(char) == 1
une taille d'instance est toujours strictement plus grande que 0
sizeof ne peut pas tre appliqu une fonction, un champ de bits, une classe indfinie, void, ou un tableau ayant
une dimension non spcifie
si l'oprande est une expression, elle n'est pas value
si c'est un type, il doit tre entre parenthses
appliqu une rfrence, c'est la taille de l'objet rfrenc
appliqu un tableau, c'est la taille du tableau (nombre total d'octets)
6.1.14. l'oprateur new
new essaye de crer un objet du type demand, et retourne un pointeur sur cet objet
si l'objet est un tableau, un pointeur sur le premier lment est retourn
new int; //type int *
new int[20]; //type int *
new int[i][50]; //type int(*)[10]
dans ce cas la premire dimension peut tre variable, les autres constantes
on peut dfinir des allocateurs supplmentaires, ou surcharger l'oprateur new par dfaut
new (a,b,c) T; //appel de operator new(sizeof(T),a,b,c)
void *operator new(size_t) peut tre appel avec l'argument 0 : un pointeur vers un objet toujours diffrent est retourn
chaque classe peut dfinir un oprateur new pour ses instances
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 70
class T;
new T; //appel de void *T::operator new(size_t) s'il existe
new U; //appel de void *operator new(size_t) si U non classe
::new V; //appel de void *operator new(size_t) global
6.1.15. l'oprateur new
un appel new combine allocation et appel de constructeur
new T(a,b,c); //appel de T::T(a,b,c) sur l'espace allou
la mme syntaxe est utilisable pour les types de base:
int * ipt=new int(200);
on ne peut pas passer de paramtre au constructeur pour les tableaux
un tableau ne peut tre allou que si la classe dcrit un constructeur par dfaut (sans paramtre) qui sera alors appel
pour chaque instance du tableau
new T[10](a,b);//interdit
on peut utiliser explicitement la version parenthse de new si on a un problme cause de parenthses dans le type :
new(int (*[15])(char)); //tableau de 15 pointeurs vers fonctions
6.1.16. l'oprateur delete
delete doit recevoir un pointeur sur un objet construit par new
delete(0) ne fait rien
pour une classe T, void T::operator delete (void *) est appel prioritairement s'il a t dfini
la valeur de l'objet point est indfinie aprs la destruction
delete appelle le destructeur de l'objet (qui doit tre virtuel)
delete[] d'un pointeur simple est terrifiant
delete simple d'un pointeur vers un tableau est abominable
6.1.17. conversion de type explicite (coercition )
toute conversion standard est possible de faon explicite
la notation coercition (cast C) est ncessaire pour convertir vers un type dont le nom est complexe
un pointeur peut tre converti en entier assez grand, et rciproquement
un pointeur sur un type peut tre converti en un pointeur sur un autre type : problmes si incompatibilits d'alignement
si l'autre type est de taille suprieure ou gale, l'aller retour de conversions ne produit pas de changement
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 71
un pointeur vers B peut tre converti en pointeur vers D qui hrite de B si B n'est pas classe de base virtuelle (suppose
que B apparat comme sous objet dans D : les valeurs de ces deux pointeurs sont normalement diffrentes)
le pointeur nul est toujours converti en lui mme
un objet peut tre converti en rfrence X& si un pointeur sur cet objet peut tre converti en X*
la conversion vers une rfrence ne provoque pas d'appel de fonction de coercition, ni de constructeur
le rsultat d'une coercition vers une rfrence est une l_value (le seul cas)
6.1.18. conversion de type explicite (coercition)
on peut convertir des pointeurs vers fonctions en pointeurs vers objets et rciproquement condition que les tailles
soient compatibles (danger l'utilisation)
un pointeur vers fonction peut tre converti en pointeur vers une autre fonction : l'appel travers ce nouveau pointeur a
des effets imprvisibles
un objet ou une valeur peut tre converti en objet d'une classe seulement si un constructeur ou un oprateur a t
dclar
un pointeur sur membre peut tre converti en un pointeur sur membre diffrent quand :
les deux pointent sur des membres de la mme classe ou
les deux pointent sur des membres de classes dont l'une drive de l'autre sans ambigut
on peut convertir un type constant (objet, rfrence d'une part ou pointeur) vers un type non constant (rfrence ou
pointeur seulement) : on obtient le mme pointeur ou objet. Toutefois son utilisation pour modifier l'objet peut provoquer une
exception d'adressage (dpend de la mise en oeuvre)
on peut convertir de volatile vers non volatile
6.1.19. oprateurs pointeurs sur membres
* lie son second argument, de type pointeur sur un membre de T, son premier argument, de type T ou d'une classe
dont T est classe de base accessible
id pour ->* avec un pointeur
le rsultat est un objet ou une fonction
si c'est une fonction, il peut tre utilis pour un appel
class A{
int f1(void *);
int f2(void *);
};
typedef int (A::*Afptr)(void *);
main(){
Afptr pt = A::f1;
A a;
(a.*pt)(0);
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 72
6.1.20. oprateurs de multiplication
oprandes de * et / de type arithmtique
oprandes de % (reste) de type entier
a / 0 et a % 0 ont une valeur indfinie
(a/b)*b + a%b vaut a
6.1.21. oprateurs d'addition
arithmtique classique et arithmtique des pointeurs :
addition pointeur + entier et entier + pointeur
soustraction pointeur - entier
soustraction pointeur - pointeur (valable au sein d'un tableau, jusqu' la premire position au bout du tableau, sinon
indfini
6.1.22. oprateurs de dcalage
le dcalage vers la gauche s'accompagne d'un remplissage par des 0 droite
le dcalage vers la droite est garanti remplir gauche par des 0 si le nombre dcaler est de type non sign, ou bien
s'il est positif. Sinon danger
le rsultat est indfini si l'oprande droit est plus grand que le nombre de bits de l'oprande gauche une fois promu
unsigned int bit1mask = 1U<<1;
unsigned int bit2mask = 1U<<2;
6.1.23. oprateurs relationnels < > <= >=, et ==, !=
les arguments doivent tre de type arithmtique ou pointeur
le rsultat est de type int, valant 0 ou 1
tout pointeur peut tre compar (une expression constante valuant ) 0
tout pointeur peut tre compar un void *
des pointeurs sur des objets ou des fonctions de mme type peuvent tre compars
si deux pointeurs sur des membres non statiques d'un mme objet sont compars, et s'ils ne sont pas spars par un
label spcificateur d'accs, le pointeur sur celui dclar en dernier est plus grand que l'autre
deux pointeurs sur des membres donnes d'une mme union sont gaux
deux pointeurs sur un mme objet sont gaux
dans un tableau, le pointeur sur l'objet de plus grand index est le plus grand
les oprateurs == et != sont identiques mais de prcdence plus faible
des pointeurs sur membres de mme type peuvent tre compars
6.1.24. oprateurs logiques bit bit
ces oprateurs ne s'appliquent que sur des arguments de type entier
le rsultat est la fonction logique bit bit des arguments
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 73
ils servent notamment pour raliser des masques 2 4, 3 & 2
6.1.25. oprateurs logiques && et ||
ils associent et ils valuent de gauche droite
ils n'valuent l'argument droit que si c'est ncessaire
les oprandes ne sont pas ncessairement de mme type mais doivent tre de type arithmtique ou pointeur
6.1.26. oprateur conditionnel a ? b : c
il associe et il value de gauche droite (seulement l'un des deux derniers)
le type de l'expression (et du rsultat) est un type commun aux oprandes 2 et 3, s'il existe, aprs conversions possibles
si les arguments 2 et 3 sont des l_values, le rsultat aussi
6.1.27. affectation =, += etc
l'oprande gauche doit tre une l_value modifiable, qui donne son type au rsultat et l'expression
l'oprande droit doit pouvoir tre converti dans le type attendu gauche avant affectation (pas les numrations)
T* = T*const //OK
T*const = T* // impossible
ptr [sur membre] = ptr [sur membre] //OK
ptr [sur membre] = 0; //OK
T, volatile T = const T, volatile T; //OK
class X = ; // dfini par X& X::operator=(const X&);
class X = ; // sinon affectation membre membre
class X = class Y; // OK ssi Y hrite de X de faon non ambigu
T& = ; // affecte l'objet rfr
X op= Y est identique X = X op (Y), sauf que X n'est valu qu'une seule fois
6.1.28. oprateur d'enchanement (virgule)
virgule associe et value de gauche droite, et la valeur de l'expression gauche est abandonne
le type est celui de l'expression de droite
6.1.29. expressions constantes
elles sont ncessaires dans certaines situations : case, bornes de tableaux, longueurs de champs de bits, initialiseurs de
types numrs
elles sont connues et values la compilation, remplaces par leur valeur
elles consistent en :
des littraux
des expressions sizeof
des numrs
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 74
des valeurs const de types entiers initialises par des expressions constantes
6.1.30. propos de conversion de types
la notation C habituelle pour la coercition est possible : int i = (int) 3.2;
on utilise la notation fonctionnelle pour les types ayant un nom simple
la slection de membre a une prcdence plus forte que la coercition, ce qui rend la notation fonctionnelle plus
agrable :
((complex)n).re; //cast
complex(n).re; //fonction
quand un cast explicite n'est pas ncessaire, il faut l'enlever
la conversion explicite de pointeur vers int, ou de pointeur vers un autre pointeur est non portable (char * peut diffrer
de int *, et de int)
seules sont garanties les conversions de pointeur vers void * et retour (on peut donc passer par void *)
6.1.31. propos de mmoire dynamique
new, delete, delete [] pour les tableaux
l'oprateur delete connat la taille de l'objet devant tre dsallou par le compilateur, sauf dans le cas des tableaux.
#include <stddef.h>
void * operator new(size_t);
void operator delete (void *);
void out_of_memory(void){
cerr << "plus de memoire" << endl;
exit (1);
}
int main(){
set_new_handler(&out_of_memory);
char *p=new char[10000000000000000000000];
cout << "cette trace n'a aucune chance" << endl;
}
pas d'initialisation automatique zro
new retourne 0 en cas d'impossibilit d'allocation, mais termine sans erreur
6.2. Syntaxe des instructioNS
instruction :
dclaration
{ liste d'instructions }
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 75
expression ;
if ( expression ) instruction
if ( expression ) instruction else instruction
switch (expression) instruction
while (expression) instruction
do instruction while (expression)
for (instruction_for expression ; expression ) instruction
case expression-constante : instruction
default : instruction
break;
continue;
return expression ;
goto identificateur ;
indentificateur : instruction
instruction for :
dclaration
expression
6.2.1. slection et contrle
C++ nenrichit pas les instructions C : if, switch, case, while, do while, for, goto, label
il ny a pas de type boolen pour les tests : la valeur 0 signifie false, et toute autre valeur signifie true
les oprateurs <=, < etc. renvoient 0 si faux, et 1 sinon
toute valeur entire ou pointeur peut donc tre utilise dans un test
6.2.2. if
l'utilisation de if se fait comme en C. Certains tests peuvent tre supprims en utilisant l'oprateur de slection
conditionnelle (?:), mme en l_value, ce qu'ignorent beaucoup de programmeurs :
if (a<b) {
max = b ;
b_used = 1;
} else {
max = a;
a_used = 1;
}
devient :
max = (a<b) ? b : a;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 76
((a<b) ? b_used : a_used) = 1;
6.2.3. switch
switch est plus performant que if lorsqu'une expression est compare des constantes
le compilateur peut informer sur des oublis lorsque lon utilise des types numrs
6.2.4. goto
goto est utile dans des programmes gnrs automatiquement (analyseurs syntaxiques)
utile dans des cas particuliers de besoin en performance dans une boucle temps rel par exemple
galement et surtout pour sortir dune boucle de faon brutale lors en conomisant des tests
void f(int a){
int i, j;
for (i=0 ; i<n ; i++)
for (j=0 ; j<n ; j++)
if (nm[i][j] == a) goto found;
// not found
// ... return
found:
// found
}
6.3. commentaires et indentation
un commentaire dcrit le programme : sens, correct, complet, ( jour)
chaque fois que possible, un commentaire doit tre dcrit par le langage
notamment, un assert est prfrable tout commentaire
lindentation peut tre prise en charge automatiquement par un indenteur
6.4. exercices
6.4.1. exercice
crire linstruction while quivalente linstruction for suivante :
for (i=0 ; i<maxlen ; i++)
if (input[i] == ?) quest++;
utiliser un pointeur comme variable de contrle
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 77
6.4.2. exercice
parenthser les expressions suivantes :
a = b + c * d << 2 & 8
a & 077 != 3
a == b || a == c && c < 5
c = x != 0
0 <= i < 7
f(1,2) + 3
a = -1 + + b -- - 5
a = b == c++
a = b= c =0
a[4][2] *= * b ? c : * d * 2
a-b,c=d
6.4.3. exercice
trouvez 5 constructions C++ diffrentes dont la signification est indfinie
trouvez dix exemples de code C++ non portable
que se passe til lors dune division par zro sur votre systme
que se passe til lors de dpassement de capacit par ajout excessif, retrait excessif
6.4.4. exercice
parenthser correctement les expressions suivantes :
*p++
*--p
++a--
(int*)p->m
*p.m
*a[i]
6.4.5. exercice
crire strlen, strcpy, strcmp
6.4.6. exercice
observer les ractions du compilateur aux erreurs suivantes
void f(int a, int b) {
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 78
if (a = 3) // ...
if (a&077 == 0) //...
a := b+1;
imaginez des erreurs plus simples et voyez comment le compilateur ragit
6.4.7. exercice
crire la fonction cat qui concatne deux chanes
crire reverse, une fonction qui renverse une chaine
6.4.8. exercice
crire un programme qui limine les commentaires C++ dans un programme
attention aux chanes de caractres
6.4.9. exercice
que fait le programme suivant , et pourquoi lcrire :
void send (register*to, register *from, register count){
register n=(count+7)/8;
switch (count%8){
case 0 : do { *to++ = *from++;
case 7: *to++ = *from++;
case 6: *to++ = *from++;
case 5: *to++ = *from++;
case 4: *to++ = *from++;
case 3: *to++ = *from++;
case 2: *to++ = *from++;
case 1: *to++ = *from++;
} while (--n>0);
}
}
6.4.10. exercice
crire la fonction atoi qui prend une chane de caractres et retourne un int
octal et hexadcimal
constantes caractres
crire la fonction inverse itoa
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 79
7. Surcharge d'oprateur
7.1. introduction
C++ permet de dfinir des oprateurs pour toutes les classes dfinies par un programmeur
Exemples :
le type complexe, pour lequel on dfinit a + b,
le type vecteur, pour lequel on dfinit loprateur []
7.2. fonctions oprateurs
+ - * / % ^^& | !
= < > += -= *= /= %= ^= &=
|= << >> >>= <<= == != <= >= &&
|| ++ -- ->* , -> [] () new delete
Attention : il est impossible de changer la prcdence des oprateurs, ni leur sens d'appariement. "=" associe de droite
gauche, alors que "<<" associe de gauche droite. Ce comportement est fig.
Attention : il est impossible de changer la syntaxe des expressions (nouveaux oprateurs, ou bien modification de
binaire en unaire par exemple)
le nom dune fonction oprateur est operator suivi du symbole adquat, avec ou sans espace
operator ==
7.2.1. oprateurs binaires et unaires
binaire : dfinissable comme fonction membre un argument, ou comme fonction globale deux arguments
unaire : dfinissable comme fonction membre sans argument, ou comme fonction globale un argument
a@b sinterprte soit comme a.operator@(b), soit comme operator@(a,b)
@a sinterprte soit comme a.operator@(), soit comme operator@(a)
Lorsque les deux sont dfinis, le choix est fait avec les rgles habituelles
a@ (postfixe) sinterprte par a.operator(int) ou par operator@(a,int)
7.2.2. spcification pr dfinie des oprateurs
=, [], () et -> doivent tre des fonctions membres non statiques. += nest pas dduit automatiquement de + et de =
=, &, et , (enchanement) ont une valeur pr dfinie. Ils peuvent tre rendus inaccessibles en les dclarant privs dans
la classe.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 80
7.2.3. oprateurs et types utilisateur
Une fonction oprateur doit soit tre membre dune classe utilisateur, soit prendre une classe utilisateur en paramtre.
C++ est donc extensible, mais pas modifiable, sauf pour les oprateurs pr dfinis par dfaut : =, & et ,.
La commutativit dun oprateur nest pas connue du compilateur. On doit dclarer deux fonctions pour lobtenir.
7.3. conversions de types dfinis par le programmeur
On ne doit normalement pas dfinir autant doprateurs amis que le ncessitent des conversions automatiques voulues,
grce aux oprateurs de conversions de types
class complex {
double re, im;
public :
complex(double r, double i) re(r), im(i) {};
friend complex operator+(complex,complex);
friend complex operator+(double,complex); // inutile
friend complex operator+(complex,double); // inutile itou
...
}
7.3.1. conversion par constructeurs
class complex {
double re, im;
public :
complex(double r, double i = 0) re(r), im(i) {};
friend complex operator+(complex,complex); // suffit maintenant
...
}
7.3.2. un principede mise en oeuvre
On dfinit en gnral les oprateurs de type *= en premier et on en drive *:
matrix& matrix::operator*=(const matrix& a)
{
//..
return *this;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 81
}
matrix matrix::operator*(const matrix& a, const matrix& b)
{
matrix prod = a;
prod *=b;
return prod;
}
Une conversion utilisateur est automatiquement applique si elle est unique.
Tout objet construit par lappel explicite dun constructeur est automatique et sera dtruit ds que ncessaire.
7.3.3. oprateurs de conversion
La conversion par constructeur est limite :
pas de conversion vers les types de base
pas possible de convertir un type nouveau en un type ancien sans modifier lancien
pas possible davoir un constructeur un seul argument sans avoir aussi de facto une conversion (toutefois le mot clef
explicit avant le constructeur permet de bloquer ce type de conversion automatique)
class tiny {
char v;
void assign (int i) { assert (! (i & 63)); v = i;}
public :
tiny(int i) { assign (i);}
tiny (const tiny &t) { i = t.v;} // ou utilisation de assign
tiny& operator=(const tiny& t) {i=t.v; return *this;}
tiny& operator=(const int& i) {assign (i); return *this;}
operator int() {return v;} // conversion en int
};
main(){
tiny c1 = 2;
tiny c2 = 62;
tiny c3 = c2 - c1;
tiny c4 = c3; // pas de vrif
int i = c1 + c2;
c1 = c2 + 2*c1; // erreur
c2 = c1 - i; // erreur
c3 = c2; // pas de vrif
}
7.3.4. oprateurs de conversion (2)
exemple officiel (mais il nest pas bon en gnral de perdre de linformation lors dune conversion)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 82
while (cin >> x) cout << x; // conversion implicite de cin en int (son tat)
Il est conseill de ne pas abuser des conversions, qui rendent les programmes difficiles lire.
7.3.5. ambigut
Le compilateur ne ralise quun niveau de conversion automatique. Pour en avoir plusieurs, il faut les expliciter.
Les conversions utilisateur ne sont utilises que sil est impossible de faire autrement. Si une conversion standard
permet de traiter lappel, elle est utilise.
7.4. littraux
On ne peut dfinir des littraux de classes.
Mais on peut invoquer les constructeurs pour des types de base.
Ainsi : complex(1,2) peut tre considr comme une constante littrale de la classe complex.
Si le constructeur est inline, une expression lincluant ne comportera pas dappel de fonction supplmentaire.
7.5. gros objets
Pour viter des copies de gros objets, les oprateurs prennent en gnral des arguments rfrence. Voir lexemple
prcdent de la classe matrix.
On ne peut retourner une rfrence cause dun problme dallocation mmoire. Il sera donc ncessaire de procder
une copie de lobjet retourn. (On ne peut pas retourner une rfrence une variable locale static, car un oprateur peut tre
utilis plusieurs fois dans une mme expression).
7.6. affectation et initialisation
Lorsquun objet alloue de lespace lors de son initialisation, il faut veiller redfinir un constructeur par copie, et un
oprateur daffectation, sous peine derreurs alatoires lors de la destruction (plusieurs appels de delete sur le mme pointeur)
exemple de string
7.7. indexation
Largument supplmentaire (index) de loprateur dindexation peut tre de nimporte quel type. On peut lutiliser
pour des dictionnaires, dont lindex est directement une chane de caractres.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 83
7.8. oprateur dappel de fonction
Cet oprateur peut servir pour appeler une fonction de lobjet qui prime sur toutes les autres.
operator()() doit tre une fonction membre.
expression (liste dexpression) est interprt comme un oprateur binaire ayant expression comme premier argument,
et liste dexpression comme deuxime argument.
X obj;
obj.fn_toujours_utilisee(); // remplac par :
obj();
7.9. indirections
l'oprateur -> est dfini comme un oprateur postfixe unaire.
class Ptr {
//
X* operator->();
}
void f (Ptr p){
p->m = 7; // (p.operator->())->m = 7;
Cet oprateur sert calculer un pointeur sur un objet. Lorsqu'on utilise la version habituelle de la notation ->, un nom
de membre est obligatoire aprs.
X* x = p->; // erreur
X* x = p.operator->(); // ok
On peut utiliser -> pour crer des pointeurs intelligents.
class X {
Y *p;
int compteur;
public :
X(Y* _p):p(_p),compteur(0){};
Y* operator->() {return p; compteur++;}
Y& operator*() {return *p; compteur++;}
Y& operator[](int i) {return p[i];compteur++;}
};
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 84
7.10. incrmentation et dcrmentation
On peut surcharger les oprateurs ++ et -- pour avoir un contrle de bornes automatique.
class CheckedPtrToT {
T* p;
int position;
int taille;
//
T *operator++(); //prfixe
T *operator++(int); //postfixe
T *operator--(); //prfixe
T *operator--(int); //postfixe
T &operator*(); //prfixe
}
void f(T t) {
T v[200];
CheckedPtrToT p(v,200);
p--; // p.operator--(1);
*p = t; // p.operator*() = t; // erreur
++p; // p.operator++();
*p = t; // p.operator*() = t; // ok
}
7.11. une classe chane de caractres
class string {
struct srep {
char *s;
int n;
srep() {n=1;}
}
srep *p;
public :
string (const char *s){
p = new srep;
p->s= new char[strlen(s)+1];
strcpy(p->s,s);
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 85
string ();{
p = new srep;
}
string (const string &from){
from.p->n++;
p = from.p;
}
// et les oprateurs ==, !=, =
}
7.12. amies et membres
On a souvent le choix entre dfinir des fonctions membres ou des fonctions globales prenant des arguments rfrence.
Ex m.inv(), ou bien inv(m) pour inverser une matrice m.
Toutes choses gales par ailleurs, on choisit toujours un membre. Les rfrences montrent de faon moins lisible que
l'objet peut tre modifi.
Une fonction modifiant l'tat d'un objet doit tre un membre, ou bien une fonction globale prenant un argument
rfrence non const.
Par contre, une fonction ncessitant une conversion de type pour tous ses arguments ne peut tre que globale. En effet
une fonction membre ne convertit jamais le type de l'objet auquel elle s'applique. Cette considration guide aussi lors de la
dfinition des oprateurs qui peuvent aussi bien tre des globales que des membres. On utilise une fonction membre si l'on
veut protger le paramtre "principal" contre une coercition automatique non voulue.
class X {
//
X(int);
int m1();
int m2()const;
friend int f1(X&);
friend int f2(const X&);
friend int f3(X);
}
1.m1(); // erreur : X(1).m1() non essay
1.m2(); // erreur : X(1).m2() non essay
f1(1); // erreur : impossible
f2(1); // ok f2(X(1))
f3(1); // ok f3(X(1))
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 86
7.13. avertissement
L'utilisation abusive des oprateurs peut conduire des programmes illisibles.
L'utilisation d'oprateurs contre emploi aussi :
int operator+(int a, int b) {return a - b;}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 87
8. Templates
8.1. introduction
Les patrons servent dfinir des types, ou des oprations, utilisant ou s'appliquant des types fournis comme
paramtres
Ce mcanisme s'appelle la gnricit
On peut ainsi dfinir des listes de "n'importe quoi", et plus gnralement des classes "conteneurs de n'importe quoi".
L'objectif est de garder la vrification de type, et les performances
Le principe consiste dcrire des schmas de programmes, qui peuvent ensuite tre complts par les fragments
manquants, la demande.
La simple utilisation d'un patron provoque la cration des programmes ncessaires.
8.2. un patron simple : patron de classe
template<class T>
class stackOf {
T* v;
T* p;
int sz;
public:
stack(int s) {v = p = new T[sz = s];}
stack() {delete[] v;}
void push(T a) {*p++ = a;}
T pop() {return *--p;}
int size() const {return p-v;}
8.2.1. utilisation
Ce template s'utilise ensuite ainsi :
stackOf<char> sc(100); // pile de 100 caractres max
stackOf<int> si(30); // pile de 30 entiers max
On peut galement avoir des classes gnriques dont les fonctions ne sont pas inline, mais les compilateurs balbutient
encore un peu dans ce domaine
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 88
template<class T> void stack<T>::push(T a) { *p++ = a;)
template<class T> void stack<T>::stack(int s) {v=p=new T[sz=s];}
Noter dans le second cas que la rptition du paramtre de type est optionnelle
8.3. listes gnriques
8.3.1. liste intrusive
struct slink {// classe lien
slink* next;
slink() : next(0){}
slink(slink* n):next(n){}
};
struct list {// classe de gestion de liens
//
public:
void insert (slink *); //ajout en tte
void append (slink *); //ajout en fin
slink *get(); //dtruit et retourne le dbut
};
class name : public slink {
char *n;
//
};
template<class T>
class listOf : private list {
public:
void insert(T* a) {list::insert(a);}
T * get() {return (T*) list::get();}
}
void f(char *s){
listOf<name> ln;
ln.insert(new name(s));
name *n = ln.get(); //pas de coercition ncessaire
avantages :
typage sr
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 89
pas de surcot
pas de rplication de code
possibilit de cacher le code source de list l'utilisateur
une liste intrusive est optimale en temps et en mmoire
inconvnients :
pas possible de raliser des listes croises
8.3.2. une liste non intrusive
template<class T>
struct Tlink : public slink {
T info;
Tlink(const T& d):info(d){}
};
template<class T>
class slist : private list {
void insert(const T& a) {list::insert(new Tlink<T>(a));}
void append(const T& a) {list::append(new Tlink<T>(a));}
T get();
};
template<class T>
slist<T>:get() {
Tlink<T> *l = (Tlink<T> *)list::get();
T d=l->info;
delete l;
return d;
}
void f(int i) { //pas de sous classe de slink
slist<int>l1;
slist<int>l2;
l1.insert(i);
l2.insert(i); //le mme i sur deux listes
}
8.3.3. avantages / inconvnients
la liste intrusive est avantageuse en performance (pas d'allocation ni de copie)
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 90
8.3.4. principe
Ne pas utiliser de rfrences comme arguments de templates : ex : slist<int&>
Cela peut provoquer des erreurs l'expansion du patron
8.3.5. listes de pointeurs
//listes de pointeurs
template<class T>
class Splist : private Slist<void *> {
public :
void insert (T* p) {Slist<void *>::insert(p);}
T* get() {return (T *) Slist<void *>::get();}
8.3.6. instance de template comme argument de template
Une instance de template est un type "normal". On peut donc utiliser un tel type comme paramtre d'un template.
typedef Slist< Slist<int> > ints; // remarquer les espaces
8.3.7. une implantation effective des listes
class list {
slink *last; //liste finie code de faon circulaire
public:
void insert(slink *a);
void append(slink *a);
slink *get();
void clear(){last = 0;}
list()last(0){}
list(slink *a)last(a->next=a){}
friend class listIter;
}
typedef void (*PFV) (const char *);
PFV setListErrorHandler(PFV f) {
PFV old = listErrorHandler;
listErrorHandler = f;
return old;
}
void defaultListErrorHandler(const char *s) {
assert(0);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 91
}
PFV listErrorHandler = &defaultListErrorHandler;
8.3.8. itration
class listIter {
slink *e; //lment courant
list *l; //liste courante
public:
listIter(list&_l):l(&_l),e(l->last){}
inline slink* operator()();
}
slink* listIter::operator()(){
slink *ret = e ? e->next : 0;
if (ret == l->last) e = 0;
return ret;
}
template<class T> class IslistIter; //dclaration pralable
template<class T> class Islist { //intrusive
friend class IslistIter;
//
}
template<class T> class SlistIter; //dclaration pralable
template<class T> class Slist { //non intrusive
friend class SlistIter;
//
}
8.3.9. itrateurs (2)
template<class T>
class IslistIter : private listIter { //hrite de classe de base
public:
IslistIter(Islist<T>& l):listIter(l){}
T* operator()(){return (T*) listIter::operator()();}
}
template<class T>
class SlistIter : private listIter { //hrite de classe de base
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 92
public:
IslistIter(Islist<T>& l):listIter(l){}
T* operator()(){
return ((Tlink<T>*)listIter::operator()())->info;
}
}
void f(name *p){
Islist<name> l1;
Slist<name> l2;
l1.insert(p);
l2.insert(p);
IslistIter<name> it1(l1);
const name *p;
while (p = it1()) { // do something }
}
8.4. fonctions gnriques globales
template<class T> void sort(vect<T>&) {
/* trie en ordre croissant */
unsigned n = v.size();
for (int i = 0 ; i<n-1 ; i++)
for (int j = n-1 ; i<j ; j--)
if (v[j]<v[j-1]) swap (v[j],v[j-1]);
}
//version particulire pour char * car < ne fonctionne pas
void sort(vect<char*>&) {
/* trie en ordre croissant */
unsigned n = v.size();
for (int i = 0 ; i<n-1 ; i++)
for (int j = n-1 ; i<j ; j--)
if (strcmp(v[j],v[j-1])<0) swap (v[j],v[j-1]);
}
void f(vect<int>&vi, vect<char*>&vc, vect<string>vs) {
vi.sort();
vc.sort();
vs.sort();
}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 93
8.4.1. exemple
On peut aussi implanter une classe de vecteurs triables
template<class T> void sort(sortableVect<T>&) {
/* trie en ordre croissant */
unsigned n = v.size();
for (int i = 0 ; i<n-1 ; i++)
for (int j = n-1 ; i<j ; j--)
if (v.lessThan(v[j],v[j-1])) swap (v[j],v[j-1]);
}
template<class T> sortableVect:public vect, public comp<T> {
public:
sortableVect(int s):vect(s){}
}
template<class T> class comp {
static int lessthan(T&a,T&b) {return a<b;}
}
class comp<char *> {
static int lessthan(T&a,T&b) {return strcmp(a,b)<0;}
}
8.5. rsolution de la surcharge des fonctions gnriques
cration d'une nouvelle fonction pour chaque type argument
pas de conversion des types
8.5.1. surcharge explicite possible :
template<class T> T max (Ta, Tb) { return a<b ? b : a;}
int max(int a, int b) {}
8.5.2. templates plusieurs arguments
template<class T, class U> T max(T a, U b) {}
8.6. arguments de template
pas besoin d'tre un argument de type :
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 94
template<class T, int sz> class buffer {
T v[sz];
}
c'est utile dans le cas o la taille est connue la compilation
chaque argument de template de fonction doit figurer dans le type d'un des arguments de la fonction. Cela permet la
slection et la gnration de la bonne fonction lors d'un appel.
Deux classes gnres par template sont gales si leurs arguments de cration sont identiques modulo un typedef,
l'valuation de constantes, etc..
8.7. drivation et templates
Une classe exprime ce qui est commun dans la reprsentation et les interfaces d'appel, et un template exprime ce qui
est commun aux types utiliss comme arguments
Deux classes gnres par template ne sont pas dans une relation d'hritage particulire
8.7.1. mise en oeuvre via les templates
certaines classes ncessitent d'allouer de la mmoire
on peut contrler cette allocation par l'utilisation d'un template
template<class T, classA> class controlled_container :
public container<T>, private A {
void f() {
T *p = new(A::operator new(sizeof(T))) T;
}
8.8. un tableau associatif
template<class V, class K> class map {
public :
V& operator[](const K &k) { // trouver le V partir du K
// grce <, et ==
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 95
9. Gestion des exceptions
9.1. gestion des erreurs
En cas de situation exceptionnelle (i.e. sortant du cadre prvu par l'algorithme), le programmeur se trouve devant
plusieurs alternatives, non quivalentes en cot de conception et de codage :
1 : terminer le programme en indiquant le lieu de l'erreur (assert())
2: retourner une valeur reprsentant l'erreur, qui doit tre propage, et traite, par toutes les fonctions appelantes
3: continuer dans un tat invalide (avec ou non affichage de message)
4: provoquer un "longjump" jusqu' un point o l'erreur peut tre traite (et un tat valide reconstruit)
C++ offre une solution lgante et performante au problme de la prise en compte des exceptions
9.2. discrimination et nommage des exceptions
dclaration d'intercepteurs :
class vector {
int sz;
int *v;
//
class range{
int index;
range(int i) : index(i){}
};
class size{};
vector(int i) : sz(i) { v = new int[i]; if (!v) throw size();}
int& operator[](int i) { if (i>=sz) throw range(i); return v[i];
}
9.2.1. utilisation
void f()
{
try {
g();
} catch (vector::range r) {
cout << "bad index" << r.index << endl;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 96
} catch (vector::size) { // une autre erreur par exemple
}
}
9.2.2. Les interceptions peuvent tre imbriques
9.2.3. On peut utiliser des templates de classes d'exceptions
Chaque classe gnre aura son propre gestionnaire d'exceptions
template<class T> class allocator {
class exhausted{};
};
void f() {
try {
// allocate for some room
} catch (allocator<int>::exhausted) {
} catch (allocator<char>::exhausted) {
}
}
La classe exception peut aussi tre globale, i.e. non intgre dans la classe qui provoque l'exception
9.2.4. regroupement d'exceptions
On peut grouper le traitement des exceptions
enum matherr {overflow, underflow, zerodivide, etc...}
try { //... }
catch (matherr m) {
switch (m) case overflow: break; case
}
On peut utiliser l'hritage dans des classes d'exceptions et profiter des fonctions virtuelles
C'est utile car cela permet de traiter toutes les exceptions, y compris celles venir
class matherr {};
class overflow : public matherr {};
class underflow : public matherr {};
class zerodivide : public matherr {};
try { }
catch (overflow) {
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 97
// tout overflow ou sous classe de overflow
} catch (matherr) {
// tout matherr qui n'est pas overflow
}
9.2.5. Exceptions drives
Une exception est gnralement intercepte par un gestionnaire d'une classe de base
Pour disposer de toute l'information relative l'exception exacte, il faut utiliser une rfrence
try {}
catch (errtype &e){}
On peut relancer une exception
try {}
catch (errtype &e){
if (cantdoit) throw; //relance l'exception exacte d'origine
}
Les gestionnaires sont essays dans l'ordre, et cet ordre est donc opportun
Le compilateur connat la hirarchie des classes et peut donc signaler des erreurs : exception masque et donc jamais
gre par exemple.
catch(...)signifie : intercepter n'importe quelle exception
try { // qqchose
} catch (...){
// autre chose
throw; //relance l'exception exacte d'origine
}
9.3. acquisition de ressources
Le mcanisme de throw garantit que l'appel des destructeurs des variables automatiques est correctement effectu
On peut tirer parti de ce mcanisme pour acqurir des ressources dans des constructeurs,
et librer ces ressources dans les destructeurs.
Exemple de la trace
9.3.1. constructeurs et destructeurs
Un objet n'est pas considr construit tant que son constructeur n'est pas termin.
Un constructeur n'est termin que pourvu que tous les sous objets ont t construits.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 98
Le destructeur ne sera appel que si l'objet est construit.
class X {
filePtr aa;
lockPtr bb;
X(const char *x, const char *y) : aa(x), bb(y) {}
};
Si le constructeur de bb lance une exception, celui de aa ayant t termin, le destructeur de aa sera appel, mais pas
celui de bb.
9.3.2. acquisition de ressources = initialisation
Un constructeur bien pens obit au principe : l'acquisition de ressources est une initialisation.
Si l'acquisition choue, le constructeur choue.
struct X{
int *p;
X(int s) {p = new int[s]; init()};
X() {delete[] p;}
}; // si init lance une exception, p n'est jamais libr
variante sre :
template<class T>class arrayOf{
T *p;
arrayOf(int s){p = new T[s];}
arrayOf(){delete[] p;}
operator T* (){return p;}
}
struct X{
arrayOf<int> p;
X(int s) : p(s){init()};
X() {}
}; // si init lance une exception, p est libr
Le code d'un constructeur n'est pas appel si new ne parvient pas allouer assez d'espace pour l'objet.
9.3.3. puisement de ressources
Lors de l'incapacit obtenir une ressource, on peut prvenir le programme appelant (en appelant une fonction de
l'appelant), ou encore lancer une exception.
On combine en gnral les deux approches de la faon suivante (exemple de l'oprateur new):
#include <stdlib.h> //pour size_t
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 99
extern void * _last_allocation;
extern void * operator new(size_t size) {
void * p;
while (0 == (p = malloc(size))) {
if (_new_handler) (*_new_handler)();
else return 0;
}
return _last_allocation = p;
}
9.3.4. puisement de ressources
// pour l'utiliser :
void my_new_handler() {
if (can_get_some_mem()) return;
throw MemoryExhausted;
}
// et dans une fonction :
void (*oldnh)() = set_new_handler (&my_new_handler);
try {}
catch (MemoryExhausted) {}
catch (...){
set_new_handler (oldnh); //remet
throw; //relance
}
set_new_handler (oldnh); //remet
9.3.5. rgle lors de l'utilisation de callbacks
Il est bon d'changer aussi peut de paramtres que possible avec les callbacks, pour viter de rendre interdpendants
des programmes qui n'ont pas de rapport.
9.4. exceptions qui ne sont pas des erreurs
Terminer lgamment une recherche hautement rcursive (dans un arbre par exemple)
Sortir d'une boucle infinie parcourue un grand nombre de fois
Attention la lisibilit des programmes rsultants, car les exceptions sont un mcanisme de contrle moins bien
structur que les autres.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 100
9.5. spcification d'interface
On peut dclarer les exceptions pouvant tre lances par une fonction :
void f() throw (x2,x3,x4);
void f() throw (x2,x3,x4)
void f() {
try { /* code */ }
catch (x1) {throw;}
catch (x2) {throw;}
catch (x3) {throw;}
catch (...) {unexpected ();} // terminate() puis abort()
}
int g() throw();//ne peut lancer aucune exception
int h(); //peut lancer toutes les exceptions
9.5.1. utilisation de set_unexpected
On peut utiliser set_unexpected pour redfinir le comportement par dfaut, et appeler throw quand mme pour relancer
une erreur qui ne figure pas dans l'interface de la fonction
typedef void (*PFV)();
PFV set_unexpected (PFV);
class STC {
PFV old;
STC(PFV f) : old(set_unexpected(f)) {}
STC(){set_unexpected(old);}
};
void rethrow () { throw;}
f_qui_laisse_passer()
{
STC(&rethrow);
f();
}
9.6. exceptions non interceptes
Une exception non intercepte provoque un appel terminate
PFV set_terminate (PFV);
Un appel terminate est suppos ne pas retourner son appelant.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 101
9.7. alternatives la gestion des erreurs
int f(args) {
try {
g(args);
} catch (x1) {// corrige, et ressaye
g(args);
} catch (x2) {// calcule et retourne un rsultat
return 2;
} catch (x3) {//relance
throw;
} catch (x4) {//change en une autre exception
throw y4;
} catch (x5) {corrige et continue la fonction
// du code
} catch (...) {traduit en une autre forme d'erreur
errno = EBZCLDF;
terminate();
}
9.8.
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 102
10. Flots
10.1. introduction
Les flots sont accessibles par l'interface "iostream.h"
Les noms de fonction sont surchargs pour tous les types souhaits
Des oprateurs sont dfinis (<< et >>)
10.2. sorties
put(cerr, "x = ");
put(cerr, x);
put(cerr, "\n");
// notation directe :
cerr << "x = " << x << "\n";
cout << a * b + c << "\n"; //prcdence assez basse de <<
class ostream : public virtual ios {
//
public :
ostream& operator<<(const char *);
ostream& operator<<(char);
ostream& operator<<(short i){return *this<<int(i);;
ostream& operator<<(int);
ostream& operator<<(long);
ostream& operator<<(float);
ostream& operator<<(double);
ostream& operator<<(const void *);//tous les pointeurs
};
10.2.1. extension pour une classe utilisateur
class complex{
//
friend ostream& operator<<(ostream& o, complex&c);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 103
}
ostream& operator<<(ostream& o, complex&c) {
return o << '(' << c.re << ',' << c.im << ')';
}
//utilisation :
main(){
complex c(1,2);
cout << "le complexe c vaut " << c << endl;
}
10.3. entres
class istream : public virtual ios {
//
public :
istream& operator<<(char *);
istream& operator<<(char&);
istream& operator<<(short&);
istream& operator<<(int&);
istream& operator<<(long&);
istream& operator<<(float&);
istream& operator<<(double&);
};
// ide du code :
istream& operator<<(T& tvar) {
//sauter les espaces
//lire un "T" dans tvar
return *this
}
int readints (Vector<int>& v){
for (int i = 0;i<v.size ; i++) {
if (cin>>v[i++]) continue; //converteur implicite en int
return i;
}
//autres traitements
}
//autres mthodes de la classe istream :
istream& get (char &c);
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 104
istream& get (char *s,int n, char fin = '\n');
10.3.1. fonctions dfinies dans <ctype.h> :
int isalpha(char);
int isupper(char);
int islower(char);
int isxdigit(char);
int isspace(char);
int iscntrl(char);//0->31, 127
int ispunct(char);//aucun des prcdents
int isalnum(char);//alpha ou digit
int isprint(char);//affichable ascii ' ' .. ''
int isgraph(char);//alnum ou ispunct
int isascii(char);//compris entre 0 et 127
//toutes sauf isascii sont values par accs direct ds tableau
//donc plus efficaces que des comparaisons
10.3.2. tats du flot
int eof() const, //fin de fichier
fail() const, //prochaine opration chouera, mais tat du flot correct (rien de perdu)
bad() const, //ouups
good() const //c'est dans ce seul tat que les oprations font quelque chose
class ios {
//
public :
enum io_state {goodbit=0, eofbit=1, failbit=2, badbit=4};
rdstate (); //retourne un ensemble de bits d'io_state
};
10.3.3. entre de types utilisateur
Le second argument doit tre une rfrence. Exemple (simplifi)
istream& operator>>(istream& s, complex&c) {
//trois formats : re , (re) , (re,im)
{
double re = 0, im = 0;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 105
char c = 0;
s >> c;
if ( c == '(' ) {
s >> re >> c;
if ( c == ',' ) {
s >> im >> c;
} // pas de else
if (c != ')') {
s.clear (ios::badbit); //
} else {
s.putback(c);
s >> re;
}
if (s) a = complex (re,im);
return s;
}
10.4. mise en forme
La classe ios de base permet de grer le lien entre un flot de sortie et un flot d'entre, ainsi que des informations lies
aux formats.
class ios {
//
public :
ostream *tie(ostream *s); //attache l'entre la sortie
ostream *tie()const; //retourne la sortie lie
int width(int w); //positionne le champ longueur
int width()const; //retourne la longueur
char fill(char); //init le caractre de remplissage
char fill()const; //retourne ce caractre
long flags(long);
long flags()const;
long setf(long setbits, long field);
long setf(long);
long unsetf(long);
int precision (int);
int precision ()const;
void clear (int i = 0);
int rdstate()const, eof()const, bad()const, fail()const, good()const;
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 106
10.4.1. liaison de flots
main () {
char s[50];
cout << "passwd :";
// grce tie, on peut omettre ici cout.flush();
cin >> s;
}
//
cin.tie(0); // permet de supprimer le lien
10.4.2. champs de sortie
Le paramtre width (0 par dfaut) spcifie le nombre de caractres utiliser pour la prochaine (seulement) sortie
numrique ou de chane de caractres. La valeur 0 signifie : autant que ncessaire.
Le paramtre fill (espace par dfaut) est le caractre utilis pour combler
cout.width(4);
cout.fill(*);
cout << '(' << 12 << ')';
// produit :
(**12)
Width ne provoque pas de troncation
10.4.3. tat du format
La classe ios maintient un paramtre (flags) dcrivant les diffrents paramtres de format.
class ios {
public :
enum {
skipws=01, //sauter les sparateurs en entre
//remplissage :
left=02, //avant la valeur
right=04, //aprs la valeur
internal=08, //entre le signe et la valeur
//base entire :
dec = 020,
oct = 040,
hex = 0100,
showbase = 0200, //montrer la base
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 107
showpoint = 0400, //affiche les zros aprs la virgule
uppercase = 01000, //majuscules
showpos = 02000, //+ avant les positifs
scientific = 04000, //.dddddd Edd
fixed = 010000, //ddd.dd
unitbuf = 020000, // aprs chaque sortie
stdio = 040000, //aprs chaque caractre
};
};
//utilisation :
mystream.flags(mystream.flags() | ios::showbase);
//ou son quivalent :
mystream.setf(ios::showbase);
10.4.4. gestion des bits exclusifs : base, remplissage, et flottants
cout.setf(ios::oct, ios::basefield); // met ce qu'il faut zro
cout.setf(ios::left, ios::adjustfield); // id
cout.setf(ios::fixed, ios::floatfield); // id
cout.setf(0, ios::floatfield); // remet la valeur par dfaut
cout.precision(4); //chiffres aprs la virgule (6 par dfaut)
10.4.5. manipulateurs
Il est parfois ncessaire de procder des oprations sur les flots autres que des entres sorties, au milieu de ces
dernires. Ex :
cout << x; cout.flush(); cout<<y;
On peut procder ainsi :
typedef ostream& (*ostreamOp)(ostream&);
ostream& flush(ostream&);
ostream& operator<<(ostream&o, ostreamOp f) {
return f(o);
}
//ensuite :
cout << x << flush << y flush;
//un tel oprateur est dj dfini dans la classe ostream :
class ostream : public ios {
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 108
//
public :
ostream& operator<<(ostream& (*)(ostream&));
10.4.6. manipulateurs de istream
istream &ws(istream& is) {return is.eatwhite();}
//
cin >> ws >> x;
//on peut tendre le mcanisme : cout << setprecision (4) << x;
Il faut construire un objet affichable
typedef ostream & (*Fostint)(ostream&, int);
class omanip_int {
int param;
Fostint fonct;
omanip_int (Fostint f, int p) : fonct(f),param(p) {}
friend ostream& operator<<(ostream&, omanip_int&)
};
omanip_int setprecision (int i) {
return omanip_int (&_set_precision, i);
}
ostream& operator<<(ostream& o, omanip_int& m) {
return m.fonct(o, m.param);
};
cout << x << setprecision(4) << y;
10.4.7. utilisation de patrons
On peut dfinir un patron pour prvoir des structures de manipulateurs pour tous les types, autres qu'entiers :
template<class T> class OMANIP {
T i;
ostream& (*f)(ostream&,T);
public:
OMANIP(ostream& (*_f)(ostream&,T),T _i) : f(_f), i(_i){}
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 109
friend ostream& operator<<(ostream& o, OMANIP& m) {
return m.f(o,m.i);
}
};
ostream& precision (ostream& o, int i) {
o.precision (i);
return o;
}
OMANIP<int> setprecision (int i) {
return OMANIP<int>(&precision, i);
}
cout << precision(5) << x;
Les templates OMANIP, IMANIP et SMANIP (pour ios) sont dfinis dans <iomanip.h>
10.4.8. intrt des structures de manipulateurs
Passer un objet plutt qu'appeler une fonction est une technique intressante, mme dans d'autres domaines que les
entres sorties.
Un objet est cr, puis pass n'importe o, et utilis comme une fonction.
Cela permet de partager les dtails d'excution entre l'appel et l'appelant.
10.4.9. Manipulateurs d'entr es sorties standard
ios& oct (ios&); // dec, hex
ostream& endl(ostream&); // ends, flush
istream& ws(istream&); //saute les blancs
SMANIP<int> setbase(int); // et setfill, setprecision, setw
SMANIP<long> resetiosflags(long); // et setiosflags
10.4.10. membres de ostream
On peut avoir un accs direct une position d'un fichier, ds qu'il est li un ostream :
class ostream : public virtual ios {
ostream& flush();
ostream& seekp(streampos); //aller une position
ostream& seekp(streamoff,seek_dir);
streampos tellp();
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 110
};
seekp permet d'aller une position donne pour criture :
fout.seekp[10]; //li un file (char file[n]);
fout<<"@"; // crit @ dans file[10]
10.4.11. membres de istream
On peut avoir un accs direct une position d'un fichier, ds qu'il est li un istream :
class istream : public virtual ios {
int peek(); // consulte le prochain caractre sans lire
istream& putback(char c);
istream& seekg(streampos); //aller une position
istream& seekg(streamoff,seek_dir);
streampos tellg();
};
seekg permet d'aller une position donne pour lecture
les lettres p et g suffixes sont ncessaires car on peut crer une classe hritant la fois de ostream et de istream
10.5. fichiers et flots
#include <fstream.h>
les classes fstream, ofstream et ifstream drivent de iostream, qui est elle mme drive de istream et ostream.
Toutes les fonctionnalits de ces classes sont donc accessibles par fstream
class ios {
public :
enum open_mode {
in = 1<<0;//ouvert en entre
out = 1<<1;//ouvert en sortie
ate = 1<<2;//ouvre et va a la fin
app = 1<<3;//ajoute
trunc = 1<<4;//tronque le fichier longueur 0
nocreate = 1<<5;//choue si le fichier nexiste pas
noreplace = 1<<6;//choue si le fichier existe
};
};
// exemple : copie d'un fichier dans un autre
main(int argc, char **argv){
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 111
assert(argc == 3);
ifstream inp(argv[1]); assert(inp);
ofstream out(argv[2]); assert(out);
char c;
while (inp.get(c) && out.put(c));
assert(inp.eof() && !out.bad());
}
10.5.1. paramtrage
Un ofstream est ouvert en criture par dfaut, un ifstream en lecture. On peut aussi paramtrer cette ouverture :
ofstream out(name, ios::out|ios::nocreate);
fstream dictionary("dict.text", ios::in|ios::out);
10.5.2. fermeture des flots
dictionary.close(); //pour fermer
A l'arrt du programme, les flots cin, cout et cerr sont automatiquement ferms
10.5.3. flots de chanes de caractres
la classe strstream est dclare dans "strsream.h"
le caractre zro terminal est interprt comme la fin du fichier
char *p = new char[size];
ostrstream out(p,size);
out << 3 << "abcd";
10.5.4. mise en tampon
Les entres sorties utilisent des mcanismes de tampons distincts suivant que le type de flot est un fichier, ou un
tableau de caractres. Le mcanisme de leur prise en compte tire profit de la possibilit d'avoir des fonctions de dbordement
(overflow et underflow) virtuelles.
10.6. entres/sorties C
On peut entremler des appels aux fonctions d'entre sortie C sur une base ligne ligne. (au niveau des caractres on
peut avoir des problmes de portabilit).
Certaines implantations de C++ demandent d'appeler une fonction membre static de la classe ios pour travailler avec
des fonctions C:
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 112
ios::sync_with_stdio ();
Cours de programmation Laurent Henocque Le langage C++
Ecole Suprieure dIngnieurs de Luminy / dpartement ES2I, Marseille 113
11. Notes rapides au programmeur C
11.1. rgles empiriques de base pour la conception d'objets
si il y a structure : instance de classe
si visible comme objet : instance de classe
si deux classes partagent un concept : classe de base, et hritage
si la classe contient un objet d'un type donn : patron
11.2. notes aux programmeurs C
moins de prprocesseur : const, enum, inline, patrons
pas de malloc : new
moins d'unions : hritage
viter void *, +pointeur, tableaux C, cast explicite sauf au coeur des classes