Vous êtes sur la page 1sur 48

LES CLASSES EN C++

Olfa FAKHFAKH POO – ENSI – 2011/2012


Plan
2

1. Déclaration et définition d’une classe

2. Constructeur et Destructeur

3. Surcharge des opérateurs

4. Données statiques

5. Généricité
Rappels
3

 Une classe est une implémentation d’un type abstrait de


données,
 Une classe est la généralisation de la notion de type défini
par l’utilisateur, dans lequel se trouvent associées des données
«Données membres» (ou attributs) et des fonctions «Fonctions
membres» (ou méthodes).

 En POO pure, les données sont « encapsulées »


 leur accès ne peut se faire que par le biais des méthodes.
Rappels
4

Rappel : les structures en C


struct point { Définit un type structure nommé
int x ; point (on dit aussi par abus de
int y ; langage, la structure point).
};

x et y : ce sont des champs ou des membres de la structure point.

En C++ :
Associer à une structure, en plus des données, des fonctions
nommées « fonctions membres » ou « méthodes ».
Déclaration et définition d’une classe…
5

Une syntaxe possible pour la définition d’une classe est :

class <nom de classe> private :


{
// déclaration des attributs
...
public :
//
Prototype et définition des méthodes
...
};

La classe est définie à l’aide d’un bloc et se termine par un ‘;’


Exemple
6
Exemple
7

class Point
{ int x; Déclaration de la classe point
int y;
public : Instanciation de la classe point
void Init(int a, int b); en un objet p
void Deplace(int a, int b);
void Affiche(); void main()
}; {
Point p;
p.Init(3,4);
void Point::Init(int a, int b) p.Affiche();
{ x = a; y = b; } p.Deplace(4,6);
p.Affiche();
void Point::Deplace(int a, int b) }
{ x += a; y += b; }
void Point::Affiche()
{ cout << x << ", " << y << endl; } On applique la méthode Affiche()
à l'objet p
Protection/visibilité
8
Protection/visibilité
9

class point void main()


{ // déclaration des membres privés
private : {
int x ; Point p;
int y ;
p.initialise(5,2);
// déclaration des membres publics p.deplace(3,6)
public :
void initialise (int, int) ; }
void affiche () ;

Private : illégal
void deplace (int, int) ;
};
Affectation d’objets
10

class point void main()


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

Provoquera la recopie des valeurs des membres


x et y de a dans les membres correspondants
de b.

Contrairement à ce que vous connaissez pour les structures, il n'est pas


toujours possible de remplacer cette instruction par :
1) b.x = a.x ;
2) b.y = a.y ;

Ici l’instruction 1 n’est pas légale car x est un membre privé.


Affectation d’objets
11

 L’affectation a = b est toujours légale, quel que soit le statut


(public ou privé) des membres données.

 On peut considérer qu’elle ne viole pas le principe


d’encapsulation,
 dans la mesure où les données privées de b (les copies de
celles de a après affectation) restent toujours inaccessibles de
manière directe.
Surcharge des méthodes
12
Modifieurs et Accesseurs
13
Définition des méthodes
14
Exemple
15
Définition des méthodes
16

class A {
Méthode inline
public :
int f() const;
inline void g(int val);
private :
int i;
};

int A::f() const


{ return i;}
Spécification de
contexte ::
inline void A::g(int val){ i=val;}
Le pointeur "this"
17
Autoréférence : le mot clé this
18

 utilisable uniquement au sein d'une fonction membre,


désigne un pointeur sur l'objet l'ayant appelé.

class point void point::affiche ()


{ int x, y ; { cout << "Adresse : " << this << " -
public : Coordonnees " << x << " " << y <<
point (int abs=0, int ord=0) // Un "\n" ;
constructeur ("inline") }
{ x=abs; y=ord ; }
void affiche () ; int point::coincide (point pt)
int coincide (point); { if ((this -> x == pt.x) && (this -> y
== pt.y)) return 1 ;
}; else return 0 ;
}
Les opérateurs de création et de
19
destruction des objets
class A { char * text;
public : text = new char[80];
int f(); ...
... delete text;
};

A * a; = (A*) malloc( sizeof(A));

a = new A; Attribut initialisé par le


int i = a->f(); modifieur f().
...
delete a;

= free a;
Le constructeur et le destructeur
20

 Constructeur
 Une fonction membre portant le même nom que sa classe se nomme
constructeur,
 Un constructeur peut avoir des arguments mais ne renvoie pas de
valeur (aucune indication de type même pas void ),
 Le constructeur est appelé implicitement tout juste après l’allocation
de l’espace mémoire destiné à l’objet.

 Destructeur
 Une fonction membre portant le même nom que sa classe, précédé
du symbole (~), se nomme destructeur,
 Un destructeur ne peut pas comporter d’arguments et il ne renvoie
pas de valeur ( aucune indication de type ne doit être prévue ),
 Le destructeur est appelé implicitement avant la libération de
l’espace mémoire associé à l’objet.
Le constructeur et le destructeur
21

class A {
public : Un Constructeur de A
A();
Un Constructeur surdéfini de A
A(int);
... Le destructeur
~A();
... Objet automatique
}; void main()
{ Le constructeur de A est exécuté
A a; automatiquement
par A().
A * ptr; Le destructeur est appelé à la sortie de la
printf("%d \n",a.f()); fonction
... ou du bloc de déclaration.
ptr = new A(1);
...
delete ptr;
}
Le destructeur est exécuté
Le constructeur et le destructeur
22

class A {
public : Un Constructeur de A
A();
Un Constructeur surdéfini de A
A(int);
... Le destructeur
~A();
... Objet dynamique
}; void main()
{
Le constructeur A(int) est appelé
A a;
A * ptr; Réalise une allocation dynamique d'espace
printf("%d \n",a.f()); mémoire pour un élément de type A
... et affecte son adresse au pointeur ptr.
ptr = new A(1);
...
delete ptr;
}
Le destructeur est exécuté
Constructeur (…)
23

• Le corps du constructeur peut être précédé par une section optionnelle


introduite par ":", spécifiquement réservée à l'initialisation des attributs.

• Il est possible de changer la valeur des attributs dans le corps du


constructeur.

• Les attributs non initialisés dans cette section prendront une valeur par
défaut dans le cas où une telle valeur existe.

 A::A(int val) initialisation


 : i(val)
 {
 i = ...;
Affectation
 }
Constructeur par défaut
24
Clonage des objets
25
Constructeur de copie
Forme générale
<id_classe> (const <id_classe> & obj) : ...
{
}

Remarque : s'il n'est pas défini, le compilateur génère un de manière


automatique ( initialisation membre à membre en invoquant le constructeur de
copie de chacun d'eux)
Constructeur de copie
26

class Point Main(){


{ Point pt(1,2);
int x; Point pt2(pt); // Construction
int y;public : par recopie de Point
Point(){x=-1;y=-1;}
Point(int a, int b){ x=a; y=b; }
}

Point( const Point & pt) le passage par référence:


// Constructeur par recopie de Point il faut réellement utiliser
{ l'objet lui-même, et non une
x = pt.x; copie.
y = pt.y;
}
...
la présence d'un "const"
}; une protection de l'objet à
recopier.
Constructeur de copie
27

class Bidon void fct (Bidon )


{ { cout << "*** appel de fct
double * adr ; // pointeur sur 1 élément ***\n" ;
public : }
Bidon() // constructeur "usuel" main(){
{ adr = new double; Bidon a ;
cout << "+ const. usuel - adr objet : " << fct (a) ;
this Bidon c(a);
<< " - adr : " << adr << "\n" ; }
}

~Bidon() // destructeur Dans le cas d'un objet qui comporte un


{ cout << "- Destr. objet - adr objet : " pointeur), lorsqu'on veut recopier un
<< this << " - adr : " << adr << "\n" ; objet, on ne recopie pas ce qui est pointé,
delete adr ; mais l'adresse du pointeur seulement.
} Du coup, on se retrouve avec deux objets
}; différents, mais qui possèdent une donnée
qui pointe vers la même chose !
Constructeur de copie
28

 A la fin de l'exécution de la fonction fct, le destructeur ~point est appelé


pour b, ce qui libère l'emplacement pointé par adr ;

 A la fin de l’éxecution de la fonction main, le destructeur est appelé pour


a, ce qui libère... Le même emplacement.

 Cette tentative constitue une erreur d'exécution dont les conséquences


varient avec l’implémentation.

b
Constructeur de copie
29

class Bidon
{
void fct (Bidon )
double * adr ; // pointeur sur 1 élément { cout << "*** appel de fct ***\n"
;
public :
}
Bidon() // constructeur "usuel"
{…}
Bidon(const Bidon & v) // constructeur de recopie main()
{ {
adr = new double ; // création nouvel objet Bidon a ;
fct (a) ;
*adr = *(v.adr); // recopie des contenus des ptr }

cout << "+ const. recopie - adr objet : " << this
<< " - adr : " << adr << "\n" ;
}
~Bidon() // destructeur
{ ….}
};
Constructeur de copie
30

 Chaque objet possédant son propre emplacement mémoire,


 les destructions successives se déroulent sans problème.

b
Surcharge des opérateurs
31

class point
{ int x, y ;
public :
Void main()
point (int abs=0, int ord=0) { x=abs ; y=ord ;} {
point operator + (const point &) ; point a(1,2) ; a.affiche() ;
Int operator == (const point &) ; point b(2,5) ; b.affiche() ;
void affiche () { cout << "coordonnees : " << x << " " point c ;
<< y << "\n" ; } c = a+b ; c.affiche() ;
};
}
point point::operator + (const point & a)
coordonnees : 1 2
{ point p ;
coordonnees : 2 5
p.x = x + a.x ; p.y = y + a.y ; coordonnees : 3 7
return p ;
}
int point::operator==(const point & p)
{ if( x==p.x && y==p.y )
return 1;
else
return 0;
}
Surcharge des opérateurs
32

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


compilateur comme l'appel :
operator + (a, b)

 Bien que cela ne présente guère d'intérêt, nous pourrions


écrire

c = operator + (a, b) au lieu de c = a + b


Surcharge des opérateurs
33
Surcharge des opérateurs
34
Surdéfinition de l’opérateur =
35

class vect
main()
{ int nelem ; // nombre d'éléments { vect a(5) , b(3);
double * adr ; // pointeur sur ces éléments
public : b=a;
}
vect (int n) // constructeur "usuel"
{ adr = new double [nelem = n] ;
cout << "+ const. usuel - adr objet : " << this << " -
adr vecteur : " << adr << "\n" ;
}
~vect () // destructeur
{ cout << "- Destr. objet - adr objet : "
<< this << " - adr vecteur : " << adr << "\n" ;
delete adr ;}
};
Surdéfinition de l’opérateur =
36

class vect main()


{ int nelem ; // nombre d'éléments { vect a(5) , b(3);
double * adr ; // pointeur sur ces éléments
public : b=a;
vect (int n) {…} // constructeur "usuel" }
~vect () { …} // destructeur
vect & vect::operator = (const vect & v)
{ if (this != &v)
{ cout << " effacement vecteur dynamique en " << adr << "\n" ;
delete adr ;
adr = new int [nelem = v.nelem] ;
cout << " nouveau vecteur dynamique en " << adr << "\n" ;
for (int i=0 ; i<nelem ; i++) adr[i] = v.adr[i] ;
nous rendons une
référence sur l'objet,
}
car nous devons rendre
else cout << " on ne fait rien \n" ;
la classe elle-même et
return * this ;} } ; non une copie…
Membre donnée statique
37

class exple2
{ static int n ;
float x ;
...
};
la déclaration :
exple2 a, b ;

 On peut dire que les membres données statiques sont des


sortes de variables globales dont la portée est limitée à
la classe.
Membre donnée statique
38
Membre donnée statique : exemple
39
class cpte_obj
{ int cpte_obj::ctr = 0 ;
// initialisation du membre statique ctr
static int ctr ; // compteur du nombre d'objets créés
public : cpte_obj::cpte_obj () // constructeur
cpte_obj () ; { cout << "++ construction : il y a
~cpte_obj () ; maintenant " << ++ctr << "
objets\n" ;
}; main() }
{ void fct () ; cpte_obj::~cpte_obj () // destructeur
cpte_obj a ; { cout << "-- destruction : il reste
fct () ; maintenant " << --ctr << " objets\n" ;
cpte_obj b ; }
}
void fct ()
{ cpte_obj u, v ;
}
Fonctions amies
40

class point int coincide (point ..., point ...)


{ {// on a accès ici aux membres
// partie privée //privés de tout objet de type point
…. }
//partie publique
friend int coincide (point, point) ;
.....
};

Fonction indépendante (coincide) amie d’une classe (point)


class matrice

Fonctions amies { double mat[3] [3] ; // matrice 3 X 3


public :
class vect
41 matrice (double t[3][3])
{ double v[3] ; // vecteur à 3 composantes
{ int i ; int j ;
public :
for (i=0 ; i<3 ; i++)
vect (double v1=0, double v2=0, double
v3=0) for (j=0 ; j<3 ; j++)
mat[i] [j] = t[i] [j] ;
{ v[0] = v1 ; v[1]=v2 ; v[2]=v3 ;}
}
friend vect prod (matrice, vect) ;
friend vect prod (matrice, vect) ;
// prod = fonction amie indépendante
void affiche () { …} };

}; vect prod (matrice m, vect x)


main() { int i, j ;
{ vect w (1,2,3) ; double som ;
vect res ; vect res ;
double tb [3][3] = { 1, 2, 3, 4, 5, 6, 7, for (i=0 ; i<3 ; i++)
8, 9 } ; { for (j=0, som=0 ; j<3 ; j++)
matrice a = tb ; som += m.mat[i] [j] * x.v[j] ; res.v[i] = som ;
res = prod(a, w) ;
}
res.affiche () ;
} return res ;
}
Fonctions amies
42

class A classe A;
{ class B
// partie privée {…
…. friend void f(A, B) ;
//partie publique };
friend void f(A, B) ;
void f(A..., B...)
..... { // on a accès ici aux membres privés
}; // de n’importe quel objet de type A ou B
}

Fonction indépendante (f) amie de deux classes (A et B)


Généricité : exemple
43

// le patron de fonctions min main()


template <class T> T min (T a, T b) { vect u (3, 2), v (4, 1), w ;
{ if (a < b) return a ; w = min (u, v) ;
else return b ;
}
cout << "min (u, v) = " ;
class vect w.affiche() ;
{ int x, y ;
}
public :
vect (int abs=0, int ord=0) { x=abs ; y=ord; }
void affiche () { cout << x << " " << y ; }
friend int operator < (vect, vect) ;
};
int operator < (vect a, vect b)
{ return a.x*a.x + a.y*a.y < b.x*b.x + b.y*b.y ;}
Généricité
template <class T> Vecteur<T>::Vecteur(int n)
44
{
template <class T>
v = new T[n];
class Vecteur {
taille = n;
T * v;
}
int taille;
template <class T> T & Vecteur<T>::operator [] (int i)
public : {
Vecteur(int); return v[i];
T & operator [] (int i); }
};
main()
{ Vecteur <int> t(5) ;
int i ; for (i=0 ; i<4 ; i++) t[i] = i ;
cout << "t : " ;
for (i=0 ; i<4 ; i++) cout << t[i] << " " ;
}
Cout
45

formatage
printf("%d %s %lu \n", 10, " Salut ", 15567L);

cout << 10 << " Salut " << 15567L << endl;

cadrage
1
printf(" %5d", 1);

cout.width(5); cout << 1;

précision
3 . 1 4 1
printf(" %.3f", 3.1415927);

cout.precision(3); cout << 3.1415927;


Cout/cerr/cin
46

cout : sortie standard


ostream
cerr : sortie des erreurs
cerr << " erreur " << endl;

cin : entrée istream

standard
int age;
char name[20];
cin >> age >> name;
Fichiers et Tampon
47

Fichiers : ifstream / ofstream


entrée / sortie
#include <fstream>
ifstream fileIn("nom_fichier_physique");
fileIn >> x;

Tampon (buffer):
entrée / sortie istrstream, ostrstream

#include <strstream>
char * p = new char[20];
ostrstream ch(p, 20);
ch << "age=" << 14;
Cout …
48

class Horloge
{
public:

};

ostream &operator << (ostream &out, Horloge H)


{
return (out << C.valH() << ":" << C.valM() << ":" << C.valS() );
}

void main()
{
Horloge h(23,59,57);
cout << h << endl;
}

Vous aimerez peut-être aussi