Vous êtes sur la page 1sur 142

1

Programmation Orientée Objet en C++:


Classes et Objets

Aziz DAROUICHI
Chapitre 5: Classes et Objets
22
Notion de classe
Portée des attributs
Définition des méthodes, Définition externe des méthodes
Actions et Prédicats
Déclaration et utilisation d’objets
Appel aux méthodes
Accès aux attributs et méthodes
Encapsulation et interface
Accesseurs et manipulateurs
Masquage/Shadowing
Pointeur sur l’objet courant : this
Constructeur, Liste d’initialisation, Chainage des constructeurs
Constructeur de copie, Destructeur
Création des instances dynamiques
Membres de classe
Typologie des méthodes d’une classe
Q&A
Notion de classe
33
Notion de classe
44
Notion de classe
55
Définition d’une classe
66

// N'oubliez pas le point-virgule à la fin !


Définition d’une classe
77

Exemple 1:

class Rectangle Nom de la classe


{
double hauteur;
double largeur; Attributs/champs (fields)

double surface(){
return hauteur*largeur;
}
Méthodes
double perimetre() {
return 2*(hauteur+largeur);
}
};
Définition d’une classe
88

Exemple 2:

class Point Nom de la classe
{

double x;
double y; Attributs/champs (fields)

void translater(double dx, double dy){


x += dx;
y += dy;
} Méthodes
double distance() {
return sqrt(x*x+y*y);
}
};
Déclaration des attributs
99
Déclaration des attributs
10
10

Attributs : c'est le nom que l'on donne aux variables contenues


dans des classes.
Exemple 1:
Les attributs hauteur et largeur, de type double, de la classe
Rectangle pourront être déclarés par :

class Rectangle {
double hauteur;
double largeur;
};
Déclaration des attributs
11
11

Exemple 2:
Nous supposerons ici qu’un objet de type Point sera représenté
par deux coordonnées entières.
Ils nous suffira de les déclarer ainsi :
int x ; // abscisse
int y ; // ordonnée
Portée des attributs
12
12

Les attributs sont des variables « globales » au module que constitue


la classe :
Ils sont directement accessibles dans toutes les méthodes de la
classe.
On parle de « portée de classe » (« variables globales à la classe »).
Il n’est donc pas nécessaire de les passer comme arguments des
méthodes.
Portée des attributs
13
13

Exemple:
class Point
{
double x;
double y;
void translater(double dx, double dy){
x += dx;
y += dy;
}
double distance() {
return sqrt(x*x+y*y);
}
};
Définition des méthodes
14
14

Une implémentation (ou définition) de méthode définit du code


exécutable qui peut être invoqué, en passant éventuellement un
nombre fixé de valeurs comme arguments.
Les méthodes sont :
des fonctions propres à la classe
qui ont accès aux attributs de la classe
Définition des méthodes
15
15

La syntaxe de la définition des méthodes d’une classe est la syntaxe


normale de définition des fonctions :
Syntaxe :
<typeDeRetour> nomDeLaMethode(<liste_des_paramètres> ) {
<corps de la méthode>
}
Elles sont simplement définies dans la classe elle-même.
Définition des méthodes
16
16

<typeDeRetour>
Quand la méthode renvoie une valeur indique le type de la valeur
renvoyée (type simple ou nom d'une classe)
double min(double a, double b)
vector<int> premiers(int n)
void si la méthode ne renvoie pas de valeur (procédure):
void afficher(double m[], int N)
Définition des méthodes
17
17

<liste_des_paramètres>
Vide si la méthode n’a pas de paramètres
void afficher()
Une suite de couples type identificateur séparés par des virgules
double max(double a, double b)
double moyenne(array<double, 7> tab)
Définition des méthodes
18
18

<corps de la méthode>
Suite de déclarations de variables locales et d’instructions
Si la méthode a un type de retour le corps de la méthode doit contenir
au moins une instruction return expression où expression délivre une
valeur compatible avec le type de retour déclaré.

double min(double a, double b) {


double vMin; // variable locale
if (a < b) vMin = a;
else vMin = b;
return vMin; //instruction de retour
}
Définition des méthodes
19
19

return sert aussi à sortir d’une méthode sans renvoyer de valeur


(méthode ayant void comme type retour).

void afficherPosition(double tab[], int taille, double val) {


for(int i(0); i < taille; i++){
if (tab[i] == val){
cout << "La position de " << val << " est " << i << endl;
return;
}
}
cout << val << " n’est pas présente dans le tableau" << endl;
}
Définition des méthodes
20
20

Les variables locales sont des variables déclarées à l’intérieur d’une


méthode:
elles conservent les données qui sont manipulées par la méthode.
elles ne sont accessibles que dans le bloc dans lequel elles ont été
déclarées, et leur valeur est perdue lorsque la méthode termine
son exécution.

void method1(...) { double method2(...) {


int i; Possibilité d’utiliser le même identificateur dans double x;
double y; deux méthodes distinctes pas de conflit, c’est la double y;
int tab[5]; déclaration locale qui est utilisée dans le corps
double tab[5];
... de la méthode.
...
} }
La récursivité des méthodes
21
21

C++ autorise la récursivité des appels de méthodes.


Exemple:
unsigned long facto(unsigned int n){
if (n == 0) return 1;
else return facto(n-1)*n;
}
Définition des méthodes
22
22

Exemple 1:
La méthode surface() de la classe Rectangle :
class Rectangle{
double hauteur;
double largeur;
double surface(){
return hauteur * largeur;
}
//…
};
Il ne faut pas passer les attributs comme arguments aux méthodes de la
classe.
Définition des méthodes
23
23

Exemple 2 :
Les méthodes peuvent avoir des paramètres :

class Point{
// attributs
int x;
int y;
// méthodes
void initialise(int abs, int ord){
x = abs ;
y = ord ;
}
//…
};
Définition des méthodes
24
24

Exemple 3 :
Les méthodes peuvent avoir des paramètres :

class Test{
//…
//…
double min(double a, double b) {
if (a < b) return a;
else return b;
}
};
Portée des variables
25
25

De manière générale
Variable visible à l'intérieur du bloc (ensembles des instructions entre
{ … }) où elle est définie.
class Visibilite{
int x;
void methodeA() {
float z, w; ... x : int z : float w : float
i = …;
}
void methodeB(float y) {
x : int y : float z : int
int z;
do {
...
float w; x : int y : float z : int w: float
z++;
} while (z < i);
x = z +w; w: non défini
}
};
Portée des variables
26
26

Remarque:
La redéfinition d’une variable masque la définition au niveau du bloc
englobant.
class Visibilite {
int x;
void methodeA() {
float z, w; ... x : int z : float w : float
i = …;
}
void methodeB(float y) {
int z; x : float y : float z : int
float x;
do {
...
float w; x : float y : float z : int w: float
z++;
} while (z < i);
x = z +…;
}
};
Définition externe des méthodes
27
27

Il est possible d’écrire les définitions des méthodes à l’extérieur de


la déclaration de la classe.
Meilleure lisibilité du code, modularisation
Pour relier la définition d’une méthode à la classe pour laquelle elle
est définie, il suffit d’utiliser l’opérateur :: de résolution de portée :
La déclaration de la classe contient les prototypes des méthodes
Les définitions correspondantes spécifiées à l’extérieur de la
déclaration de la classe se font sous la forme :
typeDeRetour NomDeLaClasse::nomMethode(<liste_des_paramètres>)
{
<corps de la méthode>
}
Définition externe des méthodes
28
28

Exemple 1:
La méthode surface() de la classe Rectangle définie externe :
class Rectangle {
double hauteur;
double largeur;
double surface(); // prototype
//...
};
// définition de la méthode
double Rectangle::surface(){
return hauteur * largeur;
}
Actions et Prédicats
29
29

En C++, on peut distinguer les méthodes qui modifient l’état de l’objet


(« actions ») de celles qui ne changent rien à l’objet (« prédicats »).
On peut pour cela ajouter le mot const après la liste des paramètres de
la méthode :
typeDeRetour nomDeLaMethode(liste_des_paramètres) const
Actions et Prédicats
30
30

Exemple:
class Rectangle {
double hauteur;
double largeur;
double surface() const; // prototype
//...
};
// définition de la méthode
double Rectangle::surface() const
{
return hauteur * largeur;
}
Déclaration d’objets
31
31

Déclaration d’un objet (ou une instance d’une classe) se fait de


façon similaire à la déclaration d’une variable:
NomDeLaClasse nom_instance;

Exemple 1:
Rectangle rect; //déclare une instance rect de la classe Rectangle.
Point p; //déclare une instance p de la classe Point.
Utilisation des objets
32
32

Pour accéder aux membres d'un objet on utilise une notation


pointée (.):
nom_instance.nom_du_membre

Le membre pouvant être soit un attribut soit une méthode.


Accès aux attributs
33
33

L’accès aux valeurs des attributs d’une instance de nom


nom_instance se fait comme pour accéder aux champs d’une
structure :

nom_instance.nom_attribut

Exemple :
La valeur de l’attribut hauteur d’une instance rect de la classe
Rectangle sera référencée par l’expression :
rect.hauteur
Accès aux attributs
34
34

Exemple :
#include <iostream>
using namespace std;
class Rectangle {
double hauteur;
double largeur;
};
int main(){
Rectangle rect;
rect.hauteur = 5.0;
rect.largeur = 6.0;
cout << "Hauteur : " << rect.hauteur << endl;
cout << "Largeur : " << rect.largeur << endl;
return 0;
}
Appel aux méthodes
35
35

L’appel aux méthodes définies pour une instance de nom


nom_instance se fait à l’aide d’expressions de la forme :
nom_instance.nom_methode(arg1,…)

Exemples:
rect.surface() //rect est une instance de la classe Rectangle
tableau.size()
Appel aux méthodes
36
36

Exemple:
// ...
class Rectangle {
double hauteur;
double largeur;
double surface() const{
return hauteur * largeur; }
};
int main(){
Rectangle rect;
rect.hauteur = 5.0;
rect.largeur = 6.0;
cout << " Surface du rectangle = " << rect.surface() << endl;
// ...
}
Accès aux attributs et méthodes
37
37

Chaque instance a ses propres attributs : aucun risque de confusion d’une


instance à une autre.

rect1.surface() : méthode surface de la classe Rectangle s’appliquant à rect1


rect1.surface() Rectangle::surface(&rect1)
Encapsulation
38
38
Encapsulation et interface
39
39

Tout ce qu’il n’est pas nécessaire de connaître à l’extérieur d’un objet


devrait être dans le corps de l’objet et identifié par le mot clé private :
class Rectangle
{
double surface() const;
// Tout ce qui suit est privé (inaccessible depuis l'extérieur)
private:
double hauteur;
double largeur;
};
Attribut d’instance privée = inaccessible depuis l’extérieur de la classe.
C’est également valable pour les méthodes.
Si aucun droit d’accès n’est précisé, par défaut, tous les éléments d'une
classe sont private.
Encapsulation et interface
40
40

L’interface, qui est accessible de l’extérieur, se déclare avec le mot-clé public:


class Rectangle
{
// Tout ce qui suit est public (accessible depuis l'extérieur)
public:
double surface() const;
// Tout ce qui suit est privé (inaccessible depuis l'extérieur)
private:
// ...
};
Encapsulation et interface
41
41

Best practice: dans la plupart des cas :


Privé :
Tous les attributs (encapsulation)
La plupart des méthodes
Public :
Quelques méthodes bien choisies (interface)

Règle d'or en POO:


Encapsulation : tous les attributs d'une classe doivent toujours être
privés.
Encapsulation et interface
42
42

En règle générale, il est recommandé de masquer les attributs


(champs) en les déclarant private et -seulement si nécessaire- de
définir des méthodes publiques pour accéder à ces attributs.
Ces méthodes sont appelées accesseurs/mutateurs ou
getters/setters, généralement nommées getxxx() et setxxx().
Il est utile de proposer des méthodes pour accéder aux attributs:
Lecture = getter
Écriture = setter
Encapsulation et interface
43
43

Getters/Setters
Donc, si le programmeur le juge utile, il inclut les méthodes publiques nécessaires:
Accesseurs (« méthodes get » ou « getters ») :
Consultation (i.e. « prédicat »)
Retour de la valeur d’une variable d’instance précise

Exemple 1:
double getHauteur() const { return hauteur; }
double getLargeur() const { return largeur; }
Accesseurs et manipulateurs
44
44

Getters/Setters
Manipulateurs (« mutateurs » ou « méthodes set » ou « setters ») :
Modification (i.e. « action »)
Affectation de l’argument à une variable d’instance précise

Exemple:
void setHauteur(double h) { hauteur = h; }
void setLargeur(double l) { largeur = l; }
Accesseurs et manipulateurs
45
45

Getters/Setters
Exemple:
#include <iostream>
using namespace std;
class Rectangle{
public:
double surface() const{ return hauteur * largeur; }
double getHauteur() const{ return hauteur; }
double getLargeur() const{ return largeur; }
void setHauteur(double h){ hauteur = h; }
void setLargeur(double l){ largeur = l; }
private:
double hauteur;
double largeur;
};
Accesseurs et manipulateurs
46
46

Exemple: (suite)
int main(){
Rectangle rect;
rect.setHauteur(3.0);
rect.setLargeur(4.0);
cout << "Hauteur : " << rect.getHauteur() << endl;
cout << "Largeur : " << rect.getLargeur() << endl;
return 0;
}

Output:
Hauteur: 3
Largeur: 4
Masquage/Shadowing
47
47

masquage = un identificateur « cache » un autre identificateur


int main(){
int i(12);
for (int i(0); i < MAX; ++i) {
cout << i << endl;
}
cout << i << endl;
return 0;
}
Masquage/Shadowing
48
48

Situation typique en POO :


Un paramètre cache un attribut:
//…
class Rectangle{
public:
void setHauteur(double hauteur) //paramètre hauteur
{
hauteur = hauteur; //ambiguïté
}
//…
private:
double hauteur; //attribut hauteur
double largeur;
};
Masquage et pointeur this
49
49

Si, dans une méthode, un attribut est masqué alors la valeur de


l’attribut peut quand même être référencée à l’aide du mot réservé
this.
this est un pointeur sur l’instance courante
this « adresse de l’objet courant »
Syntaxe pour spécifier un attribut en cas d’ambiguïté :
this -> nom_attribut

Exemple :
void setHauteur(double hauteur) {
this->hauteur = hauteur;
}
L’utilisation de this est obligatoire dans les situations de masquage.
Pointeur sur l’objet courant : this
50
50

Exemple 1: this et variables d’instance


class Point{
double x; Implicitement quand dans le corps
double y; d’une méthode un attribut est utilisé,
void translater(int dx, int dy) { c’est un attribut de l’objet courant.
x += dx;
y += dy;
}
double distance() {
return sqrt(x*x+y*y);
}
void placerAuPoint(double x, double y1){ this essentiellement utilisé pour
lever les ambiguïtés.
this->x = x;
y = y1;
}
};
Pointeur sur l’objet courant : this
51
51

Exemple 2: this et variables d’instance

int main(){ class Point{


Point a(1, 3) ; private:
Point b(2, 5) ; int x, y;
Point c(1, 3) ;
public Point(int abs, int ord){
cout << "a et b : " << a.coincide(b) <<endl; x = abs ;
cout << "a et c : " << a.coincide(c) <<endl; y = ord ;
}
}
public:
bool coincide(Point pt){
return ((pt.x == x) && (pt.y == y)) ;
}
};
Pointeur sur l’objet courant : this
52
52

Exemple 2: this et variables d’instance


int main(){ class Point{
private:
Point a(1, 3) ; int x, y;
Point b(2, 5) ;
Point c(1, 3) ; public Point(int abs, int ord){
x = abs ;
cout << "a et b : " << a.coincide(b) <<endl; y = ord ;
cout << "a et c : " << a.coincide(c) <<endl; }
public:
} bool coincide(Point pt){
return ((pt.x == this->x) && (pt.y == this->y)) ;
}
};
Classes et Objets
53
53

Exemple 1:
#include <iostream>
using namespace std;
// définition de la classe
class Rectangle{
// définition des méthodes
public:
double surface() const { return hauteur * largeur; }
double getHauteur() const { return hauteur; } //Accesseur correspondant à hauteur.
double getLargeur() const { return largeur; } //Accesseur correspondant à largeur.
void setHauteur(double h) { hauteur = h; } //Manipulateur pour hauteur
void setLargeur(double l) { largeur = l; } //Manipulateur pour hauteur
// déclaration des attributs
private:
double hauteur;
double largeur;
};
Classes et Objets
54
54

Exemple 1 : (suite)
//utilisation de la classe
int main(){
Rectangle rect;
double h, l;
cout << "Saisir la hauteur du rectangle ? " << endl;
cin >> h;
rect.setHauteur(h);
cout << "Saisir la largeur du rectangle ? " << endl;
cin >> l;
rect.setLargeur(l);
cout << "Surface du rectangle = " << rect.surface() << endl;
return 0;
}
Classes et Objets
55
55

Exemple 1:
Output:
Saisir la hauteur du rectangle ?
6
Saisir la largeur du rectangle ?
7
Surface du rectangle = 42
Classes et Objets
56
56

Définitions externes à la classe


Exemple 2:
//Prototype de la classe
class Rectangle{
public:
// prototypes des méthodes
double surface() const;
// accesseurs
double getHauteur() const;
double getLargeur() const;
// manipulateurs
void setHauteur(double);
void setLargeur(double);
private:
// déclaration des attributs
double hauteur;
double largeur; };
Classes et Objets
57
57

Définitions externes à la classe


Exemple 2: (suite)
//Définition de la classe
double Rectangle::surface() const {
return hauteur*largeur;
}
double Rectangle::getHauteur() const{
return hauteur;
}
double Rectangle::getLargeur() const{
return largeur;
}
void Rectangle::setHauteur(double h){
hauteur = h;
}
void Rectangle::setLargeur(double l){
largeur = l;
}
Best practice (1/2)
58
58

Définitions externes à la classe


//Prototype de la classe:
class Rectangle{
public:
// Prototypes des méthodes:
double surface() const;
// accesseurs
double hauteur() const;
double largeur() const;
// manipulateurs
void hauteur(double);
void largeur(double);
private:
// Déclaration des attributs:
double hauteur_;
double largeur_;
};
Best practice (2/2)
59
59

Définitions externes à la classe


//Définition de la classe:
double Rectangle::surface() const{
return hauteur_ * largeur_;}
// définition des accesseurs
double Rectangle::hauteur() const{
return hauteur_;}
double Rectangle::largeur() const{
return largeur_;}
// définition des manipulateurs
void Rectangle::hauteur(double h){
hauteur_ = h;
}
void Rectangle::largeur(double l){
largeur_ = h;
}
Constructeurs
60
60

Initialisation des attributs


Première solution : affecter individuellement une valeur à chaque attribut.
Exemple:
class Rectangle {
public:
double surface() const;
double getHauteur() const;
double getLargeur() const;
void setHauteur(double h);
void setLargeur(double l);
private:
double hauteur;
double largeur;
};
Constructeurs
61
61

Initialisation des attributs


Première solution : affecter individuellement une valeur à chaque attribut.
Exemple: (suite)
Rectangle rect;
double h, l;
cout << "Quelle hauteur ? ";
cin >> h;
rect.setHauteur(h);
cout << "Quelle largeur ? ";
cin >> l;
rect.setLargeur(l);
Constructeurs
62
62

Initialisation des attributs


Première solution : affecter individuellement une valeur à chaque attribut.
Ceci est une mauvaise solution dans le cas général :
elle implique que tous les attributs fassent partie de l’interface (public) ou soient
assortis d’un manipulateur.
casse l’encapsulation
oblige le programmeur-utilisateur de la classe à initialiser explicitement tous
les attributs.
risque d’oubli
Constructeurs
63
63

Initialisation des attributs


Deuxième solution : définir une méthode dédiée à l’initialisation des
attributs:
class Rectangle{
public:
void init(double h, double L){
hauteur = h;
largeur = L;
}
...
private:
double hauteur;
double largeur;
};
Constructeurs
64
64

Pour faire ces initialisations, il existe en C++ des méthodes


particulières appelées constructeurs.
Un constructeur est une méthode :
invoquée automatiquement lors de la déclaration d’un objet;
chargée d’effectuer toutes les opérations requises en « début de vie »
de l’objet (dont l’initialisation des attributs).
Constructeurs
65
65

Syntaxe de base
NomDeLaClasse(liste_des_paramètres)
{
/*
initialisation des attributs en utilisant liste_des_paramètres
*/
}
Exemple:
Rectangle(double h, double L){
hauteur = h;
largeur = L;
}
Constructeurs
66
66

Un constructeur est une sorte de méthode qui sera invoquée lors de


la création d’un objet de cette classe.
Un constructeur doit porter le nom de la classe et ne doit pas
comporter de type de retour (pas même void) dans sa déclaration.
Un constructeur sera invoqué automatiquement à chaque fois
qu’une instance est créée.
Le but de constructeur est d’initialiser l’objet (notamment la valeur
de ses champs).
Constructeurs
67
67

Comme les autres méthodes :


les constructeurs peuvent être surchargés
on peut donner des valeurs par défaut à leurs paramètres
Une classe peut donc avoir plusieurs constructeurs, pour peu que
leur liste de paramètres soit différente.
Constructeurs
68
68

Initialisation par constructeur


La création d'une instance (objet) est simple et répond à la syntaxe
suivante :
Syntaxe :
NomDeLaClasse nom_instance(arg1, ..., argN);
où arg1, ..., argN sont les valeurs des arguments du constructeur.

Exemple :
Rectangle r(18.0, 5.3); // invocation du constructeur à 2 paramètres
Instanciation des objets
69
69

Exemple (1/2):
class Rectangle {
public:
Rectangle(double h, double L){
m_hauteur = h;
m_largeur = L;
}
double surface() const{
return m_hauteur * m_largeur; }
// accesseurs/modificateurs si nécessaire
// ...
private:
double m_hauteur;
double m_largeur;
};
Instanciation des objets
70
70

Exemple (2/2):
// ...
int main(){
double h, l;
cout << "Quelle hauteur ? ";
cin >> h;
cout << "Quelle largeur ? ";
cin >> l;
Rectangle rect1(h,l); // instanciation de l’objet rect de type Rectangle
cout << "Surface = " << rect1.surface();
Rectangle rect2(4.0, 5.0);
cout << "Surface = " << rect2.surface();
}
Appel aux constructeurs des attributs
71
71

Un constructeur devrait normalement contenir une section d’appel


aux constructeurs des attributs....
...ainsi que l’initialisation des attributs de type de base.
C’est ce qu’on appelle la « liste d’initialisation » du constructeur.
Syntaxe générale:
NomDeLaClasse(liste_des_paramètres)
// liste d’initialisation
: attribut1(...), // appel au constructeur de attribut1
...
, attributN(...) // appel au constructeur de attributN
{
// corps du constructeur contenant d’autres opérations
}
Liste d’initialisation
72
72

Cette section introduite par « : » est optionnelle mais recommandée.


Par ailleurs :
les attributs non-initialisés dans cette section:
• prennent une valeur par défaut si ce sont des objets ;
• restent indéfinis s’ils sont de type de base ;
les attributs initialisés dans cette section peuvent être changés dans
le corps du constructeur.
Liste d’initialisation
73
73

Utilisation mixte de liste d'initialisation et affectations dans le corps


du constructeur.
Exemple:
Rectangle(double h, double L)
: m_hauteur(h) //initialisation
{
// largeur a une valeur indéfinie jusqu'ici
m_largeur = 2.0 * L + h; // par exemple...
// la valeur de largeur est définie à partir d'ici
}
Liste d’initialisation
74
74

Deux petites choses à retenir impérativement concernant les listes


d'initialisation :
Les attributs doivent apparaître dans leur ordre de déclaration.
Les initialisations réalisées dans la liste d'initialisation sont effectuées
avant les instructions situées dans le code du corps du constructeur.
Construction des attributs
75
75

Que se passe-t-il si les attributs sont eux-mêmes des objets ?


class RectangleColor{
private:
Rectangle m_rectangle;
Couleur m_couleur;
//...
};
Mauvaise solution :
RectangleColor(double h, double L, Couleur c){
m_rectangle = Rectangle(h, L);
m_couleur = c;
}
Il faut initialiser directement les attributs en faisant appel à leurs
propres constructeurs !
Appel aux constructeurs des attributs
76
76

Exemple:
class Rectangle{
Rectangle(double h, double L);
// ...
};
class RectangleColor {
RectangleColor(double h, double L, Couleur c)
: rectangle(h, L), couleur(c)
{}
private:
Rectangle m_rectangle;
Couleur m_couleur;
};
Constructeur par défaut
77
77

Le constructeur par défaut est un constructeur qui n’a pas de


paramètre ou dont tous les paramètres ont des valeurs par défaut.
Exemple 1:
// Constructeur par défaut avec liste d’initialisation
Rectangle() : m_hauteur(2.0), m_largeur(3.0)
{}
// Constructeur par défaut sans liste d’initialisation
Rectangle() {
m_hauteur = 2.0;
m_largeur = 3.0;
}

int main(){
Rectangle rect1; // sans parenthèses
}
Constructeur par défaut
78
78

Autre façon de faire : regrouper 2 constructeurs en utilisant les


valeurs par défaut des paramètres :
Exemple 2:
// DEUX constructeurs dont le constructeur par défaut
Rectangle(double c = 1.0) : m_hauteur(c), m_largeur(2.0*c)
{}
// 3ème constructeur
Rectangle(double h, double L) : m_hauteur(h), m_largeur(L)
{}

int main(){
Rectangle rect1, rect2(5.5), rect3(2.5,3.5);

}
Constructeur par défaut
79
79

Exemple 3:
// TROIS constructeurs dont le constructeur par défaut
Rectangle(double h = 1.0, double L = 1.0)
: m_hauteur(h), m_largeur(L)
{}
Constructeur par défaut par défaut
80
80

Si aucun constructeur n’est spécifié, le compilateur génère


automatiquement une version minimale du constructeur par défaut
qui :
appelle le constructeur par défaut des attributs objets.
laisse non initialisés les attributs de type de base.
Dès qu’au moins un constructeur a été spécifié, ce constructeur par
défaut par défaut n’est plus fourni.
Si donc on spécifie un constructeur sans spécifier de constructeur par
défaut, on ne peut plus construire d’objet de cette classe sans les
initialiser puisqu’il n’y a plus de constructeur par défaut.
Depuis C++11, mais on peut le rajouter si on veut.
Constructeurs par défaut
81
81

Exemple (1/4):
Constructeurs par défaut
82
82

Exemple (2/4):
Constructeurs par défaut
83
83

Exemple (3/4):
Constructeurs par défaut
84
84

Exemple (4/4):
Réactivation du constructeur par défaut par défaut
85
85

Dès qu’au moins un constructeur a été spécifié, ce constructeur par


défaut par défaut n’est plus fourni.
C’est très bien si c’est vraiment ce que l’on veut (c’est-à-dire forcer
les utilisateurs de la classe à utiliser nos constructeurs).
Mais si l’on veut quand même avoir le constructeur par défaut par
défaut, depuis C++11 on peut le réactiver en écrivant dans la
définition de la classe :
NomDeLaClasse() = default;
Réactivation du constructeur par défaut par défaut
86
86

Exemple:
class Rectangle {
public:
Rectangle() = default; //réactivation du constructeur par défaut par défaut
// 2ème constructeur
Rectangle(double h, double L) : h_hauteur(h), m_largeur(L) {}
// Méthode d’instance
double surface() const { return m_hauteur * m_largeur; }
// Variables d’instance
private:
double m_hauteur;
double m_largeur;
};
Méthodes default et delete depuis C++11
87
87

Ce que l’on a fait précédemment (= default) pour le constructeur


par défaut se généralise :
à toute méthode (pour laquelle cela est pertinent)
à la suppression de méthode, via la syntaxe « = delete »
Exemple:
class DemoClasse{
public:
double f(double x) { ... }
double f(int) = delete;
};
Chaînage des constructeurs
88
88

C++11 autorise les constructeurs d’une classe à appeler n’importe


quel autre constructeur de cette même classe.
Dans les classes définissant plusieurs constructeurs, un constructeur
peut invoquer un autre constructeur de cette classe.
Chaînage des constructeurs
89
89

Exemple:
class Rectangle{
public:
Rectangle(double h, double L) : m_hauteur(h), m_largeur(L)
{}
Rectangle() : Rectangle(0.0, 0.0)
{}
double surface() const {
return m_hauteur * m_largeur;
}
private:
double m_hauteur;
double m_largeur;
};
Initialisation par défaut des attributs
90
90

C++11 permet de donner directement une valeur par défaut aux


attributs.
Si le constructeur appelé ne modifie pas la valeur de cet attribut,
ce dernier aura alors la valeur indiquée.
Exemple:
class Rectangle {
// ...
private:
double hauteur = 0.0;
double largeur = 0.0;
// ...
};
Constructeur de copie
91
91

C++ offre un moyen de créer la copie d’une instance en utilisant le


constructeur de copie lors de l’initialisation:
Rectangle r1(11.3, 12.5);
Rectangle r2(r1); // constructeur de copie: création de l'objet r2
// et son initialisation avec les données de r1.
Ou
Rectangle r2 = r1; // constructeur de copie: création de l'objet r2
// et son initialisation avec les données de r1.
Ou
Rectangle* r2 = new Rectangle(r1); // constructeur de copie: création de l'objet
// dynamique r2 et son initialisation avec les données de r1.
r1 et r2 sont deux instances distinctes mais ayant des mêmes valeurs
pour leurs attributs.
Constructeur de copie
92
92

Le constructeur de copie est appelé dans trois situations:


1. Lors de l’initialisation d’un objet:
Création d'un nouvel objet initialisé comme étant une copie d'un
objet existant.
2. Lors d’un passage de paramètres par valeur :
double maFonction(Rectangle r); //prototype de maFonction
...
x = maFonction(r1); //appel de maFonction
Copie de r1 dans r donc invocation du constructeur de copie.
3. Lors de retour de fonction par valeur
Rectangle g() {
Rectangle rect;

return rect; // retour par valeur de rect
}
Constructeur de copie
93
93

Le constructeur de copie permet d’initialiser une instance en


copiant les attributs d’une autre instance du même type.
Deux syntaxes possibles :

NomDeLaClasse(NomDeLaClasse const& autre) { ... }

ou

NomDeLaClasse(NomDeLaClasse& autre) { ... }

Exemple:
Rectangle(Rectangle const& autre)
: m_hauteur(autre.m_hauteur), m_largeur(autre.m_largeur)
{}
Constructeur de copie
94
94

Le but de ce type de constructeur est d'initialiser un objet lors de


son instanciation à partir d'un autre objet.
Toute classe dispose d'un constructeur de copie par défaut
généré automatiquement par le compilateur s’il n’est pas
explicitement défini (constructeur de copie par défaut).
Le seul but est de recopier les attributs de l'objet un à un dans
attributs de l'objet à instancier (si l’attribut est un objet le
constructeur de cet objet est invoqué).
Donc, le rôle du constructeur de copie est de copier la valeur de
tous les attributs du premier objet dans le second.
Constructeur de copie
95
95

Ce constructeur se contente d'effectuer une copie de chacun


des membres. On retrouve là une situation analogue à celle qui est
mise en place (par défaut) lors d'une affectation entre objets de même
type. Elle posera donc les mêmes problèmes pour les objets contenant
des pointeurs sur des emplacements dynamiques.
On aura simplement affaire à une "copie superficielle", c'est-à-dire
que seules les valeurs des pointeurs seront recopiées, les
emplacements pointés ne le seront pas.

copie de surface ou copie superficielle


Constructeur de copie
96
96

Cette copie de surface suffit dans la plupart des cas.


Cependant, il est parfois nécessaire de redéfinir le constructeur
de copie, en particulier lorsque certains attributs sont des
pointeurs.
Il faut alors allouer une nouvelle zone mémoire, on parle alors de
copie profonde (allocation puis recopie).
Constructeur de copie
97
97

La règle de trois :
Si vous touchez à l’un des trois parmi:
constructeur de copie,
destructeur,
opérateur d’affectation (operator=),
alors pensez aux deux autres.
Constructeur de copie
98
98

Remarque:
Il faut faire attention entre copie et affectation.
Rectangle rect1, rect2; // création de deux objets rect1 et rect2.
rect1 = rect2; // pas de copie mais uniquement l'affectation
// car l’objet est déjà créé.
Suppression du constructeur de copie
99
99

Depuis C++11, si l’on souhaite interdire la copie, il suffit de


supprimer le constructeur de copie par défaut avec la commande
« = delete ».

Exemple:
class Incopiable {
/*... */
Incopiable(Incopiable const&) = delete;
};
Destructeur
100
100

Si l’initialisation des attributs d’une instance implique la mobilisation


de ressources : fichiers, périphériques, portions de mémoire
(pointeurs), etc.
Il est alors important de libérer ces ressources après usage.
Comme pour l’initialisation, l’invocation explicite de méthodes de
libération n’est pas satisfaisante (fastidieuse, source d’erreur,
affaiblissement de l’encapsulation).
Destructeur
101
101

C++ offre une méthode appelée destructeur invoquée


automatiquement en fin de vie de l’instance.
Il s'exécute à la fin du programme ou d'un bloc où des objets locaux
ont été définis.
Un destructeur a pour rôle de libérer la mémoire.
Il est appelé automatiquement lorsque l’objet n’est plus utilisé,
fermeture d’accolade, …
Destructeur
102
102

La syntaxe de déclaration d’un destructeur pour une classe


NomDeLaClasse est :

˜NomDeLaClasse()
{
// opérations (de libération)
}
Le destructeur d’une classe est une méthode sans paramètre donc
pas de surcharge possible
Son nom est celui de la classe, précédé du signe ˜ (tilda).
Si le destructeur n’est pas défini explicitement par le programmeur,
le compilateur en génère automatiquement une version minimale.
Constructeur et destructeur
103
103

Exemple 1:
Supposons que l’on souhaite compter le nombre d’instances d’une
classe actives à un moment donné dans un programme.
int main(){
// compteur = 0
Rectangle r1;
// compteur = 1 Appel du constructeur
{
Rectangle r2;
// compteur = 2
// ... Appel du destructeur pour r2 et r1
}
// compteur = 1
return 0;
} // compteur = 0
Constructeur et destructeur
104
104

Exemple 1:
Utilisons comme compteur une variable globale de type entier :
Le constructeur incrémente le compteur

long compteur(0);
class Rectangle{
//...
Rectangle(): m_hauteur(0.0), m_largeur(0.0) //constructeur
{
++compteur;
}
// ...
Constructeur et destructeur
105
105

Exemple 1:
On est obligé ici de définir explicitement le destructeur
int main(){
// compteur = 0
Rectangle r1;
// compteur = 1
{
Rectangle r2;
// compteur = 2
// ...
}
// compteur = 2
return 0;
} // compteur = 2
Constructeur et destructeur
106
106

Exemple 1:
Le constructeur incrémente le compteur
Le destructeur le décrémente
long compteur(0);
class Rectangle {
//...
Rectangle(): m_hauteur(0.0), m_largeur(0.0) {//constructeur
++compteur;
}
~Rectangle() {// destructeur
--compteur;
} // ...
Constructeur et destructeur
107
107

Exemple 1:
int main(){
// compteur = 0
Rectangle r1;
// compteur = 1
{
Rectangle r2;
// compteur = 2
// ...
}
// compteur = 1
return 0;
} // compteur = 0
Constructeur et destructeur
108
108

Exemple 1:
Que se passe-il si l’on souhaite utiliser la copie d’objet ?
int main(){
// compteur = 0
Appel du constructeur
Rectangle r1;
// compteur = 1
{
Rectangle r2;
// compteur = 2
Rectangle r3(r2); Appel du constructeur de copie
// compteur = ??
}
// compteur = Appel du destructeur pour r2, r3 et r1
return 0;
} // compteur =
Constructeur et destructeur
109
109

Exemple 1:
La copie d’un rectangle échappe au compteur d’instances car il n’y a
pas de définition explicite du constructeur de copie.
Il faudrait donc encore ajouter au code précédent, la définition
explicite du constructeur de copie :
Rectangle(Rectangle const& r)
: m_hauteur(r.m_hauteur), m_largeur(r.m_largeur)
{ ++compteur; }
Règle générale :
Si on doit toucher à l’un des trois parmi destructeur, constructeur
de copie et opérateur d’affectation (=), alors on doit certainement
également toucher aux deux autres (ou alors au moins se poser la
question !).
Constructeur et destructeur
110
110

Exemple 2:
class Chaine{ // Implémente une chaîne de caractères.
private:
char* s; // Le pointeur sur la chaîne de caractères.
public:
Chaine(); // Le constructeur par défaut.
Chaine(int); // Le constructeur. Il n'a pas de type.
~Chaine(); // Le destructeur.
};
Chaine::Chaine(){
s = nullptr; } // La chaîne est initialisée avec le pointeur nullptr.
Chaine::Chaine(int Taille){
s = new char[Taille+1]; // Alloue de la mémoire pour la chaîne.
s[0]='\0'; // Initialise la chaîne à "".
}
Chaine::~Chaine(){
if (s!=nullptr) delete[] s; // Restitue la mémoire utilisée si nécessaire.
}
Création des instances dynamiques
111
111

Dans le cas d'une instance dynamique, il faut commencer par déclarer


un pointeur, puis appeler l’opérateur new suivi du nom du constructeur
avec ses paramètres.

Syntaxe:
NomDeLaClasse *nom_instance;
nom_instance = new NomDeLaClasse(arg1,..., argN);

Ou directement
NomDeLaClasse *nom_instance = new NomDeLaClasse(arg1,...,argN);

où arg1, ..., argN sont les valeurs des arguments du constructeur.


Création des instances dynamiques
112
112

Exemple:
Rectangle *r1(nullptr), *r2(nullptr); // Déclaration d'un pointeur sur un objet de type Rectangle
r1 = new Rectangle(4.0, 5.0);// Instanciation de l'objet dynamique avec arguments explicites
r2 = new Rectangle; // Instanciation de l'objet dynamique avec arguments par défaut

delete r1; // On n'oublie pas de rendre la mémoire !


delete r2; // Idem
Création des instances dynamiques
113
113

Appel de méthodes d’instance


La syntaxe d'appel d'un membre d’instance par un objet dynamique est:
nom_instance -> nom_membre

Il faut juste changer le "." par une flèche "->".

Exemple:
Rectangle *rect1 = new Rectangle(2.5, 3.5);
Rectangle *rect2 = new Rectangle;
cout << "Hauteur = "<< rect1-> m_hauteur << endl;
cout << "Largeur = "<< rect1-> m_largeur << endl;
cout << "Surface du rectangle 1 = "<< rect1-> surface() << endl;
cout << "Surface du rectangle 2 = "<< (*rect2).surface() << endl;
Envoi de messages
114
114

Pour "demander" à un objet d'effectuer une opération (exécuter


l'une de ses méthodes) il faut lui envoyer un message.
Un message est composé de trois parties:
un identificateur permettant de désigner l'objet à qui le
message est envoyé.
le nom de la méthode à exécuter (cette méthode doit bien
entendu être définie dans la classe de l'objet).
les éventuels paramètres de la méthode.
Envoi de messages
115
115

Envoi de message similaire à un appel de fonction


les instructions définies dans la méthode sont exécutées (elles
s’appliquent sur les attributs de l’objet récepteur du message).
puis le contrôle est retourné au programme appelant.
Les objets communiquent entre eux par échange de messages.
Envoi de messages
116
116

Syntaxe :
nom_instance.nomDeMethode(<liste_paramètres_effectifs>)
class Point{
private: Point p1, p2;
double x{0.0}; p1.translater(10.0,10.0);
double y{0.0}; cout << “Distance de p2 à l’origine : “<< endl;
public: cout << p2.distance();
void translater(double dx, double dy){
x += dx;
y += dy;
}
double distance(){
return sqrt(x*x+y*y);
}
}; // Point

Si la méthode ne possède pas de paramètres, la liste est vide, mais comme en langage C les
parenthèses demeurent.
Mise en œuvre d’un programme comportant
plusieurs fichiers
117
117

Un fichier entête Classe.h qui définit la classe (appelé interface) va contenir


le prototype de la classe, c.à.d., la déclaration de la classe avec les attributs et
les prototypes des méthodes.
Un fichier source Classe.cpp contient la définition de la classe, c’est là
qu'on va implémenter les méthodes membres.
L’implémentation des méthodes peut se faire dans l’entête.
Un fichier source (.cpp) contient la fonction main().
Exemple:
Point.h: contient le prototype de la classe (interface);
Point.cpp: contient la définition de la classe, c.à.d., l'implémentation des
méthodes membres de la classe.
TestPoint.cpp: contient la fonction main().
Mise en œuvre d’un programme comportant
plusieurs fichiers
118
118

Exemple (1/2):
Point.h Point.cpp
#ifndef POINT_H_INCLUDED #include "Point.h“
#define POINT_H_INCLUDED #include<iostream>
class Point #include<cmath>
{ using namespace std;
public:
void translater(double dx, double dy); void Point::translater(double dx, double dy){
double distance(); x += dx;
void afficher(); y += dy;
}
private: double Point::distance() {
double x; return sqrt(x*x+y*y);
double y; }
}; void Point::afficher(){
cout << "(" << x << ", "<< y << ") " << endl;
#endif // POINT_H_INCLUDED }
Mise en œuvre d’un programme comportant
plusieurs fichiers
119
119

Exemple (2/2):
TestPoint.cpp

#include "Point.h“
#include<iostream>
using namespace std;

int main(){
Point p1, p2;
p1.translater(10.0,10.0);
p1.afficher();
cout << “distance de p2 à l’origine“ << p1.distance() << endl;
}
Mise en œuvre d’un programme comportant
plusieurs classes
120
120

Plusieurs classes dans un même fichier source


TestPoint.cpp
#include<iostream>
#include<cmath>
using namespace std;
class Point {
public:
void translater(double dx, double dy); double distance();
void afficher();
private:
double x;
double y;};
void Point::translater(double dx, double dy){ x += dx; y += dy;}
double Point::distance() { return sqrt(x*x+y*y);}
void Point::afficher(){ cout << "(" << x << ", "<< y << ") " << endl; }
int main(){
Point p1, p2;
p1.translater(10.0,10.0); p1.afficher();
cout << “distance de p2 à l’origine“ << p1.distance() << endl; }
Surcharge des méthodes
121
121

Surcharge (overloading) pas limitée aux constructeurs, elle est


possible pour n'importe quelle méthode.
Possible de définir des méthodes possédant le même nom mais
dont les arguments diffèrent.
Lorsque qu'une méthode surchargée est invoquée le compilateur
sélectionne automatiquement la méthode dont le nombre et le type
des arguments correspondent au nombre et au type des paramètres
passés dans l'appel de la méthode.
Des méthodes surchargées peuvent avoir des types de retour
identiques mais à condition qu'elles aient des arguments différents.
Surcharge des méthodes
122
122

Exemple
class Point{
private: Point p1(10,10);
double x; Point p2(1.5,1.4);
double y;
public: cout<<“Distance =”<<p1.distance();
// constructeur
cout<<“Distance entre p1 et p2 =”;
Point(double x, double y): x(x), y(y){}
cout<<p1.distance(p2);
// destructeur
~Point(){cout<< “Destructeur“ <<endl;}
// méthodes
double distance() { return sqrt(x*x+y*y); }
...
}
double distance(Point p){
return sqrt((x - p.x)*(x - p.x) + (y - p.y)*(y - p.y));
}

};
Variables et méthodes d’instance
123
123
Variables et méthodes d’instance
124
124

Variables d’instance ou attributs d’instance


Déclarées par accès: type nomDeVariableInstance
Référencées par Objet.nomDeVariableInstance
Une copie pour chaque instance (objet)
Chaque objet possède ses propres membres donnée.

Méthodes d’instance
Déclarées par accès: TypeRetour nomDeLaMethodeInstance(…)
Référencées par objet.nomDeLaMethodeInstance(…)
Membres de classe: static
125
125
Membres de classe: static
126
126
Variables de classe: static
127
127

Il peut être utile de définir pour une classe des attributs


indépendamment des instances : nombre de Points crées
Les variables statiques sont enregistrées au niveau de la classe et elles
peuvent être accédées et manipulées par toutes les instances (objets)
de cette classe.
Utilisation des variables de classe comparables aux “variables
globales“ partagées par toutes les instances.
Variables dont il n’existe qu’un seul exemplaire associé à sa classe de
définition.
Variables existent indépendamment du nombre d’instances de la
classe qui ont été créés.
Variables utilisables même si aucune instance de la classe n’existe.
Variables de classe
128
128

Déclarées par accès: static type nomDeLaVariableClasse


Référencées par NomDeLaClasse::nomDeLaVariableClasse
Une seule copie pour toutes les instances
Les variables statiques appartiennent à la classe et non aux objets
créés à partir de la classe.
Un attribut static, bien qu'il soit accessible de l'extérieur, peut très
bien être déclaré private ou protected

N. B:
Variables de classe = Variables statiques = Attributs de classe = Attributs statiques.
Variables de classe
129
129

Initialisation d’une variable statique


Il faut initialiser l'attribut statique dans l'espace global, c'est-à-dire en
dehors de toute classe ou fonction, en dehors du main() notamment.
Un attribut déclaré comme statique se comporte comme une variable
globale, c'est-à-dire une variable accessible partout dans le code.
Un attribut de classe doit être initialisé explicitement à l’extérieur de
la classe.
Les attributs de classe sont très pratiques lorsque différents objets
d’une classe doivent accéder à une même information.
Ils permettent notamment d’éviter que cette information soit
dupliquée au niveau de chaque objet.
Exemple:
// Initialiser l'attribut en dehors de toute fonction ou classe (espace global)
int MaClasse::attributStatique = 10;
Variables de classe
130
130

Exemple:
class Point {
private:
double x;
double y;
static int nbPointCrees;
public:
Point(double x, double y){
this->x = x;
this->y=y;
}

};
//initialisation de l’attribut statique
int Point::nbPointCrees=0;
Méthodes de classe
131
131
Méthodes de classe
132
132

Usage
Ce sont des méthodes qui ne s'intéressent pas à un objet particulier
Utiles pour des calculs intermédiaires internes à une classe
Utiles également pour retourner la valeur d'une variable de classe
Elles sont déclarées comme les méthodes d'instances, mais avec le mot-
clé static:
public: static double vitesseMaxToleree();
Elles sont définies hors de la classe sans static:
double Voiture::vitesseMaxToleree() {
return vitesseMaxAutorisee*1.10; }
Pour y accéder, il faut utiliser non pas un identificateur d'objet mais le
nom de la classe et de l’opérateur de résolution de portée « :: » (idem
pour les variables de classe):
Voiture::vitesseMaxToleree(); // Voiture une classe
Méthodes de classe
133
133

Exemple (1/2):
#include<iostream>
using namespace std;
class Point {
private:
double x;
double y;
static int compteur;
public:
Point(double x, double y);
~Point();
static int nombreInstances(); //Renvoie le nombre d'objets créés
};
//initialisation de l’attribut statique
int Point::compteur=0;
//Quand on crée un point, on ajoute 1 au compteur
Point:: Point(double x, double y):x(x), y(y){++compteur;}
//Et on enlève 1 au compteur lors de la destruction
Point:: ~Point(){--compteur;}
int Point::nombreInstances(){
return compteur; //On renvoie simplement la valeur du compteur
}
Méthodes de classe
134
134

Exemple (2/2):
int main()
{
//On crée deux points
Point p1(1.0, 2.0);
Point p2(3.0, 4.0);
//Et on consulte notre compteur
cout << "Il y a actuellement " << Point::nombreInstances() << " points construits." << endl;
return 0;
}

Output:
Il y a actuellement 2 points construits.
Propriétés des fonctions membres
135
135

Les fonctions membres (y compris les constructeurs) peuvent:


être surdéfinies,
avoir des arguments par défaut,
être public ou private,
être inline.
Les fonctions membres ont accès à tous les membres de tous les
objets de la classe.
Propriétés des fonctions membres
136

Surdéfinition des fonctions membre


C++ autorise la surdéfinition (ou surcharge) des fonctions
membres y compris les constructeurs (mais pas aux destructeurs);
Exemple (1/2):
class Point{
private :
double x, y;
public :
Point(); // constructeur 1 sans arguments
Point(double); // constructeur 2 avec un argument
Point(double, double); // constructeur 3 avec deux arguments
void afficher(); // fonction afficher() sans arguments
void afficher(char*); // fonction affiche() avec un argument
};
Propriétés des fonctions membres
137

Surdéfinition des fonctions membre


Exemple (2/2):
Point::Point(): x(0), y(0){}
Point::Point(double abs) : x(abs), y(abs) {}
Point::Point(double abs, double ord): x(abs), y(ord) {}
void Point::afficher(){
cout << "(" << x << ", " << y << ") " << endl;
}
void Point::afficher(char *msg) {
cout << msg << endl;
afficher();
}
Propriétés des fonctions membres
138

Arguments par défaut


Tout comme une fonction C++ classique, il est possible de définir
des arguments par défaut. Ceux-ci permettent à l'utilisateur de ne
pas renseigner certains paramètres.
On peut modifier notre classe Point pour qu’elle ne possède qu’une
seule fonction affiche à un seul argument de type chaîne.
void afficher(char* = " " ); // fonction afficher(): un argument par défaut
void Point::afficher(char *msg) {
cout << msg << "(" << x << "," <<y << ")" <<endl;
}
Point A;
A.afficher(); //affichage: (0, 0)
Point B(1.5, 2.5);
B.afficher(" Point B"); // affichage : Point B(1.5, 2.5)
Propriétés des fonctions membres
139

Les fonctions membre en ligne


Pour rendre en ligne une fonction membre, on peut:
Soit fournir directement la définition de la fonction dans la
déclaration même de la classe, dans ce cas le qualificatif inline
n’a pas à être utilisé (implicite).
Soit procéder comme pour une fonction ’’ordinaire’’ en
fournissant une définition en dehors de la déclaration de la
classe; dans ce cas, le qualificatif inline doit apparaître à la fois
devant la déclaration et devant l’en tête (explicite).
Propriétés des fonctions membres
140

Les fonctions membre en ligne


Exemple:
class Rectangle{

public :
inline Rectangle();

}; // Fin de la classe
inline Rectangle(): hauteur(0.0), largeur(0.0)
{
}
Typologie des méthodes d’une classe
141
141

Parmi les différentes méthodes que comporte une classe, on a souvent


tendance à distinguer :
Les constructeurs et les destructeurs;
Les méthodes d’accès (en anglais accessor/getter), en bon français
accesseurs, qui fournissent des informations relatives à l’état d’un
objet, c’est-à-dire aux valeurs de certains de ses champs (généralement
privés), sans les modifier ;
Les méthodes d’altération (en anglais mutator/setter), en bon
français manipulateur ou mutateur, qui modifient l’état d’un objet,
donc les valeurs de certains de ses champs.
Q&A
142
142

Vous aimerez peut-être aussi