Programmation orientée objet C++ et java

Transcription

Programmation orientée objet C++ et java
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Institut national d
des sciencces appliquées
Version 4.2
Notes de cours sur la
programmation
p
g
orientée objets
j
en C++ et Java
Eric Anquetil ([email protected])
1
03/09/2010
Eric Anquetil ([email protected])
Notes de cours sur la
programmation orientée objets
en C++ et Java
30
31
2
► Préambule
32
Une première approche
des concepts objets
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
33
34
Vers la programmation objet
Programmation modulaire (encapsulation)
C→C++
Abstraction de données C→C++
Abstraction de données / généricité … C→C++
Introduction à la programmation orientée objet
Concepts objets : la notion d’objet
Concepts objets : la notion de classe
Généricité : Héritage
Généricité : Héritage et Polymorphisme
Agrégation
L'approche objet
Les langages C++ et Java
► Notion d’objet et de classe en C++
Les classes - définition
Les classes - définition d’une méthode
Les classes - instanciation
Encapsulation
Constructeurs - Déclaration
Constructeurs - Définition
Constructeurs - Surcharge
Surcharge de fonction
Arguments par défaut
Membre static
Variable static
Fonction membre constante
Fonction inline
►Quelques éléments
pour programmer en C++
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
1
03/09/2010
- entrées / sorties
- string / vector
- espace de nommage
Structure générale d’un programme
Fichier d'en-tête - Commentaires
Entrées - sorties (Streams ou flots)
Entrées - sorties fichiers
Un 1er petit programme : la classe Date
Un 1er petit programme : utilisation
Classe String
Classe stringstream
Espace de nommage (définition / accès)
Espace de nommage (alias)
Préambule sur la STL … suite dans le chap. STL
Les conteneurs élémentaires
Les Vecteurs (vector)
Les Vecteurs (vector)
►Les propriétés de C++
- références / pointeurs
- surcharges d'opérateurs
- friend / classe interne
Références et Pointeurs
Passage par référence
Passage par valeur / Recopie (  )
Passage par référence / Pas de recopie
Retour par valeur ( recopie  )
Passage et Retour par référence
Auto-références
Passage par référence et Auto-référence
Surcharge d’opérateurs conventionnels
Conversion implicite
Définition externe étendue
Notion d’ami : Friend
Surcharge d’opérateurs et notion de Friend
Classe interne : "nested class"
►Gestion de la mémoire
- allocation
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
2
Eric Anquetil ([email protected])
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
03/09/2010
- affectation / clonage
- constructeur par recopie
Les zones mémoires
Allocation dynamique et libération
Notion de destructeur : ~X( )
Une 1ère amorce de programmation de liste
Mise en œuvre du destructeur
Allocation de n éléments
Opérateur d’ Affectation ( operator = )
Affectation en profondeur
Constructeur par recopie
Implémentation d’un constructeur par recopie
Une implémentation homogène
Une implémentation homogène
Remarques et notion de clonage
Bilan : Affectation et Constructeur par recopie
► Gestion mémoire
en Java (Rappel)
Le ramasse miette ou « garbage collector »
La méthode finalize()
►Conception objet en C++
- agrégation
- héritage
- polymorphisme
- attachement statique et dynamique
- fonction virtuelle
- classe abstraite
Abstraction - Généricité
Agrégation : classe Point / Rectangle
Agrégation : exemple de Base
Héritage : exemple de Base
Contrôle d’accès aux membres - : privé + :
publique #: protected
Contrôle d’accès à la classe de base
Constructeurs : agrégation et héritage
Redéfinition <> Surcharge
Relation entre classe de base et classe dérivée
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
Eric Anquetil ([email protected])
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
03/09/2010
Relation entre classe de base et classe dérivée
Résumé : héritage, agrégation, …
Polymorphisme : conversion entre objets
Polymorphisme : conversion entre objets
Polymorphisme : conversion entre pointeurs
Polymorphisme : conversion entre pointeurs
Fonctions virtuelles
Attachement statique et dynamique
Collection hétérogène d’objets
Classe abstraite
Destructeur virtuel
Copie en profondeur & clonage
Exemple possible de définition de figure : Figure.h
Figure.cpp
Figure_exe.cpp && résultats
►Concepts avancés en Java / C++
Un petit bilan : le modèle objet en JAVA / C++
►Héritage multiple et Interface
Héritage multiple C++ et Interface JAVA
Cas simple d’héritage multiple en C++
Héritage multiple : classe de base dupliquée
Héritage multiple : partage de classe de Base
Résolution des ambiguïtés
Utilisation de l’héritage multiple ?
►Interface Java
Interface Java
Exemple d'utilisation d'interface
Exemple d'interface : diagramme de classe
NB : Interface et héritage
Interface Versus Classe abstraite
►Classe paramétrée
notion de Template
118
119
120
121
3
Introduction : classes paramétrées
Mise en œuvre de classe template (interface .h)
Mise en œuvre de classe template (f. membres)
Template multi-type (paramétrage /type ou
/valeur)
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
4
Eric Anquetil ([email protected])
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
03/09/2010
Paramètre template par défaut
Fonction template et Spécialisation
Précautions avec «l'instanciation»
► Les Generics – en Java
Rappel
Les Generics - introduction
Les Generics – Définition de “generics”
Les Generics – Définition de “generics”
Les Generics – Héritage
Les Generics – Wildcards et Bounded Wildcards
Les méthodes Generic
►Introduction à
la librairie standard
du c++ (STL)
Introduction à la STL
Les conteneurs élementaires
Les Vecteurs
Notion d‘itérateur
Recherche - Insertion - Suppression
Les listes
Les files (queue) et piles (stack)
Conteneurs associatifs : set, map,
Les ensembles (set)
Les tables d’associations (map)
Les Objets fonction (foncteur) / operator()
Les Objets fonction / operator()
Les Objets fonction / operator() / fonction trier
(sort)
►Concepts avancés en Java
►Flots(stream) en Java
Les flots(stream) en Java : java.io.*
Les flots(stream) : flots d'octets (8 bits)
Les flots(stream) : flots de char (16 bits)
Les flots(stream) : flots de char avec tampon
Les flots(stream) : flots de données avec tampon
Les flots(stream) : flots de données avec tampon
Les flots basiques : orientés byte (octet)
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
Eric Anquetil ([email protected])
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
03/09/2010
Les flots avancés : orientés char (Unicode)
► Java 5 (Tiger) / Rappel
printf - scanner
Printf : Sortie standard formatée
le scanner : entrée formatée
►Sérialisation en Java
Sérialisation : introduction
Sérialisation : mise en œuvre automatique
Sérialisation : mise en œuvre automatique
Sérialisation : un 1er exemple
Sérialisation avec Serializable
Sérialisation : un 2ème exemple
Sérialisation : un 2ème exemple
Sérialisation : mise en œuvre manuelle
Sérialisation : manuelle / Exemple
Sérialisation : manuelle / exemple
Sérialisation : partiellement manuelle / transient
Sérialisation : partiellement manuelle / transient
Sérialisation : partiellement manuelle /
Serializable
Sérialisation : partiellement manuelle /
Serializable
Sérialisation : manuelle / exemple
Sérialisation : un premier Bilan
Sérialisation : les données statiques
Sérialisation : les données statiques / exemple
Sérialisation : les données statiques / exemple
Sérialisation : les données statiques / exemple
►Masquage / Java
Redéfinition et surcharge (pas de masquage en
Java)
Redéfinition et surcharge (pas de masquage en
Java)
►RTTI
Run Time Type Identification
184
5
RTTI et Java : getClass / getName / forName /
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
6
Eric Anquetil ([email protected])
185
186
187
03/09/2010
newInstance
RTTI et C++ : type_info / typeid
RTTI et C++ : dynamic Cast
►Égalité et
218
219
220
221
Comparaison d'objets en Java
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
222
Égalité d'objets
Égalité d'objets (surcharge de equals)
Égalité d'objets (redéfinition de equals)
Comparaison d'instances et héritage
Comparaison rigide : méthode equals()
Comparaison rigide
Comparaison souple : méthode comparable()
Comparaison : exemple de diagramme de classe
Exemple de comparaisons souples et rigides
► Gestion des exceptions
Notion d'erreur
Traitement des cas d'erreurs exceptionnelles
Exemple général sur le mécanisme d'exception
Le principe
Protocole C++ : émission d'exceptions
Protocole C++ : spécification d'exceptions
Protocole C++ : fonction terminate
Exceptions standards en C++
Capture et traitement d'exceptions
Protocole Java : lancement d'exceptions
Retransmission d’une exception
Exception standard en Java
Protocole Java : Java.lang.Throwable
Créer vos propres classes d'exceptions
Protocole Java : bloc finally
Remarques sur la gestion mémoire
Bilan sur les exceptions
►Application d’un design pattern
Mise en œuvre
du modèle « commande »
Rappels des objectifs du modèle « commande »
Mise en œuvre du undo/redo
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
Eric Anquetil ([email protected])
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
03/09/2010
Manipulation de « figures » : undo/redo
Manipulation de figures : undo/redo
Mise en œuvre du modèle « commande » / undo
Mise en œuvre du modèle « commande » / undo
Mise en œuvre du modèle « commande » / undo
Mise en œuvre du modèle « commande » / undo
Mise en œuvre du modèle « commande » / undo
Retour sur le modèle « commande » / undo
Modèle « commande » / gestion de commandes
simples
►Utilisation du modèle « Memento »
pour la mise en place du « Undo »
Description du Modèle “Memento”
Exemple d’utilisation : Undo pour la manipulation
d’objets de type A
La classe Memento - MementoA
La classe Auteur – classe A
Le Surveillant - CommandA
Le Surveillant – CommandA / Code
Utilisation /Test
► La notion de frameworks
Concept de « framework »
Concept de « framework »
► l'Architecture
Document / Vue
des MFC
239
240
241
242
243
244
2 mots sur l'Architecture Document / Vue des
MFC
Exemple de Modèle Document / Vue
Les interdépendances
La notion de document
La notion de vue
► Exemple de conception
d’un Framework
245
246
247
7
Exemple de conception d’un Framework complet
Méthodologie : organisation des classes
Abstraction / Utilisation des concepts génériques
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
8
Eric Anquetil ([email protected])
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
03/09/2010
Prise en compte des types utilisateurs
Typage dynamique (RTTI)
Framework : notion d'interface graphique
Diagramme de classe / exemple
Autonomie du framework et notion de Canvas
Bilan sur la notion de Framework
► Introduction à l'interfaçage
de Java avec des librairies C/C++
La JNI : Java Native Interface
JNI : Java Native Interface
JNI : les possibilités d'interfaçage
JNI : Les différentes étapes de l'interfaçage
JNI : Les différentes étapes de l'interfaçage
JNI : Les différentes étapes de l'interfaçage
JNI : Les différentes étapes de l'interfaçage
JNI : envoie de String
JNI : accès aux attributs d'une classe
JNI : accès aux attributs d'une classe / objet
JNI : invocation d'une méthode Java
JNI : fonctionnalités avancées
►►►►
Annexes
et Rappels
► Bref introduction
à Java 5 (Tiger)
Introduction : Java5 (Tiger)
Autoboxing et Auto-Unboxing des types primitifs
Itérations sur des collections : nouvelle boucle for
Type énuméré : enum
Nombre d’arguments variable pour une méthode
Les imports statiques
► Clonage et copie en profondeur
Notion de copie en profondeur
Notion de copie en profondeur
La méthode clone( ) de la classe Object
Mise en œuvre de la méthode clone()
Mise en œuvre de la méthode clone()
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
Eric Anquetil ([email protected])
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
9
03/09/2010
Clonage et héritage
Remarques sur le clonage en Java
► Classe interne
Classe interne : inner class
Classe interne : membre d'une classe
Classe interne : locale
Classe interne : anonyme
Classe interne : anonyme
► Introduction aux
Windows forms
Les Windows forms
Deux mots sur .net et C++ managé
Une application WinForms : présentation
Une application WinForms : le projet
Une application WinForms : EDI et Design
Une application WinForms : Ajout de contrôles
Une application WinForms : Le code généré
Une application WinForms : Le code généré
Réactions aux évènements
Introduction d’une seconde « Form »
Introduction d’une seconde « Form »
Exemple de classe Rectangle / Carre
► Initiation à
visual C++ / MFC
Visual C++
Exemple de types de projets
Exemple : une application graphique simple
1ère étape : composants graphiques de l'IHM
2ème étape : réaction à un évènement
Utilisation du Class Wizard
Écriture du code des méthodes
Initialisation par l'IHM de l'Edit box
"IDC_Compteur"
Création d'un fenêtre de dessin
Création d'une vue (fenêtre fille du cadre)
Affichage fenêtre depuis la boîte de dialogue
Échange de données Fenêtre / Boîte de dialogue
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
10
Eric Anquetil ([email protected])
314
315
03/09/2010
Quelques Remarques ....
Quelques Remarques ....
Eric Anquetil ([email protected]) / CPOO C++ et Java / Version
4.2 / 02/09/2010
11
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
Version 4.2
Notes de cours sur la
programmation orientée objets
en C++ et Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Préambule
Une première approche
des concepts objets
Vers la programmation objet
Programmation modulaire (encapsulation) C
4
™
™
La programmation fonctionnelle ou procédurale
« l’accent est mis sur l’exécution du programme »
Exemple C :
gestion d'une pile de car
ƒ Une première organisation des traitements
ƒ Définition de fonctions qui admettent des arguments et rendent des valeurs
ƒ Chaînage et réutilisation de fonctions pour en définir d'autres
™
La programmation modulaire (encapsulation)
ƒ Objectif : centraliser les traitements associés à un type, autour du type
ƒ Encapsulation : les fonctions et les données associées sont rassemblées dans
une même unité physique : le module (définition d’une interface. ex: .h)
ƒ Les utilisateurs du module peuvent ignorer les détails de l’implémentation
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Fonctions interdépendantes …
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Découpage fonctionnel permettant de factoriser certains comportements
ƒ Mais maintenance complexe en cas d'évolution
// Pile.h (interface (.h) du module pile)
// donnée de la pile
Char*
C;
int
taille ;
// … +chaînage
// traitements associés à la pile de car
void empiler(char);
char depiler();
...
// Pile.c
// implémentation de la pile de caractères
void empiler(char c) {…}
char depiler() {…}
...
™
Utilisation du module "Pile"
// Module TOTO
// utilisation de la pile de caractères
#include "pile.h"
empiler (‘a’); ...
[email protected]
3
Abstraction de données C
Abstraction de données / généricité … C
6
™
Vers l’abstraction de données
™
// Utilisation de la pile
#include "pile.h"
type_pile p1;
p1=créer_pile() ;
empiler(&p1, ’a ’) ;
// ...
ƒ Difficultés :
ƒ Gestion de ce nouveau type : allocation, désallocation des variables
nécessaires à son implémentation, etc.
ƒ Enrichissement du type utilisateur peut entraîner une refonte du
programme…
Une pile générique … gestion encore plus difficile
ƒ Si on ajoute ou on supprime
un type de Pile, il faut
réécrire le programme...
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
// Pile.h (interface (.h) du module pile)
// donnée de la pile
typedef struct S_type_pile {
char*
C;
int
taille ; … // … +chaînage
} type_pile ;
// traitements associés la pile de car
type_pile
créer_pile();
void
empiler(type_pile*, char);
char
depiler(type_pile*);
// ...
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
« pour manipuler plusieurs piles =>abstraire la notion
de pile comme un nouveau type utilisateur. »
ƒ On a besoin « d’aide »
pour consolider ce type
de programmation
Î langage objet (Cĺ&
// Pile.h (interface (.h) du module pile)
// donnée de la pile
typedef struct S_type_pile {
char*
Pc ;
Int*
Pi ;
int
taille ;
type
t;
// type de la pile
... // … +chaînage
} type_pile ;
enum type {PileCar, PileInt};
™
Bilan (Cĺ&
ƒ Centraliser (données et
traitements) associés à
un type
… Besoin de la notion
d'objets,
de classes,
de polymorphisme…
// traitement conditionné par le type …
void afficher_pile(type_pile P)
{
switch (P.type) {
// traitement en fonction du type ….
}
}
[email protected]
5
Introduction à la programmation orientée objet
Concepts objets : la notion d’objet
7
8
™
programmation orientée objet est axée
ƒ Un objet est constitué
ƒ 1/ sur les données / encapsulées autour d’un concept appelé : « objet »
ƒ d’une collection d’attributs (définissant l’état de l’objet)
ƒ 2/ sur les traitements qui y sont associés.
ƒ et de méthodes associées
(définissant son comportement)
ƒ l’analyse, la conception, le codage.
Ø cohérence pendant le développement
Ø Facilite la réalisation de programme :
développement et exploitation de gros logiciels
de base
ƒ abstraction, encapsulation, héritage, polymorphisme, agrégation
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
modèle objet est utilisable aussi bien pour
™ Principes
nom de l'objet
ƒ les méthodes constituent l’interface
de communication
titre = "le langage C++"
attributs
ƒ la manipulation d’un objet peut s’opérer
indépendamment de sa mise en œuvre
(structure interne)
type de l'objet
livreNo1 : Livre
ƒ Modularité et masquage de l’information
Ø Les langages objets (C++, java, ...) facilitent
grandement cette approche de programmation.
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Ø La complexité des programmes est alors
répartie sur chaque « objet ».
™ Le
Les objets / Encapsulation
auteur = "Stroustrup"
nbPage = 1096
méthodes
emprunter()
rendre()
Attributs
Les attributs sont « encapsulés » dans l’objet et
par conséquent protégeables contre des accès
non autorisés
[email protected]
™ La
Concepts objets : la notion de classe
Généricité : Héritage
10
™
™
Les classes / Abstraction de données :
« On peut raffiner la notion
d’abstraction de données en
utilisant la notion d ’héritage »
ƒ Une classe permet par instanciation de construire des objets
« L’objet livreNo1
est
une instance
de la classe Livre »
livreNo1 : Livre
titre = "le langage C++"
auteur = "Stroustrup"
nbPage = 1096
emprunter()
rendre()
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Un objet est l’instance d’une classe
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
« Une classe est un prototype
qui définit la nature des méthodes et des d’attributs
communs à tous les objets d’un certain type. »
™
Spécialisation
Notion d’héritage
relation
d'héritage
ƒ Une classe (dérivée)
peut être spécialisée
à partir d’une autre
classe (de base)
ƒ Chaque sous classe
(ou classe dérivée) hérite
de toutes les
caractéristiques
de la classe de base
(attributs et méthodes)
ƒ Une classe dérivée peut
ajouter ou modifier les
attributs et méthodes
de la classe de base.
Généralisation
[email protected]
9
Généricité : Héritage et Polymorphisme
Agrégation
12
™ Polymorphisme
™
: mécanisme qui autorise l’appel d’une « même »
méthode redéfinie sur différents objets et provoque des actions
différentes selon la nature de l’objet.
Notion de relation entre
2 classes spécifiant que
les objets d'une classe
sont les composants
de l'autre.
For (int i=0; i<nbOeuvre; i++) {
Stock[i].restaurer();
}
en Java
Notes sur
la classe
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
+restaurer(): void
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
multiplicité
™
agrégation
Une bibliothèque est
composée d'un ensemble
d'œuvres
[email protected]
11
L'approche objet
Les langages C++ et Java
13
14
™
Bilan
ƒ Extension du langage C
ƒ A conquis les marchés des langages orientés objet
ƒ L'héritage
ƒ ++ Langage très performant
ƒ L'agrégation
ƒ - - Mais syntaxe assez difficile
ƒ Les plus
ƒ Facilite l'élaboration et l'évolution d'applications complexes
ƒ Réutilisabilité du code
ƒ Des langages performants : C++, Java, Eiffel, …
Attention
ƒ L'approche orientée objet est moins intuitive qu'il n'y paraît
ƒ Nécessité d'une maîtrise des concepts objets
ƒ Avoir une démarche d'analyse et de conception objet (cf. UML)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Développé chez Bell Laboratory (ATT) par Bjarne Stroustrup en 1983
ƒ L'encapsulation
ƒ + d'autres mécanismes avancés pour la généricité, ....
™
C++
ƒ La notion d'objet et de classe
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Les concepts fondateurs sont
™
Java
ƒ Concurrent plus récent de C++
ƒ Inventé par Sun entre 91 et 96
ƒ A acquis en moins d’un an une place majeure chez les acteurs de
l’informatique (grâce notamment à Internet)
ƒ ++ portabilité et indépendance de la plate-forme
(Windows, Unix, Mac, …)
ƒ ++ Langage de haut niveau
ƒ - - Mais relativement lent à l'exécution
™
Complémentarité Î Couplage possible des langages… (cf. JNI…)
[email protected]
™
Les classes - définition
Date
int _j
16
™
int _m
La notion de classe
int _a
ƒ liée à la notion de définition de type
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Void init (int j, int m, int a)
int jour ( )
int mois ( )
int annee ()
void plus_jours (int n)
ƒ représentation concrète d’un concept
™
Version 4.2
Définition (.h) : class X { … };
Données membres
Fonctions
membres
class Date {
int _j, _m, _a ;
public:
void init (int j, int m, int a) ;
int jour ( ) ;
int mois ( ) ;
int annee () ;
void plus_jours (int n) ;
};
// initialisation
// fonctions d’accès
// additionne n jours
• les membres privés " private " (par défaut)
accessibles uniquement par les fonctions membres de la classe
• les membres publics " public "
constituent l’interface pour la manipulation des objets de cette classe
accessibles par tous
[email protected]
Notion d’objet et de classe en
C++
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
.h
Les classes - définition d’une méthode
Les classes - instanciation
17
18
Définition des fonctions membres
™ Un
*structure d’un programme
objet est une instance d’une classe :
ƒ Définition en dehors de la classe (.cpp)
ƒ Une fonction membre connaît toujours l’objet qui l’a invoqué
« variable dont le type correspond à la classe »
.cpp
« l ’accès à l’objet appelant est implicite dans une méthode »
.cpp
Classe
aujourdhui.init (10,08,1998);
arguments explicites
ƒ On a un accès explicite à l’objet appelant à travers le pointeur this :
.cpp
void Date::init(int j, int m, int a) {
this -> _j
=j;
this -> _m
=m;
this -> _a = a ;
}
// idem que (*this)._j = j;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
.cpp
void Date::init(int j, int m, int a) {
_j
=j;
_m
=m;
_a
=a;
}
Date demain;
argument implicite
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
:: portée d’une méthode
Date aujourdhui;
™ Accès
*constructeur
Identificateur (nom de l ’objet)
par un objet à un membre (fonction ou donnée) de classe :
objet.membre;
™ Utilisation
d’une méthode :
« l ’action se rapporte souvent
à l’objet appelant »
.cpp
*affectation
aujourdhui.init(10,08,1998);
demain=aujourdhui;
demain.plus_jours(1);
aujourdhui
_a = 1998
_j = 10
_m =08
annee()
init()
jour()
mois()
plus_jours()
[email protected]
™
Encapsulation
Constructeurs - Déclaration
19
20
™
« Un constructeur est une fonction membre spéciale invoquée
automatiquement à chaque création d’un objet »
*héritage et
membres protégés
Encapsulation et contrôle d’accès
™ Constructeur
ƒ les (fonctions) membres "public" = interface utilisateur
par défaut
ƒ si aucun constructeur n’a été défini, la classe possède un constructeur par
défaut sans paramètre
.cpp
Date aujourdhui;
// construction d’un objet date (aujourdhui)
ƒ permet la manipulation des objets de la classe
aujourdhui. _a ;
// accès interdit
aujourdhui. init(36,08,1998) ; // à vérifier
ƒ indépendance de la représentation / interface
ƒ permet le changement de représentation interne en gardant la même interface
(méthodes publiques)
™
Modularité d’une classe
*structure d’un programme
ƒ définition de la classe (.h)
ƒ déclaration des méthodes (.cpp)
™ Déclaration
d’un constructeur (fonction membre)
ƒ un constructeur possède le même nom que la classe
ƒ seuls les constructeurs définis dans la classe sont maintenant utilisables
.h
class Date {
// ... Idem code précédent
Date (int, int, int);
};
.cpp
Date aujourdhui=Date(10,08,1998); // ok, initialisation constructeur
Date hier(9,08,1998);
// ok, idem
Date demain;
// erreur ! Plus de constructeur
//
correspondant
[email protected]
ƒ permet une vérification de validité
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
.cpp
ƒ garantit une protection
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ les (données) membres "private" = représentation interne des objets
Constructeurs - Définition
Constructeurs - Surcharge
22
™
Définition d’un constructeur
™ Une
ƒ Les constructeurs ne retournent jamais de valeur :
leur rôle est d’initialiser un objet.
classe peut posséder plusieurs constructeurs
.h
ƒ structure basique
ƒ 1/ construction de l’objet
Date::Date (int j, int m, int a) {
_j=j; _m=m; _a=a;
}
ƒ affectation directe des champs
ƒ nécessaire dans certains cas.
ex: agrégation d’objets sans constructeur par défaut…
.cpp
Date::Date (int j, int m, int a): _j(j), _m(m), _a(a)
{}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
.cpp
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ 2/ affectation des champs
class Date {
// ...
Date (int j, int m, int a);
Date (int j, string m, int a);
Date (string s);
Date ();
};
™ Surcharge
Surcharge de fonction
// 1 seul argument :: Conversion implicite
// constructeur par défaut redéfini
du Constructeur par défaut Date()
ƒ invoqué à la création d’un objet sans information sur sa construction
ƒ réservation mémoire : indispensable pour l’allocation de tableaux, etc.
.cpp
* STL
Date d(01,01,2000);
Date d2( "1 janvier 2000" );
Date d3;
vector<Date> tab_d(10);
// constructeur Date (int j, int m, int a)
// constructeur Date (string s)
// constructeur par défaut Date( )
// invocation 10 fois du
// constructeur par défaut Date()
[email protected]
21
Surcharge de fonction
Arguments par défaut
23
24
fonction peut être surchargée
* surcharge d ’opérateur
™ Arguments
ƒ Surcharge : utilisation du même nom avec des paramètres différents
(en type et/ou en nombre :: signature de la méthode)
« on parle de Surcharge si le choix de la fonction
est déterminé par le type des paramètres d’appel :: sa signature »
(qui sera définie comme membre statique de la classe, cf. transp. suivant)
.h
}
return max ( max (a, b), c) ;
}
void main() {
float x,y;
x=max(2.5, 3.8);
y=max(2.4, 4.5, 8.9);
}
ƒ Attention aux ambiguïtés
double max (float a, float b) {...} // erreur ; le type de retour n’intervient
// pas dans la signature
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
float max (float a, float b, float c) {
return (a>b) ? a : b ;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ L’analyse de la signature détermine la fonction à utiliser
float max (float a, float b) {
par défaut
ƒ Soulage le nombre de fonctions surchargées
ƒ Ex : les arguments non fournis correspondent à la date par défaut jourd
.cpp
class Date {
// …
Date (int j=0, int m=0, int a=0);
};
Date::Date (int j, int m, int a) {
if (j==0) _j = jourd._j ;
else
_j = j ;
if (m==0) _m = jourd._m ;
else
_m = m ;
if (a==0) _a = jourd._a ;
else
_a = a ;
}
Autre solution
.h
class Date {
// …
Date( int j=jourd._j,
int m=jourd._m,
int a=jourd._a);
};
.cpp
Date::Date (int j, int m, int a) {
_j = j ; _m = m ; _a = a ;
}
Date d(10,08); <=> Date d(10,08,0); <=> Date d(10,08,Date::jourd._a);
[email protected]
™ Toute
Membre static
Variable static
25
26
Membre static d’une classe / Attribut de classe
class Date {
int _j, _m, _a ;
static Date jourd ;
// jour par défaut
public:
// ...
static void init_jourd(int, int, int) ;
// pour réinitialiser jourd
};
_a= 2000
_j = 1
_m = 1
_a= 2000
_j = 4
_m = 11
ƒ Utilisation d’un membre static (classe::membre_static)
.cpp
Date Date::jourd(1,1,2000);
Date::init_jourd(1,2,2000);
Date d ;
void f( ) {
static int compteur = 0 ;
int n ;
…
compteur++ ;
}
_a= 2000
_j = 3
_m= 11
Date::demain
Date::jourd
Variable static locale à une fonction
ƒ une variable déclarée static dans une fonction est une variable persistante
Date::hier
// définition explicite obligatoire de jourd
(à mettre dans date.cpp)
// ré-initialisation de jourd possible
// constructeur par défaut
// d a été initialisée à la date 01-02-2000
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
.h
Date
_a
_j
_m
jourd
™
™
// variable static (persistante)
// variable locale
Variable static globale (notation C)
ƒ permet de limiter la portée d’une variable globale à son module
static int coucou;
// variable globale, privée à ce module
[email protected]
ƒ variable ou fonction ayant trait à une classe et non à un objet spécifique
ƒ une instance unique pour chaque objet de la classe
ƒ accessible par une classe et sans objet
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Fonction membre constante
Fonction inline
28
™
™
Bien différentier les fonctions d’accès et les fonctions de mutation
.h
class Date {
.h
La définition const : objet associé non modifiable
ƒ permet la vérification du compilateur et clarifie l’interface utilisateur
.h
class Date {
public:
Date add_jours(int n) const; // l’objet appelant reste inchangé
// ...
// rend (date + n jours)
}
.cpp
Date b = a.add_jours(30);
// b=a+30, a est inchangé
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
int Date::jour( ) const { return _j ; }
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public:
int jour( ) const ; // l’objet (argument implicite) reste inchangé
void plus_jours(int n) ;
// changement possible de l’objet
// ...
};
.cpp
Fonction inline : évite l’appel de fonction
class Date {
public:
int jour( ) const ;
// ...
};
inline int Date::jour( ) const { return _j ; } // à définir dans le .h
™
Les fonctions inline offrent :
ƒ protection des données membres
ƒ lisibilité / interface
ƒ évitent la perte de performance (traduction étendue à la compilation)
ƒ MAIS : à n’utiliser que pour des fonctions très courtes (longueur du code)
[email protected]
27
Structure générale d’un programme
30
™ Un
module est composé de 2 fichiers (.h et .cpp)
ƒ Fichier d'en-tête : Module.h
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Définition des classes
.h
ƒ Déclaration des types synonymes (typedef)
Version 4.2
- entrées / sorties
- string / vector
- espace de nommage
ƒ Déclaration des fonctions globales
ƒ Définition des fonctions inline
ƒ Fichier source : Module.cpp (inclut son fichier d'en-tête)
ƒ Définition des classes et variables globales partagées
ƒ Définition des fonctions non inline
.cpp
™ Le
programme principal
ƒ Fichier source : Programme.cpp
ƒ Inclut les modules dont il a besoin
.cpp
ƒ Contient la fonction main(...) :
int main(int argc, char* argv[]) { ... };
// Module.cpp
#include "module.h"
...
// Programme.cpp
#include "module.h"
int main (int argc, char* argv[])
{ ... };
[email protected]
Quelques éléments
pour programmer en C++
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Déclaration des variables globales
// Module.h
#ifndef module_h
#define module_h
...
#endif
Fichier d'en-tête - Commentaires
Entrées - sorties (Streams ou flots)
31
32
Les entrées/sorties sont gérées en C++ par des flots(stream)
Fichiers d'en-tête
™
™
2 opérateurs binaires (stream x expression -> stream) prédéfinis :
ƒ opérateur d’écriture dans un flot : <<
<string>
<cstring>
<string.h>
"Date.h"
ƒ opérateur de lecture dans un flot : >>
// inclusion des fichiers d'en-tête système Ansi C++
// inclusion des fichiers d'en-tête système Ansi C
// idem mais ancienne notation
// inclusion de fichier d'en-tête local
™
Commentaires
//
commentaire ligne
/*
commentaires
multi-lignes
* documentation automatique
doc++, doxygen, JavaDoc, …
*/
#if 0
// directive de précompilation pour masquer cette partie de code malgré
// la présence de commentaires imbriqués
#endif
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Conventions
#include
#include
#include
#include
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Directive de précompilation : #include
ƒ inclusion de définition de type, de constantes prédéfinies, de procédures, …
Flots d’entrées / sorties standards : iostream
ƒ cin
(entrée standard)
ƒ cout (sortie standard)
ƒ cerr (sortie erreur standard)
.cpp
#include <iostream>
main() {
int nb;
cout << " Un nombre entier : " ;
cin >> nb;
cout << "Nombre à afficher : " << nb << endl ;
}
[email protected]
™
Entrées - sorties fichiers
Un 1er petit programme : la classe Date
34
#ifndef DATE_H
#define DATE_H
Flots d ’entrées / sorties fichiers : fstream
Date
ƒ ifstream, ofstream
.cpp
_a
_j
_m
jourd
jours_par_mois
Date()
annee()
est_bissextile()
est_valide()
init_jourd()
jour()
mois()
plus_jours()
#include <fstream>
ofstream fs (" fsortie.tex ") ;
// ouverture en sortie
ifstream fe (" fentree.tex ") ;
// ouverture en entrée
fstream
fs2 (" fsortie2.tex ", ios::out) ; // ouverture en sortie
int n;
while (fe >>n) {
// lecture
fs << "entier envoyé dans fsortie.tex : " << n << endl ;
fs2 << "entier envoyé dans fsortie2.tex : " << n << endl ;
}
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
main () {
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Date.h
class Date {
private:
int _j; int _m; int _a;
static Date jourd;
static int jours_par_mois[12];
bool est_valide() const;
bool est_bissextile(int annee) const;
public:
Date(int j=0, int m=0, int a=0);
int jour() const;
int mois() const;
int annee() const;
void plus_jours(int n);
static void init_jourd(int j, int m, int a);
};
inline int Date::jour() const
{ return _j; }
inline int Date::mois() const
{ return _m; }
inline int Date::annee() const
{ return _a; }
#endif
#include "date.h"
#include <iostream.h>
#include <assert.h>
Date.cpp
int Date::jours_par_mois[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
Date Date::jourd (1,1,2000);
void Date::init_jourd (int j, int m, int a) {
Date::jourd._j=j; Date::jourd._m=m; Date::jourd._a=a;
assert(Date::jourd.est_valide());
}
Date::Date (int j, int m, int a) {
if (j==0)
_j
= jourd._j ; else _j = j ;
if (m==0)
this->_m
= jourd._m ; else _m = m ; // idem
if (a==0)
(*this)._a
= jourd._a ; else _a = a ; // idem
assert(est_valide());
}
void Date::plus_jours(int n) {
// ... faire un algorithme pour incrémenter correctement les jours
}
bool Date::est_valide() const
{ if (_j <= 0)
return false;
if (_m <= 0 || _m > 12) return false;
if (_a == 0)
return false;
if (_m == 2 && _j == 29) return est_bissextile(a);
return _j <= jours_par_mois[_m - 1];
}
bool Date::est_bissextile(int annee) const
{ if (annee % 4 != 0)
return false;
if (annee < 1582)
return true;
if (annee % 100 != 0) return true;
if (annee % 400 != 0) return false;
return true;
};
[email protected]
33
UnDate
1er petit programme : utilisation
initialisation avec mois = 8
et annee = 2002
date d initialisee = 1 8 2002
Exécution de Test.exe
sans paramètre
date par defaut d = 1 1 2000
Usage: Test.exe mois annee
initialisation par defaut
date d initialisee = 1 1 2000
}
La classe string (C++ ANSI / Librairie standard du C++)
ƒ manipulation sécurisée des strings
Chap. STL
#include <string>
string s0 = "bonjour" ; // initialisation d’une string
string s1 ;
// ok, par défaut création d’une string vide
ƒ les opérateurs standards : +, [], ==, <=, < , substr(), c_str() …
string nom = "fsortie" ;
string nomfichier = nom + ".tex" ;
// concaténation de strings
ofstream fs(nomfichier.c_str()) ;
// conversion d’une string
// en chaîne C
char c=nom[0];
// c = ‘ f ’
[email protected]
if (argc == 3){
m = atoi(argv[1]);
y = atoi(argv[2]);
cout << "initialisation avec mois = "
<< m << " et annee = " << y << endl;
d=Date(1, m, y); // affectation
}
else{
cout << "Usage: " << argv[0] << " mois annee" << endl;
cout << "initialisation par defaut" << endl;
}
cout << "date d initialisee = "
<< d.jour()
<< " " << d.mois()
<< " " << d.annee() << endl;
return 0;
Exécution de Test.exe 8 2002
date par defaut d = 1 1 2000
™
Test.cpp
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
#include "Date.h"
#include <stdlib.h>
#include <iostream.h>
int main(int argc, char* argv[]){
int m, y;
Date d;
cout << "date par defaut d = "<< d.jour()
<< " " << d.mois()
<< " " << d.annee() << endl;
Classe String
36
[email protected]
_a
_j
_m
jourd
jours_par_mois
Date()
annee()
est_bissextile()
est_valide()
init_jourd()
jour()
mois()
plus_jours()
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
35
Classe stringstream
Espace de nommage (définition / accès)
38
™ La
™
classe stringstream
Un espace de nommage en C++
ƒ
ƒ
ƒ
ƒ
ƒ Ecriture et lecture formatées dans une « string » de type « stream »
Manipulation des caractères dans une string comme dans un fichier.
#include <sstream>
te << "anniversaire: " << anniv.jour() << " " << anniv.mois() << endl ;
string s = te.str() ;
// contient "anniversaire: 01 01"
istringstream ts(s) ;
string texte ;
int jour, mois ;
ts >> texte >> jour >> mois ;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ostringstream te ;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Date anniv ;
Permet de rassembler sous un même préfixe de nommage un ensemble d’entités
Possibilité d’imbriquer les espaces de nommage (hiérarchie)
Pas de notion de visibilité particulière (contrôle d’accès) comme en Java
Accès à l’espace de nommage
ƒ par l’opérateur de portée « :: » (on préfixe le nom par l’espace de nommage)
ƒ ou par la clause « using nammespace identifiant ; » (accès à tout l’espace)
ƒ ou par la clause « using identifiant ; » (accès à un élément unique de l’espace)
namespace A // NB : .h et .cpp
int main(int,char**){
{
Classe2 e1;
// ok
class Classe1 { };
A::Classe1 e2;
// ok, accès en préfixant le nom
class Classe2 { };
B::Classe3 e3;
// ok, accès en préfixant le nom
namespace C{
using namespace A;
// accès à tout l’espace de nommage A
Classe1 e4;
// ok
class Classe3 { };
}
using namespace A::C; // accès en + à tout l’espace de nommage A::C
}
Classe3 e5;
// ok
namespace B
using namespace B;
// accès en + à tout l’espace de nommage B
{
Classe3 e6;
// erreur compilation : ambiguité entre
// B::Classe3 et A::C::Classe3
class Classe3 { };
}
class Classe2 { };
}
A::C::Classe3 e7;
// ok, accès en préfixant le nom
using A::C::Classe3;
// permet de masquer B::Classe3
Classe3 e8;
// ok
[email protected]
37
Espace de nommage (alias)
Préambule sur la STL … suite dans le chap. STL
39
40
Possibilité d’utiliser des alias
™
ƒ Pour éviter les ambiguïtés liées à l’utilisation de la clause using
ƒ Pour simplifier l’écriture en gardant des noms d’espace de nommage explicite
ƒ Syntaxe: namespace Alias=nomEspaceDeNommage;
namespace A=nomA;
™
// définition d’un alias
class Classe1 { };
A::Classe1 e4;
class Classe2 { };
namespace AC=nomA::nomC;
namespace nomC{
AC::Classe3 e5;
// définition d’un alias
// ok
}
}
}
namespace nomB
{
class Classe3 { };
}
class Classe2 { };
™
Intérêt de la librairie standard du C++ (STL)
ƒ Standardisation
// ok
CF. chap. STL
STL : son espace de nommage
ƒ Les éléments de la STL sont regroupés dans un espace de nommage « std »
ƒ L’inclusion des fichiers d’entête s’effectue sans le .h
ƒ Exemple : #include <string>
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ La gestion des string et des flux (iostream)
int main(int,char**){
{
class Classe3 { };
ƒ Des classes conteneurs et leur algorithmes associés
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
namespace nomA
La librairie standard du C++ intègre
ƒ Autrefois connue sous le nom de STL (Standard Template Library)
ƒ Maintenant totalement intégrée au standard du C++
ƒ Fiabilité
ƒ Les classes sont sûres, validées depuis plusieurs années
ƒ Maintenabilité
ƒ Tout le monde utilise le même standard
ƒ le code est compréhensible et les évolutions sont homogènes
ƒ Efficacité
ƒ Les composants ont été écrits par des experts, pour aboutir à un code efficace
[email protected]
™
Les conteneurs élémentaires
Les Vecteurs (vector)
41
42
™
Vector
ƒ équivalent des Vector ou ArrayList de Java
ƒ Tableaux du C++ avec possibilité d’allocation dynamique
ƒ tableaux pouvant croître dynamiquement.
ƒ Accès en O(1), ajout/supression en O(n) en milieu de vecteur
™
ƒ ajout/supression en O(n) en fin de vecteur avec redimensionnement,
ƒ Pas d’opérateur d’indéxation
ƒ Mais permettent : ajout/supression en O(1) en milieu de liste
ƒ NB: occupation mémoire souvent supérieure à un vecteur
Deque
ƒ Intermédiaire entre List et vector
ƒ Très efficace pour les ajout/suppression à une extrémité
ƒ Indexation en o(log(n))
ƒ Insertion plus rapide que vector mais moins rapide que les listes
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ push_back : ajoute un élément en fin de vecteur.
List
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ l’opérateur crochets [ ] : Accès/modification du vecteur
ƒ Représente les listes chaînées habituelles
™
Utilisation Basique
ƒ size() :Taille du vecteur
sinon en O(1)
™
Introduction
ƒ push_front : insère un élément en début de tableau
ƒ clear : vide le vecteur, le ramenant à une taille de 0.
ƒ resize : permet de modifier la taille du vecteur (en insérant ou détruisant
éventuellement des éléments en fin de vecteur).
#include <iostream>
#include <vector>
La taille du vecteur est de 9
#include <string>
La taille du vecteur est de 0
using namespace std;
int main(int, char **){
vector<string> v0; // Vecteur vide
vector<string> v1(8); // Vecteur contenant 8 string
v1.push_back("chaine");
cout << "La taille du vecteur est de " << v1.size() << endl;
v1.clear();
cout << "La taille du vecteur est de " << v1.size() << endl;
}
[email protected]
™
Les Vecteurs (vector)
43
™ Exemple
2 sur la classe Vector (tableau dynamique)
ƒ Déclaration
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
* iterator
vector<X> a (n);
// définit un tableau de n éléments de type X
a[i];
// accès au iéme élément
vector <double> tab1(5);
// ajoute un elt en fin de tableau
// (alloue + initialise)
tab1.push_back(1.0) ;
tab1.resize(10);
// redimensionne le tableau à 10 elts
tab1.pop_back();
// réduit la taille du tableau de 1
vector <double> tab2;
tab2=tab1;
// affectation par recopie
* gestion de la mémoire
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
tab1.push_back(1.2) ;
* classe paramétrée (template)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Quelques opérateurs
Version 4.2
Les propriétés de C++
- références / pointeurs
- surcharges d'opérateurs
- friend / classe interne
Références et Pointeurs
Passage par référence
45
46
™ Référence
ƒ Utilisation des Références (type& X) et des pointeurs (type* X)
// r et i font référence au même objet
// i = 2;
void cswap (int* x ; int * y)
{ int temp =*x ; *x=*y ; *y=temp;}
void swap (int& x ; int& y)
{ int temp=x ; x=y ; y=temp; }
référence est implémentée avec la notion de pointeur constant
int a=1; int b=2;
int ii = 0 ;
int& rr =ii ;
rr++ ;
// ii =1
int* pp=&rr ;
// pp pointe sur ii
}
&ii
rr :
ii:
1
[email protected]
pp:
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Void g( ) {
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Passage par référence : pour modifier les arguments
cswap(&a,&b);
// maintenant a=2 et b=1
swap(a,b);
// puis maintenant a=1 et b=2
ƒ Remarques
ƒ quand on utilise des références, le compilateur supplée aux * et aux &
ƒ passage par valeur (par défaut) : recopie de l’objet à l’appel dans la pile
ƒ passage par référence : il n’y a pas de recopie de l’objet à l’appel
ƒ les fonctions qui modifient leurs arguments utilisent des références
void trier(vector<double>& tab);
void inverser(string& st);
* STL
* String
[email protected]
™ Une
™
= nom alternatif à un objet existant
int i = 1;
int& r = i ;
r=2 ;
Passage par valeur / Recopie ( m )
Passage par référence / Pas de recopie
47
48
Contexte de la procédure
Date hier(1,10,99);
Contexte de la procédure
Date hier(1,10,99);
Date demain(2,10,99);
Date demain(2,10,99);
Xm1/10/99
Xm1/10/9
99
X
Pass_ref(hier,demain);
* Constructeur par recopie
hier { 1/10/99
demain { 2/10/99
temp
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Sans effet
sur les arguments
void pass_valeur(Date X ; Date Y) {
Date temp=X ; // initialisation
X=Y ;
Y=temp;
}
Y
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Ym2/10/99
Ym2/1
/10/99
Modification
des arguments
hier { 2/10/99
demain { 1/10/99
void pass_ref(Date& X ; Date& Y) {
Date temp=X ; // initialisation
X=Y ;
Y=temp;
}
temp
[email protected]
pass_valeur(hier,demain);
Retour par valeur ( recopie m )
Passage et Retour par référence
49
50
™
string string1="toto";
string string2="tata";
string res;
res=concat(string1,string2);
Passage par référence
« constante »
ƒ évite une recopie de l’objet en garantissant une non modification de l’objet
™
s1
Retour par référence
« gain en efficacité mais attention … »
ƒ par défaut, la valeur retournée par une fonction est passée par valeur
s2
}
obj_temp
mp m result
res = obj_temp
res { "tototata"
// affectation avec l'objet temporaire
string result =s1;// variable locale
result +=s2;
return result;
// ok car il y a recopie de la valeur de l’objet
}
string& concat (const string& s1, const string& s2) {
string result =s1;// variable locale
result +=s2;
return result;
// retour d ’une référence sur une var locale =>
}
// Erreur !!!! result est hors de portée
// après le return
[email protected]
result +=s2;
return result;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
result
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
string concat (const string& s1, const string& s2) {
string concat ( const string& s1,
const string& s2) {
string result = s1;// initialisation
Auto-références
Passage par référence et Auto-référence
52
Date d ; Date a ;
a=d.plus_an(1).plus_an(1) ;
// d =d + 2 ans …. d est modifié,
// a=d;
Date Date::add_an (int n) const {
Date d_local (_j, _m, _a) ;
// ...
d_local.plus_an(n);
return d_local;
// ok : retourne la valeur de la date
}
// NB : construction d’un objet temporaire
Date d ; Date a ;
a=d.add_an (1).add_an (1) ;
// a =d + 2 ans … d est inchangé
Extension des opérations de la classe Date
class Date {
// …
Date&
Date&
Date&
Date
Date
Date
};
// Ok : retourne une référence
// sur l ’objet appelant
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Date& Date::plus_an (int n) {
// ...
_a+=n;
return *this;
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Rappel : this = pointeur sur l’objet qui a invoqué la fonction
[email protected]
™
™
plus_jour (int n);
// additionne n jours
plus_mois (int n);
// additionne n mois
plus_an (int n);
// additionne n années
add_jour (int n) const;
add_mois (int n) const;
add_an (int n) const;
Fonctionnalités
ƒ On peut enchaîner les opérations de mutation, mais attention ...
Date d ; Date a;
a=d.plus_jour(1).plus_mois(1).plus_an(1) ; // d =d + 1 jour, 1 mois et 1an
// d est modifié, a=d;
a=d.add_jour(1).add_mois(1).add_an(1) ; // d est inchangé
// a = d + 1 jour, 1 mois et 1an
[email protected]
51
Surcharge d’opérateurs conventionnels
Conversion implicite
53
54
class Date {
Exemple
// ...
Date (int j, int m, int a)
Date (string s);
bool operator== (const Date& d) const;
long operator- (const Date& d) const;
class Date {
Exemple
// ...
Date (int j, int m, int a)
Date (string s); // constructeur(1 arg) => conversion implicite
long operator- (const Date& d) const;
};
ƒ soustraction de deux dates
long
Date::operator- (const Date& d) const { … }
™ Utilisation
<=>
long n = d1 - Date::jourd;
long n = d1.operator- (Date::jourd);
n = d2 - d1;
™
Conversion implicite via un constructeur (à 1 argument)
ƒ ex: conversion Date(string)
Date d1 = "18 janv 2002";
<=>
// <=> Date d1 = Date("18 janv 2002");
// <=> Date d1("18 janv 2002");
long n = d1 - "20 janvier 2002";
long n = d1.operator- (Date("20 janvier 2002"));
• Problème avec les opérateurs symétriques (+ , - , * , / , == )
long n = "18 janvier 2002" - d1;
// erreur
[email protected]
bool Date::operator== (const Date& d) const {
return ( _j==d._j && _m==d._m && _a==d._a )
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ égalité de deux dates … argument implicite(gauche) … explicite(droite)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
};
Définition externe étendue
Notion d’ami : Friend
55
56
class Date {
// …
Date (int j, int m, int a)
Date (string s);
};
implicite symétrique ...
("18 janvier 2002" == date::jourd)
(date::jourd == "18 janvier 2002")
// ok
// ok
™ Classe
Friend
ƒ les fonctions membres d’une classe définie comme amie d’une autre classe
peuvent accéder aux membres privés de la classe.
class List {
public:
List( ) ;
void inserer(int);
private:
Elt* _tete ;
int
_long ;
…
};
class Elt {
2
private:
List
int
_info;
Elt* _suiv;
friend class List;
friend class Pile;
};
Elt
[email protected]
bool operator== (const Date& d1 , const Date& d2) {
return (
d1.jour()==d2.jour()
&& d1.mois()==d2.mois()
&& d1.annee()==d2.annee() )
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Définition externe de l'opérateur d'égalité de deux dates
™ Conversion
Friend
ƒ une fonction définie comme amie d’une classe peut accéder aux membres
privés de la classe.
Class Vecteur {
friend int compare (const Vecteur&, const Vecteur&);
friend Vecteur Matrix::multiplier(const Vecteur&) const; // Mat * Vect
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
™ Fonction
Surcharge d’opérateurs et notion de Friend
Classe interne : "nested class"
58
™
bool operator== (const Date& d1 , const Date& d2) {
return (
d1._j==d2._j && d1._m==d2._m && d1._a==d2._a )
}
ƒ soustraction de deux dates
long operator- (const Date& d1, const Date& d2) { … }
™ Conversion
implicite symétrique ...
long n = "18 janvier 2002" - date::jourd;
long n = date::jourd - "18 janvier 2002";
// ok
// ok
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ égalité de deux dates
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Date {
// …
Date (int j, int m, int a)
Date (string s);
friend bool operator== (const Date& d1, const Date& d2);
friend long operator- (const Date& d1, const Date& d2);
friend ostream& operator<< (ostream& os, const Date& date);
};
Une classe peut être définie à l'intérieur d'une autre classe
ƒ La classe interne peut être utilisée avec la même portée que la classe qui
l'englobe (attention aux contrôles d'accès)
ƒ La classe interne a accès aux membres "statiques" et aux types (classes)
définis dans classe qui l'englobe
class Englobe {
public:
int x;
static int s;
class inner {
void f(int i) {
//
x = i;
// erreur : pas d'accès direct au membre de la classe l'englobant
s = i;
// OK, accès à un membre statique de la classe l'englobant
}
//
innerPr iPr();
// erreur : accès à un type(classe) privé
};
private:
class innerPr {
inner i();
// ok : accès à un type(classe) public
};
};
class Test {
public:
void f() {
//
inner I();
// erreur, portée incorrecte
Englobe::inner I();
// ok
//
Englobe::innerPr IPr();
// erreur accès à un type(classe) privé
}
};
[email protected]
57
Les zones mémoires
60
™
Pile d’exécution
ƒ variables locales à une fonction
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ portée niveau bloc // notion de durée de vie
Version 4.2
™
Zone de données statiques
- allocation
- affectation / clonage
- constructeur par recopie
ƒ variables « globales » déclarées à l’extérieur d ’une fonction
ƒ portée dépend de la déclaration /<>/ durée de vie
™
Zone d’allocation dynamique (tas)
new (alloue la mémoire nécessaire au
type passé en argument et retourne l’adresse)
ƒ allocation dynamique d’un objet :
X*
p = new X (arguments pour le constructeur);
X*
p1 = new X;
Date* d
= new Date;
// constructeur par défaut
[email protected]
Gestion de la mémoire
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ variables statiques
Allocation dynamique et libération
Notion de destructeur : ~X( )
62
Le destructeur doit libérer tous les éléments alloués
quand l’objet est hors de portée
Tout objet alloué dynamiquement (new) doit être
désalloué explicitement (delete)
™
™ Déclaration
Destruction d’un « objet » alloué : delete p;
ƒ l’opérateur delete permet de libérer un bloc mémoire du tas,
class List {
public:
~List( ) ; ...
private:
class Elt {
public:
int _info;
Elt* _suiv;
}
Elt* _tete ;
int
_long ;
}
pd1 = &d;
Date*
pd2 = new Date(17,08,1998);
// à éviter
Date* pd3 = pd2;
Date* pn = NULL;
delete pd1;
// erreur on ne peut libérer des blocs de la pile
delete pd2;
// Ok;
delete pd3;
// erreur, objet détruit 2 fois ;
delete pn;
// Ok;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
d;
Date*
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
son argument est un pointeur sur l’objet réclamé.
Date
du destructeur : class X ; son destructeur ~X( )
2
List
Elt
List ::~List( ) {
Elt* p =_tete ;
While (p != NULL) {
Elt* psuiv = p o _suiv ;
delete p ;
„
p = psuiv ;
Définition du destructeur
}
}
[email protected]
61
Une 1ère amorce de programmation de liste
Mise en œuvre du destructeur
63
64
Elt
_info
_suiv
Agrégation :
« Utilise »
List
_long
_tete
List()
insert()
liberer()
~List()
™ Gestion
void List::insert(int e) {
Elt* Nouv_Elt = new Elt;
Nouv_Elt->_info=e;
Nouv_Elt->_suiv=_tete;
tete=Nouv_Elt;
_long++;
}
List::List() {
cout << "Constructeur par defaut" << endl;
_tete=NULL;
_long=0;
}
ostream& operator<< (ostream& os, const List& l){
char ch = os.fill('0');
Elt* p =l._tete;
while(p != NULL) {
os << p->_info << " " ;
Elt* psuiv = p->_suiv;
p = psuiv;
}
os.fill(ch);
return os; }
des ressources mémoire (portée de bloc: destruction des objets)
fonction ( …) {
...
{ List* p = new List ;
// constructeur par défaut.
List m ;
// constructeur par défaut.
...
}
// Invocation automatique du destructeur ~List à la
}
// sortie de bloc sur m ... Pas sur *p (non détruit)
™ Appel
automatique quand l’objet libère la mémoire
(si appel explicite du delete)
List* pl = new List ;
pl o insert (…) ;
...
delete pl ; // demande de libération de la mémoire => destructeur
[email protected]
};
Destructeur : opération appelée automatiquement
pour la libération mémoire d’un OBJET
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Elt {
private:
int _info;
Elt* _suiv;
friend class List;
friend ostream& operator<<(ostream& os, const List& l);
List:: ~List() {
cout << "Destructeur" << endl;
Elt* p =_tete;
while(p != NULL) {
Elt* psuiv = p->_suiv;
delete p;
p = psuiv;
}
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class List {
public:
2
List() ;
~List() ;
List
Elt
void insert(int);
friend ostream& operator<<(ostream& os, const List& l);
private:
Elt* _tete ;
int
_long ;
void liberer( ) ;// libération de l’espace mémoire
};
Allocation de n éléments
Opérateur d’ Affectation ( operator = )
65
66
Pour allouer n éléments d’un type donné : new type[n]
L’affectation par défaut effectue une simple copie champs à champs
ƒ Tableau de char
™
ƒ char* toto = new char [100] // fournit un pointeur (type* ici char*) sur
ƒ Déclaration de 2 listes
// le premier élément du tableau
List a ;
ƒ Tableau d’objets
a.insert(...) ;
…
List b ;
ƒ Cette allocation utilise le constructeur par défaut
/ Si celui-ci n’existe pas il y aura erreur de compilation
™
Destruction d’un tableau : on utilise l’instruction delete[ ]
ƒ delete [] toto;
// destruction du tableau
ƒ delete [] desListes;
// Appel du destructeur sur
// chaque objet du tableau
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
// alloue l’emplacement
// nécessaire à 100 objets « List »
// et place l’adresse du
// premier objet dans desListes
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ On peut créer un tableau d’objets avec la même syntaxe
ƒ List* desListes = new List [100]
Opérateur d’affectation par défaut
a
b
3
2
b.insert(…) ;
• Affectation : recopie des champs
_tete et _long
a=b;
// Pb avec l ’opérateur
// d’affectation par défaut
• Lorsque b est hors de portée
la liste d’origine n’est pas détruite
la liste b est détruite deux fois !?
a
b
a
2
2
2
[email protected]
™
Affectation en profondeur
Constructeur par recopie
67
68
™
ƒ objets copiés en tant qu’argument de fonction
ƒ objets copiés en tant que retour de fonction
l
// référence constante, évite
// une recopie dans la pile
// protection pour a = a
// 1. libérer la mémoire de l’argument de gauche ~ idem destructeur
// 2. copie de l ’argument droit
…
}
Utilisation du constructeur par recopie
ƒ initialisation ( Date d1=d2 ; Date* d3= new Date(d2) )
ƒ Définition
ƒ libérer la mémoire de l’argument de gauche
ƒ copier l’argument de droite
List& List::operator= (const List& b) {
if (this==&b) return *this ;
Le constructeur par recopie par défaut effectue une simple
copie champs à champs
operator= (const X&)
™
Exemple
double moyenne (List a)
{…}
List l ;
double moy=moyenne( l ) ;
l
a
l
• Liste l avant l’appel de fonction
3
3
3
3
• Listes pendant le déroulement de la fonction (copie locale)
• Listes après l’appel de fonction (destruction de a)
[email protected]
X&
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
: opérateur d’affectation
ƒ Déclaration
class List {
public:
List( ) ;
~List( ) ;
List& operator= (const List& b);
...
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Surcharge
Implémentation d’un constructeur par recopie
Une implémentation homogène
70
™
Redéfinition d’un constructeur par recopie (en profondeur)
™ Définition
objectif : pouvoir initialiser un objet nouveau comme une copie en profondeur
d’un objet existant.
Constructeur par recopie
List::List (const List& b) {
_long = b._long;
X(const X&)
~X()
List::List (const List& b) {
List::~List( ) {
copier (b);
while (q != NULL) {
Elt* n = new Elt;
n->_suiv = NULL;
n->_info = q->_info;
if (p == NULL) _tete = n;
else p->_suiv = n;
p=n;
q=q->_suiv;
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Elt* q = b._tete;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Elt* p = NULL;
}
Destructeur
liberer( ) ;
}
}
Opérateur d’affectation
X& operator= (const X&)
List& List::operator= (const List& b) {
}
if (this != &b) {
liberer();
copier(b);
}
return *this ;
[email protected]
69
Une implémentation homogène
Remarques et notion de clonage
72
constructeur par recopie, affectation et destructeur
public:
List() ;
~List() ;
List (const List& b);
List& operator=(const List& b);
void insert(int);
friend ostream& operator<<(ostream& os, const List& l);
private:
Elt*
_tete ;
int
_long ;
void copier (const List& b) ; // copie en profondeur avec b ( .... New ... )
void liberer( ) ; // libération de l’espace mémoire ( ... Delete ... )
};
™
List
_long
_tete
List()
List()
copier()
insert()
liberer()
operator=()
~List()
class Elt {
private: int _info;
Elt* _suiv;
friend class List;
friend ostream& operator<<(ostream& os, const List& l);
};
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class List {
Elt
_info
_suiv
Les données membres de type pointeur engendrent a priori :
ƒ l’écriture d’un destructeur
ƒ la création d’un constructeur par recopie
ƒ et la redéfinition d’un opérateur d’affectation
le polymorphisme / constructeur virtuel
™
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Constructeurs,
Le clonage
le clonage en JAVA
le clonage a le même rôle que la construction par recopie,
cependant un clone retourne en plus un pointeur sur le nouvel objet.
ƒ Déclaration et définition d’un clone (à partir du constructeur par recopie)
class X {
public:
X* clone() const { return new X(*this); }
…
};
[email protected]
71
Bilan : Affectation et Constructeur par recopie
73
™
Constructeur et affectation par recopie
List inverser(const List& b) {
}
// constructeur par recopie (objet anonyme)
// destruction de la variable locale temp (~List)
List u , v ;
v = inverser(u);
// affectation + destruction de l’objet anonyme
Version 4.2
Utilisation implicite des opérateurs : constructeur par recopie,
affectation,
destructeur.
class Index {
private:
string nom ;
List l ;
int _compt ;
}
Index a, b;
a=b;
// affectation par défaut Ok ;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
// constructeur par défaut
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
List temp ;
…
return temp ;
Gestion mémoire
en Java (Rappel)
Le ramasse miette ou « garbage collector »
Java
76
™ Méthode
« Assure une gestion plus sure de la mémoire »
™
ƒ Permet de libérer les ressources
(fichier, socket, etc.)
ƒ Java dispose d’un système de récupération de mémoire automatique quand il
« estime » que l’espace occupé par un objet peut être restitué (<=> plus de
à plusieurs endroits
et tant qu'il existe une référence sur un
objet il ne sera pas détruit
String s ="toto";
T[0] = s;
}
// la référence s n'existe plus
// mais la chaîne "toto" est accessible par T[0]
// donc la mémoire n'est pas libérée
ƒ Le « ramasse miette » fonctionne en arrière plan par défaut.
La destruction est donc asynchrone (gérée par un thread)
ƒ La récupération mémoire peut aussi être invoquée explicitement par le
programmeur : System.gc()
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Appel
{
attention un objet peut être référencé
Class UneClasse {
ƒ Elle peut être directement appelée
String[] T= new String[10];
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ
finalize()
ƒ Méthode appelée par le ramasse-miettes avant la destruction d'une instance de la
mémoire
gestion d'un fichier
Durée de vie : le ramasse miette ou « garbage collector »
référence sur cet objet).
La méthode finalize()
implicite possible si
ƒ l'instance n'est plus référencée
private FileOutputStream
flotfichTemp;
// …
public void finalize() throws IOException {
ƒ et que le ramasse-miettes est
entré en action
™ Attention
temporaire
private File fichTemp= new File("ftemp");
flotFichTemp.close() // fermeture
fichTemp.delete(); // efface le fichier
}}
ƒ On ne peut pas prédire quand le ramasse-miettes va entrer en action !
ƒ Appel explicite possible (en tâche de fond) avec : System.gc()
ƒ La méthode System.runFinalization()
ƒ Lance le ramasse-miettes et attend que les méthodes finalize() soient
invoquées avant de rendre la main
ƒ La fin d'un programme n'implique pas forcement l'appel des finalize() !
ƒ Pour forcer l'appel à tous les finalize(): System.runFinalization(true)
[email protected]
Java
75
Abstraction - Généricité
78
™
La notion d'abstraction, de généricité, de réutilisation se traduit par :
ƒ La notion de classe
ƒ "moule" de construction permettant de créer des objets d'un certain type
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
- agrégation
- héritage
- polymorphisme
- attachement statique et dynamique
- fonction virtuelle
- classe abstraite
ƒ La notion d'agrégation
ƒ Exemple : la classe Rectangle utilise le concept de Point dans sa définition
ƒ => définition avec un plus haut niveau d'abstraction
Spécialisation
ƒ La notion d'héritage
ƒ Spécialisation d'un concept
ƒ Une classe dérivée
ƒ adopte,
ƒ spécialise
Généralisation
ƒ et/ou enrichit
les membres (structure, méthode) d'une classe de base
ƒ Hiérarchisation des concepts
[email protected]
Conception objet en C++
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Version 4.2
Agrégation : classe Point / Rectangle
Agrégation : exemple de Base
79
80
Agrégation forte : composition (losange noir) :
1er pas vers un diagramme de classe UML
ƒ Notation (membres) :
- : privé
+ : publique #: protected _ : static
ƒ Association : connexion sémantique bidirectionnelle entre deux classes
ƒ Agrégation : association non symétrique qui exprime une relation de type : ensemble / élément
Multiplicité
Attributs
Méthodes
La flèche précise que
seul le rectangle est
"conscient" des Points
qu'il possède
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Classe
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Association de type agrégation " ensemble / élément " (losange blanc) :
Cad : un rectangle contient 2 Points"
class Point {
public:
Point(int xx =0, int yy =0) ;
void deplacer(int x, int y) ;
void dess(Graphics& g) const ;
int x() const; int y() const;
private:
int _x; int _y; };
class Cercle {
public:
Cercle(int x=0, int y=0, int r=0);
void dess(Graphics& gc*) const;
void deplacer (int x, int y);
Point centre() const;
int rayon() const;
protected:
Point _centre; int
_rayon; };
Polygone
_coins
Polygone()
coin()
deplacer()
dess()
set_coin()
Point
_x
_y
Point()
deplacer()
dess()
x()
y()
Cercle
_centre
_rayon
Cercle()
centre()
deplacer()
dess()
rayon()
vector<Point>
class Polygone {
public:
polygone(int n=0);
void set_coin(int, Point);
Point coin(int) const;
void deplacer(int x, int y);
void dess(Graphics& g) const;
protected:
vector<Point> _coins;};
[email protected]
™
Héritage : exemple de Base
Contrôle d’accès aux membres
Rectangle()
Rectangle()
dess()
Classe Dérivée
class Rectangle : public Polygone {
public:
Rectangle();
Rectangle(Point, Point);
void dess(Graphics& gc*) const;
};
Polygone
_coins
Polygone()
coin()
deplacer()
dess()
set_coin()
Point
_x
_y
Point()
deplacer()
dess()
x()
y()
Cercle
_centre
_rayon
Cercle()
centre()
deplacer()
dess()
rayon()
vector<Point>
• Héritage public (cas le plus courant) :
la classe dérivée a accès aux membres publics et
protégés « protected » de la classe de base
[email protected]
Classe de Base
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Rectangle
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
- : privé + : publique #: protected
82
Class B {
int priv;
protected:
int pro;
public:
int pub;
void f();
friend class Ami;
}
void fext(B* p) {
p ->priv =1;
p ->pro =1;
p ->pub =1;
}
void B::f( ) {
priv =1;// ok
pro
=1;// ok
pub =1;// ok
}
class D : public B {
void fD( ) ;
}
class Ami {
void fa(B* p);
}
// erreur
// erreur
// ok
void Ami::fa(B* p) {
p->priv =1;// ok
p->pro
=1;// ok
p->pub =1;// ok
}
void D::fD( ) {
priv =1;// erreur
pro
=1;// ok
pub =1;// ok
}
[email protected]
81
Contrôle d’accès à la classe de base
Constructeurs : agrégation et héritage
83
84
public:
int pub;
class D2:protected B
{ ... };
class DD2 :public
class D3:private
void f(D1* p1, D2* p2, D3* p3)
{
B* p=p1;
// ok
}
{ ... };
D2
B
™
{ void fd2(D1*, D2*, D3*); };
Polygone::Polygone(int n) : _coins(n) { }
{ void fd3 (D1*, D2*, D3*); };
void DD2::fd2( … )
{
B* p=p1;
// ok
void D3::fd3( … )
{
B* p=p1;
// ok
p1 ->pub=1;
// ok
p1 ->pub=1;
// ok
p1 ->pub=1;
// ok
p=p2;
// erreur
p=p2;
// ok
p=p2;
// erreur
p2 ->pub=1;
// erreur
p2 ->pub=1;
// ok
p2 ->pub=1;
// erreur
p=p3;
// erreur
p=p3;
// erreur
p=p3;
// ok
p ->pub=1;
// erreur
p ->pub=1;
// erreur
p ->pub=1;
// ok
}
Constructeur et agrégation
ƒ le constructeur d’une classe a aussi pour rôle de construire
ses sous objets
Cercle::Cercle(int x, int y, int r) :_rayon(r), _centre(x,y) { }
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
};
B
™
Constructeur et héritage
ƒ en général, la classe dérivée doit faire appel :
ƒ à un constructeur de la classe de base (obligatoire de manière
implicite ou explicite)
ƒ NB: une classe dérivée ne peut invoquer que le constructeur de sa classe
de base immédiate.
sauf héritage virtuel
ƒ aux « constructeurs » de ses membres
Rectangle::Rectangle(Point pt_hg, Point pt_bd)
: Polygone(2) {
set_coin(0,pt_hg); set_coin(1,pt_bd);
}
[email protected]
class D1:public
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class B {
Redéfinition <> Surcharge
Relation entre classe de base et classe dérivée
85
86
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Redéfinition : utilisation du même nom, de la même
signature (nom + type des paramètres) et du même
type de retour que dans la classe de base
B::f() et D1::f()
Attention au masquage en C++ (<> Java)
ƒ Redéfinir la fonction B::f() dans D1
masque la fonction B::f(int) dans D1
ƒ Idem pour la surcharge
f()
f(int i)
Hériter (sans changement)
ƒ
Redéfinir la fonction B::f() =>Masquage
class D1 : public B { public: void f(); };
void D1::f() { cout << "D1::f() " }
D1
f()
cout << "objet_B.f() "; objet_B.f();
cout << "objet_B.f(2) "; objet_B.f(2);
cout << "objet_D1.f() "; objet_D1.f();
// objet_D1.f(1);
// erreur
objet_D1.B::f(1); // ok
}
ƒ
f()
f(int i)
class D0 : public B { };
objet_B.f() B::f()
void main () {
objet_B.f(2) B::f(int i)
objet_D1.f() D1::f()
B objet_B;
D1 objet_D1; B::f(int i)
class B { public: void f(); void f(int i);};
void B::f() { cout << "B::f()" << endl;}
void B::f(int i) { cout << "B::f(int i)" << endl;}
class D1 :public B { public: void f(); };
void D1::f() {cout << "D1::f()" << endl;}
B
f()
f(int i)
Une classe dérivée D* peut avoir 3 actions possibles
considérant une fonction f() de la classe de base B
ƒ
Redéfinir et Etendre la fonction B::f()
class D2: public B { public: void f(); };
void D2::f() {
cout << "D2::f() ";
B::f(); }
objet_B.f()
objet_B.f(2)
B::f()
B::f(int i)
objet_D0.f() B::f()
objet_D0.f(1) B::f(int i)
D0
D1
D2
f()
f()
void main () {
B objet_B; D0 objet_D0; D1 objet_D1;
D2 objet_D2;
cout << "objet_B.f() ";objet_B.f();
cout << "objet_B.f(2) ";objet_B.f(2);
cout << "objet_D0.f() ";objet_D0.f();
cout << "objet_D0.f(1) ";objet_D0.f(1);
objet_D1.f()
B::f(int i)
D1::f()
cout << "objet_D1.f() ";objet_D1.f();
//objet_D1.f(1); //erreur
objet_D1.B::f(1);
objet_D2.f()
D2::f() B::f()
cout << "objet_D2.f() ";objet_D2.f();
}
[email protected]
B::f() et B::f(int)
B
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Surcharge : utilisation du même nom avec des paramètres
différents (en type et/ou en nombre :: signature de la méthode)
™
B
™
surcharge <> redéfinition
[email protected]
™
Relation entre classe de base et classe dérivée
Résumé : héritage, agrégation, …
87
88
Surcharger une fonction =>Masquage
class B {
public:
void f();
void f(int i);
™
ƒ La notion de classe
f()
f(int i)
ƒ La notion d'agrégation
ƒ "moule" de construction permettant de créer des objets d'un certain type
ƒ Exemple : la classe Cercle utilise le concept
f(int,int)
void main () {
D1 objet_D1;
void D1::f(int i, int j) {
cout << "D1::f(int, int)" << endl;}
objet_D1.f(1,2) / Surcharge : D1::f(int i, int j)
objet_D1.B::f(1) / Portee explicite : B::f(int i)
Cercle
Liste
Pile
ellipse
Cercle
ƒ => définition avec un plus haut niveau d'abstraction
class D1 : public B {
void f(int i, int j);
};
Point
de Point dans sa définition
D1
cout << "objet_D1.f(1,2) / Surcharge : ";
objet_D1.f(1,2) ;
// objet_D1.f(1) ;
// erreur
cout << "objet_D1.B::f(1) / Portee explicite :";
objet_D1.B::f(1);
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
{ cout << "B::f()" << endl;}
{ cout << "B::f(int i)" << endl;}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
};
void B::f()
void B::f(int i)
La notion d'abstraction, de généricité, de réutilisation se traduit par :
B
ƒ La notion d'héritage
ƒ Spécialisation d'un concept ; une classe dérivée
ƒ adopte,
ƒ spécialise
ƒ et/ou enrichit
les membres (structure, méthode) d'une classe de base
ƒ Hiérarchisation des concepts
™
Quand utiliser de l’héritage (D ->B)
ƒ si tout objet de D est de type B
ƒ si la classe D est un cas particulier, plus précis que la classe B
[email protected]
™
Polymorphisme : conversion entre objets
Polymorphisme : conversion entre objets
89
90
™
™
Conversion statique : Obj. classe de dérivée Obj. classe de Base
Conversion statique : Obj. classe de dérivée Obj. cla
classe de Base
// ok, mais conversion statique
// (objet tronqué)
R.dess(g);
// rectangle simple
Rp.dess(g)
// rectangle plein
Limitation : ex. manipuler une collection de rectangles simples et pleins
vector <Rectangle> rects(4);
// tableau de rectangles
rects[0] = RectangleP (P1, P2, c);
// conversion statique
rects[1] = Rectangle (P1, P2);
rects[2] = … ;
...
for (int i=0; i<rects.size(); i++)
rects[i].dess(g);
// dessine uniquement des rectangles simples
[email protected]
Rectangle R=Rp;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
RectangleP Rp(P1, P2, c);
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class RectangleP : public Rectangle {
public:
RectangleP(point, point, color);
void dess(Graphics& g) const;
private:
color _couleur;
}
Polymorphisme : conversion entre pointeurs
Polymorphisme : conversion entre pointeurs
91
92
l’information n’est pas perdue mais elle n’est plus accessible ...
… Attachement statique par défaut
RectangleP*
@
Rectangle*
@
Rectangle* @ @ @
Conversion possible : Pt classe de base Pt classe dérivée
ƒ si le pointeur de type «classe de base»
est associé à un objet «classe dérivée»
RectangleP*
Encore une limitation / collection d'objets de types différents
= new RectangleP (P1, P2, c);
= RP;
// ok conversion implicite
RP2 = static_cast<RectangleP*>(R) ;
// attention (dangereux)
vector <Rectangle*> rects(4);
rects[0] = new RectangleP(P1, P2, c);
rects[1] = new Rectangle(P1, P2);
rects[2] = … ;
...
for (int i=0; i<rects.size(); i++)
rects[i] ->dess(g);
// dessine des rectangles simples
// idem à rects[i]->Rectangle::dess(g)
[email protected]
RP
R
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
RectangleP*
Rectangle*
™
™
Conversion automatique : Pt classe de dérivée Pt classe base
[email protected]
™
Fonctions virtuelles
Attachement statique et dynamique
94
™
Pour permettre la sélection dynamique de la fonction (redéfinie) correcte entre
celle de la classe de base ou des classes dérivées, il faut avoir déclaré cette fonction
comme virtuelle
™
Rectangle R;
R.dess(g);
Déclaration de fonction virtuelle
™
ƒ Exemple
Rectangle* @ @ @
vector <Rectangle*> rects(4);
...
for (int i=0; i<rects.size(); i++)
rects[i] ->dess(g); // attachement dynamique (fonction virtuelle)
// appel de Rectangle::dess ou RectangleP::dess
// en fonction du type de l’objet pointé
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public:
Rectangle(point, point);
virtual void dess(Graphics& g) const;
...
}
™
// attachement statique, appel de Rectangle ::dess
Attachement dynamique : pointeurs
Rectangle* R;
R ->dess(g);
class RectangleP : public Rectangle {
public:
RectangleP(point, point, color);
virtual void dess(Graphics& g) const;
...
Facultatif mais conseillé
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Rectangle {
Attachement statique : objets
// attachement dynamique si dess est une fonction virtuelle
// ex.: appel de Rectangle::dess ou RectangleP::dess
Attachement dynamique : argument (objet) implicite
class fenetre {
void fenetre::scroll(int dx, int dy) {
public:
...
virtual void dess(Graphics g, Rectangle r);
dess( g, r); // attachement
void scroll (int dx, int dy);
...
}
// dynamique
};
class fenetreGraph:public fenetre { // hérite de fenetre::scroll
virtual void dess(Graphics g, Rectangle r); …
};
fenetreGraph fg ;
fg.scroll(10,0);
// attachement statique … invocation de fenetre::scroll …
// mais dans scroll invocation fenetreGraph::dess !
[email protected]
93
Collection hétérogène d’objets
Classe abstraite
95
Cf. interface Java
96
Polygone
_coins
Polygone()
coin()
deplacer()
dess()
set_coin()
class Figure {
public:
virtual void dess (Graphics& g) const ;
virtual void deplacer(int x, int y) ;
...
}
Point
_x
_y
Point()
deplacer()
dess()
x()
y()
Figure
Figure()
deplacer()
dess()
~Figure()
Cercle
_centre
_rayon
Cercle()
centre()
deplacer()
dess()
rayon()
Toutes les figures
dérivent
de la classe
de base
Figure
Fonction virtuelle pure
class Figure {
public:
Figure(int x, int y) ;
virtual void dess (Graphics& g) const = 0 ;
virtual void deplacer(int x, int y); // comportement par défaut possible
protected: // si définition avec une pos. de référence …
int xOrig,yOrig;
...
}
ƒ Remarques
ƒ ( =0) signifie que la fonction est virtuelle pure : ne possède pas de définition
ƒ les classes dérivées devront redéfinir cette fonction
ƒ si une classe possède une fonction virtuelle pure, elle devient classe abstraite
™
Propriété d’une classe abstraite (concept générique)
ƒ
ƒ
ƒ
ƒ
ƒ
rassemble toutes les propriétés communes de ses classes dérivées
ne peut être directement instanciée
peut contenir des données membres
peut comporter des fonctions virtuelles
peut (doit) redéfinir des constructeurs
[email protected]
Rectangle()
Rectangle()
dess()
™
vector<Point>
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Rectangle
Pour définir un protocole générique de manipulation de
la classe de base on peut utiliser des méthodes virtuelles pures
vector <Figure*> figs(4);...
for (int i=0; i<figs.size(); i++) figs[i] ->dess(g);
[email protected]
RectangleP
_color
RectangleP()
dess()
Destructeur virtuel
Copie en profondeur & clonage
97
98
™
Toutes classes de Base « devraient » posséder un destructeur virtuel si ...
Copie d’un vecteur de figures
vector <Figure*> Figs1(9);
for (i=0;i<Figs.size();i++)
Figs2[i]=Figs1[i];
class D: public B {
public:
List _l;
...
};
// allocation dynamique
collection[1]= new D(…);
for (i=0; i<collection.size(); i++)
delete collection[i];
// désallocation explicite
// Ok : grâce au destructeur virtuel
for (i=0;i<Figs.size();i++)
Figs2[i]=Figs1[i]->clone();
class Figure {
public:
Figure(int x, int y);
virtual void dess(Graphics& g) const =0;
virtual void deplacer (int x, int y);
virtual Figure* clone() const =0;
virtual ~Figure() {}
protected: // déf. avec une pos. de réf…
int xOrig,yOrig;
};
class Cercle : public Figure {
public:
Cercle(int x=0, int y=0, int r=0);
virtual void dess(Graphics& gc) const;
virtual Figure* clone() const
{return new Cercle(*this);};
Point
int
centre() const;
rayon() const;
protected:
int
_rayon;
};
[email protected]
vector <B*> collection(4);
collection[0]= new B(…);
…
ƒ copie en profondeur / clonage
vector <Figure*> Figs2(9);
(« pour implanter une construction virtuelle »)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class B {
public:
virtual fonction(...);
virtual ~B( );
...
};
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ copie superficielle
Figure_exe.cpp && résultats
101
int main(int argc, char* argv[]){
cout << " >>> Conversion statique" << endl;
RectangleP RectP(P2,P1,1);
RectP.dess();
Rectangle Rect=RectP; cout << "-> ";
Rect.dess();
Version 4.2
cout << " >>> Attachement dynamique" << endl;
vector <Figure*> Figs(4);
Figs[0]=new Rectangle(P1,P2);
Figs[1]=new RectangleP(P1,P2,0);
Figs[2]=new Cercle(C);
Figs[3]=new Polygone(Poly);
for (int i=0;i<Figs.size();i++) {
Figs[i]->dess();
}
...
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
P1.dess();
C.dess();
Poly.dess();
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
dessin d'un point (10,10)
dessin d'un cercle (Rayon 100, Centre (20,20))
dessin d'un polygone :(10,10) (0,0) (50,80)
>>> Conversion statique
dessin d'un rectangle plein (1) (20,20) (10,10)
-> dessin d'un rectangle : (20,20) (10,10)
>>> Attachement dynamique
dessin d'un rectangle : (10,10) (20,20)
dessin d'un rectangle plein (0) (10,10) (20,20)
dessin d'un cercle (Rayon 100, Centre (20,20))
dessin d'un polygone :(10,10) (0,0) (50,80)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Point P1(10,10); Point P2(20,20);
Point P3(50,80);
Cercle C(20,20,100);
Polygone Poly(3);
Poly.set_coin(0,P1);
Poly.set_coin(2,P3);
Concepts avancés en Java / C++
Java
C++
103
Un petit bilan : le modèle objet en JAVA / C++
™
La notion de variable (discussion)
ƒ En C++
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ une variable sert à stocker les objets
Version 4.2
ƒ En JAVA
ƒ une variable sert à accéder aux objets
pointeur)
ƒ des avantages de java
ƒ les identificateurs ont tous la même taille : collections d’objets, ...
ƒ le polymorphisme s’exprime directement : attachement dynamique par défaut (en
C++ il faut utiliser des pointeurs, ..., méthodes virtuelles ...)
ƒ gestion mémoire automatique (GC)
ƒ des inconvénients de java
*notion de clone
ƒ la copie d’identificateurs ne génère qu’une référence supplémentaire sur un objet
existant / cette notion est peu intuitive ...
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ les identificateurs ne contiennent que les adresses des objets (notion de
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ les objets sont stockés en mémoire dynamique (Tas)
Héritage multiple et Interface
Java
C++
105
Héritage multiple C++ et Interface JAVA
™
C ++ / Héritage multiple
Professeur
C++
106
Cas simple d’héritage multiple en C++
™
Vacataire
Déclaration et utilisation
ƒ Un vacataire est à la fois étudiant et employé
ƒ Processus permettant l’héritage
de plusieurs classes
Employé
class Vacataire : public Etudiant, public Employe ... ;
Étudiant
...
ƒ Java ne permet pas
l’héritage multiple
Personne
Employe
ƒ Java intègre un mécanisme
voisin (plus restrictif) :
::::::::.... héritage d’interface multiple
Imprimable
imprime
ƒ Le mécanisme d’interface est un compromis qui :
ƒ intègre les fonctionnalités essentielles de l’héritage multiple
ƒ évite une dérive vers des situations instables
Rectangle
Vacataire* V = new Vacataire(…);
™
Employé
list_employe.push_back(V);
// ok
list_etudiant.push_back(*V);
// ok ; mais tronqué ...
Etudiant
Construction
ƒ Pour les cas « simples » d’héritage multiple : construction classique
Vacataire::Vacataire (. . .)
:
employe(…) ,
etudiant(…) ,
_donnée_locale( …) { }
[email protected]
Figure
Java / notion d’interface
Vacataire
list <Etudiant> list_etudiant;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
list <Employe*> list_employe;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Peut être utile pour des cas simples,
Personne
mais peut devenir très complexe et difficilement gérable
C++
107
Héritage multiple : classe de base dupliquée
™ Présence
C++
108
d’une classe de base commune
Héritage multiple : partage de classe de Base
™
Vacataire
Solution : prévoir un Héritage « virtuel » / Partage !
ƒ Définition
class Etudiant : public Personne ... ;
class Employe: public Personne ... ;
Employé
class Etudiant : virtual public Personne
Etudiant
class Employe: virtual public Personne
class Vacataire : public Etudiant, public Employe
ƒ Un objet "Vacataire" contient 2 sous-objets "Personne"
ƒ l'appel "Vacataire1._nom" est ambiguë
Ch. Etudiant
Etudiant
Personne
_nom = toto
Vacataire
Employe
Ch. Employe
Personne
Ch. Vacataire
_nom = tata
ƒ 1 objet «Vacataire» fait référence à 1 sous-objet «Personne »
‹
Ch. Etudiant
Construction
Le constructeur d’une classe de base virtuelle
Ch. Employe
partagée est appelé (implicitement ou
explicitement) une seule fois depuis le
Ch. Vacataire
constructeur de l’objet de la classe la plus
dérivée (la plus complète : notion peu stable !).
::::::: exploiter le constructeur par défaut ::::::
Personne
Objet vacataire
[email protected]
dérive 2 fois de «Personne»
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ «Vacataire»
Personne
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Vacataire : public Etudiant, public Employe ... ;
C++
109
Résolution des ambiguïtés
Règle de prédominance (si héritage virtuel)
A priori ambiguïté entre : Etudiant/Personne::impFiche()
Utilisation de l’héritage multiple ?
Rester dans des cas simples d'utilisation ...
Étudiant
impFiche
Employé
Vacataire1.impFiche(); // ok pas d'Ambiguïté
<=> Vacataire1.Etudiant::impFiche()
C++
110
Vacataire
™
Être conscient de la complexité de l’héritage multiple
ƒ Classe de base partagée (héritage partagé ...)
Personne
ImpFiche
ƒ Construction de classe de base virtuelle (constructeur par défaut ...)
ƒ Destructeur virtuel (dans les classes de base !)
Héritage de 2 classes avec des fonctions virtuelles
ayant la même signature
Ambiguïté entre : Etudiant/Employé::impFiche()
Personne
ImpFiche
Fusion des caractéristiques
Ok si Vacataire redéfinit la fonction virtuelle "impFiche()"
void Vacataire::impFiche() const {
Etudiant::impFiche();
Employe::impFiche();
}
Vacataire
ImpFiche
Employé
ImpFiche
Étudiant
impFiche
Personne
ImpFiche
™
Ne pas confondre héritage (multiple) et agrégation
ƒ Avantage de l’héritage : le polymorphisme ... Est-il toujours utile !?
ƒ Le plus souvent héritage non justifié / d’autant plus vrai s’il est multiple
™
*notion d'interface Java
Un cadre intéressant d’utilisation :
mise en commun de mécanismes (ou de protocoles)
class Personne : public CObjet, public BDonnee ... ;
ƒ "CObjet" et "BDonnee" sont des classes
ƒ sans donnée, avec des fonctions virtuelles
ƒ elles définissent le protocole que les classes doivent mettre en œuvre pour
pouvoir être exploiter comme CObjet et BDonnee
[email protected]
Étudiant
impFiche
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Employé
ImpFiche
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Vacataire
Java
112
Interface Java
™
Définition
ƒ Une interface Java est une sorte de classe abstraite "pure" :
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Sans donnée (sauf static et final)
ƒ Possède seulement des fonctions abstraites (publiques)
Version 4.2
ƒ Une classe peut "implémenter" plusieurs Interfaces (z héritage)
méthodes de l'interface
ƒ <=> elle garantit de respecter
le protocole défini par l'interface
public class Personne implements Imprimable
{
…
™
Implantation
// redéfinition obligatoire
// imposée par l'interface Imprimable
public void imprime(){
interface Imprimable {
System.out.println(this);
public void imprime();
}
}
…
public class Employe extends Personne {…}
[email protected]
Interface Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Lorsqu'une classe implémente une interface elle garantit de définir toutes les
Exemple d'utilisation d'interface
public static void main(String[] args){
Personne p1=new Personne(29, "toto");
Employe e1=new Employe(29, "titi",7000);
Rectangle r1 = new Rectangle (new Point(1,1) ,
new Point (100,100));
Imprimable[] tabImpression= new Imprimable[3];
public class Rectangle extends Figure
tabImpression[0]=p1;
implements Imprimable {
tabImpression[1]=e1;
private Point p_hg;
tabImpression[2]=r1;
private Point p_bd;
for (int i=0; i< tabImpression.length; i++) {
public void imprime(){
tabImpression[i].imprime();
System.out.println("Rectangle : " +
}
p_hg + " " + p_bd);
}
Personne : toto : 29
}
Employe : titi : 29 / 7000
…
Rectangle : (1,1) (100,100)
Exemple d'interface : diagramme de classe
Interface :
services
offerts par
une classe
ƒ L'interface garantit que tous
les objets du tableau
(même de nature différente)
sont imprimables
Lien de
réalisation :
Personne
et
Rectangle
fournissent
l'interface
[email protected]
™
On caractérise les classes <Imprimable>
void imprime();
}
ƒ avec l'Interface <Imprimable>
ƒ Par exemple : les classes <Personne> et <Rectangle>
On peut alors rassembler dans un tableau des classes respectant le protocole
<Imprimable>
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
114
interface Imprimable {
[email protected]
Java
113
Java
115
NB : Interface et héritage
Interface Versus Classe abstraite
116
™
Héritage classique
™
ƒ Les interfaces peuvent être organisées de manière hiérarchique via le
Une Interface
ƒ spécifie la forme (spécification, définition d'un comportement) de quelque
mécanisme d’héritage.
chose (d'un concept) (<> fournir une implémentation)
ƒ Les méthodes de l'interface définissent le protocole (signature) à faire
Interface intFaceA extends intFaceB { …}
Héritage « diamant »
ƒ Il y aura automatiquement héritage multiple partagé en cas d’héritage de « type
diamant »
™
Classe abstraite
ƒ Une classe abstraite est une classe incomplète qui nécessitera une
spécialisation (une dérivation)
ƒ A utiliser pour initialiser une hiérarchisation de classes (classe de base)
[email protected]
interface intFaceA extends intFaceX, intFaceY {…}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ On peut avoir un héritage multiple d’interfaces :
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
respecter pour ce concept
C++
118
Les « templates » constituent un mécanisme de programmation générique
ƒ Exemple
ƒ La classe vector<T> a été conçue pour pouvoir intégrer un type générique T
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
vector <int>
// tableau dont les éléments sont de type int
vector <Figure*>// tableau dont les éléments sont de type Figure*
notion de Template
ƒ Mécanisme d’instanciation
ƒ La classe template vector<T> possède un type générique T.
ƒ Compilation : instancie le véritable type (ex: int),
ƒ crée une nouvelle classe
(ex: vector<int> TabNotes).
Template
Classe
Objet
vector<T>
vector<int>
TabNotes
ƒ Utilisation
ƒ Pour faciliter la construction de concepts génériques
ƒ Pour la création de classe de type « conteneur » : liste, queue, tableau, …
[email protected]
Classe paramétrée
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Introduction : classes paramétrées
Mise en œuvre de classe template (interface .h)
™
C++
120
™
Construction de l’interface
On ajoute devant la déclaration de la classe le mot clé template<class nomG>, où
nomG représente le nom du type générique
template<class T>
class File {
public:
File();
void inserer(T t);
T
retirer ( );
int
longueur ( ) const;
private:
Elt<T>*
_tete;
Elt<T>*
_queue;
int
_longueur;
};
_queue
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
template <class C>
class Elt {
public:
Elt(C, Elt<C>* = NULL);
private:
Elt<C>*
_suiv;
C
_info;
friend class File<C>;
};
_tete
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Exemple : une classe générique File
Mise en œuvre de classe template (f. membres)
Définition des fonctions membres
template<class T>
void File<T>::inserer(T t) {
Elt<T>* p = new Elt<T>(t) ;
if (_queue) _queue ->_suiv = p ;
else _tete = p ;
_queue = p;
_longueur ++;
}
_tete
template<class T>
T File<T>::retirer( ) {
assert (_tete!=NULL) ;
T t = _tete ->_info ;
Elt<T>* p = _tete ->_suiv ;
delete _tete ;
_tete = p ;
if (_tete ==NULL)
queue=NULL;
_longueur --;
return t ; // constructeur
}
// par recopie
_queue
template<class T>
File<T>::File( )
: _tete(NULL) , _queue(NULL) , longueur(0)
{}
[email protected]
C++
119
Template multi-type (paramétrage /type ou /valeur)
™ Template
C++
122
™
multi-type
ƒ On peut définir des classes avec plusieurs types génériques
Map<string, int> age;
age.set("toto", 10);
string nom="toto";
int a=age.get(nom);
template <class K, class V>
class Map {…};
template <class T, class U=defaultU>
ƒ La classe doit être définissable à la compilation
// ok
// ok
// erreur
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class TabFix {…};
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
template <class T, int dimX, int dimY>
void methode(int nb) {
int* tab1nombre = new int[nb];
TabFix<int, 1, 2 > Tab;
TabFix<int, nb, nb > Tab2;
}
Paramètre template par défaut possible
ƒ Attention à la version du compilateur (Ansi C++)
ƒ On peut mixer : types génériques et types fixés a priori (à la compilation)
TabFix<Point, 1 , 10> Tab;
Paramètre template par défaut
template<class P>
class Toto { ... }
template <class T, class U=Toto<T> >
class Truc { ... }
[email protected]
C++
121
C++
123
Fonction template et Spécialisation
™
C++
124
Précautions avec «l'instanciation»
™ Tous
Fonction template
les types ne peuvent pas être instanciés
ƒ ex1: il manque un constructeur par recopie
Spécialisation
ƒ On peut spécialiser l’instanciation pour certain type (surcharge)
max("toto", tonton");
// ne fonctionne pas avec la définition précédente
const char* max(const char* a, const char* b) {
return strcmp(a, b) > 0 ? a : b ;
}
ƒ ex2 : il manque un comparateur
Map<string, int> age;
age.set (" toto", 10);
…
age. set(" tata", 20);
// ok le comparateur ==
// existe pour les string
Map<etudiant, int> notes;
...
// Probleme si le comparateur ==
// n’existe pas pour la classe etudiant
Il faut absolument spécifier les besoins de la classe template en constructeurs
et opérateurs ainsi que son comportement
[email protected]
™
// assez difficile à gérer pour le compilateur ...
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
unsigned long x, y, z;
z=max(x,y);
File<ostream> OsFile;
NB: le constructeur par recopie ostream est privé ;
il ne peut donc pas être utilisé par la classe File<ostream>
ostream File<ostream>::retirer( ) {
…
return t;
// Pb … besoin du constructeur par recopie
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
template <Class T>
inline T max (T a, T b) {
return a>b ? a : b ;
}
Java
126
Les Generics - introduction
™
Objectifs
ƒ Possibilité d’abstraire des types (on parle de types paramétrés)
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Attention : similitudes et différences / Template C++
Version 4.2
ƒ Exemple d’utilisation : invocation de types paramétrés
Rappel
// avant java 5
List l1 = new ArrayList();
l1.add(new Integer(0));
Integer x = (Integer) l1.iterator().next();
l1.add(new Character('a'));
// liste d'Object
// ajout d'un Integer qui est un Object
// nécessité d'un cast : Object -> Interger
// Possible !?: ajout d'un Character qui est un Object
// apres java 5
List<Integer> l2 = new ArrayList<Integer>();
// Liste d'Integer (le type de la liste a été spécifié : <Integer>)
l2.add(new Integer(0));
// ajout d'un Integer à une liste d'Integer : OK!
Integer x2 = l2.iterator().next();
// Plus besoin de Cast ! On est certain du type des éléments de la liste
l2.add(new Character('a'));
// Maintenant ImPossible : vérification de type statique : à la compilation
// Maintenant =>The method add(Integer) in the type List<Integer>
//
is not applicable for the arguments (Character)
[email protected]
Les Generics – en Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Amélioration de la lisibilité et de la robustesse
Java
127
Les Generics – Définition de “generics”
™
Java
128
Les Generics – Définition de “generics”
ƒ Le « Generic » est compilé en une unique classe
On spécifie à la déclaration du « Generics » (classe paramétrée)
les paramètres formels entre <>
ƒ Les paramètres formels sont remplacés
Les « Generics » ne sont pas des « Template C++ »
ƒ Invocation d’une liste d’entier : List<Interger>
<=>
public interface IntegerList {
void add(Integer x)
Iterator<Integer> iterator();
}
Attention oui et NON
ƒ Pas de duplication du code pour chaque type de paramètre utilisé
List<String> ls = new ArrayList<String>();
List<Integer> li = new ArrayList<Integer>();
System.out.println(ls.getClass() == li.getClass());
System.out.println(ls.getClass().getName());
System.out.println(li.getClass().getName());
=> réponse
true
java.util.ArrayList
java.util.ArrayList
[email protected]
// E = paramètre formel de l'interface Iterator
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
// E = paramètre formel de l'interface List
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
à l’invocation du « Generic » par les paramètres effectifs
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
Les Generics – Héritage
™
Java
130
™
Héritage et generics
ƒ Si
CD
Alors
ClassG<CD>
hérite de
n’hérite PAS de
Les Generics – Wildcards et Bounded Wildcards
class Fenetre{
public void draw(Figure s) { s.draw(this); }
CB
ClasseG<CB>
Rectangle
public void drawAll(List<Figure> Figures) {
for (Figure s: Figures) { s.draw(this); }
} // on ne peut passer en paramètre que des List<Figure>
ƒ Pourquoi ? Si c’était possible : ls et lo référenceraient la même liste !
ƒ donc
lo.add(new Object());
String s = ls.get(0); // Pb on essaie d’assigner un objet à une string !
[email protected]
ƒ => ls pourrait contenir des objets n’étant pas des String !
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
List<String> ls = new ArrayList<String>();
List<Object> lo = ls; // Type mismatch: cannot convert from List<String> to List<Object>
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Utilisation du wildcard <?>
Cercle
Figure
public void drawAll1(List<?> Figures) {
// wildcards
for (Figure s: (List<Figure>)Figures) { s.draw(this); } // Cast … dangereux !
} // on peut passer en paramètre des List<de n’importe quel objet>
public void drawAll2(List<? extends Figure> Figures) { // Bounded Wildcards
for (Figure s: Figures) { s.draw(this); }
// ok
} // on peut passer en paramètre des List< Objet héritant de Figure>
public static void main(String[] args) {
Fenetre ca=new Fenetre();
ca.draw(new Cercle());
ca.drawAll(new ArrayList<Cercle>());
ca.drawAll1(new ArrayList<Cercle>());
ca.drawAll2(new ArrayList<Cercle>());
}
}
// The method drawAll(List<Figure>) in the type Canvas
// is not applicable for the arguments (ArrayList<Cercle>)
// ok
// ok
[email protected]
Java
129
Java
131
Les méthodes Generic
™
Rectangle
Recopie d’éléments d’une liste à l’autre
Cercle
Figure
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
public static void recopie( List<? extends Rectangle> Figures,
List<Rectangle> Rectangles) {
for (Rectangle r: Figures) { Rectangles.add(r); }
}
public static void recopie1(List<?> l1, List<?> l2) {
for (Object r: l1) { l2.add(r); }
}
™
// Erreur à la compilation !
Utilisation d’une méthode générique
public static <T> void recopie2(List<? extends T> l1, List<T> l2) {
for (T r: l1) { l2.add(r); } // ok !
}
public static <T,S extends T> void recopie3(List<S> l1, List<T> l2) {
for (T r: l1) { l2.add(r); } // ok : mais préférer la solution précédente
}
ƒ Préférer l’utilisation des Wildcards : solution + concise et + claire !
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Comment généraliser ?
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Version 4.2
Introduction à
la librairie standard
du c++ (STL)
C++
133
Introduction à la STL
™
C++
134
Les conteneurs élementaires
™
La librairie standard du C++ intègre
ƒ Des classes conteneurs et leur algorithmes associés
Vector
ƒ Tableaux du C++ avec possibilité d’allocation dynamique
ƒ La gestion des string et des flux (iostream)
ƒ Accès en O(1), ajout/supression en O(n) en milieu de vecteur
ƒ ajout/supression en O(n) en fin de vecteur avec redimensionnement,
sinon en O(1)
Intérêt de la librairie standard du C++ (STL)
™
ƒ Maintenant totalement intégrée au standard du C++
ƒ Fiabilité
ƒ Les classes sont sûres, validées depuis plusieurs années
ƒ Maintenabilité
ƒ Tout le monde utilise le même standard,
ƒ le code est compréhensible et les évolutions sont homogènes
ƒ Efficacité
ƒ Les composants ont été écrits par des experts, pour aboutir à un code efficace
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Autrefois connue sous le nom de STL (Standard Template Library)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Standardisation
List
ƒ Représente les listes chaînées habituelles
ƒ Pas d’opérateur d’indéxation
ƒ Mais permettent : ajout/supression en O(1) en milieu de liste
ƒ NB: occupation mémoire souvent supérieure à un vecteur
™
Deque
ƒ Intermédiaire entre List et vector
ƒ Très efficace pour les ajout/suppression à une extrémité
ƒ Indexation en o(log(n))
ƒ Insertion plus rapide que vector mais moins rapide que les listes
[email protected]
™
Les Vecteurs
™
C++
136
Introduction
Notion d‘itérateur
™
Notion d'Itérateur
™
Tout conteneur STL définit
ƒ équivalent des Vector ou ArrayList de Java
ƒ représente la "position" d’un élément dans une collection
ƒ tableaux pouvant croître dynamiquement.
™
ƒ le type iterator
Utilisation Basique
ƒ avec les méthodes
ƒ begin : itérateur qui pointe sur le premier élément de la collection
ƒ push_back : ajoute un élément en fin de vecteur.
ƒ end : itérateur qui pointe sur la case après le dernier élément
ƒ push_front : insère un élément en début de tableau
ƒ Opérateur * : permet d’accéder à l’élément à partir de l’itérateur
ƒ clear : vide le vecteur, le ramenant à une taille de 0.
ƒ resize : permet de modifier la taille du vecteur (en insérant ou détruisant
éventuellement des éléments en fin de vecteur).
#include <iostream>
#include <vector>
La taille du vecteur est de 9
#include <string>
La taille du vecteur est de 0
using namespace std;
int main(int, char **){
vector<string> v0; // Vecteur vide
vector<string> v1(8); // Vecteur contenant 8 string
v1.push_back("chaine");
cout << "La taille du vecteur est de " << v1.size() << endl;
v1.clear();
cout << "La taille du vecteur est de " << v1.size() << endl;
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ l’opérateur crochets [ ] : Accès/modification du vecteur
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ size() :Taille du vecteur
ƒ Opérateur ++ : avancement de l’itérateur
(NB: post-incrément (recopie de l’objet) /pré-incrément (évite la recopie) )
vector<string> v2;
v2.push_back("bonjour");
vector<string>::iterator iter;
for(iter=v2.begin(); iter!=v2.end(); iter++) cout << *iter << endl;
cout <<"affichage en utilisant les itérateurs sur flux et la fonction copy" << endl;
std::copy(v2.begin(),v2.end(),ostream_iterator<string>(cout, "\n") );
™
Les itérateurs sur vecteurs supportent les opérations + et vector<string>::iterator it;
it = v2.begin()+2; //accès à l’élément d’indice 2
int index = it - v2.begin(); // accès à l’index à partir de l’itérateur
cout << index << endl;
[email protected]
C++
135
Recherche - Insertion - Suppression
™
C++
138
™
La fonction find (Usage Générique)
ƒ Exemple de méthode spécifique
using namespace std;
int main(int, char **){
vector<string> v2;
v2.push_back("bonjour"); v2.push_back("tout"); v2.push_back("le"); v2.push_back("monde");
vector<string>::iterator iter;
it = find(v2.begin(),v2.end(),"monde");
v2.insert(it,"---");
for(iter=v2.begin(); iter!=v2.end(); iter++) cout << *iter << endl;
bonjour
le
--monde
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
#include <list>
#include <iostream>
#include <vector>
#include <string>
#include <algorithm> // pour accéder à find
v2.erase(it);
Avantages
ƒ l'insertion et la destruction d'un élément, où qu'elle se fasse dans une liste, se fait toujours en
temps constant.
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ ou d'une arithmétique des pointeurs
™
ƒ La recherche impose que l'opérateur == soit défini sur le type de donnée.
it = find(v2.begin(),v2.end(),"tout");
Les listes ne disposent pas
ƒ de l'opérateur crochets,
ƒ permet de rechercher un élément dans tout conteneur STL.
ƒ prend en paramètre
ƒ un itérateur sur le début et sur la fin du conteneur,
ƒ ainsi que l'élément à rechercher.
ƒ Retourne :
ƒ un itérateur sur la première occurence de l'élément trouvée,
ƒ ou est égal à end() si aucun élément n'a été trouvé.
vector<string>::iterator it;
Les listes
using namespace std;
int main(int, char **){
list<int> L, L2;
L.push_back(0);
L.push_front(1); // insère un élément en tête de liste
L.insert(++L.begin(), 2);
list<int>::iterator itL;
for(itL=L.begin(); itL!=L.end(); itL++) cout << *itL << endl;
L2.push_back(3); L2.push_back(4);
L.splice(L.end(),L2); // insère L2 dans L avant l’itérateur, ensuite L2 est vide
cout << "-"<< endl;
for(itL=L.begin(); itL!=L.end(); itL++) cout << *itL << endl;
L.sort(); // trie les éléments selon l’opérateur <
cout << "-"<< endl;
for(itL=L.begin(); itL!=L.end(); itL++) cout << *itL << endl;
}
1
2
0
1
2
0
3
4
0
1
2
3
4
[email protected]
C++
137
Les files (queue) et piles (stack)
ƒ Uniquement un constructeur
par défaut
ƒ Les éléments doivent avoir
les opérateur == et <=
ƒ Implémentation plutôt par
deque ou list
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Conteneurs associatifs : set, map,
™
#include <deque>
#include <queue> // pour les files
#include <stack> // pour les piles
using namespace std;
ƒ Les accès aux valeurs passent par les clefs
ƒ On peut alors extraire par exemple:
int main(int, char **){
stack<int,deque<int> > pile;
ƒ Les elts associés à une clef
queue<int,deque<int> > file;
ƒ Les elts dont la clef est sup/inf à une valeur, …
cout << "Ordre d'entree : ";
Stack (dernier arrivé, 1er servi)
ƒ Les conteneurs set et map requièrent qu'il existe un ordre sur les clefs
for (int j=0;j<5;j++) {
ƒ Même contrainte que les files
ƒ Implémentation plutôt par
deque ou vector
int i=rand()%10;
cout << i << " ";
pile.push(i); // ajout d’un élément
file.push(i); // ajout d’un élément
}
cout << endl << "Ordre de sortie pour la pile : ";
while (!pile.empty()){
Ordre d'entree : 1 7 4 0 9
cout << pile.top() << " "; // accès au sommet
Ordre de sortie pour la pile : 9 0 4 7 1
pile.pop(); // retire l’élément en sommet
Ordre de sortie pour la file : 1 7 4 0 9
}
cout << endl << "Ordre de sortie pour la file : ";
while (!file.empty()) {
cout << file.front() << " "; // accès à la tête de file
file.pop(); // retire l’élément en tête de file
}
}
Les conteneurs (set et map) reposent sur la notion de paire(clef,valeur)
ƒ Le paramètre par défaut pour ordonner les clefs est std::less<type_clef>, qui
utilise l'opérateur <
™
Deux types de conteneurs
ƒ Les ensembles (set et multiset)
ƒ Valeur et clef sont confondues
ƒ Les tables d’associations (map et multimap)
ƒ Le couple (clef, valeur) intervient
™
Les types utilisés
ƒ Le type pair (#include <utility>)
ƒ Key_type = type de la clef
ƒ Value_type = paire constituée de (const type_clef, type_valeur)
[email protected]
Queue (1er arrivé, 1er servi)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
C++
140
[email protected]
C++
139
Exemple d’utilisation de set
const int N = 6;
const string a[N] = {"01_un", "02_deux", "03_trois",
"04_quatre", "05_cinq", "06_six"};
const char* b[N] = {"06_six","07_sept", "08_huit", "09_neuf",
"10_dix", "11_onze"};
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
set<string> A(a, a + N); // initialisation des set (prédicat d’ordre par défaut sur les string)
set<string> B(b, b + N);
set<string> C;
set<string>::iterator itS;
cout << "*Set A: "<< endl;
for(itS=A.begin(); itS!=A.end(); itS++) cout << *itS << endl;
cout << "*Set B: "<< endl;
for(itS=B.begin(); itS!=B.end(); itS++) cout << *itS << endl;
cout << "**Union: " << endl; // fonctions renvoyant un itérateur sur l’ensemble construit
set_union(A.begin(), A.end(), B.begin(), B.end(),inserter(C, C.begin()));
for(itS=C.begin(); itS!=C.end(); itS++) cout << *itS << endl;
C.clear();
cout << "**Intersection: " << endl;
set_intersection(A.begin(), A.end(), B.begin(), B.end(),inserter(C, C.begin()));
for(itS=C.begin(); itS!=C.end(); itS++) cout << *itS << endl;
C.clear();
cout << "**Difference (A - B): " << endl;
set_difference(A.begin(), A.end(), B.begin(), B.end(),inserter(C, C.begin()));
for(itS=C.begin(); itS!=C.end(); itS++) cout << *itS << endl;
C++
142
Les tables d’associations (map)
™
Exemple d’utilisation de map
typedef map<int, string, std::less<int> > MapIntString;
typedef MapIntString::iterator MapIntStringIt;
typedef MapIntString::value_type PairIntString; //type pair
ostream& operator<< (ostream& a, const PairIntString& b) {
a << "(Clef : " << b.first << " Valeur : " << b.second<<")"; //type pair
return a;
}
int main(int, char **){
MapIntString map1;
MapIntStringIt itCourant;
map1[1]="un";map1[2]="deux";map1[3]="trois";
** Affichage avec acces indexe
un
deux
trois
** Affichage avec une paire d'iterateurs
(Clef : 0 Valeur : )
(Clef : 1 Valeur : un)
(Clef : 2 Valeur : deux)
(Clef : 3 Valeur : trois)
Recherche avec find
Recherche de la clef 2 = deux
cout << "** Affichage avec acces indexe" << endl;
for (int compteur=0;compteur<4;compteur++) cout << map1[compteur] << endl; //attention à[]
cout << "** Affichage avec une paire d'iterateurs " << endl;
itCourant=map1.begin();
while (itCourant != map1.end()) cout << (*(itCourant++)) << endl;
cout << "Recherche avec find" << endl;
cout << "Recherche de la clef 2 = ";
MapIntStringIt itRecherche=map1.find(2); //retourne un iterator
if (itRecherche != map1.end())
{ cout << (*itRecherche).second << endl; } //type pair
else
{ cout << "Pas trouve" << endl; }
}
[email protected]
™
*Set A:
01_un
02_deux
03_trois
04_quatre
05_cinq
06_six
*Set B:
06_six
07_sept
08_huit
09_neuf
10_dix
11_onze
**Union:
01_un
02_deux
03_trois
04_quatre
05_cinq
06_six
07_sept
08_huit
09_neuf
10_dix
11_onze
**Intersection:
06_six
**Difference (A - B):
01_un
02_deux
03_trois
04_quatre
05_cinq
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Les ensembles (set)
[email protected]
C++
141
Les Objets fonction (foncteur) / operator()
™
C++
144
™
Un objet fonction est un objet dont on a redéfini l’opérateur ()
ƒ NB : l’opérateur « operator() » peut prendre autant de paramètres que nécessaire
class elt_find { // objet fonction de type prédicat
int val;
public:
elt_find(int i) {val=i;};
bool operator()(Element s) { return s.indice == val; } // 1 paramètre
};
class elt_croissant { // objet fonction de type prédicat
public:
bool operator()( Element x, Element y) { return x.diff < y.diff; } // 2 paramètres
};
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
using namespace std;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Exemple d’utilisation / STL
#include <vector>
#include <algorithm>
#include <iostream>
class Element {
public:
int indice;
double diff;
int classe;
Element(int i,double d,int c):indice(i),diff(d),classe(c){}
};
class elt_decroissant { // objet fonction de type prédicat
public:
bool operator()( Element x, Element y) { return x.diff > y.diff; } // 2 paramètres
};
Les Objets fonction / operator()
void main () {
vector<Element> vect_ex;
vect_ex.push_back(Element(0,11.1,2));
vect_ex.push_back(Element(1,22.1,2));
vect_ex.push_back(Element(2,23.1,3));
vector<Element>::iterator ite;
//Utilisations :
ite=find_if(vect_ex.begin(), vect_ex.end(), elt_find(1));
cout << "find(indice=1) / diff = " << ite->diff << endl;
find(indice=1) / diff = 22.1
diff(2) = 23.1
diff(1) = 22.1
diff(0) = 11.1
sort(vect_ex.begin(), vect_ex.end(), elt_decroissant());
for (int i=0; i<vect_ex.size(); i++) {
cout << "diff("<<vect_ex[i].indice<<") = " << vect_ex[i].diff << endl;
}
}
[email protected]
C++
143
Les Objets fonction / operator() / fonction trier (sort)
145
™
Exemple de fonction trier : utilisation d’un foncteur
ƒ NB: au niveau de la signature des template, on peut utiliser « typename » à la place de
« class » (compilateur récent)
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
while (i!=fin) {
j=i;
++j;
while (j!=fin) {
if (estAvant(*j,*i)) std::swap(*i,*j);
++j;
}
++i;
}
}
™
objet fonction (foncteur) less Ù OrdreCroissant
template <typename T> class OrdreCroissant {
public:
bool operator()(const T& a, constT & b) const { return a<b; }
};
™
Pour trier (avec sort) un vector v dans l'ordre croissant
std::sort(v.begin(), v.end(), OrdreCroissant<int>());
Ù std::sort(v.begin(), v.end());
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Version 4.2
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
template <typename Iter, typename Ofonc>
void trier(const Iter& debut, const Iter& fin, const Ofonc& estAvant) {
Iter i = debut;
Iter j;
Concepts avancés en Java
Java
148
Les flots(stream) en Java : java.io.*
™
ƒ Flot = flux de données associé à
ƒ une source (flot d'entrée) ou une cible (flot de sortie)
ƒ Source et Cible = fichier, tampon, socket, un autre flot, etc.
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
Les flots basiques (Java 1.0) : orientés byte (octet)
ƒ Classes de base abstraites : InputStream, OutputStream
ƒ Classes dérivées :
ƒ FileInputStream, FilterInputStream, BufferedInputStream, DataInputStream ,
ect.
ƒ FileOutputStream, FilterOutputStream, BufferedOutputStream,
DataOutputStream, ect.
™
Les flots avancés (à partir de Java 1.1) : orientés char (Unicode)
ƒ Classes de base abstraites : Reader et Writer
ƒ Classes dérivées :
ƒ BufferedReader, InputStreamReader, FileReader, etc.
ƒ BufferedWriter, OutputStreamWriter, FileWriter, PrintWriter, etc.
[email protected]
Flots(stream) en Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Les entrées/sorties sont organisées autour des flots
Les flots(stream) : flots d'octets (8 bits)
Java
150
import java.io.*;
Exceptions transmises à la console
import java.io.*;
Les flots(stream) : flots de char (16 bits)
class FlotCar {
class FlotOctet {
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws IOException {
int car;
InputStream in; // flot d'octets d'entree
if (args.length == 1) {
OutputStream out; // flot d'octets de sortie
in = new FileInputStream(args[0]); // association du flot à un fichier
out = new FileOutputStream(args[1]); // association du flot à un fichier
while ((octet = in.read()) != -1) out.write(octet); // lecture /ecriture (octets)
in.close();
}
}
Lecture d'un octet
(8bits)
Rend -1 en fin de
fichier
Écriture d'un octet
(8bits)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
System.out.println("in : "+args[0]+" out : "+args[1]);
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
OutputStream out = new FileOutputStream(args[0]); // flot sortie octet -> fichier
if (args.length == 2) {
out.close();
Conversion
flot d'octets
/
flots de char (unicode)
InputStream in = System.in; // association du flot à l'entrée standard
int octet;
}
Entrée standard
InputStreamReader is=new InputStreamReader(in); // flot octet -> char (unicode)
OutputStreamWriter os=new OutputStreamWriter(out); // flot octet <- char (unicode)
while ((car = is.read()) != -1) {
os.write(car); // lecture /ecriture (char)
Lecture d'un char
(unicode / 16 bits)
System.out.println((char)car);
}
is.close(); os.close(); // fermeture du flot
in.close(); out.close(); // fermeture du flot
}
}
}
Écriture d'un char
(unicode / 16 bits)
[email protected]
Java
149
Les flots(stream) : flots de char avec tampon
Java
152
™
import java.io.*;
class FlotBuffer {
public static void main(String[] args) throws IOException {
int car;
if (args.length == 2) {
Les flots(stream) : flots de données avec tampon
Association directe
fichier
/
flots de char (unicode)
class FlotData {
public static void main(String[] args) throws IOException {
InputStream is = new FileInputStream("fo.test");
OutputStream os = new FileOutputStream("fo.test");
DataInputStream isbd = new DataInputStream(
new BufferedInputStream(is)); // flot octet(buffer)-> donnee
DataOutputStream osbd = new DataOutputStream(
new BufferedOutputStream(os));
System.out.println("in : "+args[0]+" out : "+args[1]);
BufferedReader isb = new BufferedReader(is);
BufferedWriter osb = new BufferedWriter(os);
while ((car = isb.read()) != -1) {
System.out.println((char)car);
}
Utilisation d'un tampon
(buffer) pour optimiser le
coût des entrées/sorties
Beaucoup plus rapide !
isb.close(); osb.close(); // fermeture du flot
}
}
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
OutputStreamWriter os = new FileWriter(args[1]); // flot char -> fichier
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
InputStreamReader is = new FileReader(args[0]); // flot char <- fichier
osb.write(car); // lecture /ecriture (char)
Lecture / Écriture de valeurs typées (données)
sur flot d'octets avec tampon
Caractère unicode
char c1='\u01b5'; double d1=1.11;
osbd.writeChar(c1);osbd.writeDouble(d1);
osbd.close(); // fermeture du flot
Écriture de valeurs typées : double, char,
float, etc.
System.out.println(isbd.readChar()+" "+ isbd.readDouble());
isbd.close(); // fermeture du flot
}}
Lecture de valeurs
typées
[email protected]
Java
151
Les flots(stream) : flots de données avec tampon
Les flots basiques : orientés byte (octet)
class FlotData {
public static void main(String[] args) throws IOException {
InputStreamReader is2 = new InputStreamReader(
new FileInputStream("fc.test"),"UTF16" );
OutputStreamWriter os2 = new OutputStreamWriter(
new FileOutputStream("fc.test"),"UTF16" );
BufferedReader isb2 = new BufferedReader(is2); // flot char (buffer)
PrintWriter osb2 = new PrintWriter(new BufferedWriter(os2)); // flot char lisible (buffer)
osb2.print(c1); osb2.print(" "); osb2.print(d1); Écriture au format texte
osb2.close(); // fermeture du flot
String uneLigne=isb2.readLine(); Lecture d'une ligne de texte
StringTokenizer st = new StringTokenizer(uneLigne);
System.out.println(st.nextToken()+ " "+ st.nextToken());
isb2.close(); // fermeture du flot
}}
séparation des elts de
la chaîne de texte
[email protected]
Écriture / Lecture sur flot de char (unicode)
avec tampon / écriture au format texte
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Java
154
[email protected]
Java
153
Java
155
Les flots avancés : orientés char (Unicode)
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Version 4.2
Java 5 (Tiger) / Rappel
printf - scanner
Printf : Sortie standard formatée
™
Java
158
™ Sur
Similaire à la fonction « C » printf !
System.out.printf("d1= %f et d2= %1.2f \n", d1,d2);
ƒ Cf.
java.util.Formatter
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Formatage avancé
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Sur
Résultat
d1= 1,100000 et d2= 2,00
™
l’entrée standard / Méthode next : blocante !
< maChaine
Scanner s= new Scanner(System.in);
< 2005
String entreString=s.next();
> entreString= maChaine et entreInt= 2005
int entreInt=s.nextInt();
System.out.printf("entreString= %s et entreInt= %d \n",entreString,entreInt);
s.close();
float d1=1.1f;
float d2=2f;
™
le scanner : entrée formatée
un fichier
Scanner sc = null;
try { sc = new Scanner(new File("sequence_ordres"));}
catch (java.io.FileNotFoundException e) { System.out.println(e); }
while (sc.hasNextInt()) { // est-ce qu’il y a un nouvel élt (token) à analyser ?
System.out.println(sc.nextInt()); // on récupère l’élt suivant (token)
}
™ Définition
de délimiteurs // StringTokenizer
String entree="s-a-l-u-t";
Scanner s2= new Scanner(entree).useDelimiter("\\s*-\\s*");
String sortie = s2.next() + s2.next()+ s2.next()+ s2.next()+ s2.next();
s2.close();
System.out.printf(sortie);
salut
[email protected]
Java
157
Java
160
Sérialisation : introduction
™
Objectifs de la sérialisation d'un objet
ƒ Mécanisme permettant de stocker/d'exporter "automatiquement" un objet via
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
un flot dont le support peut être : un fichier, une socket, RMI, etc.
™
Version 4.2
Avantages
ƒ Format des données d'exportation/importation géré par Java
ƒ Évite les révisions des protocoles de sauvegarde à chaque modification
de vos classes
ƒ Le format ("Java") est multi plate-formes : exemple
ƒ Sérialisation(exportation) d'un objet créé sous Windows
ƒ Désérialisation(importation) de ce même objet sous Unix
ƒ Gestion des dépendances (références), même cycliques entre objets
ƒ Le graphe des dépendances des objets sérialisés est géré automatiquement
par Java
ƒ Persistance
ƒ La sérialisation permet de mettre en œuvre la notion de persistance d'un objet
: sa durée de vie n'est plus couplée à l'exécution du programme
[email protected]
Sérialisation en Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Il n'est plus nécessaire de définir un format de stockage pour vos données
Java
161
Sérialisation : mise en œuvre automatique
™
Java
162
Sérialisation : mise en œuvre automatique
™
Pour être sérialisable la classe d'un objet doit implémenter l'interface
java.io.Serializable
Gestion d'un flot de sortie d'objets sérialisés
la Classe : ObjectOutputStream
ƒ Constructeur
ƒ Interface de typage (balisage) sans méthode (idem à Cloneable)
ƒ public ObjectOutputStream(OutputStream out) throws IOException
ƒ Sérialisation et désérialisation des objets de cette classe
très simple avec les mécanismes par défaut.
ƒ Méthodes d'écriture
val: int
Info()
toString()
main()
ƒ public void writeInt (int data) throws IOException;
ƒ public void writeDouble(double data) throws IOException; …
™
Gestion d'un flot d'entrée d'objets sérialisés
la Classe : ObjectInputStream
ƒ Constructeur
ƒ public ObjectInputStream(InputStream in)
throws IOException, StreamCorruptedException
ƒ Méthodes de lecture
ƒ public Object readObject()
throws ClassNotFoundException, IOException;
ƒ public int readInt() throws IOException; …
[email protected]
Info
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class Info implements Serializable {
private int val;
public Info(int v) {
System.out.println("constructeur Info(" + v + ")");
val = v;
}
public String toString() {
String texte = "Info=";
texte += Integer.toString(val);
return texte;
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ public void writeObject(Object obj) throws IOException;
Sérialisation : un 1er exemple
Objets sérialisés et désérialisés dans un fichier
Sérialisation avec Serializable
™
Remarques :
ƒ Aucun constructeur n'est appelé lors de la désérialisation
ƒ L'objet en entier est directement restauré
ƒ readObject() : renvoie une référence sur un Object
ƒ qu'il faut « caster » pour récupérer une référence du bon type.
ƒ Pour désérialiser un Objet, la JVM doit connaître la Classe de l'Objet
ƒ => config du Classpath ….
ƒ Il faut respecter l'ordre
ƒ de sérialisation et de désérialisation des données
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class Info implements Serializable {
public static void main(String[] args) throws IOException, ClassNotFoundException { // …
// Exceptions reportées sur la console
Info I1 = new Info(5);
System.out.println("Info I1: " + I1); System.out.println("---- Serialisation::sauvegarde dans un fichier ----");
// Création d'un flot de sortie(fichier) associé à un objet de sérialisation
ObjectOutputStream serialiseDsFichOut =new ObjectOutputStream(
new FileOutputStream("sauvegarde.ser"));
Info
serialiseDsFichOut.writeObject("sauvegarde de l'objet I1");
val: int
serialiseDsFichOut.writeObject(I1);
Info()
serialiseDsFichOut.close(); // Vide la sortie
toString()
System.out.println("---- Deserialisation::lecture depuis le fichier ----");
main()
// Création d'un flot d'entrée(fichier) associé à un objet de sérialisation
ObjectInputStream serialiseDsFichIn =
new ObjectInputStream(new FileInputStream("sauvegarde.ser"));
String texte = (String) serialiseDsFichIn.readObject();
// Le type de l'objet qui est désérialisé doit être connu de la JVM (Classpath)
Object obj = serialiseDsFichIn.readObject();
constructeur Info(5)
Info I1Bis = (Info) obj;
Info I1: Info=5
System.out.println("Info I1Bis: " + I1Bis);
---- Serialisation::sauvegarde dans un fichier ------- Deserialisation::lecture depuis le fichier ---}
Info I1Bis: Info=5
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Java
164
[email protected]
Java
163
™
™
Gestion automatique des références
Serializable
0..1
- suivant
ListInfo
suivant: ListInfo
- info
info: Info
0..1
ListInfo(in int): void
ListInfo(): void
toString(): String
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
}
Sérialisation automatique des références
public class ListInfo implements Serializable {
public static void main(String[] args)
throws IOException, ClassNotFoundException { //…
// exceptions reportées sur la console
ListInfo l1 = new ListInfo(5);
System.out.println("ListInfo l1: \n" + l1);
System.out.println("---- Serialisation ----");
public class ListInfo implements Serializable {
private ListInfo suivant;
private Info info;
public ListInfo(int v) {
System.out.println("constructeur ListInfo(" + v + ")");
info = new Info(v);
if (--v > 0) {
suivant = new ListInfo(v);
}
}
public ListInfo() {
System.out.println("constructeur ListInfo()");
}
Serializable
public String toString() {
String s = "ListInfo(";
Info
s += " " + info;
val: int
s += ") ";
Info(in int): void
if (suivant != null) {s += suivant;}
toString(): String
return s;
main(in String[]): void
}
Sérialisation : un 2ème exemple
Java
166
Serializable
val: int
Info(in int): void
toString(): String
main(in String[]): void
}}
- suivant
ListInfo
Info
// création d'un flot de sortie(fichier) pour la sérialisation
ObjectOutputStream serialiseDsFichOut =
new ObjectOutputStream(new FileOutputStream("sauv.ser"));
serialiseDsFichOut.writeObject("sauvegarde de l'objet l1");
serialiseDsFichOut.writeObject(l1);
System.out.println("---- Deserialisation ----");
// création d'un flot d'entrée(fichier) pour la sérialisation
ObjectInputStream serialiseDsFichIn =
new ObjectInputStream(new FileInputStream("sauv.ser"));
String texte = (String) serialiseDsFichIn.readObject();
ListInfo l1Bis = (ListInfo) serialiseDsFichIn.readObject();
System.out.println("ListInfo l1Bis: \n" + l1Bis);
0..1
Serializable
suivant: ListInfo
- info
info: Info
0..1
ListInfo(in int): void
ListInfo(): void
toString(): String
constructeur ListInfo(5) constructeur Info(5)
constructeur ListInfo(4) constructeur Info(4)
constructeur ListInfo(3) constructeur Info(3)
constructeur ListInfo(2) constructeur Info(2)
constructeur ListInfo(1) constructeur Info(1)
ListInfo l1:
ListInfo( Info=5) ListInfo( Info=4)
ListInfo( Info=3) ListInfo( Info=2)
ListInfo( Info=1)
---- Serialisation ------- Deserialisation ---ListInfo l1Bis:
ListInfo( Info=5) ListInfo( Info=4)
ListInfo( Info=3) ListInfo( Info=2)
ListInfo( Info=1)
[email protected]
Sérialisation : un 2ème exemple
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
165
Sérialisation : mise en œuvre manuelle
™
Java
168
Pourquoi une sérialisation contrôlée
ƒ Pour des problèmes de sécurité
ƒ Données sensibles à ne pas sauvegarder, à crypter, etc.
ƒ Pour des besoins spéciaux
ƒ Cette interface étend l'interface Serializable avec 2 méthodes:
ƒ public void writeExternal(ObjectOutput objOut)
throws IOException
ƒ public void readExternal(ObjectInput objIn)
throws IOException, ClassNotFoundException
ƒ Méthodes automatiquement appelées lors de la (dé)sérialisation de l'objet
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
L'interface Externalizable
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Sauvegarde partielle de l'objet, ou des sous objets qui le composent, etc.
™
Sérialisation : manuelle / Exemple
public class InfoExt implements Externalizable {
private int valP;
public InfoExt() {
valP = (int) (Math.random() * 10);
// initialisation à la construction avec un nombre aléatoire
System.out.println("constructeur InfoExt(" + valP + ")");
Externalizable
InfoExt
}
public String toString() {
valP: int
String texte = "InfoExt=";
InfoExt(): void
toString(): String
texte += Integer.toString(valP);
writeExternal(in ObjectOutput): void
return texte;
readExternal(in ObjectInput): void
}
public void writeExternal(ObjectOutput objOut) throws IOException {
objOut.writeInt(valP);
}
public void readExternal(ObjectInput objIn) throws IOException, ClassNotFoundException {
valP = objIn.readInt();
}
}
[email protected]
Java
167
Sérialisation : manuelle / exemple
Java
170
Serializable
0..1
Externalizable
™
ListInfo(in int): void
ListInfo(): void
toString(): String
main(in String[]): void
Résultat de l'exécution avec le même Main
constructeur ListInfo(5) constructeur InfoExt(0)
constructeur ListInfo(4) constructeur InfoExt(1)
constructeur ListInfo(3) constructeur InfoExt(5)
constructeur ListInfo(2) constructeur InfoExt(6)
constructeur ListInfo(1) constructeur InfoExt(1)
ListInfo l1:
ListInfo( InfoExt=0 ) ListInfo( InfoExt=1 ) ListInfo( InfoExt=5 ) ListInfo( InfoExt=6 ) ListInfo( InfoExt=1 )
---- Serialisation ------- Deserialisation ---constructeur InfoExt(8)
// attention, avec un objet Externalizable
constructeur InfoExt(7)
// il y a appel au constructeur par défaut !
constructeur InfoExt(0)
// qui doit donc être accessible !!
constructeur InfoExt(8)
constructeur InfoExt(9)
ListInfo l1Bis:
ListInfo( InfoExt=0 ) ListInfo( InfoExt=1 ) ListInfo( InfoExt=5 ) ListInfo( InfoExt=6 ) ListInfo( InfoExt=1 )
Restriction sur la sérialisation automatique (Serializable)
avec le mot clé "transient"
ƒ Empêche la sauvegarde/restauration des champs étiquetés "transient"
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
0..1
ƒ données sensibles à ne pas sauvegarder (sérialiser)
infoP: InfoExt
suivant: ListInfo
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
- infoP
Sérialisation automatique avec restriction sur les infos sensibles
ƒ Pour des problèmes de sécurité :
ListInfo
valP: int
™
™
- suivant
InfoExt
InfoExt(): void
toString(): String
writeExternal(in ObjectOutput): void
readExternal(in ObjectInput): void
Sérialisation : partiellement manuelle / transient
public class InfoSerRes implements Serializable {
private int val;
transient private String motDePasse; // données sensibles à ne pas sauvegarder (sérialiser)
public InfoSerRes(int v, String m) {
System.out.println("constructeur InfoSerRes(" + v + " " + m + ")");
val = v;
motDePasse = m;
Serializable
}
InfoSerRes
public String toString() {
val: int
String texte = "InfoSerRes=";
motDePasse: String
texte += Integer.toString(val);
InfoSerRes(in int, in String): void
texte += "," + motDePasse;
toString(): String
return (texte);
}
}
[email protected]
Java
169
Java
171
Sérialisation : partiellement manuelle / transient
Java
172
™
Serializable
Serializable
0..1
val: int
transient
- infoSerR
motDePasse: String
InfoSerRes(in int, in String): void
toString(): String
0..1
Une autre approche à Externalizable
ƒ Sérialisation automatique "Serializable"
avec ajout de méthodes prédéfinies
- suivant
ListInfo
InfoSerRes
Sérialisation : partiellement manuelle / Serializable
infoSerR: InfoSerRes
suivant: ListInfo
ƒ Attention à bien respecter la signature des méthodes
ListInfo(in int): void
ListInfo(): void
toString(): String
ƒ méthodes appelées automatiquement
constructeur ListInfo(5) constructeur InfoSerRes(5 secret)
constructeur ListInfo(4) constructeur InfoSerRes(4 secret)
constructeur ListInfo(3) constructeur InfoSerRes(3 secret)
constructeur ListInfo(2) constructeur InfoSerRes(2 secret)
constructeur ListInfo(1) constructeur InfoSerRes(1 secret)
ListInfo l1:
ListInfo(InfoSerRes=5,secret ) ListInfo(InfoSerRes=4,secret ) ListInfo(InfoSerRes=3,secret )
ListInfo(InfoSerRes=2,secret ) ListInfo(InfoSerRes=1,secret )
---- Serialisation ------- Deserialisation ---ListInfo l1Bis:
ListInfo(InfoSerRes=5,null ) ListInfo(InfoSerRes=4,null ) ListInfo(InfoSerRes=3,null )
ListInfo(InfoSerRes=2,null ) ListInfo(InfoSerRes=1,null )
ƒ private void writeObject(ObjectOutputStream objOutSt)
throws IOException
ƒ private void readObject(ObjectInputStream objInSt)
throws IOException, ClassNotFoundException
[email protected]
Résultat de l'exécution avec le même Main
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
à la place de la sérialisation par défaut
Sérialisation : partiellement manuelle / Serializable
Java
174
Sérialisation : manuelle / exemple
public class InfoSerModif implements Serializable {
private int val;
transient private String motDePasse;
Serializable
Serializable
0..1
InfoSerModif
ListInfo
}
infoSerM: InfoSerModif
motDePasse: String
- infoSerM
suivant: ListInfo
InfoSerModif(in int, in String): void
toString(): String
0..1
ListInfo(in int): void
writeObject(in ObjectOutputStream): void
readObject(in ObjectInputStream): void
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public InfoSerModif(int v, String m) {
System.out.println("constructeur InfoSerModif(" + v + " " + m + ")");
Serializable
val = v;
InfoSerModif
motDePasse = m;
}
val: int
public String toString() {
motDePasse: String
String texte = "InfoSerModif=";
InfoSerModif(in int, in String): void
texte += Integer.toString(val);
toString(): String
writeObject(in ObjectOutputStream): void
texte += "," + motDePasse;
readObject(in ObjectInputStream): void
return (texte);
}
private void writeObject(ObjectOutputStream objOutSt) throws IOException {
objOutSt.defaultWriteObject(); // demande de la sérialisation automatique par défaut
objOutSt.writeObject(motDePasse); // on pourrait le crypter
}
private void readObject(ObjectInputStream objInSt)
throws IOException, ClassNotFoundException {
objInSt.defaultReadObject(); // demande de la désérialisation automatique par défaut
motDePasse = (String) objInSt.readObject();
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
val: int
transient
™
- suivant
ListInfo(): void
toString(): String
Résultat de l'exécution avec le même Main
constructeur ListInfo(5) constructeur InfoSerModif(5 secret)
constructeur ListInfo(4) constructeur InfoSerModif(4 secret)
constructeur ListInfo(3) constructeur InfoSerModif(3 secret)
constructeur ListInfo(2) constructeur InfoSerModif(2 secret)
constructeur ListInfo(1) constructeur InfoSerModif(1 secret)
ListInfo l1:
ListInfo( InfoSerModif=5,secret ) ListInfo( InfoSerModif=4,secret ) ListInfo( InfoSerModif=3,secret ) ListInfo(
InfoSerModif=2,secret ) ListInfo( InfoSerModif=1,secret )
---- Serialisation ------- Deserialisation ---ListInfo l1Bis:
ListInfo( InfoSerModif=5,secret ) ListInfo( InfoSerModif=4,secret ) ListInfo( InfoSerModif=3,secret ) ListInfo(
InfoSerModif=2,secret ) ListInfo( InfoSerModif=1,secret )
[email protected]
Java
173
Sérialisation : un premier Bilan
ƒ Sérialisation automatique de l’objet dans sa globalité
ƒ Sans passer par le constructeur
ƒ Sérialisation automatique de l’objet avec protection de certaines données
ƒ Utilisation de transient
ƒ Sérialisation partiellement manuelle de l’objet
avec ajout de méthodes prédéfinies
ƒ Redéfinition manuelle des méthodes
ƒ writeObject(ObjectOutputStream)
ƒ readObject(ObjectInputStream)
ƒ N'est pas gérée automatiquement
ƒ 2 méthodes doivent être utilisées pour (dé)sérialiser
vos données statiques
ƒ public static void serializeStaticObject(ObjectOutputStream objOSt)
Externalizable
ƒ Mise en œuvre manuelle de la Sérialisation
ƒ Utilise le constructeur => constructeur par défaut obligatoire !
ƒ Redéfinition obligatoire des 2 méthodes
ƒ writeExternal(ObjectOutput)
ƒ readExternal(ObjectInput)
La sérialisation des données statiques
throws IOException
ƒ public static void deserializeStaticObject(ObjectInputStream objOSt)
throws IOException
ƒ Elles doivent être appelées explicitement lors de la sérialisation
ƒ private void writeObject(ObjectOutputStream objOutSt)
throws IOException
ƒ private void readObject(ObjectInputStream objInSt)
throws IOException, ClassNotFoundException
[email protected]
™
Sérialisation : les données statiques
™
Serializable
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Java
176
[email protected]
Java
175
Sérialisation : les données statiques / exemple
Serializable
0..1
InfoStatic
NB: int
numero: int
InfoStatic(): void
toString(): String
serializeStaticObject(in ObjectOutputStream): void
deserializeStaticObject(in ObjectInputStream): void
- suivant
Serializable
ListInfo
infoStatic: InfoStatic
- infoStatic
suivant: ListInfo
0..1
ListInfo(in int): void
ListInfo(): void
toString(): String
main(in String[]): void
public static void main(String[] args) throws IOException, ClassNotFoundException {
ListInfo l1 = new ListInfo(5);
System.out.println("ListInfo l1: \n" + l1);
System.out.println("---- Serialisation ----");
ObjectOutputStream serialiseDsFichOut = new ObjectOutputStream(new FileOutputStream("sauv.ser"));
serialiseDsFichOut.writeObject(l1);
System.out.println("---- Nouvelle Liste d'info ----");
ListInfo l2 = new ListInfo(1);
System.out.println("---- Deserialisation ----");
ObjectInputStream serialiseDsFichIn = new ObjectInputStream(new FileInputStream("sauv.ser"));
ListInfo l1Bis = (ListInfo) serialiseDsFichIn.readObject();;
System.out.println("ListInfo l1Bis: \n" + l1Bis);
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class InfoStatic implements Serializable {
public static int NB = 0;
Serializable
public final int numero;
public InfoStatic() {
InfoStatic
NB++; numero = NB;
NB: int
System.out.println(
numero: int
"constructeur InfoStatic : num("
InfoStatic(): void
+ numero + ") nb(" + NB + ")");
toString(): String
serializeStaticObject(in ObjectOutputStream): void
}
deserializeStaticObject(in ObjectInputStream): void
public String toString() {
…
}
public static void serializeStaticObject(ObjectOutputStream objOSt) throws IOException {
objOSt.writeInt(NB);
}
public static void deserializeStaticObject(ObjectInputStream objOSt) throws IOException {
NB = objOSt.readInt();
}
private void writeObject(ObjectOutputStream objOutSt) throws IOException {
objOutSt.defaultWriteObject();
serializeStaticObject(objOutSt);
}
private void readObject(ObjectInputStream objInSt) throws IOException, ClassNotFoundException {
objInSt.defaultReadObject();
deserializeStaticObject(objInSt);
}
}
Sérialisation : les données statiques / exemple
Java
178
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
177
Sérialisation : les données statiques / exemple
Serializable
0..1
InfoStatic
InfoStatic(): void
toString(): String
serializeStaticObject(in ObjectOutputStream): void
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
deserializeStaticObject(in ObjectInputStream): void
Serializable
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ListInfo
infoStatic: InfoStatic
- infoStatic
suivant: ListInfo
0..1
ListInfo(in int): void
ListInfo(): void
Version 4.2
toString(): String
main(in String[]): void
Résultats
constructeur ListInfo(5) constructeur InfoStatic : num(1) nb(1)
constructeur ListInfo(4) constructeur InfoStatic : num(2) nb(2)
constructeur ListInfo(3) constructeur InfoStatic : num(3) nb(3)
constructeur ListInfo(2) constructeur InfoStatic : num(4) nb(4)
constructeur ListInfo(1) constructeur InfoStatic : num(5) nb(5)
ListInfo l1:
ListInfo( InfoStatic=num 1 nb 5 ) ListInfo( InfoStatic=num 2 nb 5 ) ListInfo( InfoStatic=num 3 nb 5 )
ListInfo( InfoStatic=num 4 nb 5 ) ListInfo( InfoStatic=num 5 nb 5 )
---- Serialisation ------- Nouvelle Liste d'info ---constructeur ListInfo(1) constructeur InfoStatic : num(6) nb(6)
---- Deserialisation ---ListInfo l1Bis:
ListInfo( InfoStatic=num 1 nb 5 ) ListInfo( InfoStatic=num 2 nb 5 ) ListInfo( InfoStatic=num 3 nb 5 )
ListInfo( InfoStatic=num 4 nb 5 ) ListInfo( InfoStatic=num 5 nb 5 )
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
NB: int
numero: int
- suivant
[email protected]
Java
179
Masquage / Java
Redéfinition et surcharge (pas de masquage en Java)
™
Java
182
public class B {
Pas de masquage
ƒ ni pour la surcharge
public void f()
{ System.out.println ("B.f()"); }
ƒ ni pour la redéfinition
public class B {
public void f(int i)
{ System.out.println("B.f(int i)"); }
class D0 extends B {};
public void f(){ System.out.println ("B.f()"); }
public void f(int i, int j){
public static void main(String args[]) {
….
System.out.println("D1.f(int i, int j)");
}
}
}
}
class D2 extends B {
B
public void f(){ // extension
super.f();
f()
f(int i)
System.out.println("D2.f()");
}
D1
f(int,int)
D2
f()
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class D1 extends B {
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public void f(int i) { System.out.println("B.f(int i)"); }
D0
Redéfinition et surcharge (pas de masquage en Java)
}
public static void main(String args[]) {
B objet_B = new B();
D0 objet_D0= new D0 ();
D1 objet_D1= new D1();
D2 objet_D2= new D2();
objet_B.f()
objet_B.f(2)
B.f()
B.f(int i)
objet_D0.f() / heritage :
objet_D0.f(1) / heritage :
B.f()
B.f(int i)
objet_D1.f(1,2) / Surcharge :
objet_D1.f(1) / pas de masquage:
D1.f(int i, int j)
B.f(int i)
objet_D2.f() / Redefinition :
B.f()
D2.f()
B.f(int i)
objet_D2.f(1) / pas de masquage:
B
System.out.print( "objet_B.f() "); objet_B.f();
System.out.print( "objet_B.f(2) "); objet_B.f(2);
f()
f(int i)
System.out.print( "objet_D0.f() / heritage : "); objet_D0.f();
System.out.print("objet_D0.f(1) / heritage : "); objet_D0.f(1);
System.out.print( "objet_D1.f(1,2) / Surcharge : "); objet_D1.f(1,2);
D0
D1
D2
System.out.print( "objet_D1.f(1) / pas de masquage: "); objet_D1.f(1);
System.out.print( "objet_D2.f() / Redefinition : "); objet_D2.f();
System.out.print( "objet_D2.f(1) / pas de masquage: "); objet_D2.f(1);
}
f(int,int)
f()
[email protected]
Java
181
Java
184
RTTI et Java : getClass / getName / forName / newInstance
™ La
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
classe Class : permet d’avoir une description du type d’un objet
Class c =MonObjet.getClass() ;
// on récupère la description de la classe
System.out.println(c.getName() ); // accès au nom de la classe de MonObjet
Version 4.2
Run Time Type Identification
méthode statique forName de la classe Class :
permet d’obtenir l’objet Class qui correspond au nom (string)
passé en paramètre
ƒ Class c = Class.forName("Rectangle") ;
*cf. clonage
™ La
méthode newInstance()
ƒ permet de créer un nouvel objet (Object) à partir de sa description (Class)
NB : ce nouvel objet est construit avec le constructeur par défaut
(qui doit exister ! Sinon exception)
ƒ Exemple / construction d’un nouvel objet à partir de son nom (s) :
ƒ Figure newFigure = (Figure)Class.forName(s).newInstance() ;
[email protected]
RTTI
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ La
RTTI et C++ : type_info / typeid
™
C++
186
RTTI : Run Time Type Identification
™
cout << "nom d'une classe(A): "
<< typeid(A).name() << endl;
cout << "nom de la classe d'un objet(a): " << typeid(a).name() << endl;
cout << "nom de la classe d'un pointeur(pa): " << typeid(pa).name() << endl;
cout << "nom de la classe d'une variable via pointeur(*pa): " << typeid(*pa).name() << endl;
cout << « Comparaison sur les types " << endl; // opérateur == et !=
cout << "==Objet(a) et *pointeur (*pa): " << (typeid(a) == typeid(*pa)) << endl;
cout << "==Objets de classes differentes(a) et (b): " << (typeid(a) == typeid(b)) << endl;
return 0;
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
int main(int, char **){
A
a;
A*
pa = new A;
B
b;
nom d'une classe(A): class A
nom de la classe d'un objet(a): class A
nom de la classe d'un pointeur(pa): class A *
nom de la classe d'une variable via pointeur(*pa): class A
Comparaison sur les types
==Objet(a) et *pointeur (*pa): 1
==Objets de classes différentes(a) et (b): 0
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class A {};
class B {};
Fonction template : Dynamic_cast<pointeurCible> (pointeurSource)
ƒ Fait la conversion(Downcast) du pointeurSource vers le pointeurCible et le retourne si la conversion
est possible et rend 0 sinon.
ƒ Possibilité d’accéder pendant l’exécution à des
informations de type sur les objets
ƒ Principe
ƒ chaque classe possède une instance de la classe « type_info »
ƒ on accède à une réf. de cette instance en passant par la méthode « typeid »
ƒ Exemple d’utilisation des méthodes « name » et « == », « != »
#include <iostream>
#include <typeinfo> // à inclure pour l’accès au RTTI
using namespace std;
RTTI et C++ : dynamic Cast
class A {
public: // au moins une fonction virtuelle pour avoir des classes polymorphes
virtual void type() { cout << typeid(*this).name()<<endl; }
class A
};
A
class C : public A {};
class A
class D : public A {};
class A
class E : public C {};
class A
D
C
int main(int, char **){
class C
vector <A*> VeltA; vector <C*> VeltC; vector <E*> VeltE;
srand(time(0));
class C
E
int nbA(0),nbC(0),nbE(0);
class C
int cpt=rand()%10; for (int i=0; i< cpt; i++) {VeltA.push_back(new A);}
class E
cpt=rand()%10; for (int j=0; j< cpt; j++) {VeltA.push_back(new C);}
cpt=rand()%10; for (int k=0; k< cpt; k++) {VeltA.push_back(new E);}
class E
for (int ii=0; ii<VeltA.size(); ii++) {
class E
VeltA[ii]->type();
nbA :10
if (dynamic_cast<A*>(VeltA[ii])){nbA++;}
nbC :6
C* pC=dynamic_cast<C*>(VeltA[ii]); // downcast
if (pC) {nbC++; VeltC.push_back(pC);}
nbE :3
E* pE=dynamic_cast<E*>(VeltA[ii]); // downcast
if (pE) {nbE++; VeltE.push_back(pE);}
}
cout << "nbA :" << nbA << endl; cout << "nbC :" << nbC << endl; cout << "nbE :" << nbE << endl;
for (int ii=0; ii<VeltA.size(); ii++) {delete VeltA[ii];}
return 0;
}
[email protected]
C++
185
Java
188
Égalité d'objets
™
ƒ Teste l’égalité des références (identificateurs) des objets
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Ne considère jamais l’égalité du contenu d’un objet
String s ="coucou";
if (s == "coucou") …
Égalité et
Comparaison d'objets en Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
// erreur en Java
Opérateur equals
ƒ L’opérateur equals par défaut (de la classe de base Object) opère une
comparaison sur les références.
ƒ Il a été redéfini pour beaucoup de classe de la bibliothèque
if (s.equals("coucou")) …
// ok en Java
ƒ Le redéfinir pour vos classes, spécialement pour l’utilisation des conteneurs
=> Pour le polymorphisme : boolean equals (Object b) {…}
Class Point extends Figure
{ public boolean equals (Point b) // ici surcharge <> redéfinition
{ return _x== b._x && _y == b._y ; }
...
}
[email protected]
Version 4.2
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Opérateur ==
d’un opérateur equals
ƒ Possibilité de le surcharger
ƒ => pas de polymorphisme
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Point extends Figure{
//…
public boolean equals(Point p){ return ((p._x==_x) && (p._y==_y)); }
public static void main(String[] args){
Figure[] fig = new Figure[4];
fig[0] = new Ellipse(new Point(150, 150),100,100);
fig[1] = new Rectangle(new Point(140, 140), new Point(160, 160));
fig[2] = new Point(130, 200);
fig[3] = new Point(1, 2);
for (int i=0; i< fig.length; i++){
System.out.println(fig[i].equals(new Point(1,2)));
}
System.out.println(".............");
for (int i=0; i< fig.length; i++){
if (fig[i] instanceof Point) {
System.out.println(((Point)fig[i]).equals(new Point(1,2)));
}
}
}
Polygone
+
+
+
+
+
+
Polygone()
coin()
deplacer()
dessiner()
dilater()
set_coin()
Point()
clone()
deplacer()
dessiner()
dilater()
equals()
main()
x()
y()
Ellipse
+
+
+
+
+
+
+
Ellipse()
centre()
deplacer()
dessiner()
dilater()
xrayon()
yrayon()
Rectangle
+ Rectangle()
false
false
false
false
.............
false
true
d’un opérateur equals
Figure
ƒ Possibilité de le redéfinir / class Object
ƒ => polymorphisme
Point
+
+
+
+
+
+
+
+
+
Égalité d'objets (redéfinition de equals)
™ Ecriture
Figure
- deplacer()
- dessiner()
- dilater()
class Point extends Figure{
public boolean equals(Object p){
if (p instanceof Point) {
return ((((Point)p)._x==_x) && (((Point)p)._y==_y)); }
else return false;
}
public static void main(String[] args){
Figure[] fig = new Figure[4];
fig[0] = new Ellipse(new Point(150, 150),100,100);
fig[1] = new Rectangle(new Point(140, 140), new Point(160, 160));
fig[2] = new Point(130, 200);
fig[3] = new Point(1, 2);
for (int i=0; i< fig.length; i++){
System.out.println(fig[i].equals(new Point(1,2)));
}
System.out.println(".............");
for (int i=0; i< fig.length; i++){
if (fig[i] instanceof Point) {
System.out.println(((Point)fig[i]).equals(new Point(1,2)));
}}}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Ecriture
Java
190
- deplacer()
- dessiner()
- dilater()
Polygone
+
+
+
+
+
+
Polygone()
coin()
deplacer()
dessiner()
dilater()
set_coin()
Point
+
+
+
+
+
+
+
+
+
Point()
clone()
deplacer()
dessiner()
dilater()
equals()
main()
x()
y()
Ellipse
+
+
+
+
+
+
+
Ellipse()
centre()
deplacer()
dessiner()
dilater()
xrayon()
yrayon()
Rectangle
+ Rectangle()
false
false
false
true
.............
false
true
[email protected]
Égalité d'objets (surcharge de equals)
[email protected]
Java
189
Comparaison d'instances et héritage
™
Java
192
Comparaison rigide : méthode equals()
™
Comparaison d'instances de classes différentes reliées par héritage
ƒ Comparaison rigide
Principe :
ƒ Vérifier le type des
instances : getClass()
ƒ vérifie si pour deux objets de même type leurs attributs sont tous égaux.
ƒ Vérifier l'égalité des
attributs :
ƒ Comparaison souple
ƒ permet d'établir si deux objets sont comparables ; c'est-à-dire, s'il existe un
ƒ primitifs (==)
Exemple de comparaisons souhaitées
ƒ Comparer 2 mammifères
ƒ Comparer 2 singes
ƒ Comparer 2 hommes
ƒ Comparer 1 singe et 1 mammifère
ƒ Comparer 1 homme et 1 mammifère
ƒ Comparer 1 singe et 1 homme
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
ƒ relation (==)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
lien "d'héritage" entre ces deux objets et si tous les attributs qu'ils possèdent
en commun sont égaux.
ƒ agrégation forte
(equals).
Méthode de comparaison
des attributs
public class Mammifere {
private int _taille;
private int _poids;
public Mammifere (int taille, int poids) {
_taille=taille;_poids=poids;
}
public Mammifere (Mammifere M) {
_taille=M._taille;_poids=M._poids;
}
protected final boolean _equals(Mammifere obj) {
return(_taille==per._taille &&
_poids==per._poids);
}
public boolean equals(Object obj) {
if (obj==this) return true;
if ( (obj!=null) &&
(obj.getClass()==Mammifere.class)) {
return _equals((Mammifere)obj);
}
else { return false; }
Vérification du type de l'objet
puis
Comparaison des attributs
}}
[email protected]
Java
191
Comparaison rigide
™
Java
194
™
Exemple d'utilisation
ƒ Vérifier l'égalité des sous
attributs communs:
ƒ primitifs (==)
false
false
false
true
true
}
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ relation (==)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Mammifere M1=new Mammifere(170, 70);
Mammifere M2=new Mammifere(170, 59);
Mammifere M3=new Mammifere(M1);
System.out.println(M1.equals(M2));
System.out.println(M2.equals(M3));
System.out.println(M1.equals(M3));
System.out.println(M1.equals(M1));
Principe :
ƒ gérer les liens d'héritage :
instanceof()
public static void main(String[] args){
String Str1=new String("toto");
System.out.println(M1.equals(Str1));
Comparaison souple : méthode comparable()
ƒ agrégation forte
(equals).
public class Homme extends Mammifere {
String _nom;
public Homme (int taille, int poids, String nom) {
super(taille, poids); _nom=nom;
}
protected final boolean _equals(Homme obj) {
return( super._equals(obj)
&& _nom.equals(per._nom));
}
public boolean equals(Object obj){
// idem
}
Comparable en tant que Mammifère ?
Comparable en tant qu'Homme ?
public boolean comparable(Mammifere obj){
if (obj==this) return true;
boolean ok= super.comparable(obj);
if (ok && (obj instanceof Homme)) {
return _equals((Homme)obj);
}
return ok;
}}
[email protected]
Java
193
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
196
Exemple de comparaisons souples et rigides
public static void main(String[] args){
™
Mammifere M1=new Mammifere(170, 70); Mammifere M2=new Mammifere(170, 59);
Mammifere M3=new Mammifere(M1);
Singe Sg1=new Singe(170, 70, "afrique"); Singe Sg2=new Singe(170, 70, "asie");
Homme H1=new Homme(170, 70, "toto"); Homme H2=new Homme(150, 70, "titi");
String Str1=new String("toto");
System.out.println(Sg1.equals(Str1));
//false
System.out.println(Sg1.equals(M1));
//false
System.out.println(Sg1.equals(M3));
//false
System.out.println(Sg1.equals(Sg2));
//false
//System.out.println(Sg1.comparable(Str1));
System.out.println(Sg1.comparable(Sg2));
System.out.println(Sg1.comparable(M1));
System.out.println(M1.comparable(Sg1));
System.out.println(Sg1.equals(H1));
System.out.println(H1.equals(H2));
System.out.println(H1.comparable(Sg1));
System.out.println(Sg1.comparable(H1));
System.out.println(Sg1.comparable(H2));
System.out.println(Sg1.comparable(M1));
System.out.println(H1.comparable(Sg2));
// erreur a la compilation
//false
//true
//true
//false
//false
//true
//true
//false
//true
//true }
[email protected]
Comparaison : exemple de diagramme de classe
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
195
Notion d'erreur
198
™
Différents types d'erreurs
ƒ Mauvaise gestion des classes : dépiler une pile vide, ...
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Entrées utilisateurs non valides : effacer un fichier inexistant, ...
ƒ Liées aux périphériques : manque de papier dans l'imprimante, ...
Version 4.2
ƒ Limitation physique : disque plein, ...
™
Le traitement des erreurs / les différentes possibilités
ƒ Ne rien faire (absorber l'erreur)
ƒ Imprimer des messages d'erreur (utiliser assert(int), abort, #define NDEBUG)
ƒ Retourner un code d'erreur (test conditionnel)
ƒ Mettre à jour des variables globales d'erreur
ƒ Utiliser le mécanisme d'exception unifié et standardisé
.... C++ et Java supportent le mécanisme de gestion d'exception ...
[email protected]
Gestion des exceptions
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ ...
C++
200
Le traitement de cas exceptionnel ne peut très souvent être opéré que dans un
contexte supérieur à la détection de l’erreur
class TestException {
public :
void methode1();
void methode2(int i);
};
Mécanisme d'exception / gestionnaire d'exception
ƒ Simplifie en allégeant le code de la gestion locale des erreurs par une
recentralisation des procédures de traitement d'erreur
methode1
methode2
i == 1
fin methode2
methode2
erreur i est egal a 0
reprise du code
#include "TestException.h"
void main(){
TestException t;
try {
t.methode1();
2
cout << "suite1 main" << endl;
}
3 catch(exception& e) {
cout << e.what() << endl; 4
}
catch(int i) {
cout << "code d'erreur" << i << endl;
}
5 cout <<"reprise du code" << endl;
}
void TestException::methode1() {
cout << "methode1" << endl;
methode2(1);
methode2(0);
cout << "fin methode1" << endl;
}
Mise en œuvre des exceptions
ƒ on déclenche (lance) une exception par l'instruction throw (...)
ƒ on capte (attrape) une exception dans un bloc de type try { ...}
ƒ on traite (gère) une exception avec l'instruction catch (...)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Permet de transmettre le problème du traitement de l'erreur dans un contexte
qualifié (de niveau supérieur) pour gérer l'erreur
™
#include <exception>
#include <iostream.h>
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Exemple général sur le mécanisme d'exception
void TestException::methode2(int i) {
cout << " methode2" << endl;
1 if (i==0) throw exception("erreur i est egal a 0");
cout <<"i == " << i << endl;
cout << " fin methode2" << endl;
}
1
•
2
•
Arrêt de l'exécution : lancement de l'exception
3
•
Capture de l'exception par un bloc "catch"
•
4
Traitement de l'exception
•
5
Le programme reprend
Transmission du control au bloc supérieur …
[email protected]
Traitement des cas d'erreurs exceptionnelles
199
Le principe
C++
202
201
™
Protocole C++ : émission d'exceptions
™
Instructions : try / throw / catch
ƒ Un bloc de code est mis sous surveillance : instruction try
Une exception est lancée par la commande throw e;
ƒ e est un "signal d'exception"
ƒ Des méthodes peuvent lancer des exceptions avec l'instruction throw
ƒ il peut représenter n'importe quel objet ou valeur :
ƒ Un bloc de gestion d'exception est signalé par l'instruction catch
throw "message d'erreur";
// type string pas très informant
throw ErreurConnection("Pb à l'ouverture de la connexion");
ƒ Lorsqu’une méthode déclenche une exception, le programme remonte la
suite des invocations de méthodes jusqu’à atteindre une méthode qui
capture cette exception.
ƒ Si l'exception n’est jamais capturée, alors le programme s’arrête :
ƒ En C++ si l'on arrive à la fonction main() sans gérer l'exception =>
appel de la fonction terminate qui met fin au programme (abort())
ƒ Après l’exécution du gestionnaire adapté à l’exception le contrôle passe à
l’instruction qui suit le dernier gestionnaire.
ƒ Recommandation :
en général on utilise des classes comme signaux d'exceptions
ƒ Une exception lance donc un objet construit "à la volée"
ƒ Exemple
throw ErreurConnection("Pb à l'ouverture de la connexion");
ƒ Appel du constructeur ErreurConnection(string) "à la volée" de la classe
ErreurConnection.
[email protected]
ƒ Si aucune exception n’est levée dans le bloc try, le contrôle passe à
l’instruction qui suit les gestionnaires d’exception (catch).
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Déroulement
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
C++
203
Protocole C++ : spécification d'exceptions
™
C++
204
Protocole C++ : fonction terminate
™
En C++ la spécification des exceptions est possible (pas obligatoire)
Propagation du signal d'exception jusqu'à la méthode main
ƒ L'exception n’est jamais capturée
ƒ Appel à la fonction terminate()
™
int f(istream&) throw (StackError, MathError);
ƒ Par défaut
ƒ Cela garantit que seul les exceptions StackError, MathError seront levées par
ƒ elle met fin au programme
ƒ Aucune exception levée
int g(istream&) throw ();
ƒ Cela garantit qu'aucune exception ne sera levée par cette méthode.
ƒ Par défaut une méthode peut transmettre tous les types d'exceptions
[email protected]
int h(istream&);
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
cette méthode.
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Fonction terminate()
en appelant la fonction abort();
ƒ Personnaliser la fonction
terminate()
ƒ set_terminate(pointeur sur fonction);
methode1
methode2
i == 1
fin methode2
methode2
une exception n'est pas gérée !
abnormal program termination
#include "TestException.h"
void FoncPersoTerminate(void) {
cout << "une exception n'est pas gérée !"
<<endl;
}
void main(){
TestException t;
set_terminate(FoncPersoTerminate);
try {
t.methode1();
cout << "suite1 main" << endl;
}
catch(int i) {
cout << "code d'erreur" << i << endl;
}
cout <<"reprise du code" << endl;
}
[email protected]
ƒ Spécification explicite des exceptions levées
C++
205
Exceptions standards en C++
™
C++
206
Le C++ ANSI a défini une hiérarchie d’exceptions
Capture et traitement d'exceptions
™
Capture (bloc try) et traitement d'exceptions (clause catch)
try
runtime_error
……...
……...
Erreur indépendante
du programmeur
ex : mauvaise lecture
de fichier
La classe de base std::exception
ƒ Il est intéressant de dériver toute exception d’une exception standard
exception
exception() throw();
…
Virtual const char* what() const trow();
try { ….}
catch (Exception& e)
{
cout << e.what( ) << endl;
}
// traitement de l'exception de Type1
}
catch (Type2 id2) { // capture des exception de type Type2 …
// traitement de l'exception de Type2
}
// etc.
™
Remarques
ƒ Les blocs try encapsulent de nombreux appels de fonctions ...
ƒ Le transfert de contrôle est donné à la 1ère clause catch de bon type
ƒ Il est possible d’exploiter la notion d’héritage pour hiérarchiser les
exceptions => l'ordre des blocs catch doit respecter l'ordre d'héritage
[email protected]
™
logic_error
{ // code susceptible de déclencher une exception
}
catch (Type1 id1) { // capture des exception de type Type1
// ou type dérivé de Type1
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Erreur dépendante
du programmeur
ex : dépiler une pile vide
exception
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Sous le contrôle
du programmeur
Protocole Java : lancement d'exceptions
Retransmission d’une exception
208
™
™
Une exception est lancée par la commande throw e;
Il est possible de retransmettre une exception
ƒ en C++
ƒ e : est un objet qui DOIT dériver de la classe Throwable
try
throw new IllegalArgumentException("Pb en lecture");
™
{
Spécification obligatoire des exceptions susceptibles d’être lancées
ƒ Exceptions levées dans la méthode et non attrapées par celle-ci
ƒ Exceptions levées dans des méthodes appelées par la méthode …
ƒ Exceptions levées et traitées par la méthode puis propagées
public void read(DataInputStream in) throws IOException
... double s = in.readDouble ( );
... }
// peut générer une exception
ƒ Une fonction sans clause throws
ƒ garantit qu’elle ne va pas générer d’exception explicite
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
catch(...)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Toute fonction susceptible d'émettre des exceptions "explicites" doit le
mentionner (vérification à la compilation ) :
{
// code
}
{
// capture tout type d'exception
...
throw;
// retransmet l'erreur courante
}
ƒ en Java
try
{
// code
}
catch (Throwable t) // capture tout type d'exception
{
...
throw t;
}
// retransmet l'erreur courante
[email protected]
Java
207
Exception standard en Java
Java possède une hiérarchie d’exceptions standards
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
A Récupérer :
sous le contrôle
du programmeur,
Sauf les Runtime
™
Throwable
Exception
RuntimeException
Error
……...
Java.lang.Throwable
Throwable
Erreur propre
à la la machine
virtuelle, système
……...
IOExcepton
Protocole Java : Java.lang.Throwable
Appel d'une méthode abstraite,
La machine virtuelle n'a pas
assez de mémoire, …
Division par zéro,
Dépassement d'indice
dans un tableau, …
ƒ Exceptions techniques et d'erreurs (Runtime, Error) : un programme n'est
pas obligé de déclarer lever ces 2 types d'exception (raisons essentiellement
pratiques)
ƒ Exceptions explicites ou applicatives: pour toutes les autres exceptions le
programme doit déclarer les lever (imposé par le compilateur)
ƒ Pour définir de nouveaux types d'exception on hérite en général de
java.lang.Exception
™
String message
- Message d'erreur décrivant l'exception
Throwable()
Throwable(string s)
String getMessage()
Void printStackTrace()
Void printStackTrace(PrintStream)
…
- Constructeur avec et sans message d'erreur
- Retourne le message d'erreur
- Imprime sur la sortie standard ou sur un stream,
l'exception et la trace de l'exception dans la pile
Exemple de récupération du message de l'exception
try { ….}
catch (Exception e)
{ System.out.println(e.getMessage());
System.out.println(« Exception » + e);
}
// ou
// cf. notion de toString
[email protected]
Possède 2 sous-classes
standards
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Java
210
[email protected]
Java
209
™
Java
212
public class MonException extends Exception {
public MonException ( ) { }
public MonException (String msg) {
super(msg) ;
MonException: Origine: fonction g()
at UneClasse.g(UneClasse.java:9)
at UneClasse.h(UneClasse.java:13)
at UneClasse.main(UneClasse.java:17)
public class UneClasse
public void g() throws MonException { // ...
{
throw new MonException("Origine: fonction g()");
}
public void h() throws MonException { // ...
g();
}
public static void main (String[] args) {
UneClasse C1=new UneClasse();
try { C1.h(); }
catch (MonException e) { e.printStackTrace(); }
}}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
}
public class UneClasse {
public void g() throws MonException {// ...
• Le bloc "finally" est toujours exécuté :
throw new MonException("Origine: fonction g()");
qu'il y ait capture, propagation ou
}
public void h() throws MonException {// ...
déroulement normal du programme
try { g(); }
• Le programme reprend après
catch (RuntimeException e) {
le bloc "finally"
e.printStackTrace();
• Tous les blocs "finally"
}
finally {
rencontrés sont exécutés
System.out.println("finally de h()");
}
System.out.println("fin de h()");
}
finally de h()
public static void main (String[] args) {
UneClasse C1=new UneClasse();
MonException: Origine: fonction g()
try { C1.h(); }
at UneClasse.g(UneClasse.java:9)
catch (MonException e) {
at UneClasse.h(UneClasse.java:13)
e.printStackTrace();
at UneClasse.main(UneClasse.java:25)
}
finally de main()
finally {
System.out.println("finally de main()");
fin de main()
}
System.out.println("fin de main()");
}}
™
Un petit exemple Java
}
Protocole Java : bloc finally
finally
[email protected]
Créer vos propres classes d'exceptions
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
211
Remarques sur la gestion mémoire
Bilan sur les exceptions
213
214
™ En
™
C++
Les méthodes traitent les exceptions qu'elles peuvent gérer
ƒ sinon les retransmettre
ƒ D'une manière générale
ƒ Tous les objets de la pile entre le throw et le catch sont détruits proprement
™
ƒ le programme sera abandonné si vous lancez une exception et que
personne ne la récupère
ƒ attention à la gestion des bibliothèques, des framework …
ƒ ne pas utiliser d'exceptions si il y a une alternative simple
ƒ Si une nouvelle exception se produit lors de la destruction
ƒ Le programme sera abandonné
*cf. fonction set_terminate(...)
™ En
Java
ƒ Il n'y a pas de destructeur, la gestion de la mémoire est automatique
ƒ Le traitement des exceptions est par conséquent beaucoup moins lourd
qu ’en C++
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Tous les sous-objets déjà construits seront détruits proprement
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ NB: il reste le problème des pointeurs (minimiser leur utilisation)
ƒ Si une erreur est détectée dans un constructeur
Les exceptions sont des événements exceptionnels
™
Tester les conditions d'erreurs sans attendre le lancement d'une
exception
ƒ Par exemple, tester si une liste est vide avant de retirer un élément !
ƒ Lever une exception est moins rapide qu'un appel de fonction normale
™
Laisser le choix au programmeur qui va utiliser vos classes
ƒ offrez lui à la fois :
ƒ un mécanisme d'exception
ƒ un ensemble de méthodes permettant de prévenir les exceptions
[email protected]
et automatiquement en invoquant le destructeur
ƒ Ceci implique une gestion de la mémoire qui peut être coûteuse
Rappels des objectifs du modèle « commande »
216
™
Principe du modèle « commande »
™
Intérêts
ƒ Encapsuler une commande (requête) dans un objet
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Maintien d’une liste de commandes (ou queue de requêtes )
Version 4.2
Mise en œuvre
du modèle « commande »
client
Exécuteur
0..*
commandes
Receveur
1
action()
Découple l’objet qui sait réaliser la commande
de celui qui l’invoque
Commande
exécute()
Commande1
exécute()
On peut avoir autant de commandes
Concrètes que l’on veut
[email protected]
Application d’un design pattern
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Gestion facilité de l’annulation des commandes (undo/redo)
Mise en œuvre du undo/redo
Manipulation de « figures » : undo/redo
217
218
™
™
Principe de la mise en œuvre du undo/redo
avec le modèle « commande »
Mise en œuvre classique / sans le modèle « commande »
sur un exemple pratique : les « figures »
ƒ Soit les commandes sont réversibles
Dessin
ƒ Il est possible de coder la commande « inverse »
Figure
ƒ Soit il faut conserver une mémoire de l’état de l’objet receveur
# x: int
ƒ Les commandes peuvent avoir besoin de :
ƒ L’accès à l’objet receveur
ƒ Des arguments de la commande
ƒ De l’état du receveur
ƒ Gestion du undo
ƒ Conserver un historique des commandes exécutées (liste) pour pouvoir les
annuler
ƒ Gestion du redo
ƒ Conserver un historique des commandes annulées (liste) pour pouvoir les re-
exécuter
- CollectionFig
# y: int
+ supprimerFig()
+ translaterX(int)
+ faireCmd()
+ redimensionner(double)
+ undoCmd()
Rectangle
Cercle
La difficulté
est ici !!!
# r: int
# l: int
# h: int
+ redimensionner(double)
+ redimensionner(double)
[email protected]
Besoins
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
0..*
+ ajouterFig()
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ undo/redo ļ sauvegarde/restauration des états
Manipulation de figures : undo/redo
Mise en œuvre du modèle « commande » / undo
220
™
™
Utilisation du modèle « commande » / gestion du undo
Dessin
CommandeInterface
+ executer()
- des
Gestion du undo avec le modèles « commande »
ƒ
Ici les commandes sont réversibles
ƒ
Nature des associations
Interface
minimale à
respecter
+ undo()
+ ajouterFig()
-> association entre CommandeAbstraiteFig et
Figure
donne accès à la Figure sur
laquelle la commande sera
appliquée.
-> association entre CommandeSupprimer et
Dessin
donne accès à Dessin pour supprimer la
figure de la collection (CollectionFig).
Dessin
+ supprimerFig()
- des
+ faireCmd()
+ ajouterFig()
0..*
Exécuteu
r
- CollectionCmdFig
0..*
- CollectionFig
Figure
# x: int
0..*
- fig
0..*
# y: int
CommandeSupprimer
action
s
Receveu
r
CommandeTranslaterX
CommandeRedimensionner
+ translaterX(int)
- dx: int
- fact: double
+ executer()
+ executer()
+ executer()
+ undo()
+ undo()
+ undo()
+ redimensionner(double)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
CommandeAbstraiteFig
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
+ undoCmd()
+ supprimerFig()
Spécifique à
la commande
supprimer
+ faireCmd()
+ undoCmd()
CommandeAbstraiteFig
0..*
- CollectionCmdFig
0..*
- CollectionFig
Figure
# x: int
0..*
- fig
0..*
# y: int
CommandeSupprimer
+ translaterX(int)
+ redimensionner(double)
+ executer()
+ undo()
Générique à
toutes les
commandes
[email protected]
219
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class CommandeAbstraiteFig :public CommandeInterface{
public:
//
Figure& figure;
Figure* figure;
CommandeAbstraiteFig(Figure* f):figure(f){}
//
CommandeAbstraiteFig(Figure& f):figure(f){}
};
class CommandeSupprimer: public CommandeAbstraiteFig{
public:
Dessin* des;
//
Dessin& des;
CommandeSupprimer(Figure* f,Dessin* d):CommandeAbstraiteFig(f),des(d){}
//
CommandeSupprimer(Figure& f,Dessin& d):CommandeAbstraiteFig(f),des(d){}
virtual void executer();
virtual void undo() ;
};
Mise en œuvre du modèle « commande » / undo
™
C++ : Polymorphisme / pointeurs ou références
class CommandeInterface {
public:
virtual void executer() =0; // sans paramètre !
virtual void undo() =0; // sans paramètre !
};
CommandeInterface
+ executer()
+ undo()
CommandeAbstraiteFig
+ figure:
Figure*
CommandeSupprimer
+ des: Dessin*
+ executer()
+ undo()
Codage des commandes
class CommandeTranslaterX: public CommandeAbstraiteFig {
public:
int dx;
CommandeTranslaterX(Figure* f,int d):CommandeAbstraiteFig(f),dx(d){}
virtual void executer() ; // sans paramètre !
virtual void undo() ; // sans paramètre !
};
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
C++
222
void CommandeSupprimer::executer() {
cout << "Commande supprimer" << endl;
des->supprimerFig(figure);
}
void CommandeSupprimer::undo() {
cout << "Commande ajouter" << endl;
des->ajouterFig(figure);
}
void CommandeTranslaterX::executer() {
cout << "Commande translaterX" << dx << endl;
figure->translaterX(dx); // polymorphisme
}
void CommandeTranslaterX::undo() {
cout << "Commande translaterX -" <<dx << endl;
figure->translaterX(-dx); // polymorphisme
}
CommandeInterface
+ executer()
+ undo()
CommandeAbstraiteFig
+ figure:
Figure*
CommandeTranslaterX
CommandeSupprimer
- dx: int
+ des: Dessin*
+ executer()
+ executer()
+ undo()
+ undo()
[email protected]
Mise en œuvre du modèle « commande » / undo
[email protected]
C++
221
Mise en œuvre du modèle « commande » / undo
Programme principal
void main() {
Dessin monDess;
Cercle* c1=new Cercle(10,10,23);
Cercle* c2=new Cercle(20,20,44);
monDess.ajouterFig(c1);
monDess.ajouterFig(c2);
monDess.faireCmd(new CommandeTranslaterX(c1,10));
monDess.faireCmd(new CommandeTranslaterX(c2,20));
monDess.undoCmd();
monDess.undoCmd();
monDess.faireCmd(new CommandeRedimensionner (c1,10.0));
monDess.faireCmd(new CommandeSupprimer (c2,&monDess));
monDess.undoCmd();
monDess.undoCmd();
}
[email protected]
void Dessin::ajouterFig (Figure* fig) { //… }
void Dessin::supprimerFig (Figure* fig) { // …}
void Dessin::faireCmd(CommandeAbstraiteFig* c) {
c->executer(); // polymorphisme
ListeDesCommandes.push_front(c);
}
void Dessin::undoCmd() {
CommandeAbstraiteFig* c=ListeDesCommandes.front();
c->undo(); // polymorphisme
ListeDesCommandes.pop_front();
delete c;
}
Mise en œuvre du modèle « commande » / undo
™
Codage de la classe Dessin
class Dessin { // responsabilité de l’invocation et de la gestion des commandes (liste)
public:
list<CommandeAbstraiteFig*> ListeDesCommandes; // liste de pointeurs de commandes
list<Figure*> ListeDeFigures; // structure de donnée stockant les figures, liste de pointeurs de Figures;
void ajouterFig(Figure* fig) ;
void supprimerFig(Figure* fig) ;
void faireCmd(CommandeAbstraiteFig* c) ;
void undoCmd() ;
};
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
C++
224
[email protected]
C++
223
Retour sur le modèle « commande » / undo
0..*
commandes
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
CommandeInterface
Exécuteur
ƒ Exemple avec une classe « Template »
CommandeAbstraiteFig
CommandeSupprimer
Récepteur
1
Commande1
CommandeDeplacer
exécute()
CommandeRedimensionner
Figure
™
Remarques
ƒ Gestion de commandes composites (composées d’autres commandes)
ƒ Couplage avec le modèle « composite »
Gestion de commandes simples / non annulables
class CommandeInterface {
public:
virtual void executer() =0;
};
Commande
exécute()
Modèle « commande » / gestion de commandes simples
template <class Receveur>
class CommandeSimple : public CommandeInterface {
public:
typedef void(Receveur::*Action)(); //pointeur sur fonction sans paramètre
CommandeSimple(Receveur* r, Action a): receveur(r),action(a) {};
virtual void executer();
private:
void main() {
Action action;
Point* p = new Point(10,10);
Receveur* receveur;
CommandeInterface* c=new CommandeSimple<Point>(p,&Point::effacer);
};
c->executer();
}
template <class Receveur>
void CommandeSimple<Receveur>::executer(){
(receveur->*action)();
}
[email protected]
client
Dessin
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
“Main”
C++
226
[email protected]
C++
225
C++
228
Description du Modèle “Memento”
™
Modèle “Memento”: une alternative pour l’implémentation du “undo”
ƒ Utilisé notamment quand les actions sont non réversibles
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Principe : sauvegarder l’état d’un objet pour pouvoir ensuite le restaurer
™
Version 4.2
Description du Modèle : il est basé sur trois classes
ƒ classe « Auteur »
pour la mise en place du « Undo »
ƒ classe « Memento »
ƒ mémorise l’état de l’objet, information nécessaire à sa restauration ;
ƒ classe « Surveillant »
ƒ gère la sauvegarde et la restauration des états des objets via la classe
Memento.
ƒ Cette classe gére l’historique de l’état des objets pour pouvoir ramener
le dernier objet modifié dans son état précédent
[email protected]
Utilisation du modèle « Memento »
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ représente les objets dont on souhaite sauvegarder l’état ;
C++
229
Exemple d’utilisation : Undo pour la manipulation d’objets de type A
™
C++
230
™
Objectif
ƒ gérer la fonctionnalité « undo » pour la manipulation
d’objets de type A
™
La classe Memento - MementoA
MementoA
ƒ Mémoriser l’état d’un objet de type A
ƒ Mémorisation de l’état à la construction de son Memento.
Classe A
ƒ état : une valeur entière (_val).
class A {
public:
A(int val)
void doubler()
void tripler()
int getVal()
private:
int _val;
};
{ _val = val; }
{ _val = 2 * _val;}
{ _val = 3 * _val;}
{ return _val; }
class MementoA{
public:
MementoA(int etat){
_etat = etat;
}
int getEtat() {
return _etat;
}
private:
int _etat;
};
MementoA
[email protected]
ƒ 2 fonctions de modification : doubler ou tripler la valeur de l’objet.
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ 1 fonction d’accès
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ 1 constructeur
La classe Auteur – classe A
Le Surveillant - CommandA
™
Classe A complétée
MementoA* creerMementoA()
ƒ restaurer son état :
void restorerMementoA(MementoA* mem)
Exécution des actions (commandes) sur les objets A
ƒ Construction d’une commande avec en paramètre
ƒ un pointeur sur un objet A
class ƒ
A {.
public:
A(int val)
{ _val = val; }
void doubler()
{ _val = 2 * _val;}
void tripler()
{ _val = 3 * _val;}
int getVal()
{ return _val; }
MementoA *creerMementoA(){
return new MementoA(_val);
}
void restorerMementoA(MementoA *mem){
_val = mem->getEtat();
}
private:
int _val;
};
ƒ l’action à réaliser dessus (pointeur sur fonction),
ƒ Exécution de la commande via la méthode : void execute()
ƒ mémoriser l’état de l’objet dans l’historique avant de le modifier
Classe A
™
Annulation des actions : void undo().
ƒ rétablir le dernier état du dernier objet modifié et mettre à jour l’historique.
™
Représentation de l’historique : 2 listes gérées de façon synchrone
ƒ list<CommandA*> _commandList
ƒ pour mémoriser les commandes et accéder ainsi au dernier objet utilisé et
éventuellement afficher l’historique des actions réalisées.
ƒ list<MementoA*> _mementoList
ƒ pour mémoriser l’état de l’objet via la classe Memento.
[email protected]
ƒ mémoriser son état :
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
C++
232
[email protected]
C++
231
Le Surveillant – CommandA / Code
C++
234
Utilisation /Test
#include "CMemento.h"
list<CommandA*> CommandA::_commandList; // défintion des attributs static
list<MementoA*> CommandA::_mementoList;
int main()
{
A *objA1 = new A(1);
CommandA* cmd1 = new CommandA(objA1, &A::doubler); // NB: la responsabilité du delete se discute
CommandA* cmd2 = new CommandA(objA1, &A::tripler);
cout<<objA1->getVal()<< endl;
cmd1->execute();
cout<<objA1->getVal()<< endl;
1
cmd2->execute();
cout<<objA1->getVal()<< endl;
2
CommandA::undo();
6
cout<<objA1->getVal()<< endl;
2
CommandA::undo();
1
cout<<objA1->getVal()<< endl;
}
Classe A
MementoA
CommandA
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class CommandA {
public:
typedef void(A:: *Action)(); // pointeurs sur fonction de A
CommandA(A* receveur, Action action){
_receveur = receveur;
_action = action;
}
virtual void execute(){
_mementoList.push_front (_receveur->creerMementoA());
_commandList.push_front (this);
(_receveur->*_action)();
}
static void undo(){ // methode static
if (!_commandList.empty() )
{
_commandList.front()->_receveur->restorerMementoA(_mementoList.front());
delete _mementoList.front();
delete _commandList.front(); // NB: la responsabilité du delete se discute
_mementoList.pop_front() ;
_commandList.pop_front() ;
}
}
protected:
A* _receveur;
Action _action;
static list<CommandA*> _commandList; // les 2 listes sont des attributs static
static list<MementoA*>_mementoList;
};
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
C++
233
Concept de « framework »
236
Framework : ensemble de classes de base définissant les fonctionnalités
génériques de différentes applications
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Application / Classes dérivées :
doivent réécrire certaines fonctions
et peuvent en surcharger d’autres
Protocole (l’interface)
de mise en œuvre
d’une application
Classes dérivées
Fonctions virtuelles
Fonctions virtuelles pures
Framework :
gestion du séquencement
des fonctionnalités offertes
Classes de base
[email protected]
La notion de frameworks
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Version 4.2
Concept de « framework »
237
™
Dans ce chapitre, on va :
ƒ Exploiter un framework en C++ :
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ l'Architecture Document / Vue des MFC
ƒ Conception d’un éditeur
de graphe (gestion Nœuds - Arcs)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Concevoir un framework en Java
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Version 4.2
l'Architecture
Document / Vue
des MFC
C++
240
• Séparer le code qui gère les données
(Document) de celui qui assure la
restitution (Vues) de ces données
Demo.exe
CloudDoc
_points
add_point()
count()
get_point()
regression()
CloudDoc
_points
add_point()
count()
get_point()
regression()
GraphView
OnDraw()
OnLButtonDown()
TextView
OnUpdate()
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Des vues
… une représentation
des données ...
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
• Maintenir automatiquement une
cohérence entre toutes les vues et le
document
Un document
… les données ...
Exemple de Modèle Document / Vue
CDocument
GraphView
OnDraw()
OnLButtonDown()
TextView
CloudApp
CMainFrame
OnUpdate()
CloudApp()
InitInstance()
OnWindowNew()
CEditView
CView
CCtrlView
CWinApp
CMDIFrameWnd
• Le framework (MDI) / MFC fournit notamment les classes :
• Cdocument / gestion des données de l'application, …
• Cview (Cview, CEditView, …) / gestion des vues (affichage,...)
• CwinApp / enregistrement des dépendances Document/Cadre/Vue
• CMDIChildWnd / gestion du cadre des vues
• CMDIFrameWnd / gestion de la fenêtre cadre principale pour les MDI
[email protected]
2 mots sur l'Architecture Document / Vue des MFC
239
Les interdépendances
™ Une
C++
242
vue est associée à trois classes :
™
ƒ « Cview » / gestion de l’affichage et de la réaction aux événements …
ƒ « CMDIChildWnd » / description du cadre de la fenêtre …
BOOL CloudApp::InitInstance()
// redéfinition d’une méthode de CwinApp
{ CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_GRAPHVIEWTYPE,
RUNTIME_CLASS(CloudDoc),
RUNTIME_CLASS(CMDIChildWnd),
// définition par défaut
RUNTIME_CLASS(GraphView));
AddDocTemplate(pDocTemplate);
...
// définition par défaut
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
void CloudDoc::add_point(CPoint p)
{ _points.push_back(p);
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
interdépendances sont spécifiées à travers
pDocTemplate = new CMultiDocTemplate(
IDR_TEXTVIEWTYPE,
RUNTIME_CLASS(CloudDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(TextView));
AddDocTemplate(pDocTemplate);
Un document est une classe simple qui n’est associé à aucune notion
de représentation
ƒ Objectif : gestion des données
ƒ « Cdocument » / le document attaché à la vue ...
™ Les
La notion de document
CPoint CloudDoc::get_point(int i) const
{ assert(0 <= i && i < _points.size());
return _points[i];
}
int CloudDoc::count() const
{ return _points.size();
}
BOOL CloudDoc::regression(double& m, double& b) const
{ ...
}
[email protected]
C++
241
C++
243
La notion de vue
™
Une vue doit gérer :
ƒ les notions d’affichage (OnDraw, OnUpDate, …)
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
void GraphView::OnDraw(CDC* pDC)
{
CloudDoc* pDoc = dynamic_cast<CloudDoc*>(GetDocument());
int n = pDoc->count();
for (int i = 0; i < n; i++)
{ CPoint p = pDoc->get_point(i);
pDC->Ellipse(p.x - 3, p.y - 3, p.x + 3, p.y + 3);
}
double m, b;
if (pDoc->regression(m, b))
{ ...
pDC->LineTo(xright, (int) (m * xright + b));
}
}
void GraphView::OnLButtonDown(UINT nFlags, CPoint point)
{
CloudDoc* pDoc = dynamic_cast<CloudDoc*>(GetDocument());
pDoc->add_point(point);
CView::OnLButtonDown(nFlags, point);
pDoc->UpdateAllViews(NULL);
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ La réaction aux événements (OnLButtonDown, …)
Exemple de conception
d’un Framework
Méthodologie : organisation des classes
Exemple de conception d’un Framework complet
245
246
™
Conception d’un éditeur de graphe (gestion Nœuds - Arcs)
ƒ Applications
ƒ communes (framework)
ƒ graphe de circuit logique, graphe de communication réseau, ...
ƒ ex : gestion des événements souris, classe de base Nœud et Arc, ...
ƒ Encapsulation des concepts de base dans un framework
ƒ spécifiques (applications)
ƒ sélection, déplacement, connexion, ...
Demo.htlm
Icônes (exclusives)
gestion du type de
nœuds et
de liaisons
Choix exclusif du
mode d'édition
Supprimer
Déplacer
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ ex : type et dessin des formes des nœuds et des arcs, ...
Zone de
représentation :
actions dépendantes
du contexte et des
évènements souris
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Conception de l’interface utilisateur
Insérer
Séparer les fonctionnalités
Cercle
Application
CercleP
Nœud
Arc
Droite
Pointillé
Framework
[email protected]
™
Abstraction / Utilisation des concepts génériques
™
Java
248
™
La classe du framework : Nœud
abstract class Noeud implements Cloneable
{ public abstract void dessine(Graphics g);
Framework
{ ... }
(Point p)
{ _centre = p; }
public Point centre
()
{ return _centre; }
Nœud
private Point _centre; ...
}
Cercle
La classe utilisateur : Cercle
class Cercle extends Noeud {
Application
public void dessine (Graphics g) {
g.drawOval( centre().get_x() - Rayon,
centre().get_y() - Rayon, 2 * Rayon, 2 * Rayon)
}
...}
Framework
GraphEditeur
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
()
public void deplace
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public abstract boolean est_dans(Point p);
public Object clone
La classe du Framework
abstract class GraphEditeur extends Applet {
…
abstract String[] get_types();
public void enregistrement() {…}
...
public abstract Rectangle rect_englobant();
™
Prise en compte des types utilisateurs
MonEditeur
™
L'application devra définir :
Application
ƒ les classes spécifiques de type nœuds et arcs (Cercle, CercleP, ...)
ƒ la liste de ces classes spécifiques qui devront être manipulées par le
framework => redéfinition de get_types()
String[ ] get_types ( )
{
}
String [ ] types = "Cercle", "CercleP", "Droite", Pointillé" };
return types;
[email protected]
Java
247
Java
249
Typage dynamique (RTTI)
Java
250
™
Initialisation dynamique des nœuds et arcs de l’utilisateur
™
Le framework va mémoriser les objets correspondants
™
Applet : Programme Java destiné à fonctionner via un browser WEB
™
Canvas : Zone de dessin avec gestion des évènements souris, ...
ƒ GraphEditeur : Gestion de l’état globale de l’éditeur (mode d’édition) ...
Framework
public void enregistrement() {
Framework : notion d'interface graphique
ƒ GraphCanvas : Dessin du graphe - gestion des évènements souris
ƒ IconCanvas : Gestion et dessin des icônes (types arcs et nœuds)
GraphEditeur
Object obj = cls.newInstance() ;
if (obj instanceof Nœud)
{ // ajoute ce type de nœud au vecteur d'icônes des nœuds }
else if (obj instanceof Arc)
{ // ajoute ce type d ’arc au vecteur d'icônes des arcs }
}
}
Demo2.htlm
Cercle
Arc
Nœud
Canvas
Application
CercleP
Droite
Pointillé
IconCanvas
Framework
Framework Java
GraphCanvas
GraphEditeur
Applet
MonEditeur
[email protected]
{ Class cls = Class.forName(typenames[i]);
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
for (int i = 0; i < typenames.length; i++)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
String[] typenames = get_types();
Java
252
IconCanvas()
0..1
ajoutTypeNoeud()
ajoutTypeArc()
mouseReleased()
- _icon
arcCourant()
noeudCourant()
enregistrement()
get_types()
init()
mode()
setArcCourant()
GrapheCanvas
0..1
- _graph
Arc
_from: Noeud
_to: Noeud
DiagramEditor2
supprimeArc()
paint()
mouseReleased()
mouseDragged()
mouseMoved()
0..1
0..1
- _current_edge
get_types()
dessine()
estDans()
- _current_node
Noeud
+ _from
+ _to
centre()
clone()
deplace()
0..1
clone()
dessine()
estDans()
liasonNoeud()
dessine()
estDans()
pointFrontiere()
rectEnglobant()
connect()
ALigne
AFlec...
Adroitecercle
dessine()
estDans()
dessine()
estDans()
Adroitecercle()
dessine()
clone()
Nlosange()
clone()
dessine()
Nlosange
Ntriangle()
clone()
dessine()
Ntriangle
dessine()
estDans()
pointFrontiere()
NCercle
estDans()
estDans()
pointFrontiere()
rectEnglobant()
estDans()
pointFrontiere()
rectEnglobant()
rectEnglobant()
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
setNoeudCourant()
GrapheCanvas()
rechercheNoeud()
supprimeNoeud()
public class GrapheCanvas extends Canvas implements MouseListener,
MouseMotionListener {
public void mousePressed(MouseEvent evt) {
int mode = ((GrapheEditor) getParent()).mode();
Point mousePos = new Point(evt.getX(), evt.getY());
Noeud n = rechercheNoeud(mousePos);
if ((mode == INSERT) && (n == null)) {
Noeud t = ((GrapheEditor) getParent()).noeudCourant();
Noeud i = (Noeud) t.clone();
i.deplace(mousePos);
Framework
_VecNoeuds.addElement(i);
repaint();
Java
} // …
public void paint(Graphics g) {
Canvas
Dimension d = getSize();
g.drawRect(0, 0, d.width - 1, d.height - 1);
for (int i = 0; i < _VecArcs.size(); i++) {
Arc e = (Arc) _VecArcs.elementAt(i);
e.dessine(g);
GraphCanvas
}
for (int j = 0; j < _VecNoeuds.size(); j++) {
Application
Noeud n = (Noeud) _VecNoeuds.elementAt(j);
Framework
n.dessine(g);
}
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
GrapheEditor
IconCanvas
Autonomie du framework et notion de Canvas
[email protected]
Diagramme de classe / exemple
251
Bilan sur la notion de Framework
253
Le framework fournit les mécanismes de base
associés aux composants d'un système
™ Questions
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
de base pour l'utilisation d'un framework
Version 4.2
ƒ Quelles sont les classes de base fournies pour la dérivation ?
ƒ Quelles sont les fonctions virtuelles que l'on doit ou que l'on peut redéfinir ?
™ Conception
d'un framework
ƒ Il faut encapsuler (protéger au maximum les mécanismes du framework)
ƒ si il y a remise en cause des mécanismes de base du framework :
::::::::::....... il faut redéfinir le framework
ƒ valider le framework sur plusieurs applications différentes
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
La difficulté dans la conception d'un framework vient de la
gestion des multiples possibilités d'application
qui peuvent venir se greffer sur le framework.
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Quelles sont les phases d'initialisation exigées ?
Introduction à l'interfaçage
de Java avec des librairies C/C++
La JNI : Java Native Interface
Java
255
JNI : Java Native Interface
™
Java
256
JNI : les possibilités d'interfaçage
™
Objectif
ƒ Interfacer du C/C++ avec du Java dans une même application
Le framework de la JNI permet
ƒ En Java
ƒ On peut appeler des méthodes natives (C/C++)
Pourquoi faire ?
ƒ Les méthodes natives(C/C++) peuvent
ƒ Réutilisation de bibliothèques C/C++ déjà existantes
ƒ Codage dépendant de la plate-forme : accès au matériel, pilote, …
™
Comment ?
ƒ Utilisation de la JNI, de son framework
™
C/C++
JNI
JAVA
Implications
ƒ Limitation des possibilités de portage de votre application
ƒ Recodage ou recompilation des parties C/C++
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Inspecter, modifier ou créer des objets JAVA
ƒ Meilleurs performances en terme de temps de calcul
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Codage en C/C++ des parties critiques de code au niveau du temps
d'exécution
ƒ Invoquer des méthodes Java
ƒ Obtenir des informations sur les classes Java
ƒ Faire de la vérification de type dynamique (run-time type checking)
ƒ Gérer les exceptions
ƒ Les possibilités d'interfaçage sont très grandes
ƒ Elles peuvent être facilitées par des utilitaires de développement
ƒ SWIG : http://www.swig.org/
[email protected]
™
Java
257
JNI : Les différentes étapes de l'interfaçage
™
Java
258
JNI : Les différentes étapes de l'interfaçage
™
Exemple : appel à une méthode native simple
ƒ 1ère étape : le programme Java
2ème étape : Génération du fichier d'entête C++ : MaClasse.h
ƒ Compilation du code Java
ƒ Javac MaClasse
ƒ Génération automatique du fichier .h: Javah
ƒ Javah MaClasse
public static void main(String[] args) {
MaClasse obj1 = new MaClasse();
obj1.afficheCpp();
}
}
Déclaration de la méthode native
Appel de la méthode native
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MaClasse */
#ifndef _Included_MaClasse
#define _Included_MaClasse
#ifdef __cplusplusextern "C" {
#endif
/*
* Class: MaClasse
Nommage : préfixe + nom de la classe + nom de la méthode
* Method: afficheCpp
Java _ Maclasse _ afficheCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MaClasse_afficheCpp (JNIEnv *, jobject);
#ifdef __cplusplus}
#endif
#endif
[email protected]
public native void afficheCpp();
=> MaLibrairie.so (Unix)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
static {
System.loadLibrary("MaLibrairie");
}
chargement de la librairie (C/C++)
en mémoire (nom sans extension) :
automatique / plate-forme
=> MaLibrairie.dll (Windows)
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class MaClasse {
Java
259
JNI : Les différentes étapes de l'interfaçage
™
Java
260
JNI : Les différentes étapes de l'interfaçage
™
3ème étape : Codage du fichier C++
5ème étape : Exécution du programme Java
ƒ Recopier les prototypes des méthodes
ƒ Coder le contenu
ƒ L'emplacement de la librairie doit être connu de la JVM
Inclure le fichier : MaClasse.h
Î Pour pouvoir l'utiliser :
4ème étape : Génération de la librairie
ƒ .dll (Windows) ou .so (Unix)
ƒ avec l'option -Djava.library.path=<chemin>
ƒ Ou copier la DLL/librairie au niveau de la racine du projet
ƒ Ou copier la DLL/librairie dans un répertoire contenu dans la variable PATH
(de Windows.)
Î Sinon vous rencontrerez à l'utilisation l'exception :
Exception in thread "main" java.lang.UnsatisfiedLinkError:
no nom-de-la-/librairie in java.library.path
[email protected]
™
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Spécifier son emplacement en démarrant la JVM
Les paramètres ne servent pas
/*
dans cet exemple
* Class: MaClasse
* Method: AfficheCpp
* Signature: ()V
*/
JNIEXPORT
void
JNICALL Java_MaClasse_afficheCpp (JNIEnv *, jobject) {
cout << "Affichage depuis une methode C++" << endl;
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
#include "MaClasse.h"
#include <iostream.h>
Code C++
#include "MaClasse.h"
#include <iostream.h>
JNIEnv* env
Pointeur : environnement / accès aux fonction du JNI
JNIEXPORT void JNICALL Java_MaClasse_envoieString (JNIEnv* env, jobject, jstring strJava) {
// Construction d'une chaîne C++(Ascii) à partir d'une chaîne Java (Unicode)
const char* ch = env->GetStringUTFChars(strJava,0);
// Affichage de la chaîne C++
jstring strJava
cout << ch << endl;
Paramètre de la fonction envoieString
// Libération de la chaîne C++
env->ReleaseStringUTFChars(strJava,ch);
}
JNI : accès aux attributs d'une classe
…
Code Java
public native String toString();
public static void main(String[] args) {
MaClasse obj1 = new MaClasse("obj1", 2);
System.out.println(obj1);
}
Code Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class MaClasse {
static {
System.loadLibrary(" MaLibrairie ");
}
public native void envoieString(String strJava);
public static void main(String[] args) {
MaClasse obj1 = new MaClasse();
obj1.envoieString("test string");
}
}
Java
262
MaClasse
nb: int
nom: String
afficheCpp()
toString(): String
envoieString(in String)
MaClasse(in String, in int)
JNIEXPORT jstring JNICALL Java_MaClasse_toString(JNIEnv* env, jobject obj) {
char buffer[256];
jobject obj
// Obtention de la Metaclasse de MaClasse
référence sur l'objet qui a invoqué la méthode (this)
jclass cls = env -> GetObjectClass(obj);
// Récupération de l'identificateur de l'attribut nb de type int
jfieldID fid = env -> GetFieldID(cls,"nb","I");
GetFieldID(cls,"nb","I") : accès à l'identificateur
// Récupération de la valeur entière de l'attribut
Paramètres : classe, chaîne::attribut, chaîne::type
// à partir de son identificateur
int nb = env -> GetIntField(obj,fid);
// Calcule de l'identificateur de l'attribut nom de type String
GetIntField(obj,fid); : accès à l'attribut
fid = env -> GetFieldID(cls,"nom","Ljava/lang/String;");
Paramètres : l'objet, l'identificateur
// Récupération de l'objet jstring correspondant à l'attribut
jstring strJava = (jstring)env->GetObjectField(obj,fid);
// Construction d'une chaîne C++ à partir d'une chaîne Java
const char* ch = env->GetStringUTFChars(strJava,0);
// Génération d'une chaîne contenant la valeur de l'attribut
sprintf(buffer,"nb = %d, nom=%s ",nb,ch);
// On retourne un objet Java de chaîne de caractères
Code C++
return env->NewStringUTF(buffer);
}
[email protected]
JNI : envoie de String
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Java
261
Code Java
MaClasse
accesAttributJava()
MaClasse(in String, in int)
main(in String[])
JNIEXPORT void JNICALL Java_MaClasse_accesAttributJava
(JNIEnv *env, jobject obj){
Code C++
date: int
0..1
Info(in int)
public class MaClasse {
static {
System.loadLibrary("MaLibrairie");
}
public native void accesAttributJava();
public int nb;
public String nom;
public Info obj1;
public MaClasse(String s, int n) {
nom = s;
nb = n;
obj1 = new Info(2003);
}
public static void main(String[] args) {
MaClasse obj1 = new MaClasse("obj1", 2);
obj1.accesAttributJava();
}}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
MaClasse
// Obtention de la Metaclasse de MaClasse
jclass cls = env -> GetObjectClass(obj);
// Récupération de l'identificateur : attribut obj1 de type Info
jfieldID fid = env -> GetFieldID(cls,"obj1","LInfo;");
// Récupération de l'objet correspondant à l'attribut
jobject obj2 = env->GetObjectField(obj,fid);
+ obj1
date de obj1 avant modif : 2003
date de obj1 apres modif : 2004
}
Code C++
JNIEXPORT void JNICALL
Java_MaClasse_appelMethodeJava (JNIEnv *env, jobject obj){
// Récupération d'un objet de Metaclasse
jclass cls = env -> GetObjectClass(obj);
appelMethodeJava()
MaClasse(in String, in int)
getNb(): int
// Récupération de l'identificateur public int getNb()
jmethodID mid = env->GetMethodID(cls,"getNb","()I");
Code Java
public class MaClasse {
static {
System.loadLibrary("MaLibrairie");
}
public native void appelMethodeJava();
// Obtention de la Metaclasse de obj2
jclass cls2 = env -> GetObjectClass(obj2);
// Récupération de l'identificateur de l'attribut nb de type int
jfieldID fid2 = env -> GetFieldID(cls2,"date","I");
// Récupération de la valeur entière de l'attribut
int date = env -> GetIntField(obj2,fid2);
cout << "date de obj1 avant modif : " << date << endl;
// modification du champs entier de obj1
env -> SetIntField(obj2,fid2,2004);
// Récupération de la valeur entière de l'attribut
date = env -> GetIntField(obj2,fid2);
cout << "date de obj1 apres modif : " << date << endl;
return;
JNI : invocation d'une méthode Java
nb: int
nom: String
Info
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
nb: int
nom: String
obj1: Info
Java
264
GetMethodID(cls,"getNb","()I") :
Accès à l'identificateur de la méthode
Paramètres : classe, chaîne::nom de la méthode,
chaîne::(type des paramètres)type de retour
if (mid == 0) {
cout << "Probleme !" << endl;
} else {
int nb =env->CallIntMethod(obj,mid);
public int nb;
public String nom;
public MaClasse(String s, int n) {
nom = s;
nb = n;
}
public int getNb() {return nb; }
public static void main(String[] args) {
MaClasse obj1 = new MaClasse("obj1", 2);
obj1. appelMethodeJava();
}}
CallIntMethod(obj,mid) :
Appel de la méthode qui retourne un entier
Paramètres : obj, identificateur de la méthode
cout << "Appel de la methode JAVA getNb : " ;
cout << nb << endl;
}
return;
Appel de la methode JAVA getNb : 2
}
[email protected]
JNI : accès aux attributs d'une classe / objet
[email protected]
Java
263
Java
265
JNI : fonctionnalités avancées
™
Les autres fonctionnalités de la JNI Cf. Doc de Java :
http://java.sun.com/docs/
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
ƒ Les échanges de tableaux
ƒ L'appel à des méthodes de classe (static)
Version 4.2
Exploitation des utilitaires de développement pour l'interfaçage
ƒ Exploitation automatisée de classes C++ en Java via la JNI
ƒ SWIG : http://www.swig.org/
ExempleJNI.java
Exemple.i
Class1.java
SWIG
ExempleJNI.class
Compilation
Java
Class2.java
Class1.class
Class2.class
Class1.h
Class2.h
Class1.cpp
Class2.cpp
Exemple_wrap.cpp
Compilation
C++
Exemple.dll
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ La gestion des exceptions
Annexes
et Rappels
Java
268
Introduction : Java5 (Tiger)
™
Automne 2004
ƒ Révision de Java : Java 5 (nom de code Tiger) : J2SE 5.0
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
™
Version 4.2
Les Principales évolutions
ƒ Autoboxing et Auto-Unboxing des types Primitifs
à Java 5 (Tiger)
ƒ Type énuméré : enum
ƒ Nombre d’arguments variable pour une méthode
ƒ Les imports statiques
ƒ Les Generics – introduction
ƒ … les Annotations, Supervison de la JVM, Synchronisation, Client lourd
™
Intégration avec Eclipse
ƒ Nécessité de passer à la version Eclipse 3.1
pour exploiter les nouvelles fonctionnalités de Java5
ƒ Preferences>java>compiler>Compiler compliance level : 5.0
[email protected]
Bref introduction
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Les itérations sur des collections
Autoboxing et Auto-Unboxing des types primitifs
™
Java
270
™
Simplification du passage (Type Primitifs / objet)
long/Long, float/Float, char/Character
ƒ Notation plus légère et concise
Exemple
// maintenant avec Java 5
Character oCar2 = new Character('a');
// objet
char car2=oCar2;
// autoUnBoxing
// maintenant ok
// avant => Type mismatch: cannot convert from Character to char
tabDyn.addElement(car2);
// autoBoxing
// maintenant ok
// avant => The method addElement(Object) in the type Vector
// is not applicable for the arguments (char)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
List Figures=new ArrayList();
Figures.add(new Rectangle());
Vector tabDyn=new Vector();
// avant Java 5
Character oCar = new Character('a');
// Objet
char car=oCar.charValue();
// unBoxing -> type primitif
tabDyn.addElement(new Character(car)); // boxing -> Objet
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Evolution du for pour l’itération sur des collections
ƒ For (paramètre formel : Objet Iterable) { corps }
ƒ boolean/Boolean, byte/Byte, double/Double, short/Short, int/Interger,
™
Itérations sur des collections : nouvelle boucle for
//...
// avant java5
for (Iterator i = Figures.iterator(); i.hasNext(); ) {
((Figure)i.next()).draw(ca);
}
// avec Java 5
for (Object s: Figures) {
((Figure)s).draw(ca);
}
ƒ NB: On ne peut pas modifier la collection avec cette notation
[email protected]
Java
269
Type énuméré : enum
™
Java
272
Nombre d’arguments variable pour une méthode
™
Avant Java 5 : utilisation de constante de type int
™
// affichage : 1
// possible ! Danger !
Avec Java5 : la construction des enum est type-safe
public enum EtapesJava5 { ETAPE0, ETAPE1, ETAPE2 };
EtapesJava5 e2=EtapesJava5.ETAPE0;
System.out.println(e2);
// affichage : ETAPE0
e2=10;
// erreur (type-safe)Type mismatch:
// cannot convert from int to Canvas.EtapesJava5
™
D’autres raffinements sont encore possibles …
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
int e=Etapes.ETAPE1;
System.out.println(e);
e=10;
Notation : « Type … »
static void argTest(String ... args) { // nombre variable d’arguments de type String
for (String o : args) {
System.out.println(o);
}
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public class Etapes {
public static final int ETAPE0=0;
public static final int ETAPE1=1;
public static final int ETAPE2=2;
//...
}
// …
argTest("arg1","arg2","arg3");
argTest("bonjour","monsieur");
™
// 3 paramètres
// 2 Paramètres
Résultat
arg1
arg2
arg3
bonjour
monsieur
[email protected]
Java
271
Java
273
Les imports statiques
™
Objectifs
ƒ Rendre visible des méthodes et variables statiques
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
// Avant
Import static java.awt.BorderLayout.*
getContentPane().add(plum, CENTER);
ƒ Attention aux conflits de nommage
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
// Avec Java5 et les imports statiques
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
getContentPane().add(plum, BorderLayout.CENTER);
Clonage et copie en profondeur
Java
276
™
™
™ En
En C++
ƒ Copie d'identificateur : pas de recopie des objets identifiés
ƒ Attention aux copies de pointeurs (pas de recopie des objets pointés)
ƒ Il faut souvent implanter la recopie (… en profondeur si besoin …)
™ Gestion
En JAVA
Exemple : code C++ ok / code JAVA erreur
Rectangle Carre (Point p, int d) {
Point a= p ;
a
a.deplacer(-d / 2 , -d / 2);
p
Point b= p ;
b.deplacer(d / 2 , d / 2);
Rectangle r(a,b);
b
// code C++
d
return r;
}
[email protected]
Rectangle r=new Rectangle(a,b); // code Java
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Il faut souvent implanter la recopie (… en profondeur si besoin …)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
JAVA
ƒ Copie d’objets => recopie (… en profondeur si …)
ƒ Copie d'identificateur : pas de recopie des objets identifiés
™
Notion de copie en profondeur
des recopies d’objet avec le constructeur par recopie
Rectangle Carre (Point p, int d) {
Point a= new Point(p) ; // constructeur par recopie
a.deplacer(-d / 2 , -d / 2);
Point b= new Point(p) ; // constructeur par recopie
b.deplacer(d / 2 , d / 2);
Rectangle r=new Rectangle(a,b);
return r;
}
™ Utilisation
a
p
b
d
de la méthode : clone()
Rectangle Carre (Point p, int d) {
Point a= (Point)p.clone() ;
a.deplacer(-d / 2 , -d / 2);
Point b= (Point)p.clone() ;
b.deplacer(d / 2 , d / 2);
Rectangle r = new Rectangle(a,b);
return r; // résultat correct
}
[email protected]
Notion de copie en profondeur
275
La méthode clone( ) de la classe Object
Java
278
Mise en œuvre de la méthode clone()
™ Implantation
™ La
de la méthode clone()
ƒ l’interface Cloneable doit être mise en œuvre
méthode clone de la classe Object ne fait par défaut que
ƒ le contrôle d’accès à cette fonction nécessite la mise en place du traitement
d’exception
ƒ la réservation mémoire
et
plus
ƒ clone() est une fonction protégée (surcharge "public" possible)
de la classe de base Object.
ƒ l’accès à cette fonction est protégé et seules les classes mettant en œuvre
l’interface de balisage Cloneable peuvent y accéder (une sorte
d'avertissement)
=> Implantation explicite de la méthode clone() pour vos classes
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ De
*gestion d’exception
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ la recopie superficielle (ok pour : types primitifs et les objets invariants)
class Point implements Cloneable
{
public Object clone( )
{
try { return super.clone();
}
// recopie superficielle
catch (CloneNotSupportedException e) { return null; }
}
…
private int _x;
}
private int _y;
[email protected]
Java
277
Mise en œuvre de la méthode clone()
™
Java
280
Copie en profondeur
™ La
ƒ Les champs « constants » sont implicitement gérés (nombres, string, ...)
// fonction clone() à définir
// pour la classe Point
[email protected]
class Rectangle implements Cloneable {
public Object clone( ) {
try {
Rectangle r = (Rectangle)super.clone() ;
r._pt_hg = (Point) _pt_hg.clone() ;
r._pt_bd = (Point) _pt_bd.clone() ;
return r;
}
catch (CloneNotSupportedException e) {
return null;
}
}
…
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Les champs « identificateurs » doivent être clonés
(toutes les classes référencées doivent être "récursivement" clonées)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Clonage et héritage
La notion de « cloneable » est transmise aux classes dérivées
méthode super.clone(), l’héritage et l’attachement dynamique
class Niv1 implements cloneable {
public Niv1(int i) { _i=i; }
public Object clone( )
{
try { return super.clone(); }
// recopie superficielle
catch (CloneNotSupportedException e) { return null; }
}
…
private int _i;
}
class Niv2 extends Niv1 {
private int j;
public Niv2(int i) { super(i); }
...
}
// copie automatique
ƒ Quand Niv1.clone() est appelée à travers Niv2.clone() ; Object.clone() est
appelée à travers super.clone() qui travaillera alors avec Niv2
[email protected]
Java
279
Java
281
Remarques sur le clonage en Java
™ Interface
Cloneable
class Object
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
{
Version 4.2
interface Cloneable { }
protected Object clone()
{ if (! (this instanceof Cloneable))
throw new CloneNotSupportedException();
™ La
classe Vector,… : met en œuvre une copie superficielle
ƒ Recopie en profondeur :
ƒ faire appel à la méthode clone() (copie superficielle)
ƒ Vector v2=(Vector)v1.clone();
ƒ parcourir le vecteur pour cloner explicitement tous ses éléments
ƒ for (int i=0; i<v2.size(); i++)
v2.setElementAt(v2.elementAt(i)).clone(), i);
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
...
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
...
}
Classe interne
Classe interne : inner class
™ Possibilité
Java
284
de déclarer une classe à l'intérieur d'une autre classe
ƒ Une classe membre interne peut être déclarée comme : public, private,
protected.
ƒ Association de la visibilité de bloc avec la visibilité de classe
ƒ Accès aux membres de la classe englobante
ƒ Elle a accès aux membres (attributs/méthodes), même privés, de la classe
l'englobant
ƒ Permet de "cacher" les classes internes liées à une implémentation
spécifique et de rassembler les classes connexes
ƒ Classe membre
d'une classe
class Englobe { …
class
ƒ Classe locale
à une méthode
membre
d'une classe
ƒ Classe anonyme
définie à l'intérieur
d'une expression
ClasseMembre { ... }
}
class Englobe { …
}
void methode() {
class ClasseLocale { ... }
}
class Englobe { …
void methode() {
Ob.addActionListner( new ClasseAnonyme() { ... });
}
}
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
déclinaisons des classes internes
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™ Trois
Classe interne : membre d'une classe
class Englobe {
private int att1;
private class LocalePr {
private int att2;
public void test() {
att2=att1; // équivalent à this.att2=Englobe.this.att1;
} ...
}
public class
LocalePu { ... }
private LocalePr vpr;
...
}
…
Englobe
E
=
// utilisation de la classe interne privée
new Englobe();
Englobe.LocalePu vpu= E.new
LocalePu(); // classe interne publique
[email protected]
Java
283
Classe interne : locale
™ Classes
Java
286
internes déclarées dans un bloc de code
ƒ Uniquement visibles et utilisables dans leur bloc
(idem aux variables locales)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Englobe2 {
private int att1;
void methode() {
final int att2=2;
int att3=2;
class ClasseLocale {
private int att;
public void test() {
att=att1;
att=att2;
//
att=att3; // erreur (att3 non final)
}
}
}
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Elles ont accès en plus aux variables locales "Final" de leur bloc
ƒ garantit la cohérence avec les variables locales
ƒ Elles ne peuvent pas être spécifiées comme (public, private, …)
Classe interne : anonyme
ƒ Classe locale sans nom
ƒ Contraction(combinaison) : définition et instanciation d'une classe
ƒ Souvent utilisée dans le contexte de la gestion des évènements
class Englobe3 {
private int att1;
public void test(Point P) {
System.out.println(P);
P.deplacer(1,1); System.out.println(P);
}
Classe anonyme dérivée de la
public void test2() {
classe Point
test( new Point(10,10) {
public int _z;
Les arguments sont passés au
public void deplacer(int dx, int dy) {
constructeur de la classe de
_x += dx; _y += dy; _z=111;
base (Point)
}
public String toString() {
return("Point3D : " + x() + " " +y() + " " + _z);
}
});
}
public static void main(String[] args) {
Point3D : 10 10 0
Englobe3 Eng=new Englobe3();
Eng.test2();
Point3D : 11 11 111
}
}
[email protected]
Java
285
Java
287
Classe interne : anonyme
™ Une
classe anonyme peut implémenter une interface
ƒ Elle devient alors une classe dérivée de Object
ƒ Il n'y a donc jamais d'arguments à sa construction
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Version 4.2
JButton plum = new JButton("Appuyez ici");
jf.getContentPane().setLayout(new BorderLayout());
jf.getContentPane().add(plum, "East");
jf.pack();
plum.addActionListener( new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("nombre de clic "+ i++);
}
int i=1;
} );
}}
Possibilité de construire une
classe anonyme de ce type.
Contraction pour la création
directe d'une classe
anonyme (combinaison de
la définition et d'une instance)
Implémente l'interface
ActionListner
nombre de clic 1
nombre de clic 2
nombre de clic 3
fermeture de l'application
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public static void main(String [] args) {
JFrame jf = new JFrame();
jf.setSize(400,100);
jf.setVisible(true);
La méthode addActionListener
attend un objet qui implémente
l'interface ActionListner :
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
import java.awt.*;import javax.swing.*;
import java.awt.event.*;
public class jboutton {
Introduction aux
Windows forms
C++
289
Les Windows forms
™
C++
290
Deux mots sur .net et C++ managé
™
Les Microsoft Windows Forms (Winforms)
ƒ Ensemble de classes utilisées pour créer des applications graphiques
windows (framework .net 2.0) / (windows managé: pour nous C++ managé )
.net est un framework qui gère
ƒ L’exécution de l’application par le Common Langage Runtime (CLR)
ƒ implémentation de Microsoft de la spécification CLI(common Langage
ƒ Formulaires (fenêtre) : System::Windows::Forms::Form
Infrastructure) pour exécuter du code CIL (Common Intermediate
Langage) de façon managé (compilation à la volée : « just in time »)
ƒ Fenêtres de dialogue (choix d’un fichier, choix de fontes, conf. impression )
Repose sur la bibliothèque GDI+ (Graphique Device Interface)
ƒ Gestion des IHMs
ƒ tracés de formes et de courbes géométriques, gestion des images(JPG, …)…
™
Avantages
ƒ Simple à prendre en main : outils de design de l’IDE ( Visual studio 2005)
ƒ Code produit orienté objet avec un haut niveau d’abstraction
ƒ Code produit : + simple et + propre que les MFC (existent encore)
™
Le C++ managé (géré par le CLR => garbage collector, etc.)
ƒ Classe
ƒ ref class X { …}
ƒ Objet
ƒ String^ s = gcnew String(« bonjour »); // Pas besoin de delete
ƒ Les Handles
ƒ Ù à une référence sur un objet managé : ^
[email protected]
™
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Composants notion plus globale incluant formulaires, contrôles, etc.
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Contrôles (bouton, éditeur, …) : System::Windows::Forms::Control
C++
291
Une application WinForms : présentation
C++
292
Une application WinForms : le projet
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Création d’un projet associé
à une application windows forms
C++
293
Une application WinForms : EDI et Design
C++
294
Une application WinForms : Ajout de contrôles
Boîte à outils
Propriété du bouton
Évènements associés
Fenêtre créée
Nom de la méthode
appelée par réaction
à cet évènement
Ajout de contrôles
par « drag and drop »
Nom de l’objet bouton créé
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Code associé à la fenêtre créée
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Propriété de la Fenêtre
Form1.h
/// <summary>
/// Description résumée de Form1
///
/// AVERTISSEMENT : si vous modifiez le nom de cette classe, vous devrez modifier la
///
propriété 'Nom du fichier de ressources' de l'outil de compilation de ressource managée
///
pour tous les fichiers .resx dont dépend cette classe. Dans le cas contraire,
///
les concepteurs ne pourront pas interagir correctement avec les ressources
///
localisées associées à ce formulaire.
/// </summary>
public ref class Form1 : public System::Windows::Forms::Form
{
public:
Définition de la classe Form1 (C++ managé)
Form1(void)
{
InitializeComponent();
//
//TODO : ajoutez ici le code du constructeur
//
}
Une application WinForms : Le code généré
// ….
l^ label1;
private: System::Windows::Forms::Label^
tt
private: System::Windows::Forms::Button^ buttonPlus1;
private: System::Windows::Forms::Button^ buttonVersion;
public: System::Windows::Forms::NumericUpDown^ numericUpDownCompteur;
private: System::Windows::Forms::Button^ buttonDessin;
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
namespace ExempleWinform {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
C++
296
Form1.h // suite
private:
/// <summary>
/// Variable nécessaire au concepteur.
/// </summary>
System::ComponentModel::Container ^components;
#pragma region Windows Form Designer generated code
/// <summary>
/// Méthode requise pour la prise en charge du concepteur - ne modifiez pas
/// le contenu de cette méthode avec l'éditeur de code.
/// </summary>
void InitializeComponent(void)
{
is->label1 = (gcnew System
this->label1
System::Windows::Forms::Label());
tt Pl 1 = (gcnew
(
this->buttonPlus1
System::Windows::Forms::Button());
this->buttonVersion = (gcnew System::Windows::Forms::Button());
this->numericUpDownCompteur = (gcnew System::Windows::Forms::NumericUpDown());
this->buttonDessin = (gcnew System::Windows::Forms::Button());
// …
[email protected]
Une application WinForms : Le code généré
[email protected]
C++
295
Réactions aux évènements
™
C++
298
Introduction d’une seconde « Form »
™
Réactions aux évènements
Introduction d’une 2nde « Form »
ƒ Dessin : 2nd objet Form
Form1.h // suite
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
// ….
private: System::Void buttonVersion_Click(System::Object^ sender, System::EventArgs^ e) {
MessageBox::Show("Version Aout 2005");
}
private: System::Void buttonPlus1_Click(System::Object^ sender, System::EventArgs^ e) {
numericUpDownCompteur->UpButton();
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
private: Dessin^ fentreDessin;
Form1.h // suite
// ….
private: System::Void buttonDessin_Click(System::Object^ sender, System::EventArgs^ e) {
if (this->fentreDessin==nullptr){
w Dessin(numericUpDownCompteur);
this->fentreDessin = gcnew
}
this->fentreDessin->Show();
}
private: System::Void numericUpDownCompteur_ValueChanged(System::Object^ sender, System::EventArgs^ e) {
if (this->fentreDessin) this->fentreDessin->Invalidate();
}
public:
MesFigures::Carre* unCarre;
p
System::Windows::Forms::NumericUpDown^ compteur;
Down^ c)
Dessin(System::Windows::Forms::NumericUpDown^
{
InitializeComponent();
//
//TODO : ajoutez ici le code du constructeur
//
unCarre = new MesFigures::Carre(10,10);
compteur=c;
} // ….
Dessin.h
[email protected]
C++
297
C++
299
Introduction d’une seconde « Form »
™
C++
300
Introduction d’une 2nde « Form »
Exemple de classe Rectangle / Carre
Dessin d’un rectangle
ƒ Evènement
nt Paint
#include "rectangle.h"
namespace MesFigures{
rectangle.cpp
C++
MonRectangle::MonRectangle(MonPoint ph, MonPoint pb):Figure(ph.getX(), ph.getY()), _phg(ph), _pbd(pb) {}
MonRectangle::MonRectangle(int xh, int yh, int xb, int yb):Figure(xh, yh), _phg(xh, yh), _pbd(xb, yb) {}
// …
// ….
Void dessiner(System::Object^
dessiner(S
private: System::Void
sender, System::Windows::Forms::PaintEventArgs^ e) {
P ^ pen = gcnew Pen(Color::Black);
Pen^
pen->Width = 1;
y = System::Drawing::Drawing2D::DashStyle::Solid;
pen->DashStyle
e->deplacer(thi
unCarre->deplacer(this,pen,(int)compteur->Value,(int)compteur->Value);
}
Graphics^ g = f->CreateGraphics();
C++ / managé
//dessin du rectangle
g->DrawRectangle(pen, _xpos, _ypos,_pbd.getX()-_phg.getX(),_pbd.getY()-_phg.getY());
}
}//namespace
namespace MesFigures{
C++
carre.h
class Carre:public MonRectangle{
public:
//constructeurs
Carre(MonPoint ph, int lg);
Carre(int xh, int yh, int lg);
};//class
}//namespace
[email protected]
Dessin.h
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
void MonRectangle::dessiner(Form^ f, Pen^ pen) const{
MesFigures::Carre* unCarre; // initialisation dans le constructeur
System::Windows::Forms::NumericUpDown^ compteur;
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
public:
C++
302
Visual C++
™
Eric Anquetil ([email protected])
Dépt. Informatique
Insa Rennes
Visual C++ est un EDI :
environnement intégré
de développement
Worspace
Version 4.2
visual C++ / MFC
Sorties
™
MFC :
Microsoft foundation Class
ƒ Bibliothèque/framework encapsulant
la programmation graphique sous Win32
Éditeur : texte / application graphique
ƒ Visual C++ assiste le développement d'application avec les MFC
[email protected]
Initiation à
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Vues : classes / fichiers / ressources
C++
303
Exemple de types de projets
™
C++
304
Exemple : une application graphique simple
™
Projets exploitant les MFC
ƒ MFC AppWizard (dll)
Création d'un application graphique
de type dialogue
ƒ création d'une librairie
dynamique
ƒ MFC AppWizard (exe) :
ƒ création d'une application
ƒ application Windows
ƒ Win32 console Application
ƒ application avec console
ƒ Win32 Dynamic-Link Library
ƒ librairie dynamique
ƒ Win32 Static Library
ƒ librairie statique
Fichiers associés à un projet …
Worspace (.dsw) : l'espace de travail
Projet (.dsp) :
un espace de travail peut
contenir plusieurs projets
Ressources (.rc) :
ressources souvent
de types objets graphiques
Class Wizard (.clw) : informations sur vos
classes pour l'EDI
Code (.cpp, .h) :
le code de votre projet
[email protected]
ƒ Win32 Application
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Application C++ / win32
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
graphique
™
C++
305
1ère étape : composants graphiques de l'IHM
™
C++
306
2ème étape : réaction à un évènement
™
Création "graphique"
Action par défaut sur un bouton : clic gauche
ƒ 2 boutons et 1 champ de saisie (Edit Box)
ƒ Définition des propriétés de base
(clic droit souris)
Identificateur du bouton
Texte associé au bouton
void CIntroductionMFCDlg::OnVersion()
Définition de la fonction
{
// TODO: Add your control notification handler code here
AfxMessageBox("Version Aout 2003");
}
Ici : Affichage d'un message
™
Résultat : exécution
[email protected]
Propriétés
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Double clic sur le bouton =
définition d'une fonction
de réaction "clic gauche"
C++
307
Utilisation du Class Wizard
C++
308
Écriture du code des méthodes
™
Ajout : fonction de réaction à un
clic sur le bouton PlusUn
Réaction au clic sur le bouton PlusUn
void CIntroductionMFCDlg::OnPlusUn() {
// TODO: Add your control notification handler code here
m_Compteur++;
UpdateData(FALSE); // mise à jour de l'affichage
™
Initialisation par défaut de la variable "m_Compteur" / l'Edit box "IDC_Compteur"
BOOL CIntroductionMFCDlg::OnInitDialog() {
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE);
// Set big icon
SetIcon(m_hIcon, FALSE);
// Set small icon
// TODO: Add extra initialization here
m_Compteur=100;
UpdateData(FALSE); // mise à jour de l'affichage
return TRUE; // return TRUE unless you set the focus to a control
}
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Association d'une variable
au champ d'édition
définition de ses propriétés
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
}
Initialisation par l'IHM de l'Edit box "IDC_Compteur"
C++
310
Création d'un fenêtre de dessin
// TODO: Add your control notification handler code here
UpdateData(TRUE); // mise à jour de la variable
}
™
Mise à jour : IHM / Variable
UpdateData(TRUE)
Variable
IHM
UpdateData(FALSE)
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
void CIntroductionMFCDlg::OnChangeCompteur() {
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
™
Création d'une CFrameWnd (cadre)
class CCadreFenetre : public CFrameWnd {
DECLARE_DYNCREATE(CCadreFenetre)
protected:
CCadreFenetre();
// protected constructor used by dynamic creation
public:
CWnd* monPere;
CCadreFenetre(CWnd* lePere); // …
CCadreFenetre::CCadreFenetre(CWnd* lePere){
Create(NULL, "Ma fenêtre",
WS_POPUP|WS_CAPTION|WS_SYSMENU,CRect(0,0,300,300),lePere);
ShowWindow(SW_SHOWNORMAL);
monPere=lePere;
}
[email protected]
C++
309
Création d'une vue (fenêtre fille du cadre)
™
C++
312
Création de la vue
class CIntroductionMFCDlg : public CDialog
{
public:
CIntroductionMFCDlg(CWnd* pParent = NULL); // standard constructor
CCadreFenetre* maFenetre; // …
Liaison cadre / vue
class CCadreFenetre : public CFrameWnd {
// …
private:
Cvue* maVue; // pointeur de liaison avec la vue
CCadreFenetre::CCadreFenetre(CWnd* lePere) {
Create(NULL, "Ma fenêtre", WS_POPUP|WS_CAPTION|WS_SYSMENU,CRect(0,0,300,300),lePere);
ShowWindow(SW_SHOWNORMAL);
monPere=lePere;
maVue=new Cvue(this); // liaison avec la vue }
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
Cvue::Cvue(CWnd* lePere){
CRect leRect;
lePere->GetClientRect(leRect);
Create(NULL, NULL, WS_CHILD, leRect,lePere,NULL);
™
ShowWindow(SW_SHOWNORMAL);
monPere = ((CCadreFenetre*)lePere)->monPere; };
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
class Cvue : public CWnd { // Construction
public:
Cvue();
Cvue(CWnd* lePere);
private:
CWnd* monPere;
™
Affichage fenêtre depuis la boîte de dialogue
void CIntroductionMFCDlg::OnVue()
{
// TODO: Add your control notification handler code here
if (maFenetre==NULL) {
maFenetre=new CCadreFenetre(this);
}
}
BOOL CIntroductionMFCDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_Compteur=100;
UpdateData(FALSE);
maFenetre=NULL; // …
void CCadreFenetre::OnClose() {
// TODO: Add your message handler code here and/or call default
((CIntroductionMFCDlg*)monPere)->maFenetre=NULL;
CFrameWnd::OnClose(); }
Réinitialisation du pointeur
à la
destruction de la fenêtre
[email protected]
C++
311
C++
313
Échange de données Fenêtre / Boîte de dialogue
Quelques Remarques ....
314
ƒ Passer par une bonne analyse des concepts associés au problème avant toute
implémentation
Rafraîchissement de la vue
ƒ Chaque classe doit représenter un concept compact et bien défini
void CIntroductionMFCDlg::OnPlusUn() {
// TODO: Add your control notification handler code here
m_Compteur++;
if (maFenetre!=NULL) { maFenetre->Invalidate();}
UpdateData(FALSE);
}
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
int x=10; int y=10;
int x2=((CIntroductionMFCDlg*)monPere)->m_Compteur;
int y2=x2;
dc.MoveTo(x,y); dc.LineTo(x+x2,y); dc.LineTo(x+x2,y+y2); dc.LineTo(x,y+y2); dc.LineTo(x,y);
// Do not call CWnd::OnPaint() for painting messages
}
ƒ utiliser les mécanismes objets simples,...
ƒ Tester et Valider de manière unitaire vos objets
ƒ faire des main() pour chaque classe
ƒ des exemples d'utilisation
ƒ Valider vos framework progressivement sur plusieurs applications
ƒ Penser aux éléments essentiels d'une classe "type"
ƒ equals, clone(),...
// en Java
ƒ constructeur par recopie, destructeur,... // en C++
[email protected]
Dessin d'un rectangle
dans la vue
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
void Cvue::OnPaint() {
ƒ éviter les objets trop gros, avec trop de méthodes,...
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ analyse et conception objet, gestion de projet de type spirale,...
Quelques Remarques ....
315
ƒ Préférer agrégation à héritage
ƒ l'agrégation est bien souvent la meilleure option pour réutiliser des concepts
ƒ limiter l'héritage (et encore plus l'héritage multiple) pour des modélisations
adaptées
ƒ penser à la notion d'interface (Java et C++): simple, puissante et utile !
ƒ Namespace, Package,...
ƒ Respecter une convention de notation pour le nommage des variables
ƒ UneClasse
uneMethode
// en Java
ƒ A la conception d'une classe penser à l'utilisateur et à la maintenance
ƒ encapsuler, protéger, commenter,...
ƒ offrir une gestion complète des erreurs: exceptions,...
ƒ Documenter vos programmes, concepts, analyses
ƒ Doc++, javadoc,...
[email protected]
,QVWLWXWQDWLRQDOGHVVFLHQFHVDSSOLTX«HV
ƒ Exploiter les espaces de nommage pour éviter les conflits
Index
A
abstract
abstraction
affectation
agrégation
allocation
anonyme
Applet
attachement
dynamique
statique
autoboxing
auto-références
247, 248
5, 7, 10, 78, 88, 289
66, 67, 73
7, 12, 13, 21, 77, 78, 79, 80, 84, 88, 110, 192, 194, 315
61, 65
73, 283, 286, 287
248, 250
92, 94
94
92, 94
268, 269
51
contrôle d’accès
conversion implicite
copie en profondeur
copie superficielle
82, 83
22, 54, 55, 57
69, 71, 98, 274, 275, 276
98, 281
D
définition externe étendue
design pattern
destructeur
virtuel
Document / Vue
dynamic Cast
dynamique
55
215
62, 64, 65, 67, 71, 72, 73, 97, 213, 314
97, 110
237, 238, 239, 240
186
41, 43, 60, 61, 77, 93, 94, 103, 134, 249, 256, 280, 303
C
Canvas
250, 252
catch
199, 201, 206, 208, 211, 213
Classe
abstraite
96, 116
interne
58, 282, 283, 284, 285, 286, 287
paramétrées
118
clonage
59, 72, 98, 281
clone
72, 247, 276, 277, 278, 279, 280, 281, 314
collection
8, 92, 95, 136, 270
comparaison
187, 191, 192, 193, 194, 195
compilation
28, 65, 121, 207, 290
constante
27, 50, 67, 271
constructeur 20, 21, 22, 25, 54, 59, 60, 64, 65, 68, 69, 70, 71, 72, 73, 84, 110, 120,
124, 139, 162, 164, 175, 184, 202, 213, 229, 276, 314
recopie
68, 70, 73
conteneur
118, 136, 137
E
Eclipse
268
égalité
187, 188, 189, 190
encapsulation
3, 8, 19, 245
equals
188, 189, 190, 192, 194, 314
évènement
306
exception184, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 213,
214, 260, 278
F
fichier
file
final
finalize
30, 31, 37, 76, 148, 158, 160, 163, 198, 258, 259, 289
139
112
76
finally
212
flot
32, 148, 149, 150, 151, 152, 153, 154, 155, 160, 162
fonctions virtuelles
93
for 92, 249, 270, 281
framework 214, 236, 237, 244, 245, 246, 247, 248, 249, 250, 252, 253, 255, 256,
289, 290, 302, 314
friend
56, 57
G
garbage collector
generic
75, 290
128, 131
H
héritage
7, 10, 11, 13, 77, 78, 81, 84, 88, 104, 105, 106, 107, 108, 110, 112, 115,
129, 191, 194, 206, 280, 315
multiple
104, 105, 107, 108
14, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265
164, 260, 268
L
length
List
liste
249
41, 56, 62, 64, 65, 66, 67, 68, 69, 70, 71, 73, 127, 134
41, 63, 118, 127, 129, 131, 134, 138, 214, 216, 217, 248
M
main
managé
map
masquage
mémoire
MFC
23, 30, 32, 33, 76, 201, 204, 211, 260, 289, 314
289, 290
140, 142
8, 85, 181, 182
22, 41, 59, 60, 61, 64, 67, 71, 74, 75, 76, 103, 134, 213, 217, 277
237, 238, 239, 289, 301, 302, 303
N
I
IDE
289
implements
247
inline
28, 30, 123
inner class
283
instanceof
194, 249
interface3, 8, 19, 27, 28, 104, 105, 111, 112, 113, 114, 115, 116, 119, 161, 167, 245,
250, 254, 255, 277, 278, 281, 287, 289, 315
iterateur
136, 137
J
java
JNI
JVM
7, 103, 148, 157, 161, 209, 260, 265, 268
Namespace
Native
nested class
new
315
254, 255
58
60, 61, 64, 65, 68, 69, 72, 91, 92, 106, 120, 121, 207, 211, 241, 275
O
opérateur 32, 36, 38, 41, 42, 43, 44, 53, 55, 57, 61, 67, 72, 73, 124, 134, 135, 137,
138, 139, 140, 143, 188, 189, 190
operator
53, 54, 55, 57, 66, 67, 70, 71, 143, 144, 145
P
Package
pile
pointeur
polymorphisme
Printf
private
privé
protected
315
4, 5, 6, 46, 61, 67, 139, 198, 213
17, 45, 51, 61, 65, 72, 91, 103, 204, 232
11, 89, 90, 91, 92, 221
157
19, 56, 62, 71, 73, 83, 89, 119, 172, 176, 247, 284, 285
79, 82, 124
79, 80, 82, 83, 96, 284
Q
queue
118, 119, 120, 139, 216
R
ramasse-miettes
recopie
redéfinition
référence
RTTI
Stream
String
StringStream
surcharge
32, 37, 147, 148, 149, 150, 151, 152, 153
36, 129, 188, 211, 248, 249, 261, 290
37
22, 23, 53, 57, 67, 85, 123, 181, 182, 188, 189, 277
T
tableaux
terminate
throw
Throwable
try 199, 201, 206, 208, 211
type_info
typeid
types primitifs
22, 41, 42, 134, 135, 265
201, 204
199, 201, 202, 203, 207, 208, 211, 213
207, 208, 210
185
185
269, 277
U
76
47, 131, 281
69, 72, 85, 175, 181, 182, 188, 190, 241, 248
45, 46, 48, 50, 51, 52, 67, 75, 96, 103, 108, 164, 290
183, 184, 185, 186, 249
S
scanner
156, 158
sécurité
167, 170
sérialisation 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172,
173, 174, 175, 176, 177, 178, 179
set
80, 84, 121, 124, 140, 141, 204
stack
139
statique 24, 25, 26, 58, 60, 77, 79, 89, 90, 91, 94, 112, 176, 177, 178, 179, 184, 211,
265, 268, 273, 303
STL
39, 40, 132, 133, 136, 137, 144
UML
13, 79
V
Vector
22, 29, 41, 42, 43, 46, 80, 92, 98, 118, 134, 135, 136, 139, 145, 249, 281
Visual C++
302
W
Wildcards
Windows forms
Wizard
130, 131
288, 289
307