Programmation Orientée Objet et C++
Christophe Collard
Christophe Collard
Plan
Notions de base
Classes et Objets
Construction et destruction d’objets
Les fonctions amies
La surdéfinition d’opérateurs
Les patrons de fonctions et de classes
Les flots
La technique de l’héritage
Les espaces de nommage
Notions de Base
Christophe Collard
1. Les variables définies par l'utilisateur
Type de donnée Signification Taille (en octets) Plage de valeurs acceptée
char Caractère 1 -128 à 127
unsigned char Caractère non signé 1 0 à 255
short int Entier court 2 -32 768 à 32 767
unsigned short int Entier court non signé 2 0 à 65 535
int Entier
unsigned int Entier non signé
long int Entier long 4 -2 147 483 648 à 2 147 483 647
unsigned long int Entier long non signé 4 0 à 4 294 967 295
float Flottant (réel) 4 -3.4*10-38 à 3.4*1038
double Flottant double 8 -1.7*10-308 à 1.7*10308
long double Flottant double long 10 -3.4*10-4932 à 3.4*104932
bool Booléen
2 (sur processeur 16 bits) 4 (sur processeur 32 bits)
-32 768 à 32 767 -2 147 483 648 à 2 147 483 647
2 (sur processeur 16 bits) 4 (sur processeur 32 bits)
0 à 65 535 0 à 4 294 967 295
Même taille que le type int, parfois 1 sur quelques
compilateurs
Prend deux valeurs : 'true' et 'false' mais une conversion implicite (valant 0 ou 1) est faite par le compilateur lorsque l'on affecte un entier (en réalité toute autre valeur que 0 est considérée comme égale à True).
1 octet = 8 bits
1 bit = 0 ou 1
Christophe Collard
Déclaration et initialisation
int n;
n = 10;int n = 10;
Le qualificatif « const »
const int n = 10;
La valeur de « n » ne change pas.
Expression constante = valeur calculée lors de la compilation
variables locales vs variables globales
Ex : ici 2*n*5 est une constante
Remarque : chaque instruction se termine par un « ; »
Christophe Collard
2. Les fonctions
Fonctionint
doublefloat
INPUTS OUTPUT
But : accomplir une tâche
Attention : une fonction ne peut renvoyer qu’un seul type
Fonction standard : float fctname (int, double)
Fonction sans argument : float fctname ()
Fonction sans valeur de retour : void fctname (int, double)
Remarque : une fonction bien programmée peut être lue sur 1 seul écran
Christophe Collard
3. Les boucles
But : effectuer plusieurs fois le même type d’opérations
Ex: sommer les 10 premiers entiers
Attention : en C++ il faut initialiser les variables, sinon une valeur aléatoire est attribuée
for (int i=0; i<10; i++)
type du compteur
initialisation du compteurreste dans la boucle tant que cette condition est vérifiée
Incrémente le compteur de 1
Christophe Collard
Remarque:
Les variables i et j sont locales à la fonction.
Pour renvoyer la valeur j vers l’extérieur, il faut écrire :
Christophe Collard
Interprétation
cout désigne un « flot de sortie » prédéfini
<< est un opérateur dont l’opérande de gauche est un flot
et l’opérande de droite est une expression de type qcq
Ici le flot cout reçoit la valeur « bonjour »
4. Les entrées / sorties en C++
Ecriture sur la sortie standard
La bibliothèque iostream contient les déclarations nécessaires à l’utilisation
des entrées / sorties en c++
Christophe Collard
Autre exemple
Remarque
Les 2 dernières lignes peuvent s’écrire :
cout << ’’valeur de n = ‘’ << n << endl;
Interprétation
On transmet dans un premier temps une chaine de caractères au flot cout
Ensuite le flot est augmenté de la valeur de l’entier n
cout sait gérer des données de différents typesChristophe Collard
Rôle de l’opérateur différent dans ces deux cas
L’opérateur a procédé au formatage (implicite) de la valeur de n pour la
transformer en une chaine de caractères.
La possibilité d’attribuer plusieurs significations à un même opérateur :
SURDEFINITION D’OPERATEURS
Lecture sur l’entrée standard
cin >> n;
cin >> n >> p;
Christophe Collard
5. La notion de référence
Il existe 3 façons de transmettre des variables à une fonction :
- transmission par valeur
- transmission par adresse
- transmission par référence
Christophe Collard
Transmission par valeur
avant appel : 10 20
début échange : 10 20
fin échange : 20 10
après échange : 10 20
adresse
valeur
adresse
valeur
n a
les valeurs de n et p sont dupliquéeson change les valeurs des copies
Christophe Collard
Transmission par adresse
avant appel : 10 20
début échange : 10 20
fin échange : 20 10
après échange : 20 10
adresse
valeur
n a
les valeurs de n et p ne sont pas dupliquées
on change les valeurs des originauxChristophe Collard
Transmission par référence
avant appel : 10 20
début échange : 10 20
fin échange : 20 10
après échange : 20 10
adresse
valeur
n a
les valeurs de n et p ne sont pas dupliquées
on change les valeurs des originauxChristophe Collard
Remarques
la transmission par référence utilise
la simplicité de la notation de la transmission par valeur
le mécanisme de la transmission par adresse
L’utilisation de la transmission par référence s’écrit uniquement au
niveau de la fonction appelée :
void echange (int& a, int& b)
Attention aux effets de bord lors de l’appel de la fonction
echange (n, p)Appel de la fonction :
transmission par valeur ? transmission par référence ?
pas de modification des valeurs de n et p valeurs de n et p modifiéesChristophe Collard
6. Surdéfinition de fonctions
une fonction avec un même nom possède plusieurs significations
sosie numero 1 : a = 5
sosie numero 2 : a = 2.5
Que se passe t il si x est de type float,
long double, …?
conversion du type par le compilateurChristophe Collard
7. L’allocation dynamique de mémoire
l’opérateur NEW sert à allouer de la mémoire
l’opérateur DELETE sert à libérer de la mémoire
Exemple 1
Exemple 2
Pour allouer n éléments d’un « type » donné : new type [n]
new retourne un pointeur (type*) sur le 1er élément d’un tableau
adresse
valeur
p
p[0]
adresse
valeur
adresse
valeur
adresse
valeur
adresse
valeur
p[4]
L’opérateur NEW
Christophe Collard
L’opérateur DELETE
libère la mémoire allouée par l’opérateur NEW
on donne comme argument l’adresse du pointeur fournie par new
syntaxe pour les éléments de type C++ standard
int* p;
p = new int [5];
delete p;
syntaxe pour les tableaux d’objet
point* p;
p = new point [5];
delete [ ] p;
Attention le rôle de l’opérateur delete est très important.
Si on détruit un pointeur sans libérer correctement la mémoire,
celle-ci n’est plus accessible et ne peut être réallouée
Stack overflowChristophe Collard
Classes et Objets
Christophe Collard
1. Classes et encapsulation des données
généralisation de la notion de type
extension des types C++ standard à de nouveaux types définis pas l’utilisateur
regroupe des données et des méthodes
données membres fonctions membres
Classe
On a séparé les données et fonctions membres en 2 catégories
public private Christophe Collard
Encapsulation
private : données et méthodes non accessibles à l’extérieur de la classe
seules les fonctions membres y ont accès
protected : données et méthodes non accessibles à l’extérieur de la classe
accès possible par les classes dérivées (cf plus tard)
public : données et méthodes accessibles à l’extérieur de la classe
Remarques
pour modifier des données privées il faut passer via des méthodes publiques
En POO pure, les données sont encapsulées et leur accès ne peut se faire
que par le biais de méthodes
Christophe Collard
Définition des fonctions membres (méthodes)
x et y modifiablesinitialise méthode de point
le symbole :: est un opérateur de résolution de portée
l’identificateur initialise est celui défini dans la classe point
Christophe Collard
Utilisation de la classe
Remarques
point est un nouveau type défini par l’utilisateur
a et b sont des instances de la classe point
a et b sont encore appelés des objets de type point
si aucun des mots private ou public n’apparaît dans la classe, tout
est considéré comme étant private => rien n’est accessible
Christophe Collard
Affectation d’objets
Christophe Collard
Affectation d’objets
adresse
valeur
adresse
valeur
y y
adresse
valeur
x
adresse
valeur
x
b a
copie des membres
Christophe Collard
Remarques
seules les données membres sont copiée (pas les méthodes)
ceci n’est possible que pour des objets de même type
ce système de copie « partielle » ne fonctionne pas pour des
données dynamiques (il faudra surdéfinir un opérateur =)
Affectation d’objets
Christophe Collard
2. Constructeur et destructeur
création d’un nouvel objet
initialisation de ses données
allocation de mémoire
Processus automatisé
CONSTRUCTEUR
destruction d’un objet
libération de mémoire
Processus automatisé
DESTRUCTEUR
Fonctions membres appelées automatiquement
à chaque création / destruction d’objet
Christophe Collard
Exem
ple
Résulta
t: affic
he 1
0 v
ale
urs
alé
ato
ires
Christophe Collard
Remarques
le constructeur ne renvoie rien (même pas void)
le destructeur ne renvoie rien et ne prend aucun argument
a partir du moment où la classe possède un contructeur, il faut créer
un objet avec les arguments requis pas le constructeur
une classe peu contenir plusieurs constructeurs
le constructeur porte le même nom que la classe
le destructeur porte le nom de la classe précédé du symbole ~
hasard suite (); invalide ici
une classe ne peut contenir qu’un seul destructeur (car pas d’argument)
constructeur par défaut
constructeur d’initialisation des membres
constructeur par recopie
Christophe Collard
Attention :
le rôle du destructeur est très important.
Si on détruit un objet sans libérer correctement la mémoire, celle-
ci n’est plus accessible et ne peut être réallouée
Stack overflow
Christophe Collard
3. Les données membres statiques
Les différents objets issus d’une même classe possèdent chacun leurs
propres données membres
La déclaration suivantepoint a, b;
conduit à
adresse
valeur
adresse
valeur
y y
adresse
valeur
x
adresse
valeur
x
a b
Christophe Collard
Une façon de permettre à plusieurs objets de partager des données
consiste à les déclarer avec le qualificatif static
adresse
valeur
n
adresse
valeur
x
adresse
valeur
x
a b
Les membres statiques existent en 1 seul exemplaire, indépendamment
des objets de la classe correspondante (même si aucun objet existe)
Les membres statiques sont toujours initialisés à 0
static int ctr = 5; INTERDIT par le compilateurChristophe Collard
4. Exploitation d’une classe
Dissocier l’implémentation d’une classe de son utilisation
Mettre dans un fichier séparé la classe et son implémentation
Création de bibliothèques que l’on regroupe par thèmes
5. Propriétés des fonctions membres
Surdéfinition des fonctions membres
La surdéfinition de fonctions « ordinaires » en C++ s’applique
aux fonctions membre d’une classe, y compris au constructeur
Elle ne peut s’appliquer au destructeur qui ne reçoit aucun argumentChristophe Collard
Exem
ple
Christophe Collard
Résultat
position (0,0)
coordonnees du point
position (5,5)
Point
position (3,12)
Remarques
N’importe quelle méthode peut appeler une autre méthode de la
même classe (public, protected ou private).
N’importe quelle méthode peut s’appeler elle-même (récursivité),
mais il faut prévoir un moyen de finir le processus.
Pour accéder aux données/méthodes private ou protected, il faut
passer via un méthode publique de la classe.
On peut définir dans des fonctions des arguments par défaut afin de
limiter le nombre de fonctions surdéfinies Christophe Collard
Arguments par défaut
Dans la définition de la classe point, on peut remplacer
void affiche ();
void afficher (char*);
parvoid affiche (char* = ‘’’’);
void point::affiche (); est supprimée
void point::affiche (char* message=‘’’’);
Remarque
Ceci s’applique aussi aux constructeurs Christophe Collard
Les objets transmis en argument d’une fonction membre
définir une méthode « coincide » dans la classe point pour
comparer 2 objets de type point
Exemple
son appel s’effectue de la manière suivante
a.coincide (b)
ou par symétrie du problème
b.coincide (a)
Christophe Collard
Résultat
a et b 0 (false)
b et c 1 (true)Christophe Collard
Remarques
Appel du constructeur avec 1 seul argument
point b (1); point b (1,0);
Le second argument est initialisé avec la valeur par défaut
Ici, les objets sont transmis par copie à la fonction coincideChristophe Collard
Remarques
le principe d’encapsulation est-il violé ?
a.coincide(b)
l’objet « a » accède aux données privées de l’objet transmis « b »
En C++, l’unité de protection est la classe et non l’objet.
Si A et B sont 2 classes différentes, une fonction membre de A ne
peut accéder aux données privées de B (sauf à la déclarer comme
amie de la classe B – cf. plus tard) Christophe Collard
Transmission d’un objet par adresse
adresse
valeur
adresse
valeur
y
y
adresse
valeur
x
adresse
valeur
x
a
b
adpt
a.coincide (b)
Christophe Collard
Attention aux effets de bord
la transmission par adresse est efficace car les données ne sont
pas dupliquées (gain de mémoire, gain de temps)
les données de l’objet transmis ne sont pas protégées contre les
modifications
pour protéger les données de l’objet transmis de toute modification,
on utilise le qualificatif const :
dans la déclaration de la classe
dans l’implémentation de la fonction
les données de l’objet appelant sa fonction membre ne peuvent être
protégées
Christophe Collard
Transmission d’un objet par référence
Les remarques précédentes sur les effets de bord restent valable
Attention : la transmission par valeur (copie) d’objets contenant des
variables allouées dynamiquement pose problème ! Christophe Collard
Retour d’un objet par une fonction
par valeur
par adresse
par référence
la transmission d’objet par valeur ne fait qu’une copie partielle de l’objet
(attention aux objets contenant des pointeurs)
si une fonction retourne un objet par adresse ou par référence, il faut
éviter que l’objet retourné soit local (celui-ci étant détruit à la sortie de la
fonction !)
point& point::symetrique ();retour incorrect (res est détruit à la
sortie de la fonction duplique)Christophe Collard
Auto-référence : le mot clé this
On peut avoir besoin d’utiliser l’adresse d’un objet ayant appelé une fonction
A l’intérieur de la méthode affiche, on ne connaît pas le nom de l’objet ayant
appelé cette fonction.
Quand on en a besoin, on peut y accéder grâce au mot clé this.
Christophe Collard
Les fonctions membres constantes
Rappel
const int n = 20;
La variable n est constante et n’évolue pas (calculée à la compilation)
On peut définir des objets constants
Notion non triviale
Les opérations sur les objets sont réalisées par ses méthodes.
L’utilisateur peut préciser les fonctions membres
autorisées à travailler avec des objets constants
Christophe Collard
La méthode affiche est autorisée à travailler avec des objets constants.
Elle peut modifier les valeurs d’un objet de type point.
Il est possible de surdéfinir une fonction membre en se basant sur la
présence ou non du qualificatif const.
void affiche () const; // fonction 1
void affiche (); // fonction 2
a.affiche(); appelle la fonction 1
c.affiche(); appelle la fonction 2ExChristophe Collard
Construction, destruction et
initialisation d’objets
Christophe Collard
Les objets automatiques & statiques
Durée de vie
Les objets automatiques: créés par déclaration dans une fonction ou
un bloc et détruits à la sortie de cette fonction ou de ce bloc.
Les objets statiques: créés par déclaration en dehors de toute
fonction ou dans une fonction avec le qualificatif « static ». Ils existent
avant l’exécution de la fonction main et sont détruits a la fin de
l’exécution du programme
Les objets temporaires
Appel direct au constructeur d’une classe
objet temporaire
Christophe Collard
Exemple
point (1,2); appel direct au constructeur de la classe point
objet temporaire
a = point (1,2); copie l’objet temporaire dans a
La copie fonctionne car par d’allocation dynamique de mémoire dans ‘’point’’
L’objet temporaire est détruit quand il n’est plus utilisé (ici a la fin du main)Christophe Collard
Les objets dynamiques
Classes sans constructeur
déclaration d’un objet dynamique point* adr;
allocation dynamique de mémoire adr = new point;
réserve 2 emplacements mémoire pour stocker des données de type int
accès aux méthodes adr -> initialise (1,3);
adr -> affiche ();
(*adr).initialise (1,3);
(*adr).affiche ();
destruction (explicite) de l’objet delete adr;
Christophe Collard
Classes avec constructeur(s)
déclaration d’un objet dynamique point* adr;
allocation dynamique de mémoire adr = new point (1,2);
appel au constructeur point (int, int)
Christophe Collard
Lorsqu’il y a plusieurs constructeurs, l’opérateur new choisit le bon
constructeur grâce au nombre et/ou à la nature des arguments
Remarques
S’il n’existe pas de constructeur ou s’il existe un constructeur sans
argument, new point; ou new point (); sont acceptés
Si tous les constructeurs possèdent au moins un argument, new point;
et new point (); sont rejetés
Christophe Collard
Le constructeur par recopie
Mise en évidence du problème
Christophe Collard
schéma de l’opération effectuée lors de l’appel de la méthode add
transmission de b par valeur
size
p
b
tableau dynamique de double
Christophe Collard
schéma de l’opération effectuée lors de l’appel de la méthode add
transmission de b par valeur
size
p
b
tableau dynamique de double
size
p
v
copie des données de b dans v
• copie de size (int)
• copie p (pointeur)
b.p et v.p pointent
sur le même tableau
Christophe Collard
schéma de l’opération effectuée lors de la sortie de la fonction add
destruction de la copie v
size
p
b
tableau dynamique de double
size
p
v
appel au destructeur
• libère v.size
• libère le tableau situé en v.p
Christophe Collard
retour au main
b.p ne pointe plus sur rien
size
p
b
appel au destructeur
• libère b.size
• libère le tableau situé en b.p
fin du main ()
segmentation fault
Christophe Collard
Solution
size
p
b
size
p
v
dupliquer le tableau de valeurs
On définit un construteur par recopie (appelé automatiquement lors
de la copie d’un objet) de la forme :
vector (const vector&); vector (vector&);ou bien
En général, un constructeur par recopie n’a pas de raison de modifier l’objet
passé en argument. De plus, une fonction prévue pour un objet constant
peut toujours s’utiliser pour un objet non constant (réciproque fausse)
vector (const vector&); Christophe Collard
Application
etc …
Christophe Collard
Résumé
La transmission par valeur d’un argument ou d’une valeur de retour d’une
fonction met en œuvre une recopie. Elle est réalisée soit:
• par le constructeur de recopie par défaut (si aucun n’a été défini)
• par le constructeur de recopie surdéfini dans la classe
Lorsqu’un objet comporte des données dynamiques, il est
indispensable de définir un constructeur par recopie
On y indique comment dupliquer correctement les données de l’objet
Christophe Collard
Les tableaux d’objets
En C++ un tableau peut posséder des éléments de n’importe quels
types, y compris ceux définis par les utilisateurs via les classes
On peut déclarer un tableau « courbe » de points:
point courbe [20];
Chaque élément du tableau peut accéder aux méthodes de sa classe :
courbe[10].affiche();
Christophe Collard
Remarques
• Un tableau d’objets n’est pas un objet
• En POO pure, le concept de tableau d’objet n’existe pas
• Il est toujours possible de définir une classe dont un des membres
est un tableau d’objets
class courbe
{ point p [20];
…..
}
Un constructeur par défaut est appelé pour chaque élément du tableau
• soit la classe ne possède aucun constructeur
• soit elle doit posséder un constructeur par défaut
Christophe Collard
Exemple
point (7,0) point (3,0) point (11,0) point (0,0) point (0,0)
tableau de 5 objets de type point
Christophe Collard
Les tableaux dynamiques d’objets
création du tableau dynamique d’objets
• soit la classe ne possède aucun constructeur
• soit elle doit posséder un constructeur par défaut
destruction du tableau dynamique d’objets
delete [ ] adcourbe;
indique qu’il s’agit d’un tableau d’objets
Christophe Collard
Objets membre
Une classe peut posséder des données membre qui soient définis
par l’utilisateur via une classe :
Christophe Collard
Les fonctions amies
Christophe Collard
POO pure Encapsulation des données
données membres privées accessibles seulement
par les méthodes publiques de la classe
une méthode d’une autre classe doit passer via les
méthodes publiques de la classe pour accéder aux
données privées
problème dans certains cas
Exemple
On définit une classe vector et une classe matrix.
Produit matrice-vecteur nécessite l’accès aux données privées des 2 classes
Christophe Collard
Solutions
• déclarer les données dans la partie public
• utiliser des méthode publiques pour accéder aux données privées
• arrêter le C++ et se remettre au fortran
• utiliser des fonctions amies dans ses classes
Christophe Collard
Solutions
• déclarer les données dans la partie public
• utiliser des méthode publiques pour accéder aux données privées
• arrêter le C++ et se remettre au fortran
trop tard vu l’investissement déjà réalisé
• utiliser des fonctions amies dans ses classes
Christophe Collard
Solutions
• déclarer les données dans la partie public
perte du bénéfice de l’encapsulation (protection des données)
• utiliser des méthode publiques pour accéder aux données privées
• arrêter le C++ et se remettre au fortran
trop tard vu l’investissement déjà réalisé
• utiliser des fonctions amies dans ses classes
Christophe Collard
Solutions
• déclarer les données dans la partie public
perte du bénéfice de l’encapsulation (protection des données)
• utiliser des méthode publiques pour accéder aux données privées
oui, mais pas toujours optimal pour protéger les données d’un objet
• arrêter le C++ et se remettre au fortran
trop tard vu l’investissement déjà réalisé
• utiliser des fonctions amies dans ses classes
Christophe Collard
Il existe plusieurs situations d’amitié
• fonction indépendante amie d’une classe
• fonction membre d’une classe et amie d’une autre classe
• fonction amie de plusieurs classes
• toutes les fonctions membre d’une classe, amies d’une autre classe
Fonction indépendante amie d’une classe
Une fonction amie se déclare avec le mot clé friend
Exemple
Christophe Collard
Résultat a et b coincident
a et c ne coincident pas Christophe Collard
Remarques
l’emplacement de la déclaration d’amitié à l’intérieur de la classe
n’a pas d’importance
on ne peut pas utiliser d’argument implicite (this) dans une
fonction amie, car elle n’appartient pas à la classe
en général, une fonction amie possède 1 ou plusieurs arguments
et/ou une valeur de retour du type de la classe ( qui justifie la
déclaration d’amitié)
quand une fonction amie retourne un élément du type de la
classe, il est fréquent que ce soit un objet local à la fonction.
La transmission doit alors s’effectuer par valeur.
Christophe Collard
ici les arguments de coincide sont transmis par valeur
on pourrait les transmettre par référence
Fonction membre d’une classe et amie d’une autre
cas particulier de la situation précédente
indiquer dans la déclaration d’amitié à quelle classe elle appartient
utiliser l’opérateur de résolution de portée ::
la fonction f appartient à la classe B
la fonction f est amie de la classe A
la fonction f accède aux
données de A et B
Christophe Collard
Remarques
le compilateur a besoin de connaître les caractéristiques de B pour
compiler la classe A.
friend int B::f (char, A);
int f (char, A);
le compilateur a besoin se savoir que la classe A existe, mais sans
connaître ses caractéristiques.
Christophe Collard
Ecriture correcte du code
Christophe Collard
Fonction amie de plusieurs classes
une fonction, qu’elle soit indépendante ou bien membre d’une classe
peut faire l’objet de déclaration d’amitié dans plusieurs classes
f peut accéder aux données privées de A et de BChristophe Collard
Toutes les fonctions d’une classe sont amies d’une autre
C’est la généralisation de la notion de fonction amie
On pourrait déclarer toutes les fonctions d’une classe B comme
amies d’une classe A, mais il est plus simple de le faire de
manière globale dans la class A :
Christophe Collard
Une application de fonction amie indépendante
Christophe Collard
Une application de fonction amie membre d’une classe
Christophe Collard
La surdéfinition d’opérateurs
Christophe Collard
Christophe Collard
On considère une classe vector 2D :
class vector
{ int x,y;
…
};
On définit 2 objets de type vector a et b
a
b
Peut on écrire comme pour un type standard C++ la somme a + b ?
Christophe Collard
Il faut surdéfinir l’opérateur + pour la classe
définir une fonction operator + au sein de la classe
utiliser le mot clé operator suivi de l’opérateur à surdéfinir
la fonction operator + peut être :
• soit une fonction membre de la classe
• soit une fonction indépendante amie de la classe
• soit une fonction indépendante de la classe
Afin de protéger les données et d’accélérer le code, on choisit en général
de surdéfinir l’opérateur comme fonction indépendante amie de la classe.
Christophe Collard
Surdéfinition d’opérateur avec une fonction amie
Résultat
coordonnees (1,2)
coordonnees (2,5)
coordonnees (3,7)
coordonnees (6,14)
Christophe Collard
Surdéfinition d’opérateur avec une fonction membre
Résultat identique
Christophe Collard
Remarques
la fonction operator + est appelé de la manière suivante :
fontion indépendante : a + b operator + (a,b)
fontion membre : a + b a.operator + (b)
la fonction membre operator + fait apparaître une dissymétrie et
l’objet a ne peut pas être protégé
Opérateurs et transmission par référence
Dans les deux exemples précédents, on utilise la transmission par valeur
Pour des objets de grande taille, il vaut mieux utiliser la transmission
par référence. On peut alors protéger les objets transmis avec ‘’const’’
point operator + (const point& a, const point&b)
Le retour de l’objet point se fait obligatoirement par valeur
Christophe Collard
Les opérateurs ++ et --
Résultat
a1 (3,6)
b (2,5)
a2 (3,6)
b (3,6)
Christophe Collard
Surdéfinition de l’opérateur =
En l’absence de sudéfinition de l’opérateur =, il y a une simple recopie
du 2nd opérande dans le 1er
pose problème pour les objets contenant des pointeurs
size
p
a
tableau dynamique de double
size
p
b
vector a(5), b;
b = a;
cf. constructeur par recopie
Christophe Collard
Christophe Collard
Surdéfinition de l’opérateur [ ]
exemple de la classe vector
l’opérateur [ ] permet d’accéder au ième élément du vecteur
En informatique on commence à compter à partir de 0
En mathématiques on commence à compter à partir de 1
C’est l’opérateur [ ] qui fera la conversion
C++ impose de définir l’opérateur [ ] comme fonction membre
int& operator [ ] (int);
retour par référence obligatoire afin d’utiliser l’opérateur pour affecter
des valeurs
Christophe Collard
Résultat 3 6 9
Christophe Collard
Remarque
L’opérateur [ ] ne peut pas être appliqué à un objet constant.
Il aurait fallut le définir de la façon suivante
int& operator [ ] (int) const;
Christophe Collard
Surdéfinition des opérateurs new et delete
La surdéfinition se fait obligatoirement par une fonction membre
La fonction NEW reçoit un argument de type size_t (bibliothèque stddef)
taille en octets de l’objet à allouer
La fonction NEW renvoit un void* (adresse où est stocké l’objet)
La fonction DELETE reçoit un pointeur en argument (adresse objet)
La fonction ne renvoit rien (void)
Remarques
La surdéfinition de l’opérateur new implique la prise en charge de la
gestion de la mémoire
NEW et DELETE ne reçoivent pas d’argument implicite (this)
Christophe Collard
Christophe Collard
Résultat
++ nombre total de points = 1
++ nombre total de points dynamiques = 1
++ nombre total de points = 2
++ nombre total de points = 3
++ nombre total de points dynamiques = 2
++ nombre total de points = 4
-- nombre total de points = 3
-- nombre total de points dynamiques = 1
-- nombre total de points = 2
-- nombre total de points dynamiques = 0
-- nombre total de points = 1
-- nombre total de points = 0
point a(3,5);
new point (1,3);
appel implicite par new
point b;
new point (2,0);
appel implicite au constructeur
appel implicite par delete ad1
delete ad1;
appel implicite par delete ad2
delete ad2
fin prog. destruction de a
fin prog. destruction de b
Action Affichage
Christophe Collard
Remarques
La surdéfinition des opérateurs NEW et DELETE n’a d’incidence que
sur les objets dynamiques
Que NEW soit surdéfini ou non, son appel est toujours implicitement
suivi de celui d’un constructeur
De même, DELETE fait appel implicitement à un destructeur
Il est toujours possible de définir les opérateurs NEW et DELETE de
manière globale
déclarer NEW et DELETE comme fonctions indépendantes
appel à cet opérateur par tous les types (y compris
ceux de base du C++)
plus de possibilité d’appeler l’opérateur new prédéfini
ex int* adi = new int; y fait appel
Christophe Collard
Les patrons de fonctions
Les patrons de classes
Christophe Collard
La surdéfinition de fonctions permet de donner un nom unique à plusieurs
fonctions réalisant un travail différent
La notion de patron est plus puissante et plus restrictive
Plus puissante
on écrit une seule fois la définition d’une fonction pour que le compilateur
puisse l’adapter automatiquement à n’importe quel type
Plus restrictive
toutes les fonctions ainsi fabriquées ont la même définition et le même
algorithme
But
écrire une fonction qui soit valable quel que soit le type des arguments
utilisés
Christophe Collard
Exemple
int min (int a, int b)
{ return (a < b) ? a : b;
}
float min (float a, float b)
{ return (a < b) ? a : b;
}
double min (double a, double b)
{ return (a < b) ? a : b;
}
long int min (long int a, long int b)
{ return (a < b) ? a : b;
}
etc …
On écrit la même fonction pour tous les types existant en C++
c’est long, très long, très très long
et en plus il faut le faire pour toutes les fonctions
ça multiplie les lignes de code et rend le code illisible
il faut compléter le code quand on définit ses propres classes
Christophe Collard
On résout ce problème en utilisant les patrons de fonctions
cette méthode est très puissante
Elle permet de définir des méthodes pour des types qui n’existent pas encore
patron type
fonction
Résultat min (n,p) = 4
min (x,y) = 2.5
Christophe Collard
Application à un type classe
Remarque il suffit de donner un sens à l’opérateur < pour des objet de
type point pour pouvoir utiliser min (sans rien ajouter !)
Christophe Collard
Généralisation et conversion
Quel type retourne fct ?
Christophe Collard
Généralisation et conversion
fct (n, x, p) int (conversion de float vers int pour x)
fct (x, n, y) float (conversion de int vers float pour n)
fct (n, p, q) int
fct (n, p, x) erreur (ne pas laisser choisir le compilateur à votre place !)
Christophe Collard
Généralisation et conversion
fct (n, x, p) int (conversion de float vers int pour x)
fct (x, n, y) float (conversion de int vers float pour n)
fct (n, p, q) int
fct (n, p, x) erreur (ne pas laisser choisir le compilateur à votre place !)
Remarque dans fct, on peut initialiser des variables de type T ou U
Christophe Collard
exemple
Christophe Collard
Surdéfinition des patrons
Remarque
on peut transmettre des éléments de n’importe quel type aux fonctions
grâce aux patrons
les fonctions surdéfinies doivent avoir un nombre d’arguments différent
afin d’éviter les ambigüités
Christophe Collard
Les patrons de classes
Mise en évidence du problème
Comment stocker des points avec des coordonnées int, float, double, … ?
Utiliser des patrons de classe
Christophe Collard
La définition inline :
La définition à l’extérieur de la classe :
nom de la classe
nom du patronnom de la fonciton
Christophe Collard
Réécriture du code
Christophe Collard
Les flots
Christophe Collard
les opérateurs << et >> assurent le transfert de l’information
le formatage de l’information
Le flot cout est connecté à la sortie standard
Le flot cin est connecté à l’entrée standard
Un flot est un objet d’une classe prédéfinie :
ostream pour le flot de sortie
istream pour le flot d’entrée
Chacune de ces 2 classes surdéfinit les opérateurs << et >> pour les
différents types de base du C++ (fichier iostream)
Christophe Collard
Surdéfinition des opérateurs << et >>
Christophe Collard
La technique de l’héritage
Christophe Collard
Le concept de l’héritage (ou de classes dérivées) constitue l’un des
fondements de la POO
Intérêt
classe de base
classe dérivée
propriétés de la classe
propriétés classe de base + nouvelles propriétés
Classe dérivée :
• nouvelle classe
• définie à partir de la classe de base
• hérite des propriétés de la classe de base
• ajoute de nouvelles propriétés à la classe de base
• ne modifie pas la classe de base
permet de développer de nouveaux outils en se basant sur les acquis de
la classe de base
Christophe Collard
Remarque
L’héritage n’est pas limité à un seul niveau
• une classe dérivée peut devenir classe de base pour une autre classe
• plusieurs classes peuvent être dérivées d’une même classe
Christophe Collard
Mise en œuvre de l’héritage
Classe de base
Christophe Collard
Classe dérivée
On ajoute une information à cette classe : la couleur du point
Programme principal
Christophe Collard
Utilisation des membres d’une classe de base dans une
classe dérivée
Quand on appelle p.affiche() pour un objet de type pointcol, cette fonction
n’est pas définie dans la classe enfant (pointcol)
C’est la fonction affiche de la classe parent (point) qui est appelée
C’est la fonction affiche de la classe parent (point) qui est appelée
Christophe Collard
Utilisation des membres d’une classe de base dans une
classe dérivée
Quand on appelle p.affiche() pour un objet de type pointcol, cette fonction
n’est pas définie dans la classe enfant (pointcol)
C’est la fonction affiche de la classe parent (point) qui est appelée
C’est la fonction affiche de la classe parent (point) qui est appelée
Définir une méthode affichec () dans pointcol du type :
Christophe Collard
Problème :
pointcol n’a pas accès aux données privées de point (x et y)
soit mettre les données de point dans la partie protected
soit utiliser une méthode publique de point
Surdéfinition des fonctions membre
les fonctions affiche () et afficec () effectuent les même tâches
leur donner le même nom (surdéfinition)
Christophe Collard
Christophe Collard
Appel des constructeurs et destructeurs
Christophe Collard
Le constructeur par recopie
Christophe Collard
Le contrôle des accès
But : protection des données de la classe de base
les données et méthodes privées sont inaccessibles en dehors leur classe
les données et méthodes publiques sont accessibles partout
comment protéger les données de la classe de base et les rendre
accessibles par la classe dérivée ?
Christophe Collard
Le contrôle des accès
But : protection des données de la classe de base
les données et méthodes privées sont inaccessibles en dehors leur classe
les données et méthodes publiques sont accessibles partout
comment protéger les données de la classe de base et les rendre
accessibles par la classe dérivée ?
définir les données et méthodes protégées
Christophe Collard
Remarques
les fonctions amies d’une classe dérivée possèdent les même droits
que les fonctions membre
la déclaration d’amitié ne s’hérite pas
f : fonction amie de la classe A
B : classe dérivant de la classe Af n’est pas amie de B
il est possible d’effectuer des dérivations différentes de public
class B : public class A
statut initial accès aux FMA accès externe nouveau statut accès externe nouveau statut accès externe nouveau statut accès externe
public public protected private
protected protected protected private
private private private private
classe de base dérivée public dérivée protected dérivée private
Christophe Collard
Utilisation
classe de base
dérivée 3dérivée 2dérivée 1 dérivée 4
partie commune d’un problème
solution 1 solution 2 solution 3 solution 4
gain de temps en programmation
par de pénalité de temps pour les fonctions non utilisées dans la
classe dérivée, car ne sont pas inclues lors de l’édition de lien
perte de temps lors d’appel de fonctions imbriquées
Christophe Collard
L’héritage multiple
Christophe Collard
Les espaces de nommage
Christophe Collard
zones de déclaration permettant de délimiter la recherche des noms
des identificateurs par le compilateur
Mot clé : namespace
But
regrouper les identificateurs logiquement pour éviter les conflits de
nom entre plusieurs parties d’un même projet
Remarque
par défaut, C++ utilise un espace de nommage (namespace std) de
portée globale dans lequel il doit y avoir aucun conflit de nom
Définition d’un espace de nommage
Christophe Collard
Remarque
un namespace peut être découpé en plusieurs morceaux
les identificateurs définis à l’intérieur d’un même namespace
ne doivent pas entrer en conflit
Christophe Collard
Accès aux membres d’un namespace
Il se fait grâce à l’opérateur de résolution de portée
Définition de fonctions d’un namespace
La fonction peut aussi être implantée à l’extérieur du namespace
en utilisant l’opérateur de résolution de portée
Christophe Collard
On peut de même définir des classes dans un namespace
Définition d’un namespace dans un namespace
Alias de namespace
Lorsqu’un namespace porte un nom compliqué, il peut-être
avantageux de définir un alias
namespace nom_alias=nom;
Christophe Collard
La directive using
elle permet d’utiliser tous les identificateurs d’un namespace sans
spécifier cet espace devant chaque fonction ou variable