Vous êtes sur la page 1sur 229

Atelier C++

17/10/16 1
Plan
I.  Préambule jeudi 29/09/16
II.  Introduction jeudi 29/09/16
III.  Du C vers C++ jeudi 29/09/16
IV.  Concepts de base (abstraction/encapsulation) jeudi 12/10/16
V.  Classes -- C++ jeudi 12/10/16
VI.  Héritage jeudi 26/10/16
VII.  Polymorphisme -- C++ jeudi 03/12/15
VIII.  STL jeudi 17/12/15
IX.  Exceptions jeudi 17/12/15

17/10/16 2
Préambule

1.  Motivations
2.  Objectifs du cours
3.  Bibliographie
4.  Notation

17/10/16 3
Motivations

n  Jusqu’à présent, vous avez appris à écrire des


programmes de plus en plus complexes.

n  Il faut donc maintenant des moyens pour


organiser ces programmes de façon plus
efficace.

C’est l’un des objectifs principaux de l’orientation


d’objet.

4
Motivations

q Les applications à résoudre sont de plus en plus


complexes :
§  Complexité des processus à résoudre
§  Complexité des processus de développements (on développe de plus
en plus en équipe)

q  Qualité des solutions:


§  la correction ou la validité
§  Extensibilité
§  Réutilisabilité
§  Efficacité

17/10/16
5
Motivations

17/10/16
6
Motivations

Changement du
besoin de
6% 13% l'utilisateur
Changement de
9% format des données

Urgences fixes
12%
Mise au point
42%
18% Changement de
matériel

Divers

Répartition de la Maintenance
7
Motivations: La création d’un logiciel,
c’est un tout

l  L’analyse (UML, Merise, …)


l  L’algorithmique ( Pseudo-code, …)
l  La programmation ( C/C++, JAVA, Python, …)

Problème sans Enoncé précis Ecriture des


Programme
formulation précise du problème algorithmes

Langage Langage Langages de


courant algorithmique programmation

Analyse Algorithmique Programmation

17/10/16
8
L’orienté objets (OO)

«orienté objet» = organisation du logiciel comme


une collection d’objets autonomes coopérant
ensemble comprenant à la fois une structure de
données et un comportement.

17/10/16
9
Objectifs du cours

q Apprendre et assimiler le style et le paradigme de la


programmation Orientée Objets (OO=O2).

q Se familiariser avec le langage de programmation C++;


apprendre à l’utiliser pour programmer avec un style Objet.

q Se familiariser avec la bibliothèque STL de C++.

17/10/16 10
Bibliographie

• Notions OO
• Timothy Budd, "Introduction à la programmation par objets", Addison-
Wesley, 1992, 385pp, ISBN 2-87908-003-7, Bibliothèque ENSI (2303 -
N172 BUD)
• Hugues. BERSINI, "L'orienté objet Cours et exercices en UML2 avec
Phyton, Java, C# et C++", EYROLLES, 2004.
• Bertrand Meyer, Conception et programmation par objets
• J. Cox, Object-oriented programming
• Langages
• Bjarne Stroustrup. The C++ Programming Language. Addison-Wesley,
Reading, MA, USA, third edition, 1997.
• Visual C++ / Microsoft Press
• G.Masini & al. Les langages à objets.
• Internet …

17/10/16
11
Introduction

1.  Historique
2.  Rappel sur le langage C

17/10/16 12
Historique
n  Langages informatiques et OO:
52 64 72 82
~1843 1945 54 59 67 75 85 95 2005

… Effervescence POO Age d’or POO …

1° programme Premiers langages objets


(Ada Lovelace) Cobol C#
Microsoft
SmallTalk
Plankalkül
(Zuse) C
java
Dennis Ritchie
Sun Microsystems
A-0 Simula67
(Grace Hopper) C++
Altair BASIC Bjarne Stroustrup
BASIC (B. Gates & P. Allen)
Fortran (Kemeny & Kurtz)

17/10/16 13
Historique

Ø Origine : Simula 67 (Oslo, 1967 )

Une technique clé pour obtenir la réutilisabilité et l’extensibilité


en logiciel.
• Construction de logiciel par extension et combinaison
• Technique de décomposition et d’architecture.
• Un aspect fondamental : l’héritage.
• Pour écrire du code de taille assez importante (dépassant le 1
million de lignes ! )
• Un autre aspect, plus particulièrement mis en valeur :
• Une nouvelle notion de type, plus forte et plus flexible

17/10/16 14
Historique

Ø  L’OO en informatique aujourd’hui?


n  Quasi-totalité des applications programmées en OO (POO)
n  Presque tous les langages intègrent la notion d’objet

Ø  L’OO permet de répondre aux exigences actuelles des


applications informatiques :
n  Applications conviviales et graphiques (mode « fenêtre »)
n  Applications complexes
n  Réutilisation du code
n  Maintenance du code

17/10/16 15
Domaines d’applications

ü Programmation iconique
ü Jeux
ü Environnements de programmation
ü Graphisme
ü Base de données
ü Réseaux
ü Multimédia
ü Intelligence artificielle

17/10/16
16
Historique C++
n  1980 au laboratoire AT&T Bell (Stroustrup)
n  Les classes introduites pré-compilateur de C
n  1985 : 1ère version publique
n  1995-1997 : révision standard ANSI
n  soit pour améliorer les caractéristiques de la norme
ANSI, soit pour préparer le terrain pour les aspects
Objets
n  Disponible sur toutes les plateformes. Il est distribué en
logiciel :
n  domaine publique (environnement GNU),
n  plusieurs sociétés commerciales (Microsoft,
Borland, Zortech, …).

17/10/16
17
Présentation C++

n  Le C est inclus (à 99%) dans le C++


n  Le C++ rajoute des notions de programmation
orientée objet (classe, héritage, polymorphisme…
comme en Java), ainsi que des facilités d’écriture
(surcharge d’opérateurs…)

1
17/10/16
8
Rappel sur le Langage C

1
17/10/16
9
Le Langage C

n  Le langage C est né au début des années 70 par Dennie


Ritchie aux Laboratoires Bell d'AT&T.
n  Le langage C est un langage de bas niveau dans le sens où
il permet l’accès à des données que manipulent les
ordinateurs (bits, octets, adresses).
n  Langage polyvalent assez proche du langage machine
permettant le développement de systèmes d'exploitation.
n  Il a été créé pour mettre en œuvre le système UNIX : Plus
de 90% du noyau du système UNIX est écrit en langage C.

17/10/16
20
Le Langage C
n  Il permet également de développer les programmes
applicatifs scientifiques et de gestion de bases de données.
n  De nombreux logiciels du domaine des ordinateurs
personnels, tels que Microsoft Word ou Microsoft Excel,
sont eux-aussi écrits à partir de langage C ou de son
successeur orienté objet : C++
n  Le langage C possède assez peu d'instructions, il fait par
contre appel à des bibliothèques, fournies en plus ou moins
grand nombre avec le compilateur :
Exemples:
math.h : bibliothèque de fonctions mathématiques
stdio.h : bibliothèque d'entrées/sorties standard

17/10/16
21
Structure d'un programme C
#include <stdio.h>
#define DEBUT -10 Directives du
#define FIN 10 préprocesseur : accès avant
#define MSG "Programme de démonstration\n" la compilation

int fonc1(int x);


int fonc2(int x); Déclaration des fonctions
void main()
{ /* début du bloc de la fonction main*/
int i; /* définition des variables locales */
Programme
i=0; principal
fonc1(i) ;
fonc2(i) ;
} /* fin du bloc de la fonction main */

int fonc1(int x) {
return x; Définitions
}
des fonctions
int fonc2(int x) {
return (x * x);
}
17/10/16
22
Structure d’un programme C
n  Programme source C :
q  des directives de précompilation commençant par #,

n  une collection d’objets (variables et fonctions), dont la


définition est éventuellement stockée dans des fichiers séparés.
q  Les commentaires débutent par /* et finissent par */, ils peuvent
s’étendre sur plusieurs lignes
n  Tout programme C comporte une fonction main() qui constitue le
programme principal et comporte 2 parties :
q  la déclaration de toutes les variables et fonctions utilisées

q  Un bloc d’instructions simples : une instruction est délimitée par


un ;

n  Une variable est un objet manipulé par le programme, qui possède un


nom et un type. Le type définit l'ensemble des valeurs possibles pour
l'objet.

17/10/16
23
Structure d’un programme C
n  Les autres fonctions sont des sous-programmes ou modules.
q  Il s'agit de mécanismes permettant de donner un nom à un bloc de
traitements afin de pouvoir le réutiliser en différents points du
programme.

n  Une fonction permet d'enfermer certains traitements dans une "boîte


noire", dont on peut ensuite se servir sans se soucier de la manière dont
elle a été programmée.
n  Toutes les fonctions sont constituées de:
q  entête (type et nom de la fonction suivis d'une liste d'arguments

entre parenthèses),
q  bloc (instruction composée) constituant le corps de la fonction. Il
est défini par une suite d'instructions simples à l'intérieur
d'accolades "{ }".

17/10/16
24
Exemple de programme C
#include <stdio.h>
#define PI 3.14159
/* calcul de la surface d’un cercle */
main()
{
double rayon, surface;
double calcul (double rayon);
printf ("Rayon = ? ");
scanf ( "%f ", &rayon);
surface=calcul(rayon);
printf ("Surface= %f \n ", surface);
}
/* définition de fonction */
double calcul (double r)
{
/*définition de la variable locale */
double a;
A=PI*r*r;
return (a);
17/10/16
} 25
Syntaxe du C
Header de la bibliothèque standard
#include <stdio.h> in/out. (pour printf)
#define pi 3.14 Equivalence : Le pré-processeur
remplacera tous les pi par 3.14
float d,c;
Déclaration de deux variables réelles globales

int main() En tête du programme principal


{ Début de la fonction main

d=2.0 ; Calculs
c=pi*d ; Appel de la fonction puts (envoie une chaîne
puts("bonjour à tous\n"); de caractères sur le périphérique de sortie)
printf("la circonférence est %f m\n",c);
} appel de la printf (affiche des chaînes
formatés, ici c est affiché sous format réel)

17/10/16
Fin de la fonction main 26
Du programme au code exécutable

n  Le source d'une application écrite en langage C peut être stockée dans


un ou plusieurs fichiers dont le suffixe « .c »
n  Une fois le programme écrit, on ne peut pas l’exécuter directement.
n  Pour que l’ordinateur comprenne ce que l’on veut lui faire, il faut
traduire le programme en langage machine. C’est la compilation.
n  La compilation enchaîne 3 étapes :
q  Appel au pré-processeur ou pré-compilateur: c’est un utilitaire

qui traite le fichier source avant le compilateur. Il est manipulateur


de chaînes de caractères. Il retire les parties de commentaires, qui
sont comprises entre /* et */. Il prend aussi en compte les lignes du
texte source commençant par # pour créer le texte que le
compilateur analysera.

17/10/16
27
Directives de précompilation
n  Directives d’inclusion :
q  Elles commencent par # include (# en 1ère colonne)

q  Les 4 directives suivantes sont en général nécessaires et suffisantes

# include <stdio.h> Pour les entrées sorties


# include <stdlib.h> Pour les fonctions standards
# include <string.h> Pour la manipulation des chaînes de caractères
# include <math.h> Pour les fonctions mathématiques
n  Déclaration de constantes :
q  Elles sont déclarées par # define (# en 1ère colonne) suivi d’un

identificateur en MAJUSCULES et de la valeur éventuellement


calculée par une expression arithmétique
# define MAX 100
# define PI 3.14159265358979
# define DEUX_PI 2 * PI

17/10/16
28
Du programme au code exécutable
q  Appel au compilateur: création des codes machine destinés au
microprocesseur utilisé. Le compilateur indique les erreurs de
syntaxe mais ignore les fonctions-bibliothèque appelées par le
programme. Le compilateur génère un fichier binaire, appelé
fichier objet. Ce fichier possède des références insatisfaites qui
seront résolues par l’éditeur de liens.

q  Appel à l’éditeur de liens: Le code machine des fonctions-


bibliothèque est chargé, L’éditeur de liens prend ensuite les
fichiers objet et les associe pour créer un module exécutable. Il
se sert de bibliothèques pour résoudre les références indéfinies.

17/10/16
29
Plusieurs Fichiers

17/10/16
30
Du programme au code exécutable

17/10/16
31
#include Bibliothèques pré compilées
<stdio.h> (fichiers objet)
Bibliothèques Fichiers
en C (texte) header
main() *.c *.h
{ puts(" Bonjour
à tous ");
}

Editeur de lien
Préprocesseur Compilateur C LINKER
Remplace les Transforme le fichier C en un Lie (donne des adresses
#define et effectue fichier objet (code machine), les aux fonctions) tous les
les #include fonctions pré compilées sont fichiers objets et crée un
Fichier déclarées dans les fichiers *.h fichier exécutable
source C
contenant la
fonction
main

Fichier de Programme
symboles exécutable
pour debug

FLUX DE DONNEES D’UN COMPILATEUR C

17/10/16
32
Librairies

n  Deux types de librairies sous MS-Windows :


q  Librairies Statique (.lib):
n  devient une partie intégrante.
q  Librairie Dynamique (.dll):
n  partagée entre plusieurs programmes.

17/10/16
33
Programme ??

bin a.out .exe Exécutable(s)

lib
.o .so .lib .dll

Programme
Librairies et fichiers objets

include .h

Fichiers de description (header)

src .c
Fichiers d’implantation (source code)
17/10/16
34
La Compilation : Résumé
Fichiers
Code source C
d’en-tête C
.c
.h Préprocesseur

Code pré-processé

Compilateur
Librairies
.lib .so

Fichier(s) Objet Editeur de liens


exécutable
.o a.out .exe
35
17/10/16
Environnement de développement
Integré (EDI)
n  Un IDE intègre tous les outils dont vous avez besoin pour préparer,
déboguer, tester et exécuter un programme.
n  Préparation d'un programme nécessite les étapes fondamentales suivantes:
n  Modifier votre module pour produire un fichier source
n  Compiler votre module pour produire un fichier objet
n  Liez le fichier objet avec les modules objet d'autres pour produire un fichier
exécutable (un programme).
n  Exécutez le fichier exécutable (le programme).
n  Debugger: Un programme qui vous permet d'exécuter votre code de
manière interactive
n  Exemple IDE : codeblocks, dev, visual, borland, …

17/10/16
36
IDE Windows

17/10/16
37
Du C vers C++

17/10/16 38
Du C vers C++
n  Chaque flux est en fait un objet.
q  La sortie d'objets sur les flux de sortie (cout et cerr) se fait avec l'opérateur
<<.
q  La lecture d'objets sur le flux d'entrée (cin) repose sur l'opérateur >>.
n  Pour pouvoir utiliser les flux, il faut inclure la librairie iostream

#include <iostream.h>
....
int age;
char nom[64];
cin >> nom;
cin >> age;
cout << "Coucou " << nom << ", tu as " << age << " ans" << endl;

17/10/16 39
Du C vers C++

n  les commentaires
q  En C, les commentaires sont déterminés par les balises /* et
*/.
q  Le C++ apporte une nouvelle manière de définir des
commentaires à l'aide de la balise //.

int x; // c’est une déclaration

17/10/16 40
Du C vers C++
n  Les entrées/sorties
q  En C, le programme pouvait communiquer avec l'extérieur sur trois canaux :
n  l'entrée standard : stdin
n  la sortie standard : stdout
n  l'erreur standard : stderr

q  En C++, on retrouve cette notion des troix canaux sur lesquels vont travailler
troix flux dédiés :
n  le flux en entrée : cin
n  le flux en sortie : cout
n  le flux d'erreur : cerr

17/10/16 41
Du C vers C++

Emplacement libre des déclarations


for (int i=0; i<MAX; i++) { …}

int i=5;
int j=2;
for (int i=0; i<10; i++)
{
j+=i; // on est sur le i local
}
cout << i << endl; // i vaut 5 !
cout << j << endl; // j vaut 47 !

17/10/16 42
Du C vers C++
n  Les nouveaux types : type bool
q  Le C ne possède pas de type booléen spécifique.
q  C++ introduit le type bool pour palier à cette carence. Il s'accompagne des
mot-clés true et false
q  la conversion int-boolean respecte toujours le formalisme du C.
bool flag=true;
....
do
{
....
if (....)
flag=false;
....
} while (flag==true);
....

17/10/16 43
Du C vers C++
n  Les nouveaux types : type référence

q  En C : impossibilité de réaliser un passage de paramètres par adresse. Tous


les paramètres sont passés par valeur. Aussi, si l'on souhaite modifier dans la
fonction la valeur d'un paramètre, il faut transmettre explicitement son
adresse.

q  Le C++ a apporté d'autres types de données : les références. Ils reposent sur
une extension des attributions de l'opérateur &.

q  Les références sont des synonymes d'identificateurs. Elles permettent de


manipuler une variable sous un autre nom que celui sous laquelle cette
dernière a été déclarée.

17/10/16 44
Du C vers C++
n  les nouveaux types : type référence

q  Par exemple, si « id » est le nom d'une variable, il est possible de


créer une référence « ref » de cette variable. Les deux
identificateurs id et ref représentent alors la même variable, et
celle-ci peut être accédée et modifiée à l'aide de ces deux
identificateurs indistinctement.

q  il est donc impossible de déclarer une référence sans l'initialiser


(doit être lié à un identificateur de variable)

q  Syntaxe : type &référence = identificateur;

17/10/16 45
Du C vers C++
n  la notion de référence
n  désigne un emplacement mémoire

n  qui est en fait l'alias d'une autre variable

n  une référence est donc initialisée au moment de sa


définition
n  une référence désigne TOUJOURS le même
emplacement mémoire
n  permet de s'affranchir des pointeurs

n  se déclare avec l'opérateur &

17/10/16
46
Du C vers C++ (le type référence)

int i=0; int &ri=i; // Référence sur la variable i.


ri=ri+i; // Double la valeur de i (et de ri).

q  Il est possible de faire des références sur des valeurs numériques.


Dans ce cas, les références doivent être déclarées comme étant
constantes, puisqu'une valeur est une constante :
const int &ri=3; // Référence sur 3.
ri=5; //erreur l-value specifies const object
int &error=4; // Erreur ! La référence n'est pas
constante.

17/10/16 47
Du C vers C++
q  Le C++ pâlie au problème du passage de paramètre par adresse. Il se distingue
du passage par valeur par l'utilisation d'une référence dans la spécification des
paramètres. Ensuite, dans le corps de la fonction, on accède "normalement" à la
variable, sans avoir besoin de déréférencer.
Version C Version C++
void Permut (int * a, int * b) void Permut (int & a, int & b)
{ {
int tmp=*a; int tmp=a;
*a=*b; a=b;
*b=tmp; b=tmp;
} }
.... ....
int i=2, j=4; int i=2, j=4;
Permut (&i, &j); Permut (i, j);
/* i vaut 4 et j vaut 2 */ // i vaut 4 et j vaut 2

17/10/16 48
Du C vers C++ (le type référence)

int n,m ;
int& i=n ; // i variable référence
sur n
i=m;
// Signifie n=m et
// non que i devient une référence
sur m !

17/10/16
49
Du C vers C++ (le type référence)

int n;
int &p = n; // p est une référence à n
// p occupe le même emplacement mémoire
que n
n = 3;
cout<< p; // l’affichage donnera 3

17/10/16
50
Du C vers C++ (le type référence)
n  int i=5, j=6;
int & k=i; // k variable reference sur i

cout << i << " " << j << " " << k << endl; // affiche 5 6 5
n  k=3;
cout << i << " " << j << " " << k << endl; // affiche 3 6 3
n  i=8;
cout << i << " " << j << " " << k << endl; // affiche 8 6 8
n  k=j;
cout << i << " " << j << " " << k << endl; // affiche 6 6 6
k=1;
cout << i << " " << j << " " << k << endl; // affiche 1 6 1 (ok)

17/10/16
51
Du C vers C++ (le type référence)
long i;
long k;

long &j; référence vers rien


long &j=4; référence vers une constante
long &j=i+2; référence vers une expression

long &j=i;
j=k;

Pas de référence à une expression

référence = pointeur constant dont on ne manipule que le contenu

17/10/16
52
Du C vers C++ (le type référence)

n  L'un des défauts les plus irritants en C réside dans


l'impossibilité de réaliser un passage de paramètres
par référence.

n  Le C++ palie cette lacune en introduisant (enfin !) le


passage de paramètre par référence.

17/10/16
53
Du C vers C++ (le type référence)

n  Compromis entre passage par adresse et


passage par valeur
n  On passe le paramètre et non son adresse à la
fonction
n  Le système fait un passage par adresse caché

n  Dans le corps de la fonction, on manipule le


paramètre, et non son pointeur

17/10/16
54
Le passage de paramètres en c++

17/10/16
55
Le passage de paramètres en c++

17/10/16
56
Le passage de paramètres en c++

17/10/16
57
Du C vers C++ (pointeur)

n  Un pointeur est une amélioration de la notion d’adresse en


mémoire

n  Un pointeur c’est l’adresse en mémoire d’un objet ainsi que le


type exact de l’objet qui se trouve à cette adresse.

n  L’idée est que si pi est un « pointeur sur un entier », alors


connaître pi permet de trouver cet entier dans la mémoire
(opération d’indirection) et de le manipuler (addition, etc)
puisqu’on sait que c’est un entier

17/10/16 58
Du C vers C++ (pointeur)
n  Supposons qu’une variable entière i existe dans le programme,
comment obtenir l’adresse en mémoire de i ?

n  On utilise l’opérateur & (opérateur de prise d’adresse, à ne


pas confondre avec le & de la déclaration de référence !),

n  &i : signifie « adresse de i qui est entier ». Puisque i est un


entier, alors &i est du type « pointeur sur un entier ».

n  A partir d’un pointeur sur un entier contenant bien l’adresse


d’un entier, comment manipuler cet entier ?
q  Il faut utiliser l’opérateur * (opérateur d’indirection)

17/10/16 59
Du C vers C++ (pointeur)

n  En effet, une variable et ses différentes références ont la même


adresse, puisqu'elles permettent d'accéder à un même objet.

n  Utiliser une référence pour manipuler un objet revient donc


exactement au même que de manipuler un pointeur constant
contenant l'adresse de cet objet.
référence ≡pointeur constant contenant l’adresse de l’objet

n  Les références permettent simplement d'obtenir le même résultat


que les pointeurs, mais avec une plus grande facilité d'écriture.

17/10/16 60
Du C vers C++ (pointeur)
int i=0;
int i=0;
int *pi=&i;
int &ri=i;
*pi=*pi+1; // Manipulation de i via
ri=ri+1; // Manipulation de i via ri..
pi.
Nous constatons que la référence ri peut être identifiée avec l'expression *pi,
qui représente bel et bien la variable i.

La référence ri encapsule la manipulation de l'adresse de la variable i et s'utilise


comme l'expression *pi.

La différence se trouve ici dans le fait que les références doivent être initialisées
d'une part, et que l'on n'a pas à effectuer le déréférencement d'autre part.

17/10/16 61
Du C vers C++ (l'allocation dynamique)

n  En C, l'allocation/désallocation dynamique étaient


gérées par les routines malloc/free et consort (calloc,
malloc, etc...).
n  Le mécanisme d'allocation dynamique a été
complètement repensé dans le C++ de manière à
apporter davantage de robustesse. Il repose sur deux
nouveaux opérateurs :
q  new pour l'allocation : int *ipt=new int;

q  delete pour la désallocation : delete ipt;

17/10/16
62
Du C vers C++ (l'allocation dynamique)
#include <malloc.h>
type*ptr;
/*réservation d’un espace mémoire pour les valeurs*/
ptr=(type*)malloc(sizeof(type)*NbrDeValeurs);
/* libération */
free
type *ptr1;
type *ptr2;
/*réservation d’un espace mémoire pour les valeurs*/
ptr1=new type;
ptr2= new type[NbrDeValeurs];

/* libération */
delete ptr1; delete[ ] ptr2;
17/10/16
63
Du C vers C++ (l'allocation dynamique)

n  Pour les tableaux, elle est légèrement différente:


q  allocation : tab=new int[10];
q  désallocation : delete[] tab;

n  Notez enfin l'abandon de la macro NULL, dont la


portabilité était plus que douteuse, pour symboliser les
pointeurs sur rien. En C++, on utilise à la place le
chiffre 0, tout simplement.

17/10/16
64
Du C vers C++ (l'allocation dynamique)
q  Les opérateurs new et delete :

new : indiquer le type et le nombre de données à réserver pour une


seule valeur.
double *p_doub;
p_doub = new double; // allocation
libérer la mémoire avec :
delete p_doub; // libération

17/10/16
65
Du C vers C++ (l'allocation dynamique)
q Les opérateurs new[] et delete[] :

Tableaux dynamiques :
char *txt;
long taille;

taille=42;
txt = new char[42]; // allocation de 42 char

// libération avec l'opérateur delete[]

delete []txt;

17/10/16
66
Du C vers C++ (l'allocation dynamique)
int *ad; // déclaration d’un pointeur sur un entier
ad = new int; // réservation de place en mémoire pour un entier

On aurait pu déclarer directement int *ad = new int;

char *adc;
adc = new char[100]; // réservation de place en mémoire pour 100 caractères

On aurait pu déclarer directement char *adc = new char[100];

int *adi;
adi = new int[40]; // réservation de place en mémoire pour 40 entiers

On aurait pu déclarer directement int *adi = new int[40];

delete ad; // libération de place


delete [] adc;
delete [] adi;
17/10/16
67
Du C vers C++ (l'allocation dynamique)
Code Code objet du programme

Données statiques
Valeurs constantes
Pile
Piles d’appels de fonctions

Tas Allocation dynamique de


mémoire

17/10/16 68
Mémoire allouée de Mémoire Allouée
manière statique (Pile) Dynamiquement (Tas)

Pile/Tas (Stack/Heap) Variables globales


Arguments
Valeurs de retour
Pointers

Cell * ConstruireListe(int taille) {


int i;
Cell *cour, *tete; struct Cell {
tete = NULL; int valeur;
for (i=taille; i >= 0; i--) { Cell * suivant;
cour = (Cell*) malloc (sizeof(Cell)); }
cour->valeur = i;
cour->suivant = tete;
// Point d’arrêt 2
tete = cour;
} void main () {
return tete; Cell * tete ;
} tete = ConstruireListe(4);
}
69

17/10/16
17/10/16
70
17/10/16
71
Les espaces de nommage

n  En C, il était difficile de faire cohabiter plusieurs


versions d'une même structure de données.

n  Pour éviter le conflit de noms, on était obligé de


modifier les noms de chaque structure.

n  C++ propose un moyen simple de résoudre ce


problème : les espaces de nommage.

17/10/16
72
Les espaces de nommage

n  Les espaces de nommage permettent de définir une


unité cohérente dans laquelle les déclarations des
différents objets sont regroupées (types, constantes,
variables, fonctions).

n  Les identificateurs présents dans l'espace de


nommage possèdent alors une portée qui leur est
spécifique.

17/10/16
73
Les espaces de nommage

17/10/16
74
Les espaces de nommage

17/10/16
75
Exemples (cout)
1.  #include< iostream>
2.  int main()
using
using std::cout
namespace std;
3.  { using std::endl
4.  std::cout << ‘’Salut.\n’’;
5.  std::cout << ‘’ Je tape 5: ‘’ << 5 << ‘’\n’’;
6.  std:cout << ‘’ L’opérateur std::endl’’:
7.  std:cout << ‘’ provoque un saut de ligne à l’écran.’’;
8.  std:cout << std::endl;
9.  std:cout << ‘’ voici une très gand nombre : \t’’ << 70000;
10.  std:cout << std::endl;
11.  std:cout << ‘’8 et 5 font : \t’’;
12.  std:cout << 8+5 <<std::endl;
13.  std:cout <<‘’ voici une fraction : \t’’;
14.  std:cout << (float) 5/8 <<std::endl;
15.  return 0;
16.  }

17/10/16 76
Les espaces de nommage
n  définition/utilisation du namespace
namespace A
{ spécifier l'espace de nommage par défaut à
typedef unsigned int B; l'aide du mot-clé using.
using namespace A;
.... B i;
}
....
A::B i; // une variable de type B

spécifier l'espace de nommage par défaut à l'aide du mot-clé


using.
using namespace A;
B i;

17/10/16
77
Les espaces de nommage
n  Exemple (différenciation par les namespaces)
namespace Nul
{
class Pile { ... };
....
}
namespace Pro
{
class Pile { ... };
....
}
....
int main (int, char **)
{
Nul::Pile p1; // une pile de debutant
Pro::Pile p2; // une pile de vrai pro
....
}

17/10/16
78
Les fonctions inline

n  En C, lorsqu'on souhaite factoriser un morceau de


code sans créer une fonction, on a la possibilité de
définir une macro.

n  Les macros peuvent entraîner des effets de bords


désastreux lorsqu'elles sont mal définies. D'autre part,
il n'y a aucun contrôle sur le type des arguments.

17/10/16
79
Les fonctions inline
n  En C++, l'introduction du mot-clé inline va nous permettre
d'éviter le recours aux macros.
n  Lorsqu'une fonction est déclarée inline, le compilateur se
charge de la convertir en macro, lorsque c'est possible.
n  on a ainsi la sécurité d'une fonction et la rapidité d'une macro.

q  #define MAX(a,b) (((a)>=(b))? (a) : (b))


....
inline int Max (int a, int b) {return (a>=b) ? a : b);}

17/10/16
80
Les fonctions inline
en C :
#define CARRE(x) x*x
int main()
{
long a=CARRE(2+4);
printf("%ld",a);
}

17/10/16
81
Les fonctions inline
en C++ :
inline long carre(long);

int main()
{
cout << carre(2+4) << endl;
}

long carre(long t)
{
return t*t;
}

affiche 36

17/10/16
82
Surcharge de fonctions

q  La signature de fonction présente la carte


d'identité auprès du compilateur.

ü  en C : son nom
ü  en C++ : son nom + types des paramètres

q  Unicité de l'identité.

17/10/16
83
la surcharge des fonctions
n  Surcharge de fonctions
•  Elle permet de déclarer puis définir des fonctions ayant
un nom identique mais une signature différente.
•  Attention toutefois : le type de retour ne fait pas partie
de la signature. La surcharge doit par conséquent
préserver le type de retour, elle ne touche qu'aux
paramètres.
n  Exemples
q  int f(int gros_entier);

q  int f(double gros_reel);

q  int f(const char gros_nom[], bool gros_flag);

17/10/16
84
la surcharge des fonctions

q  La surcharge est une forme faible de


polymorphisme.

q  Elle est surtout utilisée dans les classes, pour définir


plusieurs variantes du constructeur.

q  La surcharge peut se révéler particulièrement


intéressante lorsqu'on souhaite éviter des
conversions de types indésirables lors du passage
des paramètres.

17/10/16
85
Surcharge de fonctions
Exemple

prototype signature

void f(int,int); f_int_int


void f(int,double); f_int_double
void f(double,int); f_double_int

les 3 fonctions coexistent dans un programme

Erreur du compilateur si on ajoute :

int f(int,int);

-le type de retour ne fait pas partie de la signature.

-Le choix de la fonction à l'appel.

17/10/16
86
Les paramètres avec valeur par défaut

n  C++ procure cette facilité en nous autorisant à fournir


une valeur par défaut aux paramètres.

n  Il existe cependant une restriction importante dans la


mise en œuvre des paramètres par défaut:
q  À partir du moment où un paramètre possède une valeur par
défaut, tous les paramètre suivant doivent également en posséder
une.

17/10/16
87
Les paramètres avec valeur par défaut

n  En effet, dans le cas contraire, cela pourrait poser


des problèmes pour le compilateur :
q  int f(int a=0, int b, int c=0);
....
i=f(1, 2, 3); // OK
j=f(4); // toujours OK ~ f(0, 4, 0)
k=f(5, 6); // argh ! ~ f(5, 6, 0) ou f(0, 5, 6) ?
// non respect de la contigüité

En revanche, l'exemple suivant est valide :


q  void f(double x, double y=0.0, double z=0.0);
....
f(a); // OK ~ f(a, 0.0, 0.0)
f(a, b); // OK ~ f(a, b, 0.0)
f(a, b, c); // OK ~ f(a, b, c)
// respect de la contiguïté

17/10/16
88
Les paramètres anonymes

float fct(char, int=10, float=0.0);

n  l'appel fct('a') est équivalent à fct('a',10,0.0)


n  l'appel fct('a',12) est équivalent à fct('a',12,0.0)
n  l'appel fct() est illégal

17/10/16 89
Concepts de base
(abstraction/encapsulation)

17/10/16 90
Programmation classique

Ø Difficulté de réutiliser du code déjà écrit et testé.


Ø Maintenance coûteuse ( Instabilité, sécurité, coût)

17/10/16
91
La programmation orientée objets

Séparation entre le traitement et les données

Variables/
constantes

Fonctions

17/10/16 92
La programmation orientée objets

Rectangle
Ou est le lien entre Largeur
les variables ??!! Hauteur
Aucune notion Surface
sémantique

Robustesse
Changement
h Erreur de manipulation
Produit l
Modularité

Lisibilité

17/10/16 93
La programmation orientée objets
Un des objectifs principaux de la notion d’objet :
n  organiser des programmes complexes grâce aux notions :

q  d’encapsulation

q  d’abstraction

q  d’héritage

q  et de polymorphisme

17/10/16 94
Notions d’encapsulation
n  regrouperdans le même objet
informatique («concept»), les données et Rectangle
les traitements qui lui sont spécifiques :
q  attributs : les données incluses dans un objet Largeur
q  méthodes : les fonctions Hauteur
(= traitements) définies dans un objet
Surface

ü Les objets sont définis par leurs attributs


et leurs méthodes.

17/10/16 95
Notions d’abstraction
n  Pour être véritablement intéressant, Dans la programation
un objet doit permettre un certain procédurale :
// On définit autant de
degré d’abstraction. données que de rectangles
n  Le processus d’abstraction consiste double largeur1=2.5;
double hauteur=4.0; rect1
à identifier pour un ensemble
d’éléments : double largeur2=4.5;
rect2
double hauteur2=5.0;
q  des caractéristiques communes à

tous les éléments //Pour calculer la surface : 2


q  des mécanismes communs à tous
Surface(largeur1,hauteur1);
Surface(largeur2,hauteur2);
les éléments
Rectangle Source d’erreur
ü  description générique de l’ensemble hauteur Rect1.Surface();
considéré : Se focaliser sur largeur
Rect2.Surface();
l’essentiel, cacher les détails. Surface

17/10/16 96
Notions d’abstraction
Exemple : Rectangles

n la
notion d’«objet rectangle» n’est intéressante que si l’on peut lui
associer des propriétés et/ou mécanismes généraux (valables pour
l’ensemble des rectangles)

n Les notions de largeur et hauteur sont des propriétés générales des


rectangles (attributs),

n Le mécanisme permettant de calculer la surface d’un rectangle


(surface = largeur × hauteur) est commun à tous les rectangles
(méthodes)
17/10/16 97
Classes et Instances, Types et Variables
En programmation Objet :
n le résultat des processus d’encapsulation et d’abstraction s’appelle
une classe
n  classe = catégorie d’objets

n  une classe définit un type

n  une réalisation particulière d’une classe s’appelle une instance

n  instance = objet

n  un objet est une variable

17/10/16 98
Classe en C++
n  En C++ une classe se déclare par le mot-clé class.
n  Exemple : class Rectangle { ... };

q  Ceci définit un nouveau type du langage.

n  La déclaration d’une instance d’une classe se fait de façon similaire


à la déclaration d’une variable :
q  nom_classe nom_instance ;

n  Exemple :

q  Rectangle rect1;

déclare une instance rect1 de la classe Rectangle.

17/10/16 99
Déclaration des attributs
La syntaxe de la déclaration des attributs est la
même que celle des champs d’une structure :
type nom_attribut ;
Exemple :
n les attributs hauteur et largeur, de type double, de
la classe Rectangle pourront être déclarés par :

17/10/16 100
Accès aux attributs
n  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 :
n  la valeur de l’attribut hauteur d’une instance rect1 de la classe
Rectangle sera référencée par l’expression :
rect1.hauteur

17/10/16 101
Déclaration des méthodes d’une classe

n  La Déclaration des fonctions (méthodes) d’une classe peut se faire


soit :
q  en une étape : déclaration + définition: Un trop grand nombre de
définitions de fonctions peuvent encombrer la définition d’une
classe.
q  en deux étapes : déclaration puis définition: définir les fonctions

à l’extérieur de leur classe donc il faut définir les prototypes des


fonctions dans la classe.

17/10/16 102
Définition des méthodes interne à la classe
n  La syntaxe de la définition des méthodes d’une classe est la syntaxe normale
de définition des fonctions :
type_retour nom_methode (type_param1 nom_param1, ...)
{ // corps de la méthode }
n  mais elles sont simplement mises dans la classe elle-même.
Exemple : la méthode surface() de la classe Rectangle :

mais où sont passés les paramètres ?

17/10/16 103
Portée des attributs

n  Les attributs d’une classe constituent des variables directement


accessibles dans toutes les méthodes de la classe (i.e. des «
variables globales à la classe »).
n  On parle de « portée de classe ».
n  Il n’est donc pas nécessaire de les passer comme arguments
des méthodes.
n  Par exemple, dans toutes les méthodes de la classe Rectangle,
l’identificateur hauteur (resp. largeur) fait a priori référence à
la valeur de l’attribut hauteur (resp. largeur) de l’instance
concernée (par l’appel de la méthode en question).

17/10/16 104
Déclaration des méthodes
n  Les méthodes sont :
q  des fonctions propres à la classe

q  qui ont donc accès aux attributs de la classe

n  Il ne faut donc pas passer les attributs comme arguments aux


méthodes de la classe !

17/10/16 105
Paramètres des méthodes
n  Mais ce n’est pas parce qu’on n’a pas besoin de passer les
attributs de la classe comme arguments aux méthodes de cette
classe, que les méthodes n’ont jamais de paramètres.
n  Les méthodes peuvent avoir des paramètres : ceux qui sont
nécessaires (et donc extérieurs à l’instance) pour exécuter la
méthode en question !

17/10/16 106
Définition externe des méthodes
n  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
n  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 :
q  La déclaration de la classe contient les prototypes des
méthodes.
q  les définitions correspondantes spécifiées à l’extérieur de la

déclaration de la classe se font sous la forme :


typeRetour NomClasse::nomFonction(type1 param1, type2
param2, ...) { ... }
17/10/16 107
Déclaration d’une classe en deux étapes
(1)
q  1ère étape : Écrire la définition de la classe
class vecteur
{
//définition des attributs
float x,y,z;
//déclaration des méthodes
void saisir(void);
void afficher(void)
float norme(void);
void produit(float);
void additionner(vecteur);
};

17/10/16 108
Déclaration d’une classe en deux étapes
(2)
n  2ème étape : Implantation des méthodes
void vecteur::afficher(void)
{ float vecteur::norme(void)
{float r;
cout<<"["<<x<<","<<y<<","<<z<<"]";
r=sqrt(x*x+y*y+z*z);
} return r;
void vecteur::saisir(void) }
{
cout<<"x?";cin>>x;
cout<<"y?";cin>>y;
cout<<"z?";cin>>z;
}

17/10/16 109
Appels aux méthodes
n  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(val_arg1, ...)
n  Exemple : la méthode

void surface() const;


définie pour la classe Rectangle peut être appelée pour une
instance rect1 de cette classe par :
rect1.surface()
n  Autres exemples :

une_figure.colorie(rouge);
vect.saisir();

17/10/16 110
Actions et Prédicats
n  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 »).
n  On peut pour cela ajouter le mot const après la liste des paramètres de la
méthode :

type_retour nom_methode (typ_para1,


nom_para1, ...) const
Si vous déclarez une action en tant
que prédicat (const), vous aurez à
la compilation le message d’erreur:

assignment of data-member ‘...’ in


read-only structure

17/10/16 111
Portée des membres (1)
n  Tout ce qui 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 : c’est la notion de portée
n  Donc les données et les fonctions private sont utilisables par
les objets de la classe seulement.
n  Note : Si aucun droit d’accès n’est précisé, c’est private par
défaut.
n  Donc, dans notre exemple quel est la porté de la fonction
surface() ?

17/10/16 112
Portée des membres (2)
n  À l’inverse, l’interface, qui est accessible de l’extérieur, se
déclare avec le mot-clé public.
n  Public : Données et fonctions utilisables par d’autres objets et
fonctions.

n  Dans la plupart des cas :


q  Privé :

n  Tous les attributs

n  La plupart des méthodes

q  Public :

n  Quelques méthodes bien choisies (interface)

17/10/16 113
Constructeur d’une classe
n  Un constructeur est une méthode ayant le même nom que la classe
n’ayant pas de type de retour.

n  Si, on n’écrit pas un constructeur, un constructeur est fournit


automatiquement (constructeur par défaut). Ce dernier ne prend
aucun argument et son corps est vide.

n  Il est important de réaliser que si vous ajoutez une déclaration de


constructeur comportant des arguments à une classe qui n’avait pas
de constructeur explicite auparavant ; vous perdez le constructeur
par défaut.
n  Le constructeur sera appelé lors de l'instanciation simple d'un objet
ou d'une création dynamique (utilisation de new)
17/10/16 114
Constructeur d’une classe (2)
class vecteur
{
private:

public:
vecteur();
vecteur(float,float,float );

};

17/10/16 115
Constructeur d’une classe contenant des objets comme
attributs (1)
n  Que se passe-t-il si les attributs sont eux-mêmes des objets ?

On a ici deux objets qui sont des


attributs de la classe RectangleColore
Lors de l’instanciation d’un objet de la
classe RectangleColore qu’est ce qui
se passe ???
RectangleColore RC;
RC
Problème : Et si les constructeurs de ces deux classes prenaient
R des arguments en paramètres !!!
Appel au constructeur de la classe Rectangle
C

Appel au constructeur de la classe Couleur

17/10/16 116
Constructeur d’une classe contenant des objets comme
attributs (2)
Un constructeur devrait normalement contenir une section d’appel aux
constructeurs des attributs....
...ainsi que l’initialisation des attributs de type de base.

Solution proposée par C++ : « liste d’initialisation » du constructeur.

Syntaxe générale :
NomClasse(liste_paramètres)
// liste d’initialisation
: attribut1(...), // appel au constructeur de attribut1
...
attributN(...) // appel au constructeur de attributN
{ // autres opérations }

17/10/16 117
Constructeur d’une classe contenant des objets comme
attributs (3)
n  Exemple

17/10/16 118
Liste d’initialisation
n  Cette section introduite par « : » est optionnelle lorsqu’on n’a pas d’objet
qui nécessite un constructeur avec paramètres mais elle est recommandée.
n  les attributs non-initialisés dans cette section
q  prennent une valeur par défaut si ce sont des objets ;
q  restent indéfinis s’ils sont de type de base ;
n  les attributs initialisés dans cette section peuvent être changés dans le corps
du constructeur.

17/10/16 119
Constructeur de recopie (1)

n  C++ offre la possibilité de créer une instance à partir d’une


instance déjà existante : la copie d’une instance
le constructeur de recopie (ou de copie)

Rectangle r1(12.3, 24.5);


r2 sera la copie de r1 mais de point de vue
Rectangle r2(r1); logique pas physique, i.e., une copie des
valeurs des attributs

Lors de la création, r1 et r2 sont deux instances distinctes mais ayant les


mêmes valeurs pour leurs attributs.

17/10/16 120
Constructeur de recopie (2)
Syntaxe :
n Question avant d’aborder la syntaxe du constructeur :

Quand se produit le déclenchement du constructeur de


recopie ?
A chaque création d’une instance à partir d’une instance existante
Qu’est ce qui se passe lors du passage d’un argument par
valeur à une fonction ?.
Une copie de la variable est crée et les changements à l’intérieur de
la fonction se font sur la copie
La syntaxe suivante est-elle correcte ?
NomClasse(NomClasse nomObjetSource) { ... }
Si non quel est le problème rencontré par cette syntaxe

17/10/16 121
Constructeur de recopie (3)
n  Supposons que nous ayons définis le constructeur de recopie
suivant :
q  Rectangle(Rectangle a) { …}

Suivons l’exécution de l’instanciation suivante :


Rectangle r2(1.0,2.0);
Rectangle r1(r2); Passage de r2 par valeur : Création
d’une copie de r2 DONC appel d’un
Passage de r2’ par valeur : Création
constructeur de recopie :
d’une copie de r2’ DONC appel d’un
Rectangle r2’(r2)
constructeur de recopie :
Rectangle r2’’(r2’) Passagede r2’’ par valeur : Création
d’une copie de r2’’ DONC appel d’un
constructeur de recopie :
Rectangle r2’’’(r2’’)

17/10/16 122
Constructeur de recopie (3)
n  Solution

NomClasse ( const NomClasse& nomObjetSource) { ... }

Avec const, on interdit la


modification de l’objet Afin de supprimer la
source. boucle infinie
Question : Le constructeur
de recopie n’est pas
sensé modifier l’objet
source, comment faire
alors pour le protéger?

17/10/16 123
Constructeur de recopie (4)
n  Un constructeur de copie est automatiquement généré par le
compilateur s’il n’est pas explicitement défini (constructeur de
copie par défaut)

n  Ce constructeur opère une initialisation membre à membre des


attributs (si l’attribut est un objet le constructeur de cet objet
est invoqué)
q  copie de surface

n  Cette copie de surface est suffisante 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 !
17/10/16 124
Destructeur d’une classe (1)
n  Libérer des attributs dynamiques ou   Le destructeur est automatiquement
fermer de fichiers lancée à l'exécution de l'ordre de
libération mémoire de l'instance
n  Syntaxe (donc à la fin du cycle de vie de
q  ~nomdelaclasse(void) l’objet)

class vecteur delete nomobjet;


{
private: Un destructeur peut-il contenir des
… paramètres ?
public:
Un destructeur possède-il une valeur de
….. retour ?
~ vecteur(){….};

};
NON
17/10/16 125
Le pointeur "this"
class A {
public :
int f();
void f(int);
private :
void f(int i)
int i;
{
};
return this->i = i;
}
this peut être interprété comme un identifiant
de l'objet. Il fait toujours référence à l'instance
pour laquelle la méthode est invoqué.

17/10/16
126
Le pointeur "this"

17/10/16 127
Le pointeur "this"

17/10/16 128
class A { Un constructeur de A
public :
A();
A(int); Un constructeur surdéfini de A
...
~A();
... Le destructeur
};

void main() Objet automatique


{ Le constructeur de A est exécuté automatiquement
A a; par A().
A * ptr; Le destructeur est appelé à la sortie de la fonction
cout<<"\n"<<a.f(); ou du bloc de déclaration.
...
ptr = new A(1);
cout<<ptr->f());
...
delete ptr;
}
Le destructeur de A est exécuté

17/10/16
129
Constructeur/ Destructeur…

Les objets automatiques sont ceux créés par une déclaration :

§  dans une fonction : L’objet est créé lors de la rencontre de sa


déclaration.
A a;
Il est détruit à la fin de l'exécution de la fonction.

§ dans un bloc : l’objet est aussi créé lors de la rencontre de sa


déclaration.
Il est détruit lors de la sortie du bloc.

17/10/16
130
Constructeur/ Destructeur…

Les objets statiques sont ceux créés par une déclaration située :

§  en dehors de toute fonction,


§  dans une fonction, mais assortie du qualificatif static.

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


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

17/10/16
131
Les membres données statiques (1)

n  A chaque déclaration d’une instance, celle-ci possède ses


propres membres données.
n  Exemple :
class exple1
{ int n ;
float x ;
..... } ;
n  une déclaration telle que : exple1 a, b ; Conduira au schéma suivant :

17/10/16 132
Les membres données statiques (2)
Question : Est-ce qu’il existe des cas ou on a besoin d’une variable membre
commune à tous les objets ?
n Un membre static est un membre commun à tous les objets de la classe.

n Le qualificatif static permet de définir un membre de donnée static:

n Exemple :

class exple2
{ static int n ;
float x ;
...} ;

Avec la déclaration (exple2 a, b ;) Objet a Objet b


Un membre statique est accessible via la classe : class::varstat; Exemple :
exple2::n

17/10/16 133
Initialisation des membres données statiques
n  Peut-on initialiser un membre static à l’aide d’un
constructeur ?
n  Peut-on le faire lors de la déclaration?
NON
n  Problème de multi initialisation dans le constructeur.
n  Problème de compilation séparée dans la déclaration dans la
classe.
n  Un membre statique doit donc être initialisé explicitement (à
l'extérieur de la déclaration de la classe) par une instruction
telle que : int exple2::n = 5 ;
n  Cette démarche est utilisable aussi bien pour les membres
statiques privés que publics.
17/10/16 134
Surcharge des méthodes

n  Chaque méthode possède une signature :


q  nom de la méthode
q  paramètres admis en entrée (et ordre des paramètres)
q  résultat fourni en sortie (facultatif)

n  Une même classe peut contenir la même méthode dotée de signatures différentes

float calculer()
int calculer(int)

17/10/16 135
Surcharge des opérateurs (1)

n  C’est quoi la surcharge des opérateurs


Surcharger une fonction : un opérateur est une
deux fonctions ayant le opération sur un ou entre
même nom mais pas les deux opérande(s)
mêmes paramètres

Redéfinir les opérateurs afin de les adapter aux


besoins de la classe ou des opérandes traitées

17/10/16 136
Surcharge des opérateurs (2)
Syntaxe :
n Valuer_De_Retour Operatoroperateur(operand) ;

Exemple
class complex{
double re,im;
public :
complex(double r,double i):re(r),im(i){}
void affichage (){cout <<"résultat est : " <<c1.im<<" "<<c1.re<<"\n";
}
complex operator+(complex);
complex operator*(complex);};
Le programmeur définit ces deux opérateurs à l’aide de complex::operator+(…) et
complex::operator*(…) .
Si b et c sont de type complexe alors,
b+c signifie b.operator+(c)

17/10/16 137
Surcharge des opérateurs (3)

17/10/16 138
Opérateur surchargable
n  La majorité des opérateurs est surchargeable à part quelques
uns qui sont :
q  ::

q  .

q  ?:

Remarque :
On ne peut utiliser que les opérateurs déjà existant (c’est
normal, c’est de la surcharge)
Il faut conserver la pluralité (unaire, binaire) de l'opérateur
initial.

17/10/16 139
Généricité
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); }
char min (char a, char b) { return ((a < b)? a : b); }
n 

template <class T>


T min (T a, T b) { return ((a < b)? a : b); }
int main() {
int a = min(10, 20); // int min(int, int)
float b = min(10.0, 25.0); // float min(float, float) char c =
min('a', 'W'); // char min(char, char) }
17/10/16 140
Généricité

17/10/16 141
Généricité

17/10/16 142
La méthode amie
n  Fonction extérieure à la classe ayant accès aux données privées de
la classes
n  Contraire à la P.O.O. mais utile dans certain cas
n  Plusieurs situations d’« amitié » :
• Une fonction indépendante, amie d’une classe
• Une méthode d’une classe, amie d’une autre classe
• Une fonction amie de plusieurs classes
• Toutes les méthodes d’une classe amies d’une autre classe

17/10/16 143
La méthode amie

Exemple 2

17/10/16 144
Exercice 1: décrire chaque instruction
class vect main()
{ int nelem ; // nombre d'éléments
{ vect a(5) ,
double * adr ; // pointeur sur ces éléments
public : b(3);
vect (int n) // constructeur "usuel"
{…} b=a;
~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] ;
}
else cout << " on ne fait rien \n" ;
return * this ;
}
};

17/10/16
145
Exercice 2: décrire chaque instruction

template <class T>


class Vecteur { template <class T>
Vecteur<T>::Vecteur(int n)
T * v;
{
int taille;
v = new T[n];
public :
taille = n;
Vecteur(int);
}
T & operator [] (int i);
};
template <class T> T &
Vecteur<T>::operator [] (int i)
{
return v[i];
}

17/10/16
146
Exercice 3

n  On souhaite pouvoir déclarer un vecteur soit en fournissant explicitement


ces 2 composantes, soit en ne fournissant aucune, auquel cas le vecteur crée
possédera deux composantes nulles

n  Ecrire le ou le(s) constructeur(s) correspondant(s) :

q  En utilisant des fonctions membres surdéfinies

q  En utilisant une seule fonction membre

17/10/16 147
Exercice 4
n  Introduire une fonction membre nommée coïncide permettant de savoir si
deux vecteurs ont même composantes :

q  En utilisant une transmission par valeur

q  En utilisant une transmission par adresse

q  En utilisant une transmission par référence

n  Si v1 et v2 désignent deux vecteurs de type vecteur comment s’écrit le test


de coïncidence de ces 2 vecteurs dans chacun des 3 cas considérés.

17/10/16 148
L’héritage en C++

17/10/16 149
L’héritage en C++
n  Le troisième aspect essentiel des objets est la notion d’héritage
n  L’héritage est une technique extrêmement efficace permeMant
l’enrichissement des classes par la création de classes plus
spécifiques, appelées sous-classes, à partir de classes plus générales
déjà existantes, appelées sur-classes.

17/10/16 150
L’héritage en C++
n  Plus précisement, lorsqu’une sous-classe est définie [à partir d’une
sur-classe], elle va hériter de l’ensemble des aMributs et méthodes
de sa sur-classe, c’est-à-dire que ces aMributs et méthodes seront
disponibles pour les instances de la sous-classe, sans qu’il soit
nécessaire de les redéfinir explicitement.

17/10/16 151
L’héritage en C++

17/10/16 152
L’héritage en C++
n  Dans les objets tels que nous les avons vus jusqu’à maintenant,
l’ensemble des propriétés était rendues systématiquement
accessibles [par le biais du mot-clef public].

n  Dans ce cas, il est possible, depuis n’importe quel endroit du
programme, d’invoquer une méthode et de lire ou modifier la
valeur d’un aMribut.

n  CeMe politique étant contraire aux objectifs de l’encapsulation, nous
allons voir comment limiter l’accès aux propriétés d’une classe par
un mécanisme de masquage d’information.

17/10/16 153
L’héritage en C++
n  On définit trois niveaux d’accès possibles aux constituants
d’une classe:

q  le niveau public (public): visibilité totale;
q  le niveau protégé (protected): visibilité restreinte aux méthodes de la
classe et de sa descendance;
q  le niveau privé (private): visibilité strictement restreinte aux
méthodes de la classe

17/10/16 154
L’héritage en C++

n  Chaque niveau d’accès est introduit par un mot-clef


précédant les propriétés auxquelles il se rapporte:

17/10/16 155
L’héritage en C++
n  Les propriétés définies comme protégées ne sont
accessibles que pour les méthodes de la classe et de sa
descendance.
n  Le niveau protégé correspond donc à une extension du
niveau privé aux propriétés des sous-classes

17/10/16 156
L’héritage en C++
n  Restriction des accès lors de l’héritage
n  Il est possible de modifier les niveaux d’accès lors de
l’héritage; les propriétés héritées peuvent avoir [dans les
sous-classes] des niveaux d’accès différents de ceux
définis dans la sur-classe.
n  Le niveau d’accès souhaité pour les propriétés héritées
est spécifié en préfixant l’identificateur de la classe
parente par l’un des 3 mots-clef désignant les niveaux
d’accès:

17/10/16 157
L’héritage en C++
n  La table ci-dessous résume les changements de niveaux
d’accès aux propriétés héritées, en fonction du niveau
initial et du type d’héritage:

17/10/16 158
L’héritage en C++
n  Les propriétés «publiques» sont celles qui doivent être
accessibles pour les utilisateurs des instances d’une
classe; elles constituent de ce fait l’interface de
communication définie pour ces instances.
n  Les propriétés «protégées» sont celles que le concepteur
de la classe met à disposition des programmeurs pour
d’éventuelles modifications [par héritage] de ceMe classe
(enrichissement); elles constituent de ce fait l’interface de
programmation définie pour ceMe classe.
n  Les propriétés «privées» sont celles qui constituent la
structure interne de la classe, que le concepteur ne veut
pas rendre visible.

17/10/16 159
Exemple : classe dérivée
class Employe {
public:
Employe(string nom_employe, double salaire_initial);
void set_salaire(double nouveau_salaire);
double get_salaire() const;
string get_nom() const; héritage
private:
string nom;
double salaire;
};
class Directeur : public Employe {
public:
Directeur(string nom_employe, double salaire_initial);
void ajouter_employe(Employe* employe);
Employe get_employe(string nom) const;
private:
/* Collection d’employés */ employes_supervises;
};
Attribut spécifique à
l’héritier
Nouvelle méthode
17/10/16
160
Instanciation d’une classe dérivée

Employe P1("Ali",100);
Employe P2("Hédi",120); P1
Employe P3("Amira",110); Ali
Directeur D("Salah",130); 100

D.ajouter_employe( &P1);
D.ajouter_employe( &P2);

D P2 P3
Salah Hédi
120 Amira
130 110

17/10/16
161
Exemple : visibilité

class A {
private : class B : public A {
int i; public :
public : void f()
int j; {
protected : void main() i = 0;
int k; { j = 0;
}; A a; k = 0;
a.i = 0; }
a.j = 0; };
a.k = 0;
}

17/10/16
162
Exemple : Horloge

n  Soit la classe Horloge, qui permet


d’obtenir l’heure locale, de deux façons:

F  normale : (23:45)
F  à l’américaine [am/pm] (pm 11:45)

17/10/16
163
Cas : Horloge sans héritage

void Horloge::afficher()
class Horloge {
{
CC hh,mm;
if ( a_americaine)
bool a_americaine;
// am h:m ou pm h:m
public :
else
Horloge(int h, int m
// h:m
bool americaine = false)
}
:hh(h,24),mm(m,60)
{a_americaine = amercicaine;}
void operator ++(); void main()
int valh(); {
int valm(); Horloge H1(22,50,true);
void afficher(); Horloge H2(23,55,false);
}; }

17/10/16
164
Cas : Horloge avec héritage

class Horloge {
Horloge CC hh,mm;
public :
Horloge(int h, int m);
int valh();
Clock
int valm();
void afficher();
class Clock : public Horloge };
{
void main()
public :
{
Clock(int h, int m);
Horloge H1(22,50);
...
Clock H2(23,55);
};
}

17/10/16
165
Redéfinition des méthodes de base

•  Les méthodes de la classe de base peuvent être


redéfinies dans la classe dérivée.

•  Les méthodes redéfinies de la classe de base


demeurent accessibles via l'opérateur de
résolution de portée ("::").

17/10/16
166
Cas : Clock – classe dérivée

void Clock::afficher()
class Clock : public Horloge
{
{
if ( valh() < 12 )
public :
// am h:m
Clock(int h, int m);
else
void afficher ();
// pm h-12:m
};
}

void main()
{
Clock H1(22,50);
H1.afficher();
H1.Horloge::afficher();
}
17/10/16
167
Exemple :
Redéfinition de méthodes
void Horloge::afficher()
{ cout<< valh() << ":" << valm() << endl; }

void Clock::afficher()
{
if ( valh() < 12 ) {
cout << "am ";
Appel de la fonction
Horloge::afficher();
afficher() du parent
} else {

cout << "pm " << valh() -12 << ":" << valm() << endl;
}

17/10/16
168
Redéfinition des membres données d’une
classe dérivée
class A
{ ..... NB. le membre a défini dans B
int a ; class B : public A s'ajoute au membre a hérité de
char c ; { float a ; A;
..... ..... il ne le remplace pas.
}; };

main()
{ B b;
b.a; // fait référence au membre a de type float de b.
b.A::a; // fait référence au membre a de type int de a.
};

17/10/16
169
Redéfinition et surdéfinition
class A
lorsqu’une fonction est redéfinie
{ public : dans une classe dérivée, elle
void f(int n) { ..... } class B : public A masque une fonction de même
void f(char c) { ..... } { public : signature de la classe de base.
// f est surdéfinie dans A void f(float x) { ..... }
}; // on ajoute une troisème
définition dans B
};
main()
{ int n ; char c ; A a ; B b ;
a.f(n) ; // appelle A:f(int) (règles habituelles)
a.f(c) ; // appelle A:f(char) (règles habituelles)
b.f(n) ; // appelle B:f(float) (alors que peut-être A:f(int) conviendrait)
b.f(c) ; // appelle B:f(float) (alors que peut-être A:f(char) conviendrait)
}
17/10/16
170
Méthodes non héritées

Les classes dérivées n’héritent pas :


•  Des constructeurs
(défaut, paramètres, copie);
•  Du destructeur;

•  De l’opérateur d’affectation;

•  Des relations d’amitié.

17/10/16
171
Constructeur et destructeur
n  Lors de la création d’un objet d’une classe dérivée, les
constructeurs sont appelés dans l’ordre suivant:
q  Les constructeurs des objets attributs de la classe
de base,
q  Le constructeur de la classe de base,

q  Les constructeurs des objets attributs de la classe


dérivée;
q  Le constructeur de la classe dérivée.

Les destructeurs sont appelés en ordre inverse des


constructeurs.
17/10/16
172
Exemple : constructeur

void main()
class A {
{
public :
B b;
A() { cout << "A::A()" << endl;}
cout << "**" << endl;
~A() { cout << "A::~A()" << endl;}
}
};

class B : public A { A::A()


public : B::B()
B() { cout << "B::B()" << endl;} **
~B() { cout << "B::~B()" << endl;} B::~B()
}; A::~A()

17/10/16
173
Constructeur et destructeur

17/10/16 174
Transmission d'informations entre
constructeurs
class point class pointcol : public point
{… {…
public : public :
point (int , int ); pointcol (int, int, short) ;
… ~pointcol ();
~point (); …
… };
}; …
pointcol::pointcol (int abs, int ord,
short cl) : point (abs, ord)
{

}

17/10/16
175
Constructeur et destructeur

17/10/16 176
Constructeur et destructeur

17/10/16 177
Constructeur de Horloge &
Clock
Horloge::Horloge(int h, int m)
: hh(h), mm(m)
{

Clock::Clock(int h, int s) : Horloge(h,s)


{

17/10/16
178
CAS DU CONSTRUCTEUR DE
RECOPIE
n  Le constructeur de recopie (qu'il s'agisse de ce lui
par défaut ou de ce lui qui est fourni
explicitement) est appelé en cas :
q  d'initialisation d'un objet par un objet de même
type ,
q  de transmission de la valeur d'un objet en argument

ou en retour d'une fonction.

17/10/16 179
CAS DU CONSTRUCTEUR DE
RECOPIE
class A { ... } ;
class B : public A { ... } ;
void fct (B) ; // fct est une fonction recevant un argument de type B
...
B b1 (...) ; // arguments éventuels pour un "constructeur usuel"
fct (b1) ; // appel de fct à qui on doit transmettre b1 par valeur, ce
//qui implique l'appel d'un constructeur de recopie de la classe B

Cas1. La classe dérivée (B) n'a pas défini de constructeur de recopie

Cas2. La classe dérivée (B) a défini un constructeur de recopie

17/10/16 180
Cas1. La classe dérivé e (B) n'a pas défini de
constructeur de recopie
n  Il y a appel du constructeur de recopie par défaut de B: la recopie
se fait membre par membre :
q  La "partie" de b1 appartenant à la classe A sera traitée comme
un membre de type A.
q  Il y aura donc appel du constructeur de recopie de A pour tous

les membres donnée correspondants.


n  Si A a défini un tel constructeur, il sera appelé ; dans le cas
contraire , on se servira du constructeur de recopie par défaut
de A.

Cas2. La classe dérivée (B) a défini un


constructeur de recopie
n  le constructeur de recopie de B est appelé

17/10/16 181
Héritage multiple

n  Une classe héritière possède plusieurs classes parentes


class B :
class A :
{public :
{public :
int g() {return 2*i;}
int f() {return i;}
private :
private :
int j;
int i;
};
};
class C : public A, public B
{
public :
int h();
}

17/10/16
182
Pb1 :
Que se passe-t-il si un même identifiant est utilisé dans deux classes parentes ?

class B :
class A :
{public :
{public :
int f() {return 2*i;}
int f() {return i;}
private :
private :
int i;
int i;
};
};
class C : public A, public B
{
public :
int g();
}; Redéfinir f() dans C

17/10/16
183
Pb1 :
Que se passe-t-il si un même identifiant est utilisé dans deux classes parentes ?

class B :
class A :
{public :
{public :
int f() {return 2*i;}
int f() {return i;}
private :
private :
int i;
int i;
};
};
class C : public A, public B
{
public :
l’opérateur de portée
int g();
}; c.B::afficher()

17/10/16
184
Pb1 :
Que se passe-t-il si un même identifiant est utilisé dans deux classes parentes ?

class B :
class A :
{public :
{public :
int f() {return 2*i;}
int f() {return i;}
private :
private :
int i;
int i;
};
};
class C : public A, public B
{
public :
int g();
};
using NomSuperClasse::NomAttributOuMethodeAmbigu ;

17/10/16
185
Exemple : pointcoul hérite de point et de coul
Class coul
class point
{ short couleur;
{int x, int y; public :
public : coul (int );
point (int , int ); ~coul();
~point (); Affiche();
Affiche(): };
}; Class pointcoul : public point, public coul
{…
public :

pointcoul (int abs, int ord, int cl) : point (abs,


ord), coul (cl) { … }
~pointcoul ();
void affiche ()
{ point::affiche () ; coul::affiche () ;}
17/10/16 }; 186
Pb2 :
Héritage répété : un hydravion hérite des classes d’avion et bateau qui toute deux héritent de véhicule. Que
deviennent les caractéristiques de la classe répétée ? Sont-elles dupliquées ou fusionnées ?

class A {
public :
int f() {return i;}
};
class B : public A { class C : public A {
}; };

class D : public B, public C {


public :
int g(); Héritage virtuel :
}; class B : virtual public A

17/10/16
187
Les classes virtuelles
n  Il peut se produire qu’une super-classe soit incluse plusieurs
fois dans une hiérarchie à héritage multiple :

•  Les attributs/méthodes de la super-classe seront inclus plusieurs fois !


•  Chaque objet de la classe Ovovivipare possédera deux copies des attributs
de la classe Animal .
Les classes virtuelles

n  j’ai une tête à cornes et une tête de poisson !

189
Les classes virtuelles
n  Pour éviter la duplication des attributs d’une super-classe
plusieurs fois incluse lors d’héritages multiples, il faut déclarer
son lien d’héritage avec toutes ses sous-classes comme virtuel.
n  Cette super-classe sera alors dite « virtuelle » (à ne pas confondre
avec classe abstraite !!)
n  Syntaxe : class NomSousClasse : public virtual
NomSuperClasseVirtuelle
n  Exemple :

A noter que c’est la classe pouvant être héritée plusieurs fois qui est
virtuelle (i.e. ici la super-super-classe) et non pas directement les
classes utilisées dans l’héritage multiple (i.e. les super-classes).
Les classes virtuelles

n  Un seul objet de la super-classe Animal est hérité par l’héritage


commun des sous-classes Ovipare et Vivipare .
Les classes virtuelles

17/10/16 192
Conclusion
•  Les classes dérivées sont un mécanisme simple pour
définir une nouvelle classe en ajoutant des facilités à une
classe existante sans reprogrammer ou recompiler la classe
de base.

•  En utilisant les classes dérivées d’une classe existante, on


définit une interface commune aux classes dérivées de telle
manière que les objets de ces classes dérivées sont
manipulés de façon identique par certaines parties du
programme.

Réutilisation
•  On peut ainsi utiliser l’héritage pour les besoins de
généralisation, de réutilisation.

17/10/16
193
Le polymorphisme en C++

17/10/16 194
Introduction

prenons exemple des personnages de jeux vidéo

Personne

Guerier

Magicien

Vouleur

sorcier

17/10/16 195
Introduction
Class Personnage

Class Voleur Class Magicien Class Guerrier

Class Sorcier

17/10/16
Introduction
n  Supposons qu’on veuille écrire un code pour un personnage
qui va rencontrer des magiciens, des guerrier,… (supposons
que l’on ai une collection de personnages qu’il va rencontrer)
n  Que faire sachant que la façon dont un Personnage en
rencontre un autre peut prendre plusieurs formes : le saluer
( Magicien ), le frapper ( Guerrier ), le voler ( Voleur )... ??!!!!

n  Grâce à l’héritage, le Une


même code pourra être appliqué à un
fonction qui va chercher le type du
Magicien, un Guerrierpersonnage
, ... qui sont des Personnages
et appeler .
sa fonction !!!!!!!!!!!!!!

17/10/16 197
Introduction
n  Rappel de notions d’héritage à ne pas oublier
  Dans une hiérarchie de classes, la sous-classe hérite de la
super-classe :
˜  tous les attributs/méthodes (sauf constructeurs et
destructeur)
˜  le type : on peut affecter un objet de type sous-classe à
une variable de type super-classe :
Personnage p;
Guerrier g;
// ...
p = g;

L’héritage est transitif : un Sorcier est un Magicien qui est un Personnage

17/10/16 198
Class Personnage Introduction
string nom
int energie
int duree_vie
Rencontrer(Personnage&)
{ saluer() ;}

Class Voleur Class Magicien Class Guerrier

Voler(Personnage&) Arme arme


Baguette baguette Rencontrer(Personnage&)
Rencontrer(Personnage&)
{Voler() ;} {frapper()}

Class Sorcier
Baton baton
Rencontrer(Personnage&)
{Envouter()}
17/10/16 199
Introduction
Etudions le pseudo code d’un joueur qui rencontrera des
personnes
RecontrerPersos()
Si le personnage posséde
{ sa propre fonction
Personnage Joueur; rencontrer il l’utilise
vector<Personnage> autres ; sinon il utilisera la
for (int i=0; i<autres.size();i++) fonction de la super
classe
Autres.rencontrer(joueur);
}
Pas de
fonction
rencontrer
donc :
Saluer
Voler Frapper Envouter

17/10/16 200
Introduction

  Si grâce à l’héritage on peut avoir des fonctions différentes


selon le personnage pourquoi ne pas avoir un mécanisme
qui permet d’avoir une fonction générique appliquée à tous
les personnages et qui s’adaptera au type du personnage en
ayant un comportement différent, propre à chacun

POLYMORPHISME
17/10/16 201
Polymorphisme: Définition

17/10/16
202
Polymorphisme: Définition
n  Le polymorphisme est un moyen de manipuler des objets
hétéroclites de la même manière, pourvu qu’ils disposent
d’une interface commune.
n  Un objet polymorphe est un objet susceptible de prendre
plusieurs formes pendant l’exécution.
n  Le polymorphisme représente la capacité du système à choisir
dynamiquement la méthode qui correspond au type de l’objet
en cours de manipulation.
n  Le polymorphisme est implémenté en C++ avec les fonctions
virtuelles (virtual) et l’héritage.

17/10/16 203
La résolution des liens
n  Une instance de sous-classe B est substituable à une instance
de super-classe A .
n  Que se passe-t-il lorsque B redéfinit une méthode de A ?

Quel fonction rencontrer


sera exécutée ??
Celle de Personnage ou
celle de Guerrier

Autrement dit, est ce que c’est le type de la variable qui prime dans l’affectation de la fonction à
exécuter ou c’est le type de l’objet effectivement contenu dans la variable ??

17/10/16 204
La résolution des liens
n  En C++, c’est le type de la variable qui détermine la méthode à
exécuter :
q  résolution statique des liens

Problème ?!!!! Que faire ? Résolution dynamique des liens

17/10/16 205
Résolution dynamique des liens

n  Il pourrait dans certains cas sembler plus naturel de choisir la


méthode correspondant à la nature réelle de l’instance.
n  Dans ces cas, il faut permettre la résolution dynamique des
liens :
q  Le choix de la méthode à exécuter se fait à l’exécution,

en fonction de la nature réelle des instances


n  2 ingrédients pour cela :

références/pointeurs et méthodes virtuelles

17/10/16 206
Déclaration des méthodes virtuelles
n  En C++, on indique au compilateur qu’une méthode peut faire
l’objet d’une résolution dynamique des liens en la déclarant
comme virtuelle (mot clé virtual )
n  Cette déclaration doit se faire dans la classe la plus générale
qui admet cette méthode (c’est-à-dire lors du prototypage
d’origine)
n  Les redéfinitions éventuelles dans les sous-classes seront aussi
considérées comme virtuelles par transitivité.
  Syntaxe :
virtual Type nom_fonction(liste de paramètres) [const];
class Personnage {
  Exemple : virtual void rencontrer(Personnage& autre)
const
{ cout << "Bonjour !" << endl; }
};
17/10/16 207
Que faut-il ajouter ici
NOOOON
Class Personnage Exemple
pour
Ca seque
faitle string nom Et pour la transitivité
polymorphisme
implicitement mais si int energie
alors? Comment ca
marche ? int duree_vie
vous voulez le faire se passe ?!! Doit-on
tous seul ne changevirtual Rencontrer(Personnage&) définir toute les sous
virtual { saluer() ;}
rien classes contenant la
méthode virtuelle
comme vrtual ?
Class Voleur Class Magicien Class Guerrier

Voler(Personnage&) Arme arme


Baguette baguette Rencontrer(Personnage&)
Rencontrer(Personnage&)
{Voler() ;} {frapper()}

Class Sorcier
Baton baton
Rencontrer(Personnage&)
{Envouter()}
17/10/16 208
Est-ce que cet exemple est correct ?
Exemple
&
&

g
un
« sangoku » Passage par valeur donc
200 une copie d’un objet de « sangoku »
kamehameha type Personnage 200 Plus de
« un=g» Polymorphisme,
Guerrier Personnage Que faire !!!!!

17/10/16 209
N’oubliez jamais
n  Il pourrait dans certains cas sembler plus naturel de choisir la
méthode correspondant à la nature réelle de l’instance.
n  Dans ces cas, il faut permettre la résolution dynamique des
liens :
q  Le choix de la méthode à exécuter se fait à l’exécution, en
fonction de la nature réelle des instances

n  2 ingrédients pour cela :


références/pointeurs et méthodes virtuelles

17/10/16 210
Destructeur virtuel
•  Un destructeur peut être défini comme virtuel. Cependant, un
constructeur ne pourra jamais l’être.
n  Contexte
•  Destruction d’un objet de la classe dérivée qui est référencé
par un pointeur de la classe de base,
n  Résultat
•  Si le destructeur est virtuel
  alors le destructeur de la classe dérivée est appelé .
  Sinon seul le destructeur de la classe de base est appelé.

211
Destructeur virtuel (exemple)
ObjetGeo *OB = new Cube();

class ObjetGeo { class ObjetGeo {


public: public:
~ virtual ObjetGeo(); ~ ObjetGeo();
}; };
class Cube { class Cube {
public: public:
~ Cube(); ~ Cube();
}; };

delete OB;

Le destructeur de Cube est appelé en premier seul le destructeur de


+ le destructeur de ObjetGeo sera appelé. ObjetGeo sera appelé.

212
Méthodes virtuelles : résumé et compléments

n En résumé :
Lorsqu’une méthode virtuelle est invoquée à partir d’une
référence ou d’un pointeur vers une instance, c’est la méthode
du type réel de l’instance qui sera exécutée.
Attention
 Il est conseillé de toujours définir les destructeurs comme virtuels
 Un constructeur ne peut pas être virtuel
 L’aspect virtuel des méthodes est ignoré dans les constructeurs.

17/10/16 213
Abstraction et polymorphisme

Contexte :
n Au sommet d’une hiérarchie de classe, il n’est
pas toujours possible de : donner une définition
générale de certaines méthodes, compatibles avec
toutes les sous-classes, même si l’on sait que toutes
ces sous-classes vont effectivement implémenter
ces méthodes

17/10/16 214
Abstraction et polymorphisme
Peut-on définir la fonction
n  Exemple surface de n’importe quelle
forme fermée d’une manière
générique ?

  Solution : déclarer la méthode surface comme virtuelle pure

17/10/16 215
Méthodes virtuelles pures : définition et syntaxe
Une méthode virtuelle pure, ou abstraite :
n sert à imposer aux sous-classes (non abstraites) qu’elles doivent redéfinir la
méthode virtuelle héritée
n est signalée par un = 0 en fin de prototype,

n est, en général, incomplètement spécifiée : il n’y a très souvent pas de


définition dans la classe où elle est introduite (pas de corps).
Syntaxe :
n virtual Type nom_methode(liste de paramètres) = 0;

  Exemple :

17/10/16 216
Classes abstraites : Définition
n  Une classe abstraite est une classe contenant au moins
une méthode virtuelle pure.
n  Elle ne peut être instanciée
n  Ses sous-classes restent abstraites tant qu’elles ne
fournissent pas les définitions de toutes les méthodes
virtuelles pures dont elles héritent. (En toute rigueur :
tant qu’elles ne suppriment pas l’aspect virtuel pur (le
« =0 »).)

17/10/16 217
Classes abstraites : exemple
n  Supposons que l’on est définit la classe personnage comme
suit :

Et qu’une équipe de développeur crée la sous classe Guerrier de


Personnage de la façon suivante :

Que se passera t-il d’après vous s’ils ont oublié de définir la méthode
afficher ?
Erreur de compilation avec le message : cannot allocate an object of abstract type ‘Guerrier’ because the
following virtual functions are pure within ‘Guerrier’:
virtual void Guerrier::afficher()

17/10/16 218
Classes abstraites : exemple

n  Que se passe t-il avec les classes Cercle et Polygone ?


  Cercle définit la méthode surface, elle n’est plus abstraite
  Polygone ne définit pas la méthode surface, elle reste abstraite
17/10/16 219
Masquage, substitution et surcharge
n  Nous avons rencontré trois concepts différents :
q  la surcharge (overloading) de fonctions et de méthodes ;
q  le masquage (shadowing) (en particulier de méthodes) ;
q  la substitution (un nouveau concept (ou redéfinition, overriding)), dans
les sous-classes, de nouvelles versions de méthodes virtuelles.

Pour les méthodes virtuelles, on


pourrait donc avoir les trois ?!
Mais qui est quoi exactement ?

17/10/16 220
Masquage, substitution et surcharge : définitions

n  surcharge : même nom, mais paramètres différents, dans la même portée


(Note : en C++, il ne peut y avoir surcharge que dans la même portée.

n  masquage : entités de mêmes noms mais de portées différentes, masqués


par les règles de résolution de portée. Pour les méthodes :
q  Attention aux subtilités : une seule méthode de même nom suffit à les
masquer toutes, indépendamment des paramètres ! (ca n’existe pas en
JAVA)

n  substitution/redéfinition des méthodes virtuelles


q  résolution dynamique : c’est la méthode de l’instance qui est appelée (si
pointeur ou référence)
q  Si l’on redéfinit qu’une seule méthode (virtuelle) surchargée, alors les
autres sont masquées.

17/10/16 221
Masquage, substitution et surcharge : exemple

17/10/16 222
Masquage, substitution et surcharge : exemple

Lorsqu’il n’y a
pas de
polymorphisme
c’est une
résolution
statique des
liens
B::m1(string)
A::m1(int) N’oubliez pas que pa est un pointeur sur A

A::m1(int)

17/10/16 223
Constructeur par recopie

17/10/16 224
17/10/16 225
17/10/16 226
Pointeur this
n  comment les fonctions membres, qui appartiennent à la classe, peuvent
accéder aux données d'un objet, qui est une instance de cette classe ?

q  À chaque appel d'une fonction membre, le compilateur passe


implicitement un pointeur sur les données de l'objet en paramètre.
q  Le pointeur sur l'objet est accessible à l'intérieur de la fonction membre. Il
porte le nom « this »

q  *this représente l'objet lui-même. Fait référence à l’objet pour lequel une
fonction membre a été appelé

q  Dans une fonction non-static, le mot clé this est un pointeur sur l’objet
pour lequel la fonction a été appelée.

17/10/16 227
Libraries

17/10/16
228
Abstraction et Encapsulation
En plus du regroupement des données et des traitements relatifs à
une entité, l’encapsulation permet en effet de définir deux niveaux
de perception des objets :
n niveau externe : partie « visible » (par les programmeurs-
utilisateurs) :
q  l’interface :
n  prototypes de quelques méthodes bien choisies
n  résultat du processus d’abstraction
n niveau interne : détails d’implémentation
q  corps :
n  méthodes et attributs accessibles uniquement depuis l’intérieur de l’objet (ou
d’objets similaires)
n  définition de toutes les méthodes de l’objet

17/10/16 229