Vous êtes sur la page 1sur 55

Cours P.O.O.

ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

CHAPITRE 4

LES CLASSES EN C++

Faten BEN HMIDA Université de La Manouba – ENSI – 2012/2013

Plan
2

Déclaration, Définition et Utilisation d’une classe


Structure du programme
Protection et visibilité des données
Constructeur & Destructeur
Affectation d’objets
Clonage d’objets : Constructeur de recopie
Membres statiques

Faten Ben Hmida 1


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Déclaration d’une classe


3

Partie interface de la classe : regroupe la déclaration des


attributs et les prototypes des méthodes publiques de la classe.

Se fait dans un fichier en-tête d’extension .h qui porte le nom de


la classe et qui se présente sous la forme suivante :
class Nom_classe Il peut y avoir également une section
{ protected : utilisée en cas de mise en
œuvre de l’héritage.
public:
//Déclarations des attributs et des méthodes publiques
private:
//Déclarations des attributs et des méthodes privées
};

Définition d’une classe


4

Partie implémentation de la classe : contient les définitions


complètes des méthodes de la classe (corps des fonctions).

Se fait dans un fichier source d’extension .cpp qui porte le nom


de la classe et qui se présente sous la forme suivante :
#include "Nom_classe.h" On écrit #include<fichier.h> pour
les fichier standards et
#include"fichier.h" pour les
// pour chaque méthode fichiers écrits par le programmeur

type_retour Nom_Classe::nom_methode(paramètres)
{
// corps de la méthode Opérateur de résolution de portée :
La méthode nom_methode de la classe
} nom_classe

Faten Ben Hmida 2


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Utilisation d’une classe


5

Une fois déclarée et définie, une classe peut être utilisée pour
créer des objets (instanciée).

Se fait dans un fichier source d’extension .cpp (par exemple dans


la fonction main) :
#include "Nom_classe.h" Instanciation de la classe
int main() Nom_classe et création d’un
nouvel objet nom_objet
{
Nom_classe nom_objet;
... L’accès aux données et fonctions
membres publics d’un objet se fait
nom_objet.nom_methode(); en utilisant le point (comme dans les
} structures)

Structure du programme
6

Généralement en C++, les programmes seront organisés de la


manière suivante :

Pour chaque classe :

un fichier .h contenant sa déclaration (attributs et prototypes des


méthodes)

un fichier .cpp contenant sa définition (implémentation des


méthodes)

un fichier .cpp contenant le traitement principal (fonction main)

Faten Ben Hmida 3


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Structure du programme
7

Déclaration

Définition

Utilisation

Exemple
8

//-----------Point.h------------ //---------------Point.cpp----------------
class Point #include <iostream>
{ #include "Point.h"
private: using namespace std;
int x;
int y; void Point::initialiser (int abs, int ord)
{
public: x = abs ;
void initialiser(int, int); y = ord ;
void deplacer(int,int); }
void afficher();
}; void Point::deplacer (int dx, int dy)
{
//----------Main.cpp------------ x = x + dx ;
#include "Point.h" y = y + dy ;
int main() }
{ Point a, b ;
a.initialiser (5, 2) ; Void Point::afficher ()
a.afficher () ; {
a.deplacer (-2, 4) ; cout << "Coordonnées du point : (" << x
a.afficher () ; << ", " << y << ")" << endl ;
b.initialiser (1,-1) ; }
b.afficher () ; }

Faten Ben Hmida 4


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Structure du programme
9
Une deuxième manière d’organiser le programme
//------------Main.cpp-------------- //----------Main.cpp(suite)-----------
#include <iostream> void Point::deplacer (int dx, int dy)
using namespace std; {
x = x + dx ;
class Point y = y + dy ;
{ }
private:
int x; void Point::afficher ()
int y; {
cout<<"("<<x<<", "<< y<<")"<< endl;
public: }
void initialiser(int, int);
void deplacer(int,int); int main()
void afficher(); {
}; Point a, b ;
a.initialiser (5, 2) ;
void Point::initialiser (int abs, a.afficher () ;
int ord) a.deplacer (-2, 4) ;
{ a.afficher () ;
x = abs ; b.initialiser (1,-1) ;
y = ord ; b.afficher () ;
} }

Structure du programme
10
Une troisième manière d’organiser le programme
//------------Main.cpp-------------- //----------Main.cpp(suite)----------
#include <iostream> void afficher ()
using namespace std; {
cout<<"("<<x<<", "<< y<<")"<<
class Point endl;
{ }
private: };
int x;
int y; int main()
{
public: Point a, b ;
void initialiser(int abs, int ord) a.initialiser (5, 2) ;
{ a.afficher () ;
x = abs ; a.deplacer (-2, 4) ;
y = ord ; a.afficher () ;
} b.initialiser (1,-1) ;
b.afficher () ;
void deplacer (int dx, int dy) }
{
x = x + dx ;
y = y + dy ;
}

Faten Ben Hmida 5


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Protection/Visibilité des données


11

Dans l’exemple précédent, tous les attributs de la classe Point


sont privés, ce qui correspond à une encapsulation complète des
données. Ainsi, une tentative d'utilisation directe du membre a :
a.x = 5; //interdit
conduirait à une erreur de compilation.

Cette instruction serait acceptée si x était un attribut public.

En général, on cherchera à respecter le principe d'encapsulation


des données, quitte à prévoir des fonctions membres appropriées
pour y accéder (accesseurs).

Protection/Visibilité des données


12

Les mots clés public et private peuvent apparaître à plusieurs


reprises dans la définition d'une classe, comme dans cet exemple :
class X
{ private :
...
public :
...
private :
...
} ;

Si aucun de ces deux mots n'apparaît au début de la définition,


tout se passe comme si private y avait été placé, c’est le niveau
de visibilité par défaut en C++.

Faten Ben Hmida 6


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur
13

Méthode spéciale appelée automatiquement à chaque création d’un


objet et qui permet de l’initialiser.

Le constructeur porte toujours le même nom que la classe.

Il ne retourne rien (pas de mention d’un type de retour, même pas void).

Il peut prendre plusieurs paramètres en fonction des attributs à


initialiser.

Une classe peut avoir plusieurs constructeurs à condition que les règles
de surcharge soient respectées.

Lorsqu'une classe ne comporte pas de constructeur, le compilateur


génère un constructeur par défaut qui ne prend aucun paramètre.

Constructeur
14

//---------Point.h---------- //------------Point.cpp-------------
class Point #include <iostream>
{ #include "Point.h"
private: using namespace std;
int x;
int y; Point::Point(int n)
{
public: x = n;
Point(int); y = n;
Point(int, int); }
...
}; Point::Point(int n, int p)
{
//--------Main.cpp---------- x = n;
#include "Point.h" y = p;
int main() }
{ Point a(3);
Point b(1,2); ...
...
}

Faten Ben Hmida 7


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur
15

A partir du moment où une classe possède un ou plusieurs constructeurs,


il n’est plus possible de faire appel au constructeur par défaut.

Dans la classe Point on ne peut plus créer des objets sans passer des
paramètres ( Point p; ) sauf si on définit explicitement un constructeur
qui ne prend pas d’arguments ( Point(); ) .
Point(); // Déclaration
...
Point::Point() // Définition
{
x = 0;
y = 0;
}
...
Point p; // Appel (on n’écrit pas Point p();)

Constructeur
16

Les initialisations des attributs peuvent se faire par affectations dans le


corps du constructeur (tel que défini précédemment) ou bien grâce aux
listes d’initialisations.

La syntaxe d’une liste d’initialisation est la suivante :


: attribut_1(valeur_1), ... , attribut_n(valeur_n)

Elle se place juste après l’en-tête du constructeur.

Exemple :
Point::Point(int n, int p) : x(n), y(p)
{
//autres instructions
}

Faten Ben Hmida 8


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur
17

Un objet peut comporter aussi bien des attributs statiques que des
attributs dynamiques.

Dans ce cas, le rôle du constructeur ne se limite pas uniquement à


l’initialisation des attributs statiques, mais doit aussi prendre en charge
l’allocation de la mémoire pour les attributs dynamiques.
class Etudiant Etudiant::Etudiant(int id, int nb)
{ private: :ident(id), nbNotes(nb)
int ident; {
float* notes; notes = new float[nbNotes];
int nbNotes; }
...
int main()
public: { Etudiant e(1, 8);
Etudiant(int, int);
...
... }
};

Construction d’objets
18

La construction d’un objet se fait par appel au constructeur. Elle


peut se faire de plusieurs manières selon le type de l’objet à
créer.

Il existe différents types d’objets :


Les objets statiques
Les objets automatiques
Les objets dynamiques

Faten Ben Hmida 9


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Construction d’objets
19

Objets statiques

Ils sont déclarés globalement, en dehors de toute fonction ou bloc


d’instructions.

A leur création, leurs données membres (attributs) sont


automatiquement initialisées à des valeurs nulles.

Les objets statiques sont créés avant le début de l'exécution de la


fonction main() et détruits après la fin de son exécution.

Syntaxe : NomClasse nomObjet;


ou bien : NomClasse nomObjet(arguments);

Construction d’objets
20

Objets automatiques

Ils sont déclarés localement à l’intérieur d’une fonction ou d’un


bloc d’instructions.
A leur création, leurs données membres (attributs) ne sont pas
initialisées sauf en cas d’appel d’un constructeur défini à cet effet.
Les objets automatiques sont créés à la rencontre de leur
déclaration et détruits à la fin de l’exécution de la fonction ou à
la sortie du bloc où ils sont déclarés.
Syntaxe : NomClasse nomObjet;
ou bien : NomClasse nomObjet(arguments);

Faten Ben Hmida 10


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Construction d’objets
21

//-------------Main.cpp---------------- //-------Point.h--------
#include "Point.h" class Point
{
private:
Point a; //objet statique
int x;
Point b(3,6); //objet statique int y;
public:
int main() Point();
{ a.afficher(); Point(int);
b.afficher(); Point(int, int);
Point c(5); //objet automatique ...
};
for(int i=1; i<=3; i++)
{ Résultat d’exécution
Point d(i,2*i); //objet automatique (0, 0)
d.afficher(); (3, 6)
(5, 5)
} //destruction de d
(1, 2)
} //destruction de c puis de a et b (2, 4)
(3, 6)

Construction d’objets
22

Objets dynamiques

Ils sont alloués dynamiquement et accessibles à travers un pointeur


(comme toute autre variable dynamique).
A leur création, leurs données membres (attributs) ne sont pas
initialisées sauf en cas d’appel d’un constructeur défini à cet effet.
Les objets dynamiques sont créés par appel à l’opérateur new et
doivent être détruits par appel explicite à l’opérateur delete.
Syntaxe : NomClasse* nomObjet = new NomClasse;
ou bien : NomClasse* nomObjet = new NomClasse(arguments);

Faten Ben Hmida 11


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Construction d’objets
23

Objets dynamiques (suite)

L’accès aux membres d’un objet dynamique ne se fait plus par .


mais par -> comme suit : nomObjet->membre

//-------------Main.cpp---------------- //-------Point.h--------
#include "Point.h" class Point
int main() {
private:
{
int x;
Point* ptr; //pointeur sur Point int y;
ptr = new Point(0); //objet dynamique
ptr->deplacer(2,3); public:
ptr->afficher(); Point();
Point(int);
...
void afficher();
delete ptr; //destruction de ptr ...
} };

Destructeur
24

Méthode spéciale appelée automatiquement à chaque destruction d’un


objet et qui permet d’effectuer les opérations de nettoyage de l’espace
mémoire occupé par les membres de l’objet.

Le destructeur porte le même nom que la classe précédé du symbole ~.

Il ne retourne rien (pas de mention d’un type de retour, même pas void)
et ne prend pas de paramètres.

Une classe ne peut avoir qu’un seul destructeur.

Lorsqu'une classe ne comporte pas de destructeur, le compilateur


génère un destructeur par défaut.

L’appel du destructeur se fait automatiquement et pas explicitement.

Faten Ben Hmida 12


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Destructeur
25

Un objet peut comporter aussi bien des attributs statiques que des
attributs dynamiques.

La définition explicite d’un destructeur n’est pas obligatoire


lorsque tous les attributs de l’objet sont statiques.

Elle devient indispensable en cas de présence d’attributs


dynamiques. La libération de ces derniers doit apparaître
explicitement dans le corps du destructeur (utilisation de
l’opérateur delete).

Destructeur
26
//---------Point.h---------- //------------Point.cpp-------------
class Point ...
{ private: Point::Point(int n)
int x; Présence uniquement { x = n;
int y; d’attributs statiques y = n;
public: }
Point(int); Point::~Point() //facultatif
~Point(); //destructeur {
... }
}; ...
//--------Etudiant.h-------- //-----------Etudiant.cpp-----------
class Etudiant ...
{ private: Etudiant::Etudiant(int id, int nb)
int ident; Présence d’un :ident(id), nbNotes(nb)
int nbNotes; attribut { notes = new float[nbNotes];
float* notes; dynamique ! }
public:
Etudiant(int, int); Etudiant::~Etudiant() //indispensable
~Etudiant(); //destructeur { delete[] notes; //libération
... }
}; ...

Faten Ben Hmida 13


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Destruction d’objets
27

La destruction des objets automatiques se fait automatiquement à


la sortie de la fonction ou du bloc dans lequel ils ont été créés.

La destruction des objets statiques se fait automatiquement à la


fin de l’exécution du programme principal.

La destruction des objets dynamiques doit se faire explicitement


avec l’appel à l’opérateur delete.

Attention ! Ne pas confondre attribut dynamique d’un objet


(statique ou dynamique) et un objet dynamique !

Destruction d’objets
28

//-------------Main.cpp---------------- //-------Point.h--------
... class Point
Point a; //objet statique {
int main() private:
{ a.afficher(); int x;
Point b(5); //objet automatique int y;
for(int i=1; i<=3; i++) public:
{ Point c(i,2*i); //objet automatique Point();
c.afficher(); Point(int);
} //destruction de c Point(int, int);
Point* d = new Point(4, 5); ~Point();
//objet dynamique ...
d->afficher(); };
delete d; //destruction de d
} //destruction de b puis de a

Faten Ben Hmida 14


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Affectation d’objets
29

Cas des objets statiques et automatiques


Soit la déclaration suivante :
Point a, b; //a et b sont deux objets de Point

L’instruction b = a ; provoque la recopie des valeurs des


attributs de a dans les attributs correspondants de b.

Elle est équivalente aux instructions suivantes qui sont quant à


elles interdites :
b.x = a.x ;
b.y = a.y ;
car les attributs de la classe Point sont privés donc inaccessibles.

Affectation d’objets
30

Cas des objets statiques et automatiques


Remarques
L’affectation b = a est toujours légale, quel que soit le statut
(public ou privé) des attributs de a et de b. On peut considérer
qu’elle ne viole pas le principe d’encapsulation, dans la mesure
où les données privées de b restent toujours inaccessibles de
manière directe.
Attention ! Une simple recopie à l’aide de l’opérateur = s’avère
insuffisante lorsque l’objet comporte des pointeurs sur des
emplacements dynamiques, dans ce cas la recopie ne concernera
pas cette partie de l’objet, elle sera "superficielle" (copie de
l’adresse contenue dans le pointeur uniquement).

Faten Ben Hmida 15


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Affectation d’objets
31

Objets ne contenant que des attributs statiques


Point p1(12, 25), p2; p1 : Point p2 : Point
p2 = p1; Copie des valeurs
X = 12 des attributs X = 12
Y = 25 Y = 25

Objets contenant des attributs dynamiques


Etudiant e1(1, 8), e2;
e2 = e1;
e1 : Etudiant e2 : Etudiant Problème !
La copie est superficielle,
Copie des valeurs seule l’adresse contenue
id = 1 id = 1 dans le pointeur est
des attributs
nbNotes = 8 nbNotes = 8 copiée !

notes = @ ||||||| notes = @ |||||||

Affectation d’objets
32

Cas des objets dynamiques


Soit les déclarations suivantes :
Point* a = new Point;
Point* b;
//a et b sont deux objets dynamiques issus de Point

L’instruction b = a; fait pointer b sur le même objet pointé par a.

a *a : Point

Faten Ben Hmida 16


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Clonage d’objets : Constructeur de recopie


33

L’opération d’affectation d’objets s’est avérée insuffisante pour


effectuer convenablement la copie d’un objet.
Solution : Constructeur de recopie

Le constructeur de recopie est un constructeur spécial qui permet de


créer un objet à partir d’un autre objet (un clone).

Le constructeur de recopie doit prévoir d’effectuer :


Les allocations de mémoire nécessaires pour les attributs dynamiques
Les copies des valeurs des attributs dynamiques.

Lorsqu'une classe ne comporte pas de constructeur de recopie, le


compilateur en génère un par défaut mais qui effectue une copie
superficielle d’où la nécessité de définir explicitement pour chaque
classe un constructeur de recopie.

Constructeur de recopie
34

Déclaration :
nomClasse(nomClasse&);

Définition :
nomClasse::nomClasse(nomClasse& obj) : ...
{
//opérations d’allocation de la mémoire
//opérations de copie des attributs dynamiques
}

Utilisation :
Attention !
nomClasse nomClone = nomObjet; Ne pas confondre avec une affectation
d’objets, il s’agit d’une initialisation qui
nomClasse nomClone(nomObjet);
provoque l’appel automatique du
constructeur de recopie.

Faten Ben Hmida 17


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur de recopie
35

class Etudiant Etudiant::Etudiant(int id, int nb)


{ private: :ident(id), nbNotes(nb)
int ident; { notes = new float[nbNotes]; }
float* notes; ...
int nbNotes;
Etudiant::Etudiant(Etudiant& e)
... :ident(e.ident), nbNotes(e.nbNotes)
public:
{ notes = new float[nbNotes];
Etudiant(int, int);
for(int i=0;i<nbNotes;i++)
Etudiant(Etudiant&);
... *(notes+i) = *((e.notes)+i);
}; }

int main()
{ Etudiant e1(1, 8); Définition du constructeur de recopie.
Etudiant e2(e1); -----------------------------------------------------------------
Etudiant e3 = e1; Ces deux initialisations font appel automatiquement
... au constructeur de recopie qui (tel que défini) effectue
}
une copie profonde (clone) de l’objet e1

Constructeur de recopie
36

e1 : Etudiant e2 : Etudiant
Copie des valeurs
id = 1 id = 1
des attributs
nbNotes = 8 nbNotes = 8
notes = @ ||||||| notes = @’ |||||||

Copie profonde des


attributs dynamiques

Faten Ben Hmida 18


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur de recopie
37

Le rôle du constructeur de recopie ne se limite pas uniquement à


la création de copies d’un même objet.

On distingue deux autres cas où l’existence d’un constructeur de


recopie est indispensable :

Passage par valeur d’un objet à une fonction


Retour par valeur d’un objet par une fonction

Constructeur de recopie
38

Ce qui se passe sans constructeur de recopie


class Tab Tab::Tab(int d) : dim(d)
{ private: { adr = new int[dim];
int dim; cout << "Construction usuelle, adr. objet : "
int* adr; << this << endl; }
public: Tab::~Tab()
Tab(int); { delete[] adr;
~Tab(); cout << "Destruction, adr. objet : " << this
}; << " adr. tableau : " << adr << endl; }

void fct(Tab a) Résultat de l’exécution


{ cout << "Appel de Construction usuelle, adr. objet : 0x22ff20
fonction" << endl; } Appel de fonction
Destruction, adr. objet : 0x22ff10 adr.
int main() tableau : 0x7c2ef8
{ Tab t(5); Destruction, adr. objet : 0x22ff20 adr.
fct(t); } tableau : 0x7c2ef8

Faten Ben Hmida 19


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur de recopie
39

Ce qui se passe sans constructeur de recopie


Dans la classe Tab, aucun constructeur de recopie n’a été défini, le compilateur se
charge alors d’en générer un. Ce dernier effectue une copie superficielle de t dans
a lors de l’appel de la fonction fct() (copie du paramètre effectif dans le
paramètre formel) t : Tab Copie superficielle a : Tab
des attributs
dim = 5 dim = 5
notes = @ | | | | notes = @

A la sortie de la fonction fct(), le paramètre formel a est détruit, ce qui engendre


une destruction de l’attribut dynamique de t et donc engendre une altération de
l’objet t !
t : Tab a : Tab

dim = 5 dim = 5
notes = @ | | | | notes = @

Constructeur de recopie
40

Ce qui se passe avec le constructeur de recopie


class Tab Tab::Tab(int d) : dim(d)
{ private: { ... }
int dim; Tab::Tab(Tab& t) : dim(t.dim)
int* adr; { adr = new int[dim];
public: for (int i=0;i<dim;i++) *(adr+i) = *(t.adr+i);
Tab(int); cout << "Construction recopie, adr. objet : "
Tab(Tab&); << this << endl; }
~Tab(); Tab::~Tab()
}; { ... }

void fct(Tab a) Résultat de l’exécution


{ cout << "Appel de Construction usuelle, adr. objet : 0x22ff20
fonction" << endl; } Construction recopie, adr. objet : 0x22ff10
Appel de fonction
int main() Destruction, adr. objet : 0x22ff10 adr.
{ Tab t(5); tableau : 0x2d2f18
fct(t); } Destruction, adr. objet : 0x22ff20 adr.
tableau : 0x2d2ef8

Faten Ben Hmida 20


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Constructeur de recopie
41

Ce qui se passe avec le constructeur de recopie


Dans la classe Tab, le constructeur de recopie a été explicitement défini. Ce dernier
effectue une copie profonde de t dans a lors de l’appel de la fonction fct()
(copie du paramètre effectif dans le paramètre formel)
t : Tab Copie profonde a : Tab
des attributs
dim = 5 dim = 5
notes = @ | | | | notes = @’ | | | |

A la sortie de la fonction fct(), le paramètre formel a est détruit, ce qui est sans
effet sur le paramètre effectif t !
t : Tab a : Tab

dim = 5 dim = 5
notes = @ | | | | notes = @’ | | | |

Attributs statiques (static)


42

Généralement, lorsqu’on crée différents objets à partir d’une


même classe, chaque objet possède ses propres attributs.

Exemple :
class maClasse
{
int n;
float x;
...
};
...
maClasse a, b;

Faten Ben Hmida 21


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Attributs statiques (static)


43

Un attribut statique est un attribut partagé entre toutes les


instances d’une classe. Un tel attribut est déclaré en utilisant le
qualificatif static.

Exemple :
class maClasse
{
static int n;
float x;
...
};
...
maClasse a, b;

Si un objet modifie l’attribut statique, tous les autres objets ont


instantanément accès à la nouvelle valeur de cet attribut.

Attributs statiques (static)


44

Un attribut statique existe en un unique exemplaire


indépendamment des objets de la classe (même si aucun objet n’a
été instancié) : attribut de classe.

Un attribut statique doit être initialisé explicitement à l'extérieur


de la déclaration de la classe en utilisant l’opérateur de
résolution de portée ::

Exemple :
class maClasse
{
static int n;
float x;
...
};
int maClasse::n = 5; //initialisation de l’attribut statique

Faten Ben Hmida 22


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Attributs statiques (static)


45

Exemple
Ajouter à la classe Point définie précédemment, un attribut
permettant de compter le nombre de ses instances existantes.

class Point Point::Point(int n, int p) : x(n), y(p)


{ {
private: cpt++;
static int cpt; cout<<"nombre d’objets:"<<cpt<<endl;
int x, y; }
public: Point::~Point()
Point(int, int); {
~Point(); cpt--;
}; cout<<"nombre d’objets:"<<cpt<<endl;
int Point::cpt = 0; }

Méthodes statiques (static)


46

Une méthode statique est une méthode appartenant à une classe


est définie indépendamment de toute instanciation de cette
dernière.

Une méthode statique est déclarée en utilisant le qualificatif


static. Elle ne peut manipuler que des attributs statiques (définis
avec le mot clé static)

Une méthode statique peut être appelée indépendamment des


objets de la classe (même si aucun objet n’a été instancié) :
méthode de classe. Dans ce cas, elle est appelée en utilisant le
nom de la classe à laquelle elle appartient et l’opérateur de
résolution de portée :: (accès direct sans passer par une instance).

Faten Ben Hmida 23


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Méthodes statiques (static)


47

Exemple
Ajouter à la classe Point définie précédemment, une méthode
permettant d’afficher le nombre de ses instances existantes.

class Point Point::Point(int n, int p) : x(n), y(p)


{ { cpt++; }
private: Point::~Point()
static int cpt; { cpt--; }
int x, y; void Point::compter()
{ cout<<"nombre d’objets:"<<cpt<<endl; }
public: int main()
Point(int, int); { Point::compter();
~Point(); Point a(1,6);
static void compter(); a.compter();
}; Point b(3,5);
Point::compter();
int Point::cpt = 0; }

Fonctions amies
48

POO encapsulation des données : attributs privés accessibles


uniquement à travers les méthodes publiques de la même classe.

Dans certains cas, une méthode non-membre d’un classe a besoin


d’accéder aux attributs de cette classe. Solutions possibles :

Rendre les attributs publics compromettre leur protection


Passer par des méthodes d’accès perdre en temps d’exécution

Solution intéressante : notion de fonction amie : Lors de la


définition d'une classe, il est possible de déclarer qu'une ou
plusieurs fonctions extérieures à la classe sont des "amies" ce qui
les autorise à accéder aux attributs privés au même titre que
n'importe quelle fonction membre.

Faten Ben Hmida 24


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Fonctions amies
49

Pour déclarer une fonction amie d’une classe il suffit d’insérer son
prototype dans la définition de la classe en le faisant précéder
par le mot clé friend.
class maClasse
{ // Attributs
public:
// Méthodes
friend type_retour nom_fonction(arguments);
}

Plusieurs situations d’ "amitié", principalement :


Fonction indépendante amie d’une classe.
Fonction membre d’un classe amie d’une autre classe.

Fonctions amies
50

Exemples

1) Définir une fonction indépendante amie de la classe Point nommée


"coincide" permettant de tester la coïncidence de deux objets de type
Point.

2) Définir une classe Vecteur permettant de représenter un vecteur de 3


composantes de type double (tableau), une classe Matrice permettant
de représenter une matrice carrée de dimension 3. Définir la fonction
indépendante "produit" permettant d’effectuer le produit d’un vecteur
et d’une matrice.

Modifier le code précédent de manière à ce que "produit" devienne


une méthode de la classe Vecteur.

Faten Ben Hmida 25


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Fonctions amies
51

Remarques
Fonction indépendante amie de plusieurs classes à la fois

Toutes les méthodes d’une classe sont amies avec une autre classe :
pour dire que toutes les fonctions membres de la classe B sont amies de
la classe A, on place dans la classe A, la déclaration

Surcharge des opérateurs


52

En plus de la possibilité de surcharge des fonctions, C++ permet


de surcharger des opérateurs (+, *, /, ++, --, =, +=, new, [], …).

Surcharger un opérateur : lui permettre d’être appliqué et de se


comporter différemment avec divers types d’opérandes.

Exemple : l’opérateur + est déjà surchargé en C++ puisque dans


une expression telle que a + b le symbole + peut désigner,
suivant le type de a et b :
l'addition de deux entiers
l’addition de deux réels (float)
l’addition de deux réels double précision (double)
etc.

Faten Ben Hmida 26


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


53

Il est possible de surcharger encore l’opérateur + pour qu’il soit


applicable à des objets issus de classes définies par le
programmeur.

Avantage : permettre de créer à travers des classes de nouveaux


types munis d’opérateurs comme les types de base.

Exemple : Définir une classe "Complexe" et pouvoir donner une


signification à des expressions telles que : a+b, a-b, a*b, a/b, …

Remarque : la plupart des opérateurs en C++ peuvent être


surchargés à l’exception de :: (résolution de portée) . (accès à
un membre) :? (opérateur conditionnel) sizeof (taille en octets).

Surcharge des opérateurs


54

Pour surcharger un opérateur en C++, on doit définir une fonction


nommée operator suivie du symbole de l’opérateur à surcharger.

Cette fonction peut être :


Une méthode de la classe à laquelle s’applique l’opérateur
Une fonction indépendante amie avec cette classe

Exemple : pour surcharger l’opérateur + et l’appliquer à des


objets de type Point :
Point Point::operator+(Point) //méthode de la classe Point

Point operator+(Point, Point) //fonction amie de Point

Faten Ben Hmida 27


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


55

#include <iostream> int main()


using namespace std; { Point a(1,2);
class Point a.affiche();
{ int x, y; Point b(2,5);
public : b.affiche();
Point(int abs=0, int ord=0) Point c;
{ x = abs; y = ord; } c = a + b;
Point operator+ (Point); c.affiche();
void affiche(); c = a + b + c;
}; c.affiche();
void Point::affiche() }
{ cout << "coordonnees : "
<< x << " " << y << "\n"; Résultat de l’exécution
}
Point Point::operator+(Point a) coordonnees : 1 2
{ Point p; coordonnees : 2 5
p.x = x + a.x; coordonnees : 3 7
p.y = y + a.y; coordonnees : 6 14
return p ;
}

Surcharge des opérateurs


56

#include <iostream> int main()


using namespace std; { Point a(1,2);
class Point a.affiche();
{ int x, y; Point b(2,5);
public : b.affiche();
Point(int abs=0, int ord=0) Point c;
{ x = abs; y = ord; } c = a + b;
friend Point operator+(Point,Point); c.affiche();
void affiche(); c = a + b + c;
}; c.affiche();
void Point::affiche() }
{ cout << "coordonnees : "
<< x << " " << y << "\n"; Résultat de l’exécution
}
Point operator+(Point a, Point b) coordonnees : 1 2
{ Point p; coordonnees : 2 5
p.x = a.x + b.x; coordonnees : 3 7
p.y = a.y + b.y; coordonnees : 6 14
return p ;
}

Faten Ben Hmida 28


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


57

Remarques

Une expression telle que a + b est en fait interprétée par le


compilateur comme un appel operator+(a, b).

Nous pouvons toujours écrire c = operator+(a, b) au lieu de


c = a + b mais cela ne présente aucun intérêt.

Une expression telle que a + b + c est évaluée en tenant


compte des règles de priorité et d'associativité habituelles de
l'opérateur +. Cette expression est évaluée comme (a + b) + c
et en utilisant la notation fonctionnelle
operator+(operator+(a, b), c).

Surcharge des opérateurs


58

Cas des opérateurs ++ et --

Notation préfixée ++a ≠ Notation postfixée a++


int i, j = 5; int i, j = 5;
i = ++j; // i=6 et j=6 i = j++; // i=5 et j=6

Besoin de définir à la fois un opérateur ++ utilisable en notation


préfixée et un autre utilisable en notation postfixée.

Pour ce faire, il existe une convention qui consiste à ajouter un


argument fictif supplémentaire à la version postfixée de la
fonction operator++.

Faten Ben Hmida 29


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


59

Cas des opérateurs ++ et --

Dans le cas où ++ est défini sous la forme d’une fonction membre :

La fonction nomClasse operator ++() sera utilisée en cas de


notation préfixée.

La fonction nomClasse operator ++(int) sera utilisée en cas


de notation postfixée.

L’argument de type int est totalement fictif, il permet uniquement


au compilateur de choisir l'opérateur à utiliser mais aucune valeur
ne sera réellement transmise lors de l'appel.

Surcharge des opérateurs


60

Cas des opérateurs ++ et --

Dans le cas où ++ est défini sous forme d’une fonction amie :

La fonction nomClasse operator ++(nomClasse) sera utilisée


en cas de notation préfixée.

La fonction nomClasse operator ++(NomClasse, int) sera


utilisée en cas de notation postfixée.

Dans les 2 cas (méthode de classe ou fonction amie), les mêmes


considérations s'appliquent à l'opérateur --.

Faten Ben Hmida 30


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


61

#include <iostream> int main()


using namespace std; { Point a1(2, 5);
class Point Point a2(2, 5), b;
{ int x, y; b = ++a1;
public : cout << "a1 : ";
Point(int abs=0, int ord=0) a1.affiche ();
{ x = abs; y = ord; } cout << "b : ";
Point operator++(); //préfixée b.affiche ();
Point operator++(int); //postfixée b = a2++;
void affiche(); cout << "a2 : ";
}; a2.affiche ();
cout << "b : ";
void Point::affiche() b.affiche () ;
{ cout << x << " " << y << "\n" ; } }

Point Point::operator++() Résultat de l’exécution


{ x++; y++; return *this; } a1 : 3 6
b: 3 6
Point Point::operator++(int n) a2 : 3 6
{ Point p=*this; x++; y++; return p; } b: 2 5

Surcharge des opérateurs


62

Faten Ben Hmida 31


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


63

Surcharge des opérateurs


64

Cas de l’opérateur =

L’affectation d’objets présente le même problème de la création


d’objets par copie (clonage) à l’exception de quelques détails
près :

Possibilité d'affectation d'un objet à lui-même.

Avant affectation, il existe deux objets "complets" (c'est-à-dire avec


leur partie dynamique). Dans le cas de la construction par recopie, il
n'existait qu'un seul objet, le second étant à créer.

Faten Ben Hmida 32


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


65

Cas de l’opérateur =

Problème de l’affectation d’objets :


class Vecteur
{ int nb ; // nombre d'éléments
int* adr ; // adresse
public :
Vecteur (int n) // constructeur
...
};
...
Vecteur a(5), b(3);
...
b = a;

Surcharge des opérateurs


66

Cas de l’opérateur =

Solution : surcharge de l’opérateur d’affectation =

Démarche : (pour une affectation b = a correcte)

Libération de la partie dynamique de b;

Création dynamique d'un nouvel emplacement dans lequel on


recopie les valeurs de l'emplacement pointé par a.

Copie des valeurs des attributs de b.

Prise en compte de l’affectation d’un objet à lui-même (a=a).


Prise en compte des affectations multiples (a=b=c).

Faten Ben Hmida 33


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Surcharge des opérateurs


67

#include <iostream>
using namespace std;
class Vecteur
{ int nb; Equivaut à un passage
int* adr; d’arguments par
public : valeur mais évite la
Vecteur(int n)
copie d’arguments et
{ adr = new int[nb=n];
for(int i=0; i<nb; i++) adr[i] = 0; donc le recours au
} constructeur de
~Vecteur() { delete adr; } recopie
Vecteur& operator=(const Vecteur&);
};
Vecteur& Vecteur::operator=(const Vecteur& v)
{ if (this != &v) Retour par référence :
{ delete adr; pour bien gérer les
adr = new int[nb=v.nb] ; affectations multiples
for (int i=0; i<nb; i++) adr[i] = v.adr[i];
(a=b=c)
}
return *this;
}

Surcharge des opérateurs


68

Remarque importante

La définition d’un constructeur de recopie ne permet pas de


résoudre le problème d’affectation d’objets.

La surcharge de l’opérateur d’affectation ne permet pas de


résoudre le problème de copie d’objets.

Le constructeur de recopie ne remplace pas l’opérateur


d’affectation et vice versa.

Faten Ben Hmida 34


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Forme canonique d’une classe


69

Du moment qu'une classe possède des attributs dynamiques, la


copie d'objets de cette classe (aussi bien par le constructeur de
recopie par défaut que par l'opérateur d'affectation par défaut)
n'est pas satisfaisante (superficielle).

Dans ce cas, il es donc nécessaire de munir la classe des quatre


fonctions membres suivantes au moins :

Constructeur : pour l'allocation des attributs dynamiques de l'objet.


Destructeur : pour la libération des emplacements dynamiques créés
par l'objet.
Constructeur de recopie.
Opérateur d'affectation.

Forme canonique d’une classe


70

Il convient de définir une classe en respectant le canevas suivant


appelé souvent « forme canonique » :

class T
{ ...
public :
T (...); //constructeurs
T (const T &); //constructeur de recopie
~T (); //destructeur
T& operator=(const T&); //affectation
};

Faten Ben Hmida 35


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Généricité
71

En C++, il est possible de définir des modèles génériques de


fonctions et de classes qu’on appelle « patron » ou « template »

Patron (template) de fonctions : modèle de fonctions ou fonction


générique écrire une seule fois la définition d'une fonction qui
sera adaptée automatiquement par le compilateur à n'importe
quel type.

Patron (template) de classes : modèle de classes ou classe


générique écrire une seule fois la définition d’une classe qui
sera adaptée automatiquement par le compilateur à n'importe
quel type.

Généricité
72

Patron de fonctions

La fonction fournissant le minimum de deux valeurs de même type


passées en arguments, peut être généralisée.

Au lieu d’écrire :
int minimum(int a, int b) float minimum(float a, float b) ...
{ {
if (a < b) return a; if (a < b) return a;
else return b; else return b;
} }

On définit un patron pour la fonction minimum qui soit applicable


quelque soit le type utilisé.

Faten Ben Hmida 36


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Généricité
73

Patron de fonctions

Le patron de la fonction minimum est défini comme suit :

template <class T> T minimum (T a, T b)


{
if (a < b) return a;
else return b;
}

Ainsi elle peut être utilisée indifféremment pour n’importe quel


type de données.

Pour les classes : nécessité de surcharger l’opérateur < pour que


ce soit applicable correctement.

Généricité
74

Patron de fonctions
#include <iostream>
using namespace std ;
// création d'un patron de fonctions minimum
template <class T> T minimum (T a, T b)
{ if (a < b) return a;
else return b;
}
// exemple d'utilisation du patron de fonctions minimum
main()
{ int n=4, p=12;
float x=2.5, y=3.25;
cout << "minimum(n,p) = " << minimum(n,p) << endl;
// int minimum(int,int)
cout << "minimum(x,y) = " << minimum(x,y) << endl;
// float minimum(float, float)
}

Faten Ben Hmida 37


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Généricité
75

Patron de fonctions
#include <iostream>
using namespace std ; // exemple d'utilisation
template <class T> T minimum (T a, T b) int main()
{ if (a < b) return a; { Vecteur u(3,2), v(4,1), w;
else return b; w = minimum(u,v);
} cout << "minimum(u,v) = ";
class Vecteur w.affiche() ;
{ int x, y; }
public:
Vecteur(int abs=0, int ord=0) { x=abs; y=ord; }
void affiche() { cout << x << " " << y; }
friend int operator<(Vecteur, Vecteur);
};
int operator<(Vecteur a, Vecteur b)
{ return (a.x*a.x + a.y*a.y < b.x*b.x + b.y*b.y);
}

Généricité
76

Patron de classes

La classe permettant de représenter un point ayant deux


coordonnées d’un type donné.

Au lieu d’écrire :
class Point class Point ...
{ int x; int y; { float x; float y;
public: public:
Point(int a=0, int b=0); Point(float a=0, float b=0);
void affiche(); void affiche();
... ...
}; };

On définit un patron pour la classe Point qui soit applicable


quelque soit le type des coordonnées utilisé.

Faten Ben Hmida 38


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Généricité
77

Patron de classes
Le patron de la classe Point est défini comme suit :
template <class T> class Point
{
T x; T y;
public:
Point (T a=0, T b=0);
void affiche();
};
template <class T> void Point<T>::affiche()
{ ...
}

Ainsi elle peut être utilisée indifféremment pour n’importe quel


type de coordonnées.

Généricité
78

Patron de classes
#include <iostream>
using namespace std ;
template <class T> class Point
{ T x; T y;
public:
Point(T a=0, T b=0)
{ x = a; y = b; }
void affiche() ;
};
template <class T> void Point<T>::affiche()
{ cout << "Coordonnees : " << x << " " << y << endl;
}
int main ()
{ Point <int> ai (3, 5); ai.affiche();
Point <char> ac ('d', 'y'); ac.affiche();
Point <double> ad (3.5, 2.3); ad.affiche();
}

Faten Ben Hmida 39


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Généricité
79

Patron de classes
#include <iostream> int main()
using namespace std ; { Vecteur <int> v(5) ;
template <class T> class Vecteur for(int i=0; i<4 ; i++)
{ T* tab; v[i] = i ;
int taille; cout << "v : ";
public : for(int i=0; i<4; i++)
Vecteur(int); cout << v[i] << " ";
T& operator[](int i); }
};
template <class T> Vecteur<T>::Vecteur(int n)
{ tab = new T[n];
taille = n;
}
template <class T> T& Vecteur<T>::operator[](int i)
{ return tab[i];
}

Exercice
80

Faten Ben Hmida 40


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Exercice
81

Exercice
82

Faten Ben Hmida 41


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots
83

Ecriture sur la sortie standard avec des instructions du type :


cout << x ;

Cette expression fait appel à l'opérateur << auquel elle fournit


deux opérandes : le "flot de sortie" concerné (ici cout) et
l'expression dont on souhaite écrire la valeur (ici x)

Lecture sur la sortie standard avec des instructions du type :


cin >> y ;

Cette expression fait appel à l'opérateur >> auquel elle fournit


deux opérandes : le "flot d’entrée" concerné (ici cin) et
l'expression dont on souhaite écrire la valeur (ici y)

Les flots
84

D'une manière générale, un flot peut être considéré comme un


"canal" :
recevant de l'information : flot de sortie,
fournissant de l'information : flot d'entrée.

Les opérateurs << et >> servent à assurer le transfert de


l'information, ainsi que son éventuel formatage.

Un flot peut être connecté à un périphérique ou à un fichier. Par


convention :
le flot prédéfini cout est connecté à la "sortie standard"
le flot prédéfini cin est connecté à "l'entrée standard"

Faten Ben Hmida 42


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots
85

Généralement :

Entrée standard : clavier


Sortie standard : écran

Possibilité de rediriger l’entrée standard ou la sortie standard


vers un fichier.

En dehors de ces flots prédéfinis, l'utilisateur peut définir lui-même


d'autres flots qu'il pourra connecter à un fichier de son choix.

Les flots
86

Un flot est en fait un objet d'une classe prédéfinie, à savoir :

La classe ostream pour un flot de sortie.


La classe istream pour un flot d'entrée.

Chacune de ces deux classes surcharge les opérateurs << et >>


pour les différents types de base.

L’emploi de ces classes nécessite l'incorporation du fichier en-tête


iostream

Faten Ben Hmida 43


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – la classe ostream


87

Dans la classe ostream l'opérateur << est surdéfini (surchargé)


pour les différents types de base, sous la forme :
ostream& operator<<(expression)

Il reçoit deux opérandes :


la classe l'ayant appelé (argument implicite this).
une expression d'un type de base quelconque.

Son rôle consiste à transmettre la valeur de l'expression au flot


concerné en la formatant de façon appropriée.

Remarque : cout est un objet prédéfini de la classe ostream.

Les flots – la classe ostream


88

Possibilités de formatage avec <<


Il est possible d’agir sur la base de numérotation des données à
transmettre au flot de sortie grâce à des opérateurs prédéfinis
appelés manipulateurs.

Lorsqu'on écrit une expression entière sur un flot de sortie, on peut


choisir de l'exprimer dans la base décimale (valeur par défaut),
hexadécimale ou octale : manipulateurs dec, hex et oct.

Lorsqu'on écrit une expression booléenne sur un flot de sortie, on


peut choisir de l'exprimer soit sous la forme d’un entier (0 ou 1),
soit sous la forme false, true : manipulateurs noboolalpha et
boolalpha.

Faten Ben Hmida 44


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – la classe ostream


89

#include <iostream>
using namespace std ;
int main() par defaut : 12000
{ en hexadecimal : 2ee0
int n = 12000 ; en decimal : 12000
cout << "par defaut : " << n << "\n"; en octal : 27340
cout << "en hexadecimal : " << hex << n << "\n"; et ensuite : 27340
cout << "en decimal : " << dec << n << "\n"; par defaut : 1
cout << "en octal : " << oct << n << "\n"; avec noboolalpha : 1
cout << "et ensuite : " << n << "\n"; avec boolalpha : true
bool ok = true ; // ou ok = 1 et ensuite : true
cout << "par defaut : " << ok << "\n";
cout << "avec noboolalpha : " << noboolalpha << ok << "\n";
cout << "avec boolalpha : " << boolalpha << ok << "\n";
cout << "et ensuite : " << ok << "\n";
}

hex, dec, oct, noboolalpha et boolalpha s’appellent des manipulateurs. Ils


permettent d’effectuer des opérations de formatage sur la donnée à rediriger vers
le flot de sortie.

Les flots – la classe ostream


90

Possibilités de formatage avec <<


Il est possible d’agir sur la largeur, la précision et le remplissage
des données à transmettre au flot de sortie grâce aux
manipulateurs paramétriques.

setw(int n) : affiche la donnée sur une largeur de n caractères

setprecision(int n) : définit la précision à n chiffres

setfill(char c) : définit c comme caractère de remplissage

L’emploi des manipulateurs paramétriques nécessite l’inclusion du


fichier en-tête <iomanip>

Faten Ben Hmida 45


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – la classe ostream


91

#include <iostream>
#include <iomanip> |****1234|
using namespace std ; |*12.35|
int main()
{
int n = 1234;
float x = 12.3456;
cout << "|" << setw(8) << setfill('*') << n << "|" << endl
<< "|" << setw(6) << setprecision(2) << x << "|" << endl;
}

L’effet des manipulateurs setfill() et setprecision() reste


permanent jusqu’à modification explicite. En revanche, le
manipulateur setw() n’agit que sur la prochaine donnée à afficher
uniquement.

Les flots – la classe istream


92

Dans la classe istream l'opérateur >> est surdéfini (surchargé)


pour les différents types de base, sous la forme :
istream& operator>>(type_de_base&)

Il reçoit deux opérandes :


la classe l'ayant appelé (argument implicite this).
une variable d'un type de base quelconque.

Son rôle consiste à extraire du flot concerné les caractères


nécessaires pour former une valeur du type de base voulu.

Remarque : cin est un objet prédéfini de la classe istream.

Faten Ben Hmida 46


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots
93

Surcharge des opérateurs << et >> pour les types


définis par l’utilisateur
Les deux opérateurs << et >>, déjà surchargés dans les classes
istream et ostream pour les différents types de base, peuvent
aussi être surchargés pour n'importe quelle classe créée par
l'utilisateur.

Ces opérateurs doivent recevoir un flot en premier argument, ce


qui empêche de les surcharger sous la forme d’une méthode de
la classe concernée il s’agira de fonctions amies de la classe.

Les flots
94

Surcharge des opérateurs << et >> pour les types


définis par l’utilisateur
La valeur de retour sera la référence au flot concerné (reçu en
premier argument) pour pouvoir enchaîner les utilisations de ces
opérateurs dans une même expressions : cout << a << b << …

Toutes les fonctions de surcharge de << suivront ce schéma :


ostream& operator<<(ostream& sortie, classe objet)

Toutes les fonctions de surcharge de >> suivront ce schéma :


istream& operator>>(istream& entree, classe& objet)

Faten Ben Hmida 47


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots
95

On se propose de surcharger les opérateurs << et >> pour la


classe Point.
Nous supposerons qu'une "valeur de type Point" se présente
toujours (aussi bien en lecture qu'en écriture) sous la forme :
(entier,entier).

#include <iostream>
using namespace std ;
class Point
{ int x, y;
public:
Point (int abs=0, int ord=0)
{ x = abs ; y = ord ; }
friend ostream& operator<<(ostream&, Point);
friend istream& operator>>(istream&, Point&);
};

Les flots
96

ostream& operator<<(ostream& sortie, Point p)


{ sortie << "(" << p.x << "," << p.y << ")";
return sortie;
}

istream& operator>>(istream& entree, Point& p)


{ char c = '\0'; float x, y; int ok = 1;
entree >> c;
if (c != '(') ok = 0;
else
{ entree >> x >> c; // Le statut d’erreur du flot est
if (c != ',') ok = 0; géré par un ensemble de bits :
else // clear (fonction d’activation des
{ entree >> y >> c; bits d’erreur)
if (c != ')') ok = 0; // badbit (bit activé quand le flot
} est dans un état irrécupérable)
}
if (ok) { p.x = x; p.y = y; }
else entree.clear(ios::badbit);
return entree ;
}

Faten Ben Hmida 48


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots
97

int main()
{
Point a(2,3), b;
cout << "point a : " << a << " point b : " << b << endl;

cout << "donnez un point : ";


if (cin >> a)
cout << "point saisi : " << a << "\n";
else
cout << "information incorrecte \n";
}

Les flots – connexion à un fichier


98

Pour associer un flot de sortie à un fichier, il suffit de créer un


objet de type ofstream (classe héritière de ostream).

L'emploi de cette nouvelle classe nécessite d'inclure un fichier en-


tête nommé fstream , en plus du fichier iostream.

Le constructeur de la classe ofstream nécessite deux arguments :

Le nom du fichier concerné (sous forme d'une chaîne de caractères)

Le mode d'ouverture défini par une constante entière (la classe ios
comporte un certain nombre de constantes prédéfinies)

Faten Ben Hmida 49


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – connexion à un fichier


99

Le mode d'ouverture est défini par des constantes déclarées


dans la classe ios. Pour activer plusieurs modes à la fois, il suffit
de faire appel à l'opérateur |.
Valeur Action
ios::in Ouverture en lecture
ios::out Ouverture en écriture
ios::app Ouverture en ajout (écriture en fin de fichier)
ios::trunc Ecrasement du contenu à l’ouverture

Exemple :
ofstream sortie("file.txt", ios::out);
permet de créer un flot nommé sortie et de l’associer au fichier
file.txt après avoir ouvert ce dernier en écriture.

Les flots – connexion à un fichier


100

Une fois l’objet sortie de la classe ofstream construit,


l'écriture dans le fichier qui lui est associé peut se faire comme
pour n'importe quel flot en faisant appel à toutes les facilités de
la classe ostream (dont dérive ofstream).

Exemple :
sortie << .... << .... << .... ;

On peut également connaître le statut d'erreur du flot


correspondant en examinant sa valeur.

Exemple :
if (sortie) ....

Faten Ben Hmida 50


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – connexion à un fichier


101

#include <iostream> ce programme enregistre dans un fichier


#include <fstream> texte de nom fourni par l'utilisateur, des
using namespace std; nombres entiers saisis sur l'entrée
const int LGMAX = 20 ;
standard. L’enregistrement s’arrête dès
int main()
{ char nomfich[LGMAX+1]; int n; qu’un nombre > 100 est saisi.
cout << "nom du fichier a creer (max 20 caracteres) : ";
cin >> nomfich;
ofstream sortie(nomfich, ios::out) ;
if (!sortie) {
cout << "creation impossible \n";
}
else {
do {
cout << "donnez un entier : ";
cin >> n;
sortie << n << endl;
} while ((n<100) && (sortie));
sortie.close();
}
}

Les flots – connexion à un fichier


102

Pour associer un flot d’entrée à un fichier, il suffit de créer un


objet de type ifstream (classe héritière de istream).

L'emploi de cette nouvelle classe nécessite d'inclure le fichier en-


tête fstream , en plus du fichier iostream.

Le constructeur de la classe ifstream nécessite deux arguments :

Le nom du fichier concerné (sous forme d'une chaîne de caractères)

Le mode d'ouverture défini par une constante entière (la classe ios
comporte un certain nombre de constantes prédéfinies)

Faten Ben Hmida 51


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – connexion à un fichier


103

Le mode d'ouverture est défini par des constantes déclarées


dans la classe ios. Pour activer plusieurs modes à la fois, il suffit
de faire appel à l'opérateur |.
Valeur Action
ios::in Ouverture en lecture
ios::out Ouverture en écriture
ios::app Ouverture en ajout (écriture en fin de fichier)
ios::trunc Ecrasement du contenu à l’ouverture

Exemple :
ifstream entree("file.txt", ios::in);
permet de créer un flot nommé entree et de l’associer au
fichier file.txt après avoir ouvert ce dernier en lecture.

Les flots – connexion à un fichier


104

Une fois l’objet entree de la classe ifstream construit, la


lecture du fichier qui lui est associé peut se faire comme pour
n'importe quel flot en faisant appel à toutes les facilités de la
classe istream (dont dérive ifstream).

Exemple :
entree >> .... >> .... >> .... ;

On peut également connaître le statut d'erreur du flot


correspondant en examinant sa valeur.

Exemple :
if (entree) ....

Faten Ben Hmida 52


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

Les flots – connexion à un fichier


105

#include <iostream> ce programme permet de lister le fichier


#include <fstream> texte de nom fourni par l'utilisateur et
using namespace std; créé à partir du programme précédent.
const int LGMAX = 20 ;
int main()
{ char nomfich[LGMAX+1]; int n;
cout << "nom du fichier a lister : ";
cin >> nomfich;
ifstream entree(nomfich, ios::in) ;
if (!entree) {
cout << "ouverture impossible \n";
}
else {
while (entree >> n)
cout << n << endl;
entree.close();
}
}

La classe string
106

C++ fournit une classe standard pour la création et


manipulation des chaînes de caractères : la classe string.

Un objet de type string contient, à un instant donné, une suite


formée d'un nombre quelconque de caractères. Sa taille peut
évoluer dynamiquement au fil de l'exécution du programme.

Contrairement aux conventions utilisées pour les chaînes de


caractères en C, la notion de caractère de fin de chaîne '\0'
n'existe plus et ce caractère (de code ASCII 0) peut apparaître
au sein de la chaîne, éventuellement à plusieurs reprises.

Faten Ben Hmida 53


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

La classe string
107

Construction
La classe string dispose de plusieurs constructeurs :
//construction d'une chaîne vide
string ch1;

//construction d'une chaîne de 10 car. égaux à '*'


string ch2(10, '*');

//construction d'une chaîne de 5 car. de code nul


string ch3(5, '\0');

La classe string
108

Construction
La classe string dispose d'autres constructeurs permettant
d'initialiser une chaîne lors de sa construction :
//initialisation à partir d’une chaîne constante
string mess1("bonjour");
string mess1 = "bonjour";

//initialisation à partir d’un tableau de caractères


char* adr = "salut";
string mess2(adr); //ou string mess2 = adr;

Faten Ben Hmida 54


Cours P.O.O. ENSI - II1
Chapitre 4 : Les Classes en C++ A.U. : 2012/2013

La classe string
109

Construction
La classe string dispose aussi d’un constructeur de recopie :
string s1;
.....
string s2(s1) //ou string s2 = s1;
//construction de s2 par recopie de s1

La classe string
110

Opérateurs et fonctions usuelles


Les opérateurs <<, >>, +, +=, =, ==, !=, <=, >=, <, > sont
surchargés pour la classe string.

Fonctions fréquemment utilisées :


size() : fournit la taille d’une chaîne
find() : recherche une chaîne ou un caractère dans une chaîne
insert() : insère une chaîne ou un caractère dans une chaîne
erase() : supprime un caractère ou une partie d’une chaîne
replace() : remplace une partie d’une chaîne par une autre

Faten Ben Hmida 55

Vous aimerez peut-être aussi