Programmation orientée objet C++ et java - irisa.fr+_V5.pdf · programmation orientée objets en...
Transcript of Programmation orientée objet C++ et java - irisa.fr+_V5.pdf · programmation orientée objets en...
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Notes de cours sur la programmation orientée objets en C++ et Java
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
CHAP. 1 : Préambule
Vers la programmation objet 9
Programmation modulaire (encapsulation) C→C++ 10
Abstraction de données C→C++ 11
Abstraction de données / généricité … C→C++ 12
Introduction à la programmation orientée objet 13
Concepts objets : la notion d’objet 14
Concepts objets : la notion de classe 15
Généricité : Héritage 16
Généricité : Héritage et Polymorphisme 17
Agrégation 18
L'approche objet 19
Les langages C++ et Java 20
CHAP. 2 : Introduction : Objet et Classe
Les classes - définition 22
Les classes - définition d’une méthode 23
Les classes - instanciation 24
Encapsulation 25
Constructeurs - Déclaration 26
Constructeurs - Définition 27
Constructeurs - Surcharge 28
Surcharge de fonction 29
Arguments par défaut 30
Membre static 31
Variable static 32
Fonction membre constante 33
Fonction inline 34
CHAP. 3 : Ecrire son premier programme
Structure générale d’un programme 36
Fichier d'en-tête - Commentaires 37
Entrées - sorties (Streams ou flots) 38
Entrées - sorties fichiers 39
Un 1er petit programme : la classe Date 40
Un 1er petit programme : utilisation 41
Classe string 42
Classe stringstream 43
Espace de nommage (définition / accès) 44
Espace de nommage (alias) 45
Préambule sur la STL … suite dans le chap. STL 46
Les conteneurs élémentaires 47
Les Vecteurs (vector) : préambule 48
Les Vecteurs (vector) : préambule 49
CHAP. 4 : Références, pointeurs, opérateurs, classes internes
Références et Pointeurs 51
Passage par référence 52
Passage par valeur / Recopie ( ) 53
Passage par référence / Pas de recopie 54
Retour par valeur ( recopie ) 55
Passage et Retour par référence 56
Auto-références 57
Passage par référence et Auto-référence 58
Surcharge d’opérateurs conventionnels 59
Conversion implicite 60
Définition externe étendue 61
Notion d’ami : Friend 62
Surcharge d’opérateurs et notion de Friend 63
Classe interne : "nested class" 64
CHAP. 5 : Mémoire: allocation, clonage, constructeur
Zones mémoires 66
Allocation dynamique et libération 67
Notion de destructeur : ~X( ) 68
Une 1ère amorce de programmation de liste 69
eric.a
nq
uetil@
iris
a.f
r
2
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
Mise en œuvre du destructeur 70
Allocation de n éléments 71
Opérateur d’ Affectation ( operator = ) 72
Affectation en profondeur 73
Constructeur par recopie 74
Implémentation d’un constructeur par recopie 75
Une implémentation homogène 76
Une implémentation homogène 77
Remarques et notion de clonage 78
Bilan : Affectation et Constructeur par recopie 79
CHAP. 6 : Java : Mémoire (Rappels)
Le ramasse miette ou « garbage collector » 81
La méthode finalize() 82
CHAP. 7 : Aggrégation, héritage, polymorphisme, classe
abstraite
Abstraction - Généricité 84
Agrégation : classe Point / Rectangle 85
Agrégation : exemple de Base 86
Héritage : exemple de Base 87
Contrôle d’accès : privé, publique, protected 88
Contrôle d’accès à la classe de base 89
Constructeurs : agrégation et héritage 90
Redéfinition <> Surcharge 91
Relation entre classe de base et classe dérivée 92
Relation entre classe de base et classe dérivée 93
Résumé : héritage, agrégation, … 94
Polymorphisme : conversion entre objets 95
Polymorphisme : conversion entre objets 96
Polymorphisme : conversion entre pointeurs 97
Polymorphisme : conversion entre pointeurs 98
Fonctions virtuelles 99
Attachement statique et dynamique 100
Collection hétérogène d’objets 101
Classe abstraite 102
Destructeur virtuel 103
Copie en profondeur & clonage 104
Exemple possible de définition de figure : Figure.h 105
Figure.cpp 106
Figure_exe.cpp && résultats 107
CHAP. 8 : Héritage multiple
Héritage multiple C++ et Interface JAVA 109
Cas simple d’héritage multiple en C++ 110
Héritage multiple : classe de base dupliquée 111
Héritage multiple : partage de classe de Base 112
Résolution des ambiguïtés 113
Utilisation de l’héritage multiple ? 114
CHAP. 9 : Java : Interface
Interface Java 116
Exemple d'utilisation d'interface 117
Exemple d'interface : diagramme de classe 118
NB : Interface et héritage 119
Interface Versus Classe abstraite 120
CHAP. 10 : Exceptions
Notion d'erreur 122
Traitement des cas d'erreurs exceptionnelles 123
Exemple général sur le mécanisme d'exception 124
Le principe 125
Protocole C++ : émission d'exceptions 126
Protocole C++ : spécification d'exceptions 127
Protocole C++ : fonction terminate 128
Exceptions standards en C++ 129
Capture et traitement d'exceptions 130
Protocole Java : lancement d'exceptions 131
eric.a
nq
uetil@
iris
a.f
r
3
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
Retransmission d’une exception 132
Exception standard en Java 133
Protocole Java : Java.lang.Throwable 134
Créer vos propres classes d'exceptions 135
Protocole Java : bloc finally 136
Remarques sur la gestion mémoire 137
Bilan sur les exceptions 138
CHAP. 11 : Template
Introduction : classes paramétrées 140
Mise en œuvre de classe template (interface .h) 141
Mise en œuvre de classe template (f. membres) 142
Template multi-type (paramétrage /type ou /valeur) 143
Paramètre template par défaut 144
Fonction template et Spécialisation 145
Précautions avec «l'instanciation» 146
CHAP. 12 : Java : Generics
Introduction 148
Définition de “generics” 149
Définition de “generics” 150
Héritage 151
Wildcards et Bounded Wildcards 152
Generic 153
CHAP. 13 : STL : Introduction
Introduction à la STL 155
Les conteneurs élementaires 156
Les Vecteurs 157
Notion d‘itérateur 158
Recherche - Insertion - Suppression 159
Les listes 160
Les files (queue) et piles (stack) 161
Conteneurs associatifs : set, map, 162
Les ensembles (set) 163
Les tables d’associations (map) 164
CHAP. 14 : Objet foncteur
Les Objets fonction / operator() 166
Les Objets fonction / operator() / fonction trier (sort) 167
CHAP. 15 : Java : Flots (Stream)
Les flots(stream) en Java : java.io.* 169
flots d'octets (8 bits) 170
flots de char (16 bits) 171
flots de char avec tampon 172
flots de données avec tampon 173
flots de données avec tampon 174
Les flots basiques : orientés byte (octet) 175
Les flots avancés : orientés char (Unicode) 176
CHAP. 16 : Java : Scanner
Printf : Sortie standard formatée 178
le scanner : entrée formatée 179
CHAP. 17 : Java : Sérialisation
introduction 181
mise en œuvre automatique 182
mise en œuvre automatique 183
un 1er exemple 184
Sérialisation avec Serializable 185
un 2ème exemple 186
un 2ème exemple 187
mise en œuvre manuelle 188
Sérialisation : manuelle / Exemple 189
Sérialisation : manuelle / exemple 190
Sérialisation : partiellement manuelle / transient 191
Sérialisation : partiellement manuelle / transient 192
Sérialisation : partiellement manuelle / Serializable 193
eric.a
nq
uetil@
iris
a.f
r
4
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
Sérialisation : partiellement manuelle / Serializable 194
Sérialisation : manuelle / exemple 195
un premier Bilan 196
Sérialisation : les données statiques 197
Sérialisation : les données statiques / exemple 198
Sérialisation : les données statiques / exemple 199
Sérialisation : les données statiques / exemple 200
CHAP. 18 : Java : Masquage
Redéfinition et surcharge 202
Redéfinition et surcharge 203
CHAP. 19 : RTTI : Run Time Type Identification
RTTI et Java : getClass / getName / forName / newInstance 205
RTTI et C++ : type_info / typeid 206
RTTI et C++ : dynamic Cast 207
CHAP. 20 : Java : Egalité & Comparaison d'objet
Égalité d'objets 209
Égalité d'objets (surcharge de equals) 210
Égalité d'objets (redéfinition de equals) 211
Comparaison d'instances et héritage 212
Comparaison rigide : méthode equals() 213
Comparaison rigide 214
Comparaison souple : méthode comparable() 215
Comparaison : exemple de diagramme de classe 216
Exemple de comparaisons souples et rigides 217
CHAP. 21 : Interopérabilité : dll & .net
Deux mots sur .net et C++ managé 219
Introduction à l’interopérabilité 220
Mixer du C/C++ avec le C++/CLI au niveau des sources 221
DLL C++ : Dynamic Link Library 222
DLL C++ : Commandes de pré-compilation 223
Wrapper C++/CLI 224
Création de la classe Wrapper en C++ managé 225
Utilisation de la classe Wrapper en C++ managé pure 226
Utilisation de la classe Wrapper en C# 227
Récapitulatif 228
Notion sur le Marshalling (conversion de type) 229
Outils pour automatiser la création du Wrapper (SWIG) 230
Test de la DLL C++ : Classes Coordonnée et Tir 231
Swig : Configuration 232
Swig: Génération & Tests 233
CHAP. 22 : WPF : Introduction
Présentation de Wpf (Windows Presentation Foundation) 235
WPF : code behind / code designer 236
XAML (eXtensible Application Markup Language) 237
Visual Studio : 1ère application wpf / Xaml 238
Visual Studio : Xaml/c# - Réalisation d'une action 239
WPF : Disposition des contrôles WPF dans une fenêtre 240
WPF: le contrôle Canvas / un petit exemple 241
WPF: un petit exemple 242
WPF: liaison avec une Dll C++ 243
WPF: une 1ère idée sur le data binding 244
Aperçu des événements routés 245
Routage d'événements 246
Visual Studio : Solution complète (cf. code) 247
CHAP. 23 : Notion de framework : ex. MFC
Concept de « framework » 249
Concept de « framework » 250
2 mots sur l'Architecture Document / Vue des MFC 251
Exemple de Modèle Document / Vue 252
Les interdépendances 253
La notion de document 254
La notion de vue 255
eric.a
nq
uetil@
iris
a.f
r
5
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
CHAP. 24 : Java : Conception d'un framework
Exemple de conception d’un Framework complet 257
Méthodologie : organisation des classes 258
Abstraction / Utilisation des concepts génériques 259
Prise en compte des types utilisateurs 260
Typage dynamique (RTTI) 261
Framework : notion d'interface graphique 262
Diagramme de classe / exemple 263
Autonomie du framework et notion de Canvas 264
Bilan sur la notion de Framework 265
CHAP. 25 : Design Pattern Commande : undo
Rappels des objectifs du modèle « commande » 267
Mise en œuvre du undo/redo 268
Manipulation de « figures » : undo/redo 269
Manipulation de figures : undo/redo 270
Mise en œuvre du modèle « commande » / undo 271
Mise en œuvre du modèle « commande » / undo 272
Mise en œuvre du modèle « commande » / undo 273
Mise en œuvre du modèle « commande » / undo 274
Mise en œuvre du modèle « commande » / undo 275
Retour sur le modèle « commande » / undo 276
Modèle « commande » / gestion de commandes simples 277
CHAP. 26 : Design Pattern Memento : Undo
Description du Modèle “Memento” 279
Exemple : Undo pour la manipulation d’objets de type A 280
La classe Memento - MementoA 281
La classe Auteur – classe A 282
Le Surveillant - CommandA 283
Le Surveillant – CommandA / Code 284
Utilisation /Test 285
CHAP. 27 : Interfaçage avec la JNI : C++/Java
JNI : Java Native Interface 287
JNI : les possibilités d'interfaçage 288
JNI : Les différentes étapes de l'interfaçage 289
JNI : Les différentes étapes de l'interfaçage 290
JNI : Les différentes étapes de l'interfaçage 291
JNI : Les différentes étapes de l'interfaçage 292
JNI : envoie de String 293
JNI : accès aux attributs d'une classe 294
JNI : accès aux attributs d'une classe / objet 295
JNI : invocation d'une méthode Java 296
JNI : fonctionnalités avancées 297
CHAP. 28 : Annexe Java : Java 5 ...
Un petit bilan : le modèle objet en JAVA / C++ 299
Introduction : Java5 (Tiger) 300
Autoboxing et Auto-Unboxing des types primitifs 301
Itérations sur des collections : nouvelle boucle for 302
Type énuméré : enum 303
Nombre d’arguments variable pour une méthode 304
Les imports statiques 305
CHAP. 29 : Annexe Java : Clonage
Notion de copie en profondeur 307
Notion de copie en profondeur 308
La méthode clone( ) de la classe Object 309
Mise en œuvre de la méthode clone() 310
Mise en œuvre de la méthode clone() 311
Clonage et héritage 312
Remarques sur le clonage en Java 313
CHAP. 30 : Annexe Java : Classe Interne
Classe interne : inner class 315
Classe interne : membre d'une classe 316
Classe interne : locale 317
eric.a
nq
uetil@
iris
a.f
r
6
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Sommaire
Classe interne : anonyme 318
Classe interne : anonyme 319
CHAP. 31 : Windows Forms : Introduction
Les Windows forms 321
Deux mots sur .net et C++ managé 322
Une application WinForms : présentation 323
Une application WinForms : le projet 324
Une application WinForms : EDI et Design 325
Une application WinForms : Ajout de contrôles 326
Une application WinForms : Le code généré 327
Une application WinForms : Le code généré 328
Réactions aux évènements 329
Introduction d’une seconde « Form » 330
Introduction d’une seconde « Form » 331
Exemple de classe Rectangle / Carre 332
CHAP. 32 : MFC : Introduction
Visual C++ 334
Exemple de types de projets 335
Exemple : une application graphique simple 336
1ère étape : composants graphiques de l'IHM 337
2ème étape : réaction à un évènement 338
Utilisation du Class Wizard 339
Écriture du code des méthodes 340
Initialisation par l'IHM de l'Edit box "IDC_Compteur" 341
Création d'un fenêtre de dessin 342
Création d'une vue (fenêtre fille du cadre) 343
Affichage fenêtre depuis la boîte de dialogue 344
Échange de données Fenêtre / Boîte de dialogue 345
CHAP. 33 : Remarques
Quelques Remarques .... 347
Quelques Remarques .... 348
eric.a
nq
uetil@
iris
a.f
r
7
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 1 Préambule
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Vers la programmation objet
La programmation fonctionnelle ou procédurale
« l’accent est mis sur l’exécution du programme »
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
Découpage fonctionnel permettant de factoriser certains comportements
Mais maintenance complexe en cas d'évolution
Fonctions interdépendantes …
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
eric.a
nq
uetil@
iris
a.f
r
9
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Programmation modulaire (encapsulation) C→C++
Exemple C :
gestion d'une pile de car
Utilisation du module "Pile"
// 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();
...
// Module TOTO
// utilisation de la pile de caractères
#include "pile.h"
empiler (‘a’); ...
// Pile.c
// implémentation de la pile de caractères
void empiler(char c) {…}
char depiler() {…}
...
eric.a
nq
uetil@
iris
a.f
r
10
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Abstraction de données C→C++
Vers l’abstraction de données
« pour manipuler plusieurs piles =>abstraire la notion de pile comme un nouveau type utilisateur. »
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…
// Utilisation de la pile
#include "pile.h"
type_pile p1;
p1=créer_pile() ;
empiler(&p1, ’a ’) ;
// ...
// 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*);
// ...
eric.a
nq
uetil@
iris
a.f
r
11
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Abstraction de données / généricité … C→C++
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...
On a besoin « d’aide »
pour consolider ce type
de programmation
langage objet (C→C++)
Bilan (C→C++)
Centraliser (données et
traitements) associés à
un type
… Besoin de la notion
d'objets,
de classes,
de polymorphisme…
// 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};
// traitement conditionné par le type …
void afficher_pile(type_pile P)
{
switch (P.type) {
// traitement en fonction du type ….
}
}
eric.a
nq
uetil@
iris
a.f
r
12
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Introduction à la programmation orientée objet
La programmation orientée objet est axée
1/ sur les données / encapsulées autour d’un concept appelé : « objet »
2/ sur les traitements qui y sont associés.
La complexité des programmes est alors répartie sur chaque « objet ».
Les langages objets (C++, java, ...) facilitent
grandement cette approche de programmation.
Le modèle objet est utilisable aussi bien pour
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
Principes de base
abstraction, encapsulation, héritage, polymorphisme, agrégation
eric.a
nq
uetil@
iris
a.f
r
13
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
livreNo1 : Livre
titre = "le langage C++"
auteur = "Stroustrup"
nbPage = 1096
emprunter()
rendre()
Chap. 1 | Concepts objets : la notion d’objet
Les objets / Encapsulation
Un objet est constitué
d’une collection d’attributs (définissant l’état de l’objet)
et de méthodes associées
(définissant son comportement)
Modularité et masquage de l’information
les méthodes constituent l’interface
de communication
la manipulation d’un objet peut s’opérer
indépendamment de sa mise en œuvre
(structure interne)
Les attributs sont « encapsulés » dans l’objet et
par conséquent protégeables contre des accès
non autorisés
Attributs
attributs
méthodes
nom de l'objet type de l'objet
eric.a
nq
uetil@
iris
a.f
r
14
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Concepts objets : la notion de classe
Les classes / Abstraction de données :
« 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. »
Un objet est l’instance d’une classe
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()
eric.a
nq
uetil@
iris
a.f
r
15
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Généricité : Héritage
Notion d’héritage
« On peut raffiner la notion
d’abstraction de données en
utilisant la notion 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
Spécialisation
relation
d'héritage
eric.a
nq
uetil@
iris
a.f
r
16
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Généricité : Héritage et Polymorphisme
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.
For (int i=0; i<nbOeuvre; i++) {
Stock[i].restaurer();
}
Notes sur
la classe
+restaurer(): void
en Java
eric.a
nq
uetil@
iris
a.f
r
17
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Agrégation
Notion de relation entre
2 classes spécifiant que
les objets d'une classe
sont les composants
de l'autre.
Une bibliothèque est
composée d'un ensemble
d'œuvres
agrégation multiplicité
eric.a
nq
uetil@
iris
a.f
r
18
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | L'approche objet
Bilan
Les concepts fondateurs sont
La notion d'objet et de classe
L'encapsulation
L'héritage
L'agrégation
+ d'autres mécanismes avancés pour la généricité, ....
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)
eric.a
nq
uetil@
iris
a.f
r
19
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 1 | Les langages C++ et Java
C++
Extension du langage C
Développé chez Bell Laboratory (ATT) par Bjarne Stroustrup en 1983
A conquis les marchés des langages orientés objet
++ Langage très performant
- - Mais syntaxe assez difficile
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…)
eric.a
nq
uetil@
iris
a.f
r
20
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 2 Introduction : Objet et Classe
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Données membres
Fonctions
membres
La notion de classe
liée à la notion de définition de type
représentation concrète d’un concept
Définition (.h) : class X { … };
class Date {
int _j, _m, _a ;
public: void init (int j, int m, int a) ; // initialisation
int jour ( ) ; // fonctions d’accès
int mois ( ) ;
int annee () ;
void plus_jours (int n) ; // additionne n jours };
Chap. 2 | Les classes - définition
• 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
Date
int _j
int _m
int _a
Void init (int j, int m, int a) int jour ( ) int mois ( ) int annee () void plus_jours (int n)
.h
eric.a
nq
uetil@
iris
a.f
r
22
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Les classes - définition d’une méthode
Définition des fonctions membres
Définition en dehors de la classe (.cpp)
Une fonction membre connaît toujours l’objet qui l’a invoqué
« l ’accès à l’objet appelant est implicite dans une méthode »
void Date::init(int j, int m, int a) { aujourdhui.init (10,08,1998);
_j = j ; _m = m ; _a = a ; }
On a un accès explicite à l’objet appelant à travers le pointeur this :
void Date::init(int j, int m, int a) {
this -> _j = j ; // idem que (*this)._j = j; this -> _m = m ; this -> _a = a ; }
*structure d’un programme
argument implicite
arguments explicites
:: portée d’une méthode
.cpp
.cpp
.cpp
eric.a
nq
uetil@
iris
a.f
r
23
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Les classes - instanciation
Un objet est une instance d’une classe :
« variable dont le type correspond à la classe »
Date aujourdhui;
Date demain;
Accès 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 »
aujourdhui.init(10,08,1998);
demain=aujourdhui;
demain.plus_jours(1);
*constructeur
*affectation
aujourdhui
_a = 1998 _j = 10 _m =08
annee() init() jour() mois() plus_jours()
Classe Identificateur (nom de l ’objet)
.cpp
.cpp
eric.a
nq
uetil@
iris
a.f
r
24
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Encapsulation
Encapsulation et contrôle d’accès
les (fonctions) membres "public" = interface utilisateur
permet la manipulation des objets de la classe
les (données) membres "private" = représentation interne des objets
garantit une protection aujourdhui. _a ; // accès interdit
permet une vérification de validité 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
définition de la classe (.h)
déclaration des méthodes (.cpp)
*structure d’un programme
*héritage et
membres protégés
.cpp
eric.a
nq
uetil@
iris
a.f
r
25
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Constructeurs - Déclaration
« Un constructeur est une fonction membre spéciale invoquée
automatiquement à chaque création d’un objet »
Constructeur par défaut
si aucun constructeur n’a été défini, la classe possède un constructeur par défaut sans paramètre
Date aujourdhui; // construction d’un objet date (aujourdhui)
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
class Date {
// ... Idem code précédent
Date (int, int, int);
};
Date aujourdhui=Date(10,08,1998); // ok, initialisation constructeur
Date hier(9,08,1998); // ok, idem
Date demain; // erreur ! Plus de constructeur // correspondant
.h
.cpp
.cpp
eric.a
nq
uetil@
iris
a.f
r
26
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Constructeurs - Définition
Définition d’un constructeur
Les constructeurs ne retournent jamais de valeur :
leur rôle est d’initialiser un objet.
structure basique
1/ construction de l’objet
2/ affectation des champs
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…
Date::Date (int j, int m, int a): _j(j), _m(m), _a(a)
{ }
.cpp
.cpp
eric.a
nq
uetil@
iris
a.f
r
27
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Constructeurs - Surcharge
Une classe peut posséder plusieurs constructeurs
class Date { // ...
Date (int j, int m, int a);
Date (int j, string m, int a);
Date (string s); // 1 seul argument :: Conversion implicite
Date (); // constructeur par défaut redéfini };
Surcharge 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.
Date d(01,01,2000); // constructeur Date (int j, int m, int a)
Date d2( "1 janvier 2000" ); // constructeur Date (string s)
Date d3; // constructeur par défaut Date( )
vector<Date> tab_d(10); // invocation 10 fois du
// constructeur par défaut Date()
* STL
Surcharge de fonction
.cpp
.h
eric.a
nq
uetil@
iris
a.f
r
28
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Surcharge de fonction
Toute fonction peut être surchargée
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 »
L’analyse de la signature détermine la fonction à utiliser
float max (float a, float b) { float max (float a, float b, float c) {
return (a>b) ? a : b ; 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
* surcharge d ’opérateur
eric.a
nq
uetil@
iris
a.f
r
29
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Arguments par défaut
Arguments par défaut
Soulage le nombre de fonctions surchargées
Ex : les arguments non fournis correspondent à la date par défaut jourd
(qui sera définie comme membre statique de la classe, cf. transp. suivant)
Date d(10,08); <=> Date d(10,08,0); <=> Date d(10,08,Date::jourd._a);
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 ;
}
class Date {
// …
Date( int j=jourd._j, int m=jourd._m, int a=jourd._a);
};
Date::Date (int j, int m, int a) {
_j = j ; _m = m ; _a = a ;
}
Autre solution
.cpp
.cpp
.h
.h
eric.a
nq
uetil@
iris
a.f
r
30
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Membre static
Membre static d’une classe / Attribut de classe
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
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
};
Utilisation d’un membre static (classe::membre_static)
Date Date::jourd(1,1,2000); // définition explicite obligatoire de jourd (à mettre dans date.cpp)
Date::init_jourd(1,2,2000); // ré-initialisation de jourd possible
Date d ; // constructeur par défaut
// d a été initialisée à la date 01-02-2000
Date::hier
_a= 2000 _j = 3 _m= 11
Date::demain
_a= 2000 _j = 4 _m = 11
Date::jourd
_a= 2000 _j = 1 _m = 1
Date _a _j _m jourd
.h
.cpp
eric.a
nq
uetil@
iris
a.f
r
31
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Variable static
Variable static locale à une fonction
une variable déclarée static dans une fonction est une variable persistante
void f( ) {
static int compteur = 0 ; // variable static (persistante)
int n ; // variable locale
…
compteur++ ;
}
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
eric.a
nq
uetil@
iris
a.f
r
32
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Fonction membre constante
Bien différentier les fonctions d’accès et les fonctions de mutation
class Date {
public:
int jour( ) const ; // l’objet (argument implicite) reste inchangé
void plus_jours(int n) ; // changement possible de l’objet
// ... }; int Date::jour( ) const { return _j ; }
La définition const : objet associé non modifiable
permet la vérification du compilateur et clarifie l’interface utilisateur
class Date {
public:
Date add_jours(int n) const; // l’objet appelant reste inchangé
// ... // rend (date + n jours) }
Date b = a.add_jours(30); // b=a+30, a est inchangé
.cpp
.cpp
.h
.h
eric.a
nq
uetil@
iris
a.f
r
33
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 2 | Fonction inline
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)
.h
eric.a
nq
uetil@
iris
a.f
r
34
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 3 Ecrire son premier programme
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Structure générale d’un programme
Un module est composé de 2 fichiers (.h et .cpp)
Fichier d'en-tête : Module.h
Définition des classes
Déclaration des types synonymes (typedef)
Déclaration des variables globales
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
Le programme principal
Fichier source : Programme.cpp
Inclut les modules dont il a besoin
Contient la fonction main(...) :
int main(int argc, char* argv[]) { ... };
// Module.h
#ifndef module_h
#define module_h
...
#endif
// Module.cpp
#include "module.h"
...
// Programme.cpp
#include "module.h"
int main (int argc, char* argv[])
{ ... };
.h
.cpp
.cpp
eric.a
nq
uetil@
iris
a.f
r
36
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Fichier d'en-tête - Commentaires
Fichiers d'en-tête
Directive de précompilation : #include
inclusion de définition de type, de constantes prédéfinies, de procédures, …
Conventions
#include <string> // inclusion des fichiers d'en-tête système Ansi C++
#include <cstring> // inclusion des fichiers d'en-tête système Ansi C
#include <string.h> // idem mais ancienne notation
#include "Date.h" // inclusion de fichier d'en-tête local
Commentaires
// commentaire ligne
/* commentaires multi-lignes */
#if 0 // directive de précompilation pour masquer cette partie de code malgré
// la présence de commentaires imbriqués
#endif
* documentation automatique
doc++, doxygen, JavaDoc, …
eric.a
nq
uetil@
iris
a.f
r
37
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Entrées - sorties (Streams ou flots)
Les entrées/sorties sont gérées en C++ par des flots(stream)
2 opérateurs binaires (stream x expression -> stream) prédéfinis :
opérateur d’écriture dans un flot : <<
opérateur de lecture dans un flot : >>
Flots d’entrées / sorties standards : iostream
cin (entrée standard)
cout (sortie standard)
cerr (sortie erreur standard)
#include <iostream>
main() {
int nb;
cout << " Un nombre entier : " ;
cin >> nb;
cout << "Nombre à afficher : " << nb << endl ; }
.cpp
eric.a
nq
uetil@
iris
a.f
r
38
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Entrées - sorties fichiers
Flots d ’entrées / sorties fichiers : fstream
ifstream, ofstream
#include <fstream>
main () {
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 ;
}
}
.cpp
eric.a
nq
uetil@
iris
a.f
r
39
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Un 1er petit programme : la classe Date
#ifndef DATE_H #define 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
Date.h #include "date.h" #include <iostream.h> #include <assert.h> 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; };
Date.cpp
eric.a
nq
uetil@
iris
a.f
r
40
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Un 1er petit programme : utilisation
#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;
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;
}
Test.cpp
date par defaut d = 1 1 2000
Usage: Test.exe mois annee
initialisation par defaut
date d initialisee = 1 1 2000
Exécution de Test.exe
sans paramètre
date par defaut d = 1 1 2000
initialisation avec mois = 8 et annee = 2002
date d initialisee = 1 8 2002
Exécution de Test.exe 8 2002
eric.a
nq
uetil@
iris
a.f
r
41
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Classe string
La classe string (C++ ANSI / Librairie standard du C++)
manipulation sécurisée des strings
#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 ’
Chap. STL
eric.a
nq
uetil@
iris
a.f
r
42
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Classe stringstream
La classe stringstream
Ecriture et lecture formatées dans une « string » de type « stream »
Manipulation des caractères dans une string comme dans un fichier.
#include <sstream>
Date anniv ;
ostringstream te ;
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 ;
eric.a
nq
uetil@
iris
a.f
r
43
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Espace de nommage (définition / accès)
Un espace de nommage en C++
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
{
class Classe1 { };
class Classe2 { };
namespace C{
class Classe3 { };
}
}
namespace B
{
class Classe3 { };
}
class Classe2 { };
int main(int,char**){
Classe2 e1; // ok
A::Classe1 e2; // ok, accès en préfixant le nom
B::Classe3 e3; // ok, accès en préfixant le nom
using namespace A; // accès à tout l’espace de nommage A
Classe1 e4; // ok
using namespace A::C; // accès en + à tout l’espace de nommage A::C
Classe3 e5; // ok
using namespace B; // accès en + à tout l’espace de nommage B
Classe3 e6; // erreur compilation : ambiguité entre // B::Classe3 et A::C::Classe3
A::C::Classe3 e7; // ok, accès en préfixant le nom
using A::C::Classe3; // permet de masquer B::Classe3
Classe3 e8; // ok
}
eric.a
nq
uetil@
iris
a.f
r
44
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Espace de nommage (alias)
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;
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>
namespace nomA
{
class Classe1 { };
class Classe2 { };
namespace nomC{
class Classe3 { };
}
}
namespace nomB
{
class Classe3 { };
}
class Classe2 { };
int main(int,char**){
namespace A=nomA; // définition d’un alias
A::Classe1 e4; // ok
namespace AC=nomA::nomC; // définition d’un alias
AC::Classe3 e5; // ok
}
CF. chap. STL
eric.a
nq
uetil@
iris
a.f
r
45
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Préambule sur la STL … suite dans le chap. STL
La librairie standard du C++ intègre
Des classes conteneurs et leur algorithmes associés
La gestion des string et des flux (iostream)
Intérêt de la librairie standard du C++ (STL)
Standardisation
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
eric.a
nq
uetil@
iris
a.f
r
46
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Les conteneurs élémentaires
Vector
Tableaux du C++ avec possibilité d’allocation dynamique
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)
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
eric.a
nq
uetil@
iris
a.f
r
47
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Les Vecteurs (vector) : préambule
Introduction
équivalent des Vector ou ArrayList de Java
tableaux pouvant croître dynamiquement.
Utilisation Basique
size() :Taille du vecteur
l’opérateur crochets [ ] : Accès/modification du vecteur
push_back : ajoute un élément en fin de vecteur.
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>
#include <string>
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;
}
La taille du vecteur est de 9
La taille du vecteur est de 0
eric.a
nq
uetil@
iris
a.f
r
48
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 3 | Les Vecteurs (vector) : préambule
Exemple 2 sur la classe Vector (tableau dynamique)
Déclaration
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);
Quelques opérateurs
tab1.push_back(1.2) ; // 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
* classe paramétrée (template)
* iterator
eric.a
nq
uetil@
iris
a.f
r
49
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 4 Références, pointeurs, opérateurs, classes internes
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Références et Pointeurs
Référence = nom alternatif à un objet existant
int i = 1;
int& r = i ; // r et i font référence au même objet
r = 2 ; // i = 2;
Une référence est implémentée avec la notion de pointeur constant
Void g( ) {
int ii = 0 ;
int& rr =ii ;
rr++ ; // ii =1
int* pp=&rr ; // pp pointe sur ii
}
1 &ii
pp:
rr :
ii:
eric.a
nq
uetil@
iris
a.f
r
51
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Passage par référence
Passage par référence : pour modifier les arguments
Utilisation des Références (type& X) et des pointeurs (type* X)
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; }
int a=1; int b=2;
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 eric.a
nq
uetil@
iris
a.f
r
52
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Passage par valeur / Recopie ( )
hier 1/10/99
demain 2/10/99
Date hier(1,10,99);
Date demain(2,10,99);
pass_valeur(hier,demain);
void pass_valeur(Date X ; Date Y) {
Date temp=X ; // initialisation
X=Y ;
Y=temp;
}
X1/10/99
Y2/10/99
temp
Contexte de la procédure
Sans effet
sur les arguments
* Constructeur par recopie
eric.a
nq
uetil@
iris
a.f
r
53
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Passage par référence / Pas de recopie
hier 2/10/99
demain 1/10/99
Date hier(1,10,99);
Date demain(2,10,99);
Pass_ref(hier,demain);
void pass_ref(Date& X ; Date& Y) {
Date temp=X ; // initialisation
X=Y ;
Y=temp;
}
Contexte de la procédure
X
Y
temp
Modification
des arguments
eric.a
nq
uetil@
iris
a.f
r
54
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Retour par valeur ( recopie )
string string1="toto";
string string2="tata";
string res;
res=concat(string1,string2);
string concat ( const string& s1,
const string& s2) {
string result = s1; // initialisation
result +=s2;
return result;
}
s1
s2
result
obj_temp result
res = obj_temp // affectation avec l'objet temporaire
res "tototata"
eric.a
nq
uetil@
iris
a.f
r
55
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Passage et Retour par référence
Passage par référence « constante »
évite une recopie de l’objet en garantissant une non modification de l’objet
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
string concat (const string& s1, const string& s2) {
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
eric.a
nq
uetil@
iris
a.f
r
56
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Auto-références
Rappel : this = pointeur sur l’objet qui a invoqué la fonction
Date& Date::plus_an (int n) { // Ok : retourne une référence
// ... // sur l ’objet appelant
_a+=n;
return *this; } 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é
eric.a
nq
uetil@
iris
a.f
r
57
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Passage par référence et Auto-référence
Extension des opérations de la classe Date
class Date {
// …
Date& plus_jour (int n); // additionne n jours
Date& plus_mois (int n); // additionne n mois
Date& plus_an (int n); // additionne n années
Date add_jour (int n) const;
Date add_mois (int n) const;
Date 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
eric.a
nq
uetil@
iris
a.f
r
58
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Exemple
Chap. 4 | Surcharge d’opérateurs conventionnels
class Date {
// ...
Date (int j, int m, int a)
Date (string s);
bool operator== (const Date& d) const;
long operator- (const Date& d) const;
};
égalité de deux dates … argument implicite(gauche) … explicite(droite)
bool Date::operator== (const Date& d) const {
return ( _j==d._j && _m==d._m && _a==d._a ) }
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;
eric.a
nq
uetil@
iris
a.f
r
59
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Exemple
Chap. 4 | Conversion implicite
class Date {
// ...
Date (int j, int m, int a)
Date (string s); // constructeur(1 arg) => conversion implicite
long operator- (const Date& d) const;
};
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
eric.a
nq
uetil@
iris
a.f
r
60
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Définition externe étendue
class Date { // …
Date (int j, int m, int a)
Date (string s);
};
Définition externe de l'opérateur d'égalité de deux dates
bool operator== (const Date& d1 , const Date& d2) {
return ( d1.jour()==d2.jour() && d1.mois()==d2.mois() && d1.annee()==d2.annee() ) }
Conversion implicite symétrique ...
("18 janvier 2002" == date::jourd) // ok
(date::jourd == "18 janvier 2002") // ok
eric.a
nq
uetil@
iris
a.f
r
61
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Notion d’ami : Friend
Fonction 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
}
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 { class Elt {
public: private:
List( ) ; int _info;
void inserer(int); Elt* _suiv;
private: friend class List;
Elt* _tete ; int _long ; friend class Pile; … }; };
2
Elt List
eric.a
nq
uetil@
iris
a.f
r
62
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Surcharge d’opérateurs et notion de Friend
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); };
égalité de deux dates
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; // ok
long n = date::jourd - "18 janvier 2002"; // ok
eric.a
nq
uetil@
iris
a.f
r
63
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 4 | Classe interne : "nested class"
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é } };
eric.a
nq
uetil@
iris
a.f
r
64
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 5 Mémoire: allocation, clonage, constructeur
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Zones mémoires
Pile d’exécution
variables locales à une fonction
portée niveau bloc // notion de durée de vie
Zone de données statiques
variables statiques
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)
allocation dynamique d’un objet : new (alloue la mémoire nécessaire au
type passé en argument et retourne l’adresse)
X* p = new X (arguments pour le constructeur);
X* p1 = new X; // constructeur par défaut
Date* d = new Date;
eric.a
nq
uetil@
iris
a.f
r
66
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Allocation dynamique et libération
Tout objet alloué dynamiquement (new) doit être
désalloué explicitement (delete)
Destruction d’un « objet » alloué : delete p;
l’opérateur delete permet de libérer un bloc mémoire du tas,
son argument est un pointeur sur l’objet réclamé.
Date d;
Date* pd1 = &d; // à éviter
Date* pd2 = new Date(17,08,1998);
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;
eric.a
nq
uetil@
iris
a.f
r
67
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
eric.a
nq
uetil@
iris
a.f
r
Chap. 5 | Notion de destructeur : ~X( )
Déclaration du destructeur : class X ; son destructeur ~X( )
class List {
public: ~List( ) ; ... private:
class Elt {
public:
int _info;
Elt* _suiv; }
Elt* _tete ; int _long ; }
2
Elt List
Le destructeur doit libérer tous les éléments alloués quand l’objet est hors de portée
List ::~List( ) {
Elt* p =_tete ;
While (p != NULL) {
Elt* psuiv = p _suiv ;
delete p ;
p = psuiv ;
}
}
Définition du destructeur
68
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Une 1ère amorce de programmation de liste
List:: ~List() { cout << "Destructeur" << endl; Elt* p =_tete; while(p != NULL) { Elt* psuiv = p->_suiv; delete p; p = psuiv; } } 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; }
class List { public: List() ; ~List() ; 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 }; class Elt { private: int _info; Elt* _suiv; friend class List; friend ostream& operator<<(ostream& os, const List& l); };
2
Elt List
Agrégation :
« Utilise »
eric.a
nq
uetil@
iris
a.f
r
69
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Mise en œuvre du destructeur
Gestion 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 insert (…) ;
...
delete pl ; // demande de libération de la mémoire => destructeur
Destructeur : opération appelée automatiquement
pour la libération mémoire d’un OBJET
eric.a
nq
uetil@
iris
a.f
r
70
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Allocation de n éléments
Pour allouer n éléments d’un type donné : new type[n]
Tableau de char
char* toto = new char [100] // fournit un pointeur (type* ici char*) sur
// le premier élément du tableau
Tableau d’objets
On peut créer un tableau d’objets avec la même syntaxe
List* desListes = new List [100] // alloue l’emplacement
// nécessaire à 100 objets « List »
// et place l’adresse du
// premier objet dans desListes
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
eric.a
nq
uetil@
iris
a.f
r
71
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Opérateur d’ Affectation ( operator = )
Opérateur d’affectation par défaut
Déclaration de 2 listes
List a ;
a.insert(...) ; …
List b ;
b.insert(…) ;
2
3 a
b
L’affectation par défaut effectue une simple copie champs à champs
2
2 a
b
• Affectation : recopie des champs _tete et _long
a = b ; // Pb avec l ’opérateur
// d’affectation par défaut
2 a • Lorsque b est hors de portée
la liste d’origine n’est pas détruite
la liste b est détruite deux fois !?
eric.a
nq
uetil@
iris
a.f
r
72
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Affectation en profondeur
Surcharge : opérateur d’affectation X& operator= (const X&)
Déclaration
class List {
public:
List( ) ;
~List( ) ;
List& operator= (const List& b); . . . // référence constante, évite
} // une recopie dans la pile
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 ; // protection pour a = a
// 1. libérer la mémoire de l’argument de gauche ~ idem destructeur
// 2. copie de l ’argument droit … }
eric.a
nq
uetil@
iris
a.f
r
73
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Constructeur par recopie
Utilisation du constructeur par recopie
initialisation ( Date d1=d2 ; Date* d3= new Date(d2) )
objets copiés en tant qu’argument de fonction
objets copiés en tant que retour de fonction
Exemple
double moyenne (List a)
{ … }
List l ;
double moy=moyenne( l ) ;
Le constructeur par recopie par défaut effectue une simple
copie champs à champs
3 l
• Liste l avant l’appel de fonction
3 l
3 a
• Listes pendant le déroulement de la fonction (copie locale)
3 l
• Listes après l’appel de fonction (destruction de a)
eric.a
nq
uetil@
iris
a.f
r
74
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Implémentation d’un constructeur par recopie
Redéfinition d’un constructeur par recopie (en profondeur)
objectif : pouvoir initialiser un objet nouveau comme une copie en profondeur
d’un objet existant.
List::List (const List& b) {
_long = b._long;
Elt* p = NULL;
Elt* q = b._tete;
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;
} }
eric.a
nq
uetil@
iris
a.f
r
75
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Une implémentation homogène
Définition
Constructeur par recopie Destructeur
X(const X&) ~X()
List::List (const List& b) { List::~List( ) {
copier (b); liberer( ) ;
} }
Opérateur d’affectation
X& operator= (const X&)
List& List::operator= (const List& b) {
if (this != &b) {
liberer();
copier(b); }
return *this ; }
eric.a
nq
uetil@
iris
a.f
r
76
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Une implémentation homogène
Constructeurs, constructeur par recopie, affectation et destructeur
class List {
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 ... ) };
class Elt {
private: int _info; Elt* _suiv; friend class List;
friend ostream& operator<<(ostream& os, const List& l);
};
eric.a
nq
uetil@
iris
a.f
r
77
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Remarques et notion de clonage
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 clonage
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); }
…
};
le clonage en JAVA
le polymorphisme / constructeur virtuel
eric.a
nq
uetil@
iris
a.f
r
78
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 5 | Bilan : Affectation et Constructeur par recopie
Constructeur et affectation par recopie
List inverser(const List& b) {
List temp ; // constructeur par défaut …
return temp ; // constructeur par recopie (objet anonyme) } // destruction de la variable locale temp (~List)
List u , v ;
v = inverser(u); // affectation + destruction de l’objet anonyme
Utilisation implicite des opérateurs : constructeur par recopie, affectation, destructeur.
class Index {
private: Index a, b;
string nom ; a = b ; // affectation par défaut Ok ;
List l ;
int _compt ; }
eric.a
nq
uetil@
iris
a.f
r
79
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 6 Java : Mémoire (Rappels)
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 6 | Le ramasse miette ou « garbage collector »
« Assure une gestion plus sure de la mémoire »
Durée de vie : le ramasse miette ou « garbage collector »
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
référence sur cet objet).
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()
String[] T= new String[10]; { 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
attention un objet peut être référencé
à plusieurs endroits
et tant qu'il existe une référence sur un
objet il ne sera pas détruit
Java
eric.a
nq
uetil@
iris
a.f
r
81
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 6 | La méthode finalize()
Méthode finalize()
Méthode appelée par le ramasse-miettes avant la destruction d'une instance de la
mémoire
Permet de libérer les ressources
(fichier, socket, etc.)
Elle peut être directement appelée
Appel implicite possible si
l'instance n'est plus référencée
et que le ramasse-miettes est
entré en action
Attention
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)
Class UneClasse {
private File fichTemp= new File("ftemp");
private FileOutputStream flotfichTemp;
// …
public void finalize() throws IOException {
flotFichTemp.close() // fermeture
fichTemp.delete(); // efface le fichier
} }
gestion d'un fichier temporaire
Java
eric.a
nq
uetil@
iris
a.f
r
82
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 7 Aggrégation, héritage, polymorphisme, classe abstraite
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Abstraction - Généricité
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
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
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
Généralisation
Spécialisation
eric.a
nq
uetil@
iris
a.f
r
84
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Agrégation : classe Point / Rectangle
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
Association de type agrégation " ensemble / élément " (losange blanc) :
Cad : un rectangle contient 2 Points"
La flèche précise que seul le rectangle est "conscient" des Points qu'il possède
Classe
Attributs
Méthodes
Multiplicité
eric.a
nq
uetil@
iris
a.f
r
85
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Agrégation : exemple de Base
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;};
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; };
Agrégation forte : composition (losange noir) :
eric.a
nq
uetil@
iris
a.f
r
86
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Héritage : exemple de Base
• 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
class Rectangle : public Polygone {
public:
Rectangle();
Rectangle(Point, Point);
void dess(Graphics& gc*) const;
};
Classe de Base
Classe Dérivée
eric.a
nq
uetil@
iris
a.f
r
87
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Contrôle d’accès : privé, publique, protected
Class B { class D : public B {
int priv; void fD( ) ;
protected: }
int pro;
public: class Ami {
int pub; void fa(B* p);
void f(); }
friend class Ami;
}
void fext(B* p) {
p ->priv =1; // erreur
p ->pro =1; // erreur
p ->pub =1; // ok }
void B::f( ) { void Ami::fa(B* p) { void D::fD( ) {
priv =1; // ok p->priv =1; // ok priv =1; // erreur
pro =1; // ok p->pro =1; // ok pro =1; // ok
pub =1; // ok p->pub =1; // ok pub =1; // ok
} } }
eric.a
nq
uetil@
iris
a.f
r
88
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Contrôle d’accès à la classe de base
class B { class D1 :public B { ... };
public: class D2 :protected B { ... };
int pub; class DD2 :public D2 { void fd2(D1*, D2*, D3*); };
} ; class D3 :private B { void fd3 (D1*, D2*, D3*); };
void f(D1* p1, D2* p2, D3* p3) void DD2::fd2( … ) void D3::fd3( … )
{ { {
B* p=p1; // ok B* p=p1; // ok 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
} } }
eric.a
nq
uetil@
iris
a.f
r
89
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Constructeurs : agrégation et héritage
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) { }
Polygone::Polygone(int n) : _coins(n) { }
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.
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); }
sauf héritage virtuel
eric.a
nq
uetil@
iris
a.f
r
90
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Redéfinition <> Surcharge
surcharge <> redéfinition
Surcharge : utilisation du même nom avec des paramètres
différents (en type et/ou en nombre :: signature de la méthode)
B::f() et B::f(int)
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
B
f() f(int i)
D1
f()
B
f() f(int i)
void main () {
B objet_B;
D1 objet_D1; 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
}
objet_B.f() B::f()
objet_B.f(2) B::f(int i)
objet_D1.f() D1::f()
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;}
eric.a
nq
uetil@
iris
a.f
r
91
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Relation entre classe de base et classe dérivée
Une classe dérivée D* peut avoir 3 actions possibles
considérant une fonction f() de la classe de base B
Hériter (sans changement)
Redéfinir la fonction B::f() =>Masquage
Redéfinir et Etendre la fonction B::f()
B
f() f(int i)
D2
f()
D1
f()
D0
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);
cout << "objet_D1.f() ";objet_D1.f();
//objet_D1.f(1); //erreur
objet_D1.B::f(1);
cout << "objet_D2.f() ";objet_D2.f();
}
objet_B.f() B::f()
objet_B.f(2) B::f(int i)
objet_D0.f() B::f()
objet_D0.f(1) B::f(int i)
objet_D1.f() D1::f()
B::f(int i)
objet_D2.f() D2::f() B::f()
class D0 : public B { };
class D1 : public B { public: void f(); };
void D1::f() { cout << "D1::f() " }
class D2: public B { public: void f(); };
void D2::f() { cout << "D2::f() ";
B::f(); }
eric.a
nq
uetil@
iris
a.f
r
92
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Relation entre classe de base et classe dérivée
Surcharger une fonction =>Masquage
B
f() f(int i)
D1
f(int,int)
void main () {
D1 objet_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);
}
objet_D1.f(1,2) / Surcharge : D1::f(int i, int j)
objet_D1.B::f(1) / Portee explicite : 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 { void f(int i, int j);
};
void D1::f(int i, int j) {
cout << "D1::f(int, int)" << endl;}
eric.a
nq
uetil@
iris
a.f
r
93
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Résumé : héritage, agrégation, …
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
La notion d'agrégation
Exemple : la classe Cercle utilise le concept
de Point dans sa définition
=> définition avec un plus haut niveau d'abstraction
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
ellipse Cercle
Point Cercle
Liste Pile
eric.a
nq
uetil@
iris
a.f
r
94
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Polymorphisme : conversion entre objets
Conversion statique : Obj. classe de dérivée Obj. classe de Base
class RectangleP : public Rectangle {
public:
RectangleP(point, point, color);
void dess(Graphics& g) const;
private:
color _couleur;
}
RectangleP Rp(P1, P2, c);
Rectangle R=Rp; // ok, mais conversion statique
// (objet tronqué)
R.dess(g); // rectangle simple
Rp.dess(g) // rectangle plein
eric.a
nq
uetil@
iris
a.f
r
95
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Polymorphisme : conversion entre objets
Conversion statique : Obj. classe de dérivée Obj. classe de Base
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
eric.a
nq
uetil@
iris
a.f
r
96
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Polymorphisme : conversion entre pointeurs
Conversion automatique : Pt classe de dérivée Pt classe base
RectangleP* RP = new RectangleP (P1, P2, c);
Rectangle* R = RP; // ok conversion implicite
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* RP2 = static_cast<RectangleP*>(R) ; // attention (dangereux)
@
@
RectangleP*
Rectangle*
eric.a
nq
uetil@
iris
a.f
r
97
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Polymorphisme : conversion entre pointeurs
Encore une limitation / collection d'objets de types différents
l’information n’est pas perdue mais elle n’est plus accessible ...
… Attachement statique par défaut
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++) // dessine des rectangles simples
rects[i] ->dess(g); // idem à rects[i]->Rectangle::dess(g)
@ @ @ Rectangle*
eric.a
nq
uetil@
iris
a.f
r
98
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
class RectangleP : public Rectangle {
public:
RectangleP(point, point, color);
virtual void dess(Graphics& g) const;
...
}
Chap. 7 | Fonctions virtuelles
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
Déclaration de fonction virtuelle
Exemple
class Rectangle {
public:
Rectangle(point, point);
virtual void dess(Graphics& g) const;
. . . }
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é
Facultatif mais conseillé
@ @ @ Rectangle*
eric.a
nq
uetil@
iris
a.f
r
99
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Attachement statique et dynamique
Attachement statique : objets
Rectangle R;
R.dess(g); // attachement statique, appel de Rectangle ::dess
Attachement dynamique : pointeurs
Rectangle* R; // attachement dynamique si dess est une fonction virtuelle
R ->dess(g); // ex.: appel de Rectangle::dess ou RectangleP::dess
Attachement dynamique : argument (objet) implicite
class fenetre {
public:
virtual void dess(Graphics g, Rectangle r);
void scroll (int dx, int dy); . . . };
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 !
void fenetre::scroll(int dx, int dy) {
...
dess( g, r); // attachement
} // dynamique
eric.a
nq
uetil@
iris
a.f
r
100
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Collection hétérogène d’objets
vector <Figure*> figs(4);...
for (int i=0; i<figs.size(); i++) figs[i] ->dess(g);
class Figure {
public:
virtual void dess (Graphics& g) const ;
virtual void deplacer(int x, int y) ; . . .
}
Toutes les figures
dérivent
de la classe
de base
Figure
eric.a
nq
uetil@
iris
a.f
r
101
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Classe abstraite
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
Pour définir un protocole générique de manipulation de
la classe de base on peut utiliser des méthodes virtuelles pures
Cf. interface Java
eric.a
nq
uetil@
iris
a.f
r
102
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Destructeur virtuel
Toutes classes de Base « devraient » posséder un destructeur virtuel si ...
class B {
public:
virtual fonction(...);
virtual ~B( );
. . .
};
vector <B*> collection(4);
collection[0]= new B(…); // allocation dynamique
collection[1]= new D(…);
for (i=0; i<collection.size(); i++) // désallocation explicite
delete collection[i]; // Ok : grâce au destructeur virtuel
class D: public B {
public:
List _l;
. . .
};
eric.a
nq
uetil@
iris
a.f
r
103
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Copie en profondeur & clonage
Copie d’un vecteur de figures
copie superficielle
copie en profondeur / clonage
(« pour implanter une construction virtuelle »)
for (i=0;i<Figs.size();i++)
Figs2[i]=Figs1[i]->clone(); 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 centre() const; int rayon() const; protected: int _rayon; };
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;
};
vector <Figure*> Figs1(9);
vector <Figure*> Figs2(9);
for (i=0;i<Figs.size();i++)
Figs2[i]=Figs1[i]; …
eric.a
nq
uetil@
iris
a.f
r
104
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 7 | Figure_exe.cpp && résultats
int main(int argc, char* argv[]){
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); P1.dess(); C.dess(); Poly.dess(); cout << " >>> Conversion statique" << endl; RectangleP RectP(P2,P1,1); RectP.dess(); Rectangle Rect=RectP; cout << "-> "; Rect.dess(); 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(); } ...
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)
eric.a
nq
uetil@
iris
a.f
r
107
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 8 Héritage multiple
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 8 | Héritage multiple C++ et Interface JAVA
C ++ / Héritage multiple
Processus permettant l’héritage
de plusieurs classes
Peut être utile pour des cas simples,
mais peut devenir très complexe et difficilement gérable
Java / notion d’interface
Java ne permet pas
l’héritage multiple
Java intègre un mécanisme
voisin (plus restrictif) :
::::::::.... héritage d’interface multiple
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
Employé Étudiant
Professeur
Personne
Vacataire
Personne Rectangle
Figure
Employe imprime
Imprimable
Java
C++
eric.a
nq
uetil@
iris
a.f
r
109
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 8 | Cas simple d’héritage multiple en C++
Déclaration et utilisation
Un vacataire est à la fois étudiant et employé
class Vacataire : public Etudiant, public Employe ... ;
...
list <Employe*> list_employe;
list <Etudiant> list_etudiant;
Vacataire* V = new Vacataire(…);
list_employe.push_back(V); // ok
list_etudiant.push_back(*V); // ok ; mais tronqué ...
Construction
Pour les cas « simples » d’héritage multiple : construction classique
Vacataire::Vacataire (. . .)
: employe(…) ,
etudiant(…) ,
_donnée_locale( …) { }
Employé Etudiant
Vacataire
C++
eric.a
nq
uetil@
iris
a.f
r
110
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Employé Etudiant
Personne
Vacataire
Chap. 8 | Héritage multiple : classe de base dupliquée
Présence d’une classe de base commune
class Etudiant : public Personne ... ;
class Employe: public Personne ... ;
class Vacataire : public Etudiant, public Employe ... ;
«Vacataire» dérive 2 fois de «Personne»
Un objet "Vacataire" contient 2 sous-objets "Personne"
l'appel "Vacataire1._nom" est ambiguë
Ch. Etudiant
Personne
Ch. Employe
Personne
Vacataire
Ch. Vacataire
Etudiant
Employe
_nom = toto
_nom = tata
C++
eric.a
nq
uetil@
iris
a.f
r
111
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 8 | Héritage multiple : partage de classe de Base
Solution : prévoir un Héritage « virtuel » / Partage !
Définition
class Etudiant : virtual public Personne
class Employe: virtual public Personne
class Vacataire : public Etudiant, public Employe
1 objet «Vacataire» fait référence à 1 sous-objet «Personne »
Construction
Le constructeur d’une classe de base virtuelle
partagée est appelé (implicitement ou
explicitement) une seule fois depuis le
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 ::::::
Ch. Etudiant
Ch. Employe
Ch. Vacataire
Personne
Objet vacataire
C++
eric.a
nq
uetil@
iris
a.f
r
112
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 8 | Résolution des ambiguïtés
Vacataire
Employé
ImpFiche
Étudiant
impFiche
Personne
ImpFiche
Personne
ImpFiche
Employé
Vacataire
Étudiant
impFiche
Employé
ImpFiche
Étudiant
impFiche
Personne
ImpFiche
Vacataire
ImpFiche Fusion des caractéristiques
Ok si Vacataire redéfinit la fonction virtuelle "impFiche()"
void Vacataire::impFiche() const {
Etudiant::impFiche();
Employe::impFiche();
}
Héritage de 2 classes avec des fonctions virtuelles
ayant la même signature
Ambiguïté entre : Etudiant/Employé::impFiche()
Règle de prédominance (si héritage virtuel)
A priori ambiguïté entre : Etudiant/Personne::impFiche()
Vacataire1.impFiche(); // ok pas d'Ambiguïté
<=> Vacataire1.Etudiant::impFiche()
C++
eric.a
nq
uetil@
iris
a.f
r
113
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
*notion d'interface Java
Chap. 8 | Utilisation de l’héritage multiple ?
Rester dans des cas simples d'utilisation ...
Être conscient de la complexité de l’héritage multiple
Classe de base partagée (héritage partagé ...)
Construction de classe de base virtuelle (constructeur par défaut ...)
Destructeur virtuel (dans les classes de base !)
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
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
C++
eric.a
nq
uetil@
iris
a.f
r
114
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 9 Java : Interface
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 9 | Interface Java
Définition
Une interface Java est une sorte de classe abstraite "pure" :
Sans donnée (sauf static et final)
Possède seulement des fonctions abstraites (publiques)
Une classe peut "implémenter" plusieurs Interfaces ( héritage)
Lorsqu'une classe implémente une interface elle garantit de définir toutes les
méthodes de l'interface
<=> elle garantit de respecter
le protocole défini par l'interface
Implantation
interface Imprimable {
public void imprime();
}
public class Personne implements Imprimable
{
…
// redéfinition obligatoire
// imposée par l'interface Imprimable
public void imprime(){
System.out.println(this);
}
…
public class Employe extends Personne {…}
Java
eric.a
nq
uetil@
iris
a.f
r
116
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 9 | Exemple d'utilisation d'interface
On caractérise les classes <Imprimable>
avec l'Interface <Imprimable>
Par exemple : les classes <Personne> et <Rectangle>
On peut alors rassembler dans un tableau des classes respectant le protocole
<Imprimable>
L'interface garantit que tous
les objets du tableau
(même de nature différente)
sont imprimables
interface Imprimable {
void imprime();
}
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];
tabImpression[0]=p1;
tabImpression[1]=e1;
tabImpression[2]=r1;
for (int i=0; i< tabImpression.length; i++) {
tabImpression[i].imprime();
} } Personne : toto : 29
Employe : titi : 29 / 7000
Rectangle : (1,1) (100,100)
public class Rectangle extends Figure implements Imprimable {
private Point p_hg;
private Point p_bd;
public void imprime(){
System.out.println("Rectangle : " +
p_hg + " " + p_bd);
}
…
Java
eric.a
nq
uetil@
iris
a.f
r
117
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 9 | Exemple d'interface : diagramme de classe
Interface : services offerts par une classe
Lien de réalisation : Personne et Rectangle fournissent l'interface
Java
eric.a
nq
uetil@
iris
a.f
r
118
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 9 | NB : Interface et héritage
Héritage classique
Les interfaces peuvent être organisées de manière hiérarchique via le
mécanisme d’héritage.
Interface intFaceA extends intFaceB { …}
On peut avoir un héritage multiple d’interfaces :
interface intFaceA extends intFaceX, intFaceY {…}
Héritage « diamant »
Il y aura automatiquement héritage multiple partagé en cas d’héritage de « type
diamant »
Java
eric.a
nq
uetil@
iris
a.f
r
119
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 9 | Interface Versus Classe abstraite
Une Interface
spécifie la forme (spécification, définition d'un comportement) de quelque
chose (d'un concept) (<> fournir une implémentation)
Les méthodes de l'interface définissent le protocole (signature) à faire
respecter pour ce concept
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)
eric.a
nq
uetil@
iris
a.f
r
120
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 10 Exceptions
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Notion d'erreur
Différents types d'erreurs
Mauvaise gestion des classes : dépiler une pile vide, ...
Entrées utilisateurs non valides : effacer un fichier inexistant, ...
Liées aux périphériques : manque de papier dans l'imprimante, ...
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 ...
eric.a
nq
uetil@
iris
a.f
r
122
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Traitement des cas d'erreurs exceptionnelles
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
Mécanisme d'exception / gestionnaire d'exception
Permet de transmettre le problème du traitement de l'erreur dans un contexte
qualifié (de niveau supérieur) pour gérer l'erreur
Simplifie en allégeant le code de la gestion locale des erreurs par une
recentralisation des procédures de traitement d'erreur
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 (...)
eric.a
nq
uetil@
iris
a.f
r
123
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Exemple général sur le mécanisme d'exception
#include <exception>
#include <iostream.h>
class TestException {
public :
void methode1();
void methode2(int i);
};
void TestException::methode1() {
cout << "methode1" << endl;
methode2(1);
methode2(0);
cout << "fin methode1" << endl;
}
void TestException::methode2(int i) {
cout << " methode2" << endl;
if (i==0) throw exception("erreur i est egal a 0");
cout <<" i == " << i << endl;
cout << " fin methode2" << endl;
}
#include "TestException.h"
void main(){
TestException t;
try {
t.methode1();
cout << "suite1 main" << endl;
}
catch(exception& e) {
cout << e.what() << endl;
}
catch(int i) {
cout << "code d'erreur" << i << endl;
}
cout <<"reprise du code" << endl;
}
1
• Arrêt de l'exécution : lancement de l'exception
• Transmission du control au bloc supérieur …
• Capture de l'exception par un bloc "catch"
• Traitement de l'exception
• Le programme reprend
1
2
3
3
4
4
5
2
5
methode1
methode2
i == 1
fin methode2
methode2
erreur i est egal a 0
reprise du code
C++
eric.a
nq
uetil@
iris
a.f
r
124
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Le principe
Instructions : try / throw / catch
Un bloc de code est mis sous surveillance : instruction try
Des méthodes peuvent lancer des exceptions avec l'instruction throw
Un bloc de gestion d'exception est signalé par l'instruction catch
Déroulement
Si aucune exception n’est levée dans le bloc try, le contrôle passe à
l’instruction qui suit les gestionnaires d’exception (catch).
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.
eric.a
nq
uetil@
iris
a.f
r
125
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole C++ : émission d'exceptions
Une exception est lancée par la commande throw e;
e est un "signal d'exception"
il peut représenter n'importe quel objet ou valeur :
throw "message d'erreur"; // type string pas très informant
throw ErreurConnection("Pb à l'ouverture de la connexion");
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.
C++
eric.a
nq
uetil@
iris
a.f
r
126
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole C++ : spécification d'exceptions
En C++ la spécification des exceptions est possible (pas obligatoire)
Spécification explicite des exceptions levées
int f(istream&) throw (StackError, MathError);
Cela garantit que seul les exceptions StackError, MathError seront levées par
cette méthode.
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
int h(istream&);
C++
eric.a
nq
uetil@
iris
a.f
r
127
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole C++ : fonction terminate
Propagation du signal d'exception jusqu'à la méthode main
L'exception n’est jamais capturée
Appel à la fonction terminate()
Fonction terminate()
Par défaut
elle met fin au programme
en appelant la fonction abort();
Personnaliser la fonction
terminate()
set_terminate(pointeur sur fonction);
#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;
}
methode1
methode2
i == 1
fin methode2
methode2
une exception n'est pas gérée !
abnormal program termination
C++
eric.a
nq
uetil@
iris
a.f
r
128
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Exceptions standards en C++
Le C++ ANSI a défini une hiérarchie d’exceptions
La classe de base std::exception
Il est intéressant de dériver toute exception d’une exception standard
try { ….}
catch (Exception& e)
{
cout << e.what( ) << endl;
}
Erreur dépendante
du programmeur
ex : dépiler une pile vide
Erreur indépendante
du programmeur
ex : mauvaise lecture
de fichier
exception
logic_error runtime_error
……... ……...
Sous le contrôle
du programmeur
exception
exception() throw();
…
Virtual const char* what() const trow();
C++
eric.a
nq
uetil@
iris
a.f
r
129
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Capture et traitement d'exceptions
Capture (bloc try) et traitement d'exceptions (clause catch)
try
{ // code susceptible de déclencher une exception
}
catch (Type1 id1) { // capture des exception de type Type1
// ou type dérivé de Type1
// 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
C++
eric.a
nq
uetil@
iris
a.f
r
130
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole Java : lancement d'exceptions
Une exception est lancée par la commande throw e;
e : est un objet qui DOIT dériver de la classe Throwable
throw new IllegalArgumentException("Pb en lecture");
Spécification obligatoire des exceptions susceptibles d’être lancées
Toute fonction susceptible d'émettre des exceptions "explicites" doit le
mentionner (vérification à la compilation ) :
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
Java
eric.a
nq
uetil@
iris
a.f
r
131
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Retransmission d’une exception
Il est possible de retransmettre une exception
en C++
try
{ // code
}
catch(...) // 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
}
eric.a
nq
uetil@
iris
a.f
r
132
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Exception standard en Java
Java possède une hiérarchie d’exceptions standards
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
Throwable
Exception Error
……...
A Récupérer :
sous le contrôle
du programmeur,
Sauf les Runtime
Erreur propre
à la la machine
virtuelle, système
……... IOExcepton RuntimeException
Possède 2 sous-classes
standards
Division par zéro, Dépassement d'indice dans un tableau, …
Appel d'une méthode abstraite, La machine virtuelle n'a pas assez de mémoire, …
Java
eric.a
nq
uetil@
iris
a.f
r
133
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole Java : Java.lang.Throwable
Java.lang.Throwable
Exemple de récupération du message de l'exception
try { ….}
catch (Exception e)
{ System.out.println(e.getMessage()); // ou
System.out.println(« Exception » + e); // cf. notion de toString
}
Throwable
String message
Throwable()
Throwable(string s)
String getMessage()
Void printStackTrace()
Void printStackTrace(PrintStream)
…
- Message d'erreur décrivant l'exception
- 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
Java
eric.a
nq
uetil@
iris
a.f
r
134
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Créer vos propres classes d'exceptions
Un petit exemple Java
public class MonException extends Exception {
public MonException ( ) { }
public MonException (String msg) {
super(msg) ; } }
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(); }
} }
MonException: Origine: fonction g()
at UneClasse.g(UneClasse.java:9)
at UneClasse.h(UneClasse.java:13)
at UneClasse.main(UneClasse.java:17)
Java
eric.a
nq
uetil@
iris
a.f
r
135
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Protocole Java : bloc finally
finally
• Le bloc "finally" est toujours exécuté :
qu'il y ait capture, propagation ou
déroulement normal du programme
• Le programme reprend après
le bloc "finally"
• Tous les blocs "finally"
rencontrés sont exécutés
public class UneClasse {
public void g() throws MonException {// ...
throw new MonException("Origine: fonction g()");
}
public void h() throws MonException {// ...
try { g(); }
catch (RuntimeException e) {
e.printStackTrace();
}
finally {
System.out.println("finally de h()");
}
System.out.println("fin de h()");
}
public static void main (String[] args) {
UneClasse C1=new UneClasse();
try { C1.h(); }
catch (MonException e) {
e.printStackTrace();
}
finally {
System.out.println("finally de main()");
}
System.out.println("fin de main()");
} }
finally de h()
MonException: Origine: fonction g()
at UneClasse.g(UneClasse.java:9)
at UneClasse.h(UneClasse.java:13)
at UneClasse.main(UneClasse.java:25)
finally de main()
fin de main()
Java
eric.a
nq
uetil@
iris
a.f
r
136
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Remarques sur la gestion mémoire
En C++
D'une manière générale
Tous les objets de la pile entre le throw et le catch sont détruits proprement
et automatiquement en invoquant le destructeur
Ceci implique une gestion de la mémoire qui peut être coûteuse
NB: il reste le problème des pointeurs (minimiser leur utilisation)
Si une erreur est détectée dans un constructeur
Tous les sous-objets déjà construits seront détruits proprement
Si une nouvelle exception se produit lors de la destruction
Le programme sera abandonné
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++
*cf. fonction set_terminate(...)
eric.a
nq
uetil@
iris
a.f
r
137
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 10 | Bilan sur les exceptions
Les méthodes traitent les exceptions qu'elles peuvent gérer
sinon les retransmettre
Les exceptions sont des événements exceptionnels
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
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
eric.a
nq
uetil@
iris
a.f
r
138
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 11 Template
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 11 | Introduction : classes paramétrées
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
vector <int> // tableau dont les éléments sont de type int
vector <Figure*> // tableau dont les éléments sont de type Figure*
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).
Utilisation
Pour faciliter la construction de concepts génériques
Pour la création de classe de type « conteneur » : liste, queue, tableau, …
Template Classe Objet
vector<T> vector<int> TabNotes
C++
eric.a
nq
uetil@
iris
a.f
r
140
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
_tete
_queue
Chap. 11 | Mise en œuvre de classe template (interface .h)
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
Exemple : une classe générique File
template <class C> template<class T>
class Elt { class File {
public: public:
Elt(C, Elt<C>* = NULL); File();
private: void inserer(T t);
Elt<C>* _suiv; T retirer ( );
C _info; int longueur ( ) const;
friend class File<C>; private:
}; Elt<T>* _tete;
Elt<T>* _queue;
int _longueur;
};
C++
eric.a
nq
uetil@
iris
a.f
r
141
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
_tete _queue
Chap. 11 | Mise en œuvre de classe template (f. membres)
Définition des fonctions membres
template<class T> template<class T>
void File<T>::inserer(T t) { T File<T>::retirer( ) {
Elt<T>* p = new Elt<T>(t) ; assert (_tete!=NULL) ;
if (_queue) _queue ->_suiv = p ; T t = _tete ->_info ;
else _tete = p ; Elt<T>* p = _tete ->_suiv ;
_queue = p; delete _tete ;
_longueur ++; _tete = p ;
} if (_tete ==NULL)
queue=NULL;
_longueur --;
return t ; // constructeur
} // par recopie
template<class T>
File<T>::File( )
: _tete(NULL) , _queue(NULL) , longueur(0)
{ }
C++
eric.a
nq
uetil@
iris
a.f
r
142
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 11 | Template multi-type (paramétrage /type ou /valeur)
Template 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);
On peut mixer : types génériques et types fixés a priori (à la compilation)
TabFix<Point, 1 , 10> Tab;
La classe doit être définissable à la compilation
void methode(int nb) {
int* tab1nombre = new int[nb]; // ok
TabFix<int, 1, 2 > Tab; // ok
TabFix<int, nb, nb > Tab2; // erreur
}
template <class K, class V>
class Map {…};
template <class T, int dimX, int dimY>
class TabFix {…};
C++
eric.a
nq
uetil@
iris
a.f
r
143
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 11 | Paramètre template par défaut
Paramètre template par défaut possible
Attention à la version du compilateur (Ansi C++)
template <class T, class U=defaultU>
template<class P>
class Toto { ... }
template <class T, class U=Toto<T> >
class Truc { ... }
C++
eric.a
nq
uetil@
iris
a.f
r
144
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 11 | Fonction template et Spécialisation
Fonction template
template <Class T>
inline T max (T a, T b) {
return a>b ? a : b ;
}
unsigned long x, y, z;
z=max(x,y); // assez difficile à gérer pour le compilateur ...
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 ;
}
C++
eric.a
nq
uetil@
iris
a.f
r
145
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 11 | Précautions avec «l'instanciation»
Tous les types ne peuvent pas être instanciés
ex1: il manque un constructeur par recopie
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
}
ex2 : il manque un comparateur
Map<string, int> age; Map<etudiant, int> notes;
age.set (" toto", 10);
… ...
age. set(" tata", 20);
// ok le comparateur == // Probleme si le comparateur ==
// existe pour les string // 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
C++
eric.a
nq
uetil@
iris
a.f
r
146
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 12 Java : Generics
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Introduction
Objectifs
Possibilité d’abstraire des types (on parle de types paramétrés)
Attention : similitudes et différences / Template C++
Exemple d’utilisation : invocation de types paramétrés
Amélioration de la lisibilité et de la robustesse
// avant java 5
List l1 = new ArrayList(); // liste d'Object
l1.add(new Integer(0)); // ajout d'un Integer qui est un Object
Integer x = (Integer) l1.iterator().next(); // nécessité d'un cast : Object -> Interger
l1.add(new Character('a')); // 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)
Java
eric.a
nq
uetil@
iris
a.f
r
148
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Définition de “generics”
On spécifie à la déclaration du « Generics » (classe paramétrée)
les paramètres formels entre <>
Les « Generics » ne sont pas des « Template C++ »
Invocation d’une liste d’entier : List<Interger>
<=> Attention oui et NON
Pas de duplication du code pour chaque type de paramètre utilisé
public interface List<E> { // E = paramètre formel de l'interface List
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> { // E = paramètre formel de l'interface Iterator
E next();
boolean hasNext();
}
public interface IntegerList {
void add(Integer x)
Iterator<Integer> iterator();
}
Java
eric.a
nq
uetil@
iris
a.f
r
149
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Définition de “generics”
Le « Generic » est compilé en une unique classe
Les paramètres formels sont remplacés
à l’invocation du « Generic » par les paramètres effectifs
=> réponse
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());
true
java.util.ArrayList
java.util.ArrayList
Java
eric.a
nq
uetil@
iris
a.f
r
150
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Héritage
Héritage et generics
Si CD hérite de CB
Alors
ClassG<CD> n’hérite PAS de ClasseG<CB>
Pourquoi ? Si c’était possible : ls et lo référenceraient la même liste !
donc
=> ls pourrait contenir des objets n’étant pas des String !
List<String> ls = new ArrayList<String>();
List<Object> lo = ls; // Type mismatch: cannot convert from List<String> to List<Object>
lo.add(new Object());
String s = ls.get(0); // Pb on essaie d’assigner un objet à une string !
Java
eric.a
nq
uetil@
iris
a.f
r
151
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Wildcards et Bounded Wildcards
Utilisation du wildcard <?>
class Fenetre{
public void draw(Figure s) { s.draw(this); }
public void drawAll(List<Figure> Figures) {
for (Figure s: Figures) { s.draw(this); }
} // on ne peut passer en paramètre que des List<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>()); // The method drawAll(List<Figure>) in the type Canvas
// is not applicable for the arguments (ArrayList<Cercle>)
ca.drawAll1(new ArrayList<Cercle>()); // ok
ca.drawAll2(new ArrayList<Cercle>()); // ok
}
}
Rectangle Cercle
Figure
Java
eric.a
nq
uetil@
iris
a.f
r
152
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 12 | Generic
Recopie d’éléments d’une liste à l’autre
Comment généraliser ?
Utilisation d’une méthode générique
Préférer l’utilisation des Wildcards : solution + concise et + claire !
public static void recopie( List<? extends Rectangle> Figures,
List<Rectangle> Rectangles) {
for (Rectangle r: Figures) { Rectangles.add(r); }
}
Rectangle Cercle
Figure
public static void recopie1(List<?> l1, List<?> l2) {
for (Object r: l1) { l2.add(r); } // Erreur à la compilation !
}
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
}
Java
eric.a
nq
uetil@
iris
a.f
r
153
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 13 STL : Introduction
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Introduction à la STL
La librairie standard du C++ intègre
Des classes conteneurs et leur algorithmes associés
La gestion des string et des flux (iostream)
Intérêt de la librairie standard du C++ (STL)
Standardisation
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
C++
eric.a
nq
uetil@
iris
a.f
r
155
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Les conteneurs élementaires
Vector
Tableaux du C++ avec possibilité d’allocation dynamique
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)
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
C++
eric.a
nq
uetil@
iris
a.f
r
156
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Les Vecteurs
Introduction
équivalent des Vector ou ArrayList de Java
tableaux pouvant croître dynamiquement.
Utilisation Basique
size() :Taille du vecteur
l’opérateur crochets [ ] : Accès/modification du vecteur
push_back : ajoute un élément en fin de vecteur.
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>
#include <string>
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;
}
La taille du vecteur est de 9
La taille du vecteur est de 0
C++
eric.a
nq
uetil@
iris
a.f
r
157
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Notion d‘itérateur
Notion d'Itérateur
représente la "position" d’un élément dans une collection
Tout conteneur STL définit
le type iterator
avec les méthodes
begin : itérateur qui pointe sur le premier élément de la collection
end : itérateur qui pointe sur la case après le dernier élément
Opérateur * : permet d’accéder à l’élément à partir de l’itérateur
Opérateur ++ : avancement de l’itérateur
(NB: post-incrément (recopie de l’objet) /pré-incrément (évite la recopie) )
Les itérateurs sur vecteurs supportent les opérations + et -
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") );
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;
C++
eric.a
nq
uetil@
iris
a.f
r
158
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Recherche - Insertion - Suppression
La fonction find (Usage Générique)
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é.
La recherche impose que l'opérateur == soit défini sur le type de donnée. #include <iostream>
#include <vector>
#include <string>
#include <algorithm> // pour accéder à find
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;
vector<string>::iterator it;
it = find(v2.begin(),v2.end(),"tout");
v2.erase(it);
it = find(v2.begin(),v2.end(),"monde");
v2.insert(it,"---");
for(iter=v2.begin(); iter!=v2.end(); iter++) cout << *iter << endl;
bonjour
le
---
monde
C++
eric.a
nq
uetil@
iris
a.f
r
159
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Les listes
Les listes ne disposent pas
de l'opérateur crochets,
ou d'une arithmétique des pointeurs
Avantages
l'insertion et la destruction d'un élément, où qu'elle se fasse dans une liste, se fait toujours en
temps constant.
Exemple de méthode spécifique
#include <list>
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
C++
eric.a
nq
uetil@
iris
a.f
r
160
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Les files (queue) et piles (stack)
Queue (1er arrivé, 1er servi)
Uniquement un constructeur
par défaut
Les éléments doivent avoir
les opérateur == et <=
Implémentation plutôt par
deque ou list
Stack (dernier arrivé, 1er servi)
Même contrainte que les files
Implémentation plutôt par
deque ou vector
#include <deque>
#include <queue> // pour les files
#include <stack> // pour les piles
using namespace std;
int main(int, char **){
stack<int,deque<int> > pile;
queue<int,deque<int> > file;
cout << "Ordre d'entree : ";
for (int j=0;j<5;j++) {
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()){
cout << pile.top() << " "; // accès au sommet
pile.pop(); // retire l’élément en sommet
}
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
}
}
Ordre d'entree : 1 7 4 0 9
Ordre de sortie pour la pile : 9 0 4 7 1
Ordre de sortie pour la file : 1 7 4 0 9
C++
eric.a
nq
uetil@
iris
a.f
r
161
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Conteneurs associatifs : set, map,
Les conteneurs (set et map) reposent sur la notion de paire(clef,valeur)
Les accès aux valeurs passent par les clefs
On peut alors extraire par exemple:
Les elts associés à une clef
Les elts dont la clef est sup/inf à une valeur, …
Les conteneurs set et map requièrent qu'il existe un ordre sur les clefs
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)
C++
eric.a
nq
uetil@
iris
a.f
r
162
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | Les ensembles (set)
Exemple d’utilisation de set
*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
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"};
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++
eric.a
nq
uetil@
iris
a.f
r
163
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 13 | 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";
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; }
}
** 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
C++
eric.a
nq
uetil@
iris
a.f
r
164
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 14 Objet foncteur 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 Element {
public:
int indice;
double diff;
int classe;
Element(int i,double d,int c):indice(i),diff(d),classe(c){}
};
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
};
class elt_decroissant { // objet fonction de type prédicat
public:
bool operator()( Element x, Element y) { return x.diff > y.diff; } // 2 paramètres
};
C++
eric.a
nq
uetil@
iris
a.f
r
165
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 14 | Les Objets fonction / operator()
Exemple d’utilisation / STL
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
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;
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;
}
}
find(indice=1) / diff = 22.1
diff(2) = 23.1
diff(1) = 22.1
diff(0) = 11.1
C++
eric.a
nq
uetil@
iris
a.f
r
166
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 14 | Les Objets fonction / operator() / fonction trier (sort)
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)
objet fonction (foncteur) less OrdreCroissant
Pour trier (avec sort) un vector v dans l'ordre croissant
template <typename Iter, typename Ofonc> void trier(const Iter& debut, const Iter& fin, const Ofonc& estAvant) { Iter i = debut; Iter j; while (i!=fin) { j=i; ++j; while (j!=fin) { if (estAvant(*j,*i)) std::swap(*i,*j); ++j; } ++i; } }
template <typename T> class OrdreCroissant { public: bool operator()(const T& a, constT & b) const { return a<b; } };
std::sort(v.begin(), v.end(), OrdreCroissant<int>());
std::sort(v.begin(), v.end());
eric.a
nq
uetil@
iris
a.f
r
167
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 15 Java : Flots (Stream)
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | Les flots(stream) en Java : java.io.*
Les entrées/sorties sont organisées autour des flots
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.
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.
Java
eric.a
nq
uetil@
iris
a.f
r
169
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | flots d'octets (8 bits)
import java.io.*;
class FlotOctet {
public static void main(String[] args) throws IOException {
InputStream in; // flot d'octets d'entree
OutputStream out; // flot d'octets de sortie
int octet;
if (args.length == 2) {
System.out.println("in : "+args[0]+" out : "+args[1]);
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();
out.close();
}
}
}
Exceptions transmises à la console
Lecture d'un octet
(8bits)
Rend -1 en fin de
fichier
Écriture d'un octet
(8bits)
Java
eric.a
nq
uetil@
iris
a.f
r
170
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | flots de char (16 bits)
import java.io.*;
class FlotCar {
public static void main(String[] args) throws IOException {
int car;
if (args.length == 1) {
InputStream in = System.in; // association du flot à l'entrée standard
OutputStream out = new FileOutputStream(args[0]); // flot sortie octet -> fichier
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)
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)
Conversion
flot d'octets
/
flots de char (unicode)
Entrée standard
Lecture d'un char
(unicode / 16 bits)
Java
eric.a
nq
uetil@
iris
a.f
r
171
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | flots de char avec tampon
import java.io.*;
class FlotBuffer {
public static void main(String[] args) throws IOException {
int car;
if (args.length == 2) {
System.out.println("in : "+args[0]+" out : "+args[1]);
InputStreamReader is = new FileReader(args[0]); // flot char <- fichier
OutputStreamWriter os = new FileWriter(args[1]); // flot char -> fichier
BufferedReader isb = new BufferedReader(is);
BufferedWriter osb = new BufferedWriter(os);
while ((car = isb.read()) != -1) {
osb.write(car); // lecture /ecriture (char)
System.out.println((char)car);
}
isb.close(); osb.close(); // fermeture du flot
}
}
}
Association directe
fichier
/
flots de char (unicode)
Utilisation d'un tampon
(buffer) pour optimiser le
coût des entrées/sorties
Beaucoup plus rapide !
Java
eric.a
nq
uetil@
iris
a.f
r
172
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | flots de données avec tampon
Lecture / Écriture de valeurs typées (données)
sur flot d'octets avec tampon
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));
char c1='\u01b5'; double d1=1.11;
osbd.writeChar(c1);osbd.writeDouble(d1);
osbd.close(); // fermeture du flot
System.out.println(isbd.readChar()+" "+ isbd.readDouble());
isbd.close(); // fermeture du flot
}}
Lecture de valeurs
typées
Écriture de valeurs typées : double, char,
float, etc.
Caractère unicode
Java
eric.a
nq
uetil@
iris
a.f
r
173
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | flots de données avec tampon
Écriture / Lecture sur flot de char (unicode)
avec tampon / écriture au format texte
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);
osb2.close(); // fermeture du flot
String uneLigne=isb2.readLine();
StringTokenizer st = new StringTokenizer(uneLigne);
System.out.println(st.nextToken()+ " "+ st.nextToken());
isb2.close(); // fermeture du flot
}}
Lecture d'une ligne de texte
séparation des elts de
la chaîne de texte
Écriture au format texte
Java
eric.a
nq
uetil@
iris
a.f
r
174
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | Les flots basiques : orientés byte (octet)
Java
eric.a
nq
uetil@
iris
a.f
r
175
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 15 | Les flots avancés : orientés char (Unicode)
Java
eric.a
nq
uetil@
iris
a.f
r
176
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 16 Java : Scanner
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 16 | Printf : Sortie standard formatée
Similaire à la fonction « C » printf !
Résultat
Formatage avancé
Cf. java.util.Formatter
float d1=1.1f;
float d2=2f;
System.out.printf("d1= %f et d2= %1.2f \n", d1,d2);
d1= 1,100000 et d2= 2,00
Java
eric.a
nq
uetil@
iris
a.f
r
178
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 16 | le scanner : entrée formatée
Sur l’entrée standard / Méthode next : blocante !
Sur un fichier
Définition de délimiteurs // StringTokenizer
Scanner s= new Scanner(System.in);
String entreString=s.next();
int entreInt=s.nextInt();
System.out.printf("entreString= %s et entreInt= %d \n",entreString,entreInt);
s.close();
< maChaine
< 2005
> entreString= maChaine et entreInt= 2005
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
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)
}
Java
eric.a
nq
uetil@
iris
a.f
r
179
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 17 Java : Sérialisation
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | introduction
Objectifs de la sérialisation d'un objet
Mécanisme permettant de stocker/d'exporter "automatiquement" un objet via
un flot dont le support peut être : un fichier, une socket, RMI, etc.
Avantages
Format des données d'exportation/importation géré par Java
Il n'est plus nécessaire de définir un format de stockage pour vos données
É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
Java
eric.a
nq
uetil@
iris
a.f
r
181
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | mise en œuvre automatique
Pour être sérialisable la classe d'un objet doit implémenter l'interface
java.io.Serializable
Interface de typage (balisage) sans méthode (idem à Cloneable)
Sérialisation et désérialisation des objets de cette classe
très simple avec les mécanismes par défaut.
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;
}
val: int
Info()
toString()
main()
Info
Java
eric.a
nq
uetil@
iris
a.f
r
182
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | mise en œuvre automatique
Gestion d'un flot de sortie d'objets sérialisés
la Classe : ObjectOutputStream
Constructeur
public ObjectOutputStream(OutputStream out) throws IOException
Méthodes d'écriture
public void writeObject(Object obj) throws IOException;
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; …
Java
eric.a
nq
uetil@
iris
a.f
r
183
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
eric.a
nq
uetil@
iris
a.f
r
Chap. 17 | un 1er exemple
Objets sérialisés et désérialisés dans un fichier
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"));
serialiseDsFichOut.writeObject("sauvegarde de l'objet I1");
serialiseDsFichOut.writeObject(I1);
serialiseDsFichOut.close(); // Vide la sortie
System.out.println("---- Deserialisation::lecture depuis le fichier ----");
// 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();
Info I1Bis = (Info) obj;
System.out.println("Info I1Bis: " + I1Bis);
}
}
constructeur Info(5)
Info I1: Info=5
---- Serialisation::sauvegarde dans un fichier ----
---- Deserialisation::lecture depuis le fichier ----
Info I1Bis: Info=5
val: int
Info()
toString()
main()
Info
Java
184
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | 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
Java
eric.a
nq
uetil@
iris
a.f
r
185
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | un 2ème exemple
Gestion automatique des références
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()");
}
public String toString() {
String s = "ListInfo(";
s += " " + info;
s += ") ";
if (suivant != null) {s += suivant;}
return s;
}
}
val: int
Info(in int): void
toString(): String
main(in String[]): void
Info
suivant: ListInfo
info: Info
ListInfo(in int): void
ListInfo(): void
toString(): String
ListInfo
- suivant0..1
- info
0..1
Serializable
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
186
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
eric.a
nq
uetil@
iris
a.f
r
Chap. 17 | un 2ème exemple
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 ----");
// 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);
}}
val: int
Info(in int): void
toString(): String
main(in String[]): void
Info
suivant: ListInfo
info: Info
ListInfo(in int): void
ListInfo(): void
toString(): String
ListInfo
- suivant0..1
- info
0..1
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)
Serializable
Serializable
Java
187
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | mise en œuvre manuelle
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
Sauvegarde partielle de l'objet, ou des sous objets qui le composent, etc.
L'interface Externalizable
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
Java
eric.a
nq
uetil@
iris
a.f
r
188
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | 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 + ")");
}
public String toString() {
String texte = "InfoExt=";
texte += Integer.toString(valP);
return texte;
}
public void writeExternal(ObjectOutput objOut) throws IOException {
objOut.writeInt(valP);
}
public void readExternal(ObjectInput objIn) throws IOException, ClassNotFoundException {
valP = objIn.readInt();
}
}
valP: int
InfoExt(): void
toString(): String
writeExternal(in ObjectOutput): void
readExternal (in ObjectInput): void
InfoExt
Externalizable
Java
eric.a
nq
uetil@
iris
a.f
r
189
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : manuelle / exemple
Résultat de l'exécution avec le même Main
valP: int
InfoExt(): void
toString(): String
writeExternal (in ObjectOutput): void
readExternal(in ObjectInput): void
InfoExt
infoP: InfoExt
suivant: ListInfo
ListInfo(in int): void
ListInfo(): void
toString(): String
main(in String[]): void
ListInfo
- suivant0..1
- infoP
0..1
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)
constructeur InfoExt(7)
constructeur InfoExt(0)
constructeur InfoExt(8)
constructeur InfoExt(9)
ListInfo l1Bis:
ListInfo( InfoExt=0 ) ListInfo( InfoExt=1 ) ListInfo( InfoExt=5 ) ListInfo( InfoExt=6 ) ListInfo( InfoExt=1 )
// attention, avec un objet Externalizable
// il y a appel au constructeur par défaut !
// qui doit donc être accessible !!
Externalizable
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
190
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : partiellement manuelle / transient
Sérialisation automatique avec restriction sur les infos sensibles
Pour des problèmes de sécurité :
données sensibles à ne pas sauvegarder (sérialiser)
Restriction sur la sérialisation automatique (Serializable)
avec le mot clé "transient"
Empêche la sauvegarde/restauration des champs étiquetés "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;
}
public String toString() {
String texte = "InfoSerRes=";
texte += Integer.toString(val);
texte += "," + motDePasse;
return (texte);
}
}
val: int
motDePasse: String
InfoSerRes(in int, in String): void
toString(): String
InfoSerRes
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
191
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : partiellement manuelle / transient
Résultat de l'exécution avec le même Main
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 )
val: int
motDePasse: String
InfoSerRes(in int, in String): void
toString(): String
InfoSerRes
infoSerR: InfoSerRes
suivant: ListInfo
ListInfo(in int): void
ListInfo(): void
toString(): String
ListInfo
- suivant0..1
- infoSerR
0..1
Serializable
transient
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
192
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : partiellement manuelle / Serializable
Une autre approche à Externalizable
Sérialisation automatique "Serializable"
avec ajout de méthodes prédéfinies
Attention à bien respecter la signature des méthodes
méthodes appelées automatiquement
à la place de la sérialisation par défaut
private void writeObject(ObjectOutputStream objOutSt)
throws IOException
private void readObject(ObjectInputStream objInSt)
throws IOException, ClassNotFoundException
Java
eric.a
nq
uetil@
iris
a.f
r
193
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : partiellement manuelle / Serializable
public class InfoSerModif implements Serializable {
private int val;
transient private String motDePasse;
public InfoSerModif(int v, String m) {
System.out.println("constructeur InfoSerModif(" + v + " " + m + ")");
val = v;
motDePasse = m;
}
public String toString() {
String texte = "InfoSerModif=";
texte += Integer.toString(val);
texte += "," + motDePasse;
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();
}
}
val: int
motDePasse: String
InfoSerModi f(in int, in String): void
toString(): String
writeObject(in ObjectOutputStream): void
readObject(in ObjectInputStream): void
InfoSerModif
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
194
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : manuelle / exemple
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 )
val: int
motDePasse: String
InfoSerModi f(in int, in String): void
toString(): String
writeObject(in ObjectOutputStream): void
readObject(in ObjectInputStream): void
InfoSerModif
infoSerM: InfoSerModi f
suivant: ListInfo
ListInfo(in int): void
ListInfo(): void
toString(): String
ListInfo
- suivant0..1
- infoSerM
0..1
Serializable Serializable
transient
Java
eric.a
nq
uetil@
iris
a.f
r
195
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | un premier Bilan
Serializable
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)
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)
Java
eric.a
nq
uetil@
iris
a.f
r
196
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : les données statiques
La sérialisation des données statiques
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)
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
Java
eric.a
nq
uetil@
iris
a.f
r
197
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : les données statiques / exemple
public class InfoStatic implements Serializable {
public static int NB = 0; public final int numero; public InfoStatic() {
NB++; numero = NB;
System.out.println(
"constructeur InfoStatic : num("
+ numero + ") nb(" + NB + ")"); }
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);
} }
NB: int
numero: int
InfoStatic(): void
toString(): String
serializeStaticObject(in ObjectOutputStream): void
deserial izeStaticObject(in ObjectInputStream): void
InfoStatic
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
198
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : les données statiques / exemple
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);
}
NB: int
numero: int
InfoStatic(): void
toString(): String
serializeStaticObject(in ObjectOutputStream): void
deserial izeStaticObject(in ObjectInputStream): void
InfoStatic
infoStatic: InfoStatic
suivant: ListInfo
ListInfo(in int): void
ListInfo(): void
toString(): String
main(in String[]): void
ListInfo
- suivant0..1
- infoStatic
0..1
Serializable
Serializable
Java
eric.a
nq
uetil@
iris
a.f
r
199
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 17 | Sérialisation : les données statiques / exemple
Résultats
NB: int
numero: int
InfoStatic(): void
toString(): String
serializeStaticObject(in ObjectOutputStream): void
deserial izeStaticObject(in ObjectInputStream): void
InfoStatic
infoStatic: InfoStatic
suivant: ListInfo
ListInfo(in int): void
ListInfo(): void
toString(): String
main(in String[]): void
ListInfo
- suivant0..1
- infoStatic
0..1
Serializable
Serializable
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 )
Java
eric.a
nq
uetil@
iris
a.f
r
200
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 18 Java : Masquage
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 18 | Redéfinition et surcharge
Pas de masquage
ni pour la surcharge
ni pour la redéfinition
B
f() f(int i)
D2
f()
D1
f(int,int)
D0
public class B {
public void f(){ System.out.println ("B.f()"); }
public void f(int i) { System.out.println("B.f(int i)"); }
public static void main(String args[]) {
….
}
}
class D0 extends B {};
class D1 extends B {
public void f(int i, int j){
System.out.println("D1.f(int i, int j)");
}
}
class D2 extends B {
public void f(){ // extension
super.f();
System.out.println("D2.f()");
}
}
Java
eric.a
nq
uetil@
iris
a.f
r
202
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 18 | Redéfinition et surcharge
public class B {
public void f() { System.out.println ("B.f()"); }
public void f(int i) { System.out.println("B.f(int i)"); }
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();
System.out.print( "objet_B.f() "); objet_B.f();
System.out.print( "objet_B.f(2) "); objet_B.f(2);
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);
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);
}
}
B
f() f(int i)
D2
f()
D1
f(int,int)
D0
objet_B.f() B.f()
objet_B.f(2) B.f(int i)
objet_D0.f() / heritage : B.f()
objet_D0.f(1) / heritage : B.f(int i)
objet_D1.f(1,2) / Surcharge : D1.f(int i, int j)
objet_D1.f(1) / pas de masquage: B.f(int i)
objet_D2.f() / Redefinition : B.f()
D2.f()
objet_D2.f(1) / pas de masquage: B.f(int i)
Java
eric.a
nq
uetil@
iris
a.f
r
203
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 19 RTTI : Run Time Type Identification
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 19 | RTTI et Java : getClass / getName / forName / newInstance
La 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
La 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") ;
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() ;
*cf. clonage
Java
eric.a
nq
uetil@
iris
a.f
r
205
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 19 | RTTI et C++ : type_info / typeid
RTTI : Run Time Type Identification
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 « == », « != »
C++
#include <iostream>
#include <typeinfo> // à inclure pour l’accès au RTTI
using namespace std;
class A {};
class B {};
int main(int, char **){
A a;
A* pa = new A;
B b;
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;
}
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
eric.a
nq
uetil@
iris
a.f
r
206
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 19 | RTTI et C++ : dynamic Cast
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.
class A {
public: // au moins une fonction virtuelle pour avoir des classes polymorphes
virtual void type() { cout << typeid(*this).name()<<endl; } };
class C : public A {};
class D : public A {};
class E : public C {};
int main(int, char **){
vector <A*> VeltA; vector <C*> VeltC; vector <E*> VeltE;
srand(time(0));
int nbA(0),nbC(0),nbE(0);
int cpt=rand()%10; for (int i=0; i< cpt; i++) {VeltA.push_back(new A);}
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);}
for (int ii=0; ii<VeltA.size(); ii++) {
VeltA[ii]->type();
if (dynamic_cast<A*>(VeltA[ii])){nbA++;}
C* pC=dynamic_cast<C*>(VeltA[ii]); // downcast
if (pC) {nbC++; VeltC.push_back(pC);}
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; }
class A
class A
class A
class A
class C
class C
class C
class E
class E
class E
nbA :10
nbC :6
nbE :3
B
E
CD
A
C++
eric.a
nq
uetil@
iris
a.f
r
207
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 20 Java : Egalité & Comparaison d'objet
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Égalité d'objets
Opérateur ==
Teste l’égalité des références (identificateurs) des objets
Ne considère jamais l’égalité du contenu d’un objet
String s ="coucou";
if (s == "coucou") … // 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 ; } ... }
Java
eric.a
nq
uetil@
iris
a.f
r
209
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Égalité d'objets (surcharge de equals)
Ecriture d’un opérateur equals
Possibilité de le surcharger
=> pas de polymorphisme
+ Rectangle()
Rectangle
+ Point()
+ clone()
+ deplacer()
+ dessiner()
+ dilater()
+ equals()
+ main()
+ x()
+ y()
Point
- deplacer()
- dessiner()
- dilater()
Figure
+ Ellipse()
+ centre()
+ deplacer()
+ dessiner()
+ dilater()
+ xrayon()
+ yrayon()
Ellipse
+ Polygone()
+ coin()
+ deplacer()
+ dessiner()
+ dilater()
+ set_coin()
Polygone
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))); } } }
false
false
false
false
.............
false
true
Java
eric.a
nq
uetil@
iris
a.f
r
210
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Égalité d'objets (redéfinition de equals)
Ecriture d’un opérateur equals
Possibilité de le redéfinir / class Object
=> polymorphisme
+ Rectangle()
Rectangle
+ Point()
+ clone()
+ deplacer()
+ dessiner()
+ dilater()
+ equals()
+ main()
+ x()
+ y()
Point
- deplacer()
- dessiner()
- dilater()
Figure
+ Ellipse()
+ centre()
+ deplacer()
+ dessiner()
+ dilater()
+ xrayon()
+ yrayon()
Ellipse
+ Polygone()
+ coin()
+ deplacer()
+ dessiner()
+ dilater()
+ set_coin()
Polygone
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))); }}}
false
false
false
true
.............
false
true
Java
eric.a
nq
uetil@
iris
a.f
r
211
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Comparaison d'instances et héritage
Comparaison d'instances de classes différentes reliées par héritage
Comparaison rigide
vérifie si pour deux objets de même type leurs attributs sont tous égaux.
Comparaison souple
permet d'établir si deux objets sont comparables ; c'est-à-dire, s'il existe un
lien "d'héritage" entre ces deux objets et si tous les attributs qu'ils possèdent
en commun sont égaux.
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
Java
eric.a
nq
uetil@
iris
a.f
r
212
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Comparaison rigide : méthode equals()
Principe :
Vérifier le type des
instances : getClass()
Vérifier l'égalité des
attributs :
primitifs (==)
relation (==)
agrégation forte
(equals).
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; }
} }
Méthode de comparaison
des attributs
Vérification du type de l'objet
puis
Comparaison des attributs
Java
eric.a
nq
uetil@
iris
a.f
r
213
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Comparaison rigide
Exemple d'utilisation
public static void main(String[] args){
Mammifere M1=new Mammifere(170, 70);
Mammifere M2=new Mammifere(170, 59);
Mammifere M3=new Mammifere(M1);
String Str1=new String("toto");
System.out.println(M1.equals(Str1));
System.out.println(M1.equals(M2));
System.out.println(M2.equals(M3));
System.out.println(M1.equals(M3));
System.out.println(M1.equals(M1));
}
}
false
false
false
true
true
Java
eric.a
nq
uetil@
iris
a.f
r
214
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Comparaison souple : méthode comparable()
Principe :
gérer les liens d'héritage :
instanceof()
Vérifier l'égalité des sous
attributs communs:
primitifs (==)
relation (==)
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 }
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;
}}
Comparable en tant que Mammifère ?
Comparable en tant qu'Homme ?
Java
eric.a
nq
uetil@
iris
a.f
r
215
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | Comparaison : exemple de diagramme de classe
Java
eric.a
nq
uetil@
iris
a.f
r
216
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 20 | 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)); // erreur a la compilation
System.out.println(Sg1.comparable(Sg2)); //false
System.out.println(Sg1.comparable(M1)); //true
System.out.println(M1.comparable(Sg1)); //true
System.out.println(Sg1.equals(H1)); //false
System.out.println(H1.equals(H2)); //false
System.out.println(H1.comparable(Sg1)); //true
System.out.println(Sg1.comparable(H1)); //true
System.out.println(Sg1.comparable(H2)); //false
System.out.println(Sg1.comparable(M1)); //true
System.out.println(H1.comparable(Sg2)); //true }
Java
eric.a
nq
uetil@
iris
a.f
r
217
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 21 Interopérabilité : dll & .net
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Deux mots sur .net et 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
Infrastructure) pour exécuter du code CIL (Common Intermediate
Langage) de façon managé (compilation à la volée : « just in time »)
Exemple de langage supporté C++/CLI, C#, …
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é : ^
C++
eric.a
nq
uetil@
iris
a.f
r
219
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Introduction à l’interopérabilité
Mixer du code natif C++ avec du code managé (.net)
Si on dispose des sources natives C++
Mixer directement les sources natives C++ avec le C++/CLI.
Si on veut intégrer une Dll native C++, sans la modifier
Création d'un wrapper en C++/CLI
Le Wrapper est utilisable dans n'importe quel langage .Net
Interface unique en .net d'accès à la bibliothèque
Utilisation d’outils pour automatiser la création du Wrapper
Swig (http://www.swig.org).
Une alternative avec la technologie COM
COM interop, le wrapper est généré automatiquement.
eric.a
nq
uetil@
iris
a.f
r
220
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Mixer du C/C++ avec le C++/CLI au niveau des sources
Mise en œuvre simple : mécanisme IJW (It Just Works)
Intégration des sources de classes C++ / méthodes C
dans une même application .Net développée en C++/CLI
crée d’une application CLR console (C++ managé)
en mode de compilation mixte (/clr)
chaque transition entre le monde managé et non
managé est couteuse.
=> limiter les transitions
class Coordonnee // code C++ « Coordonnee.h"
{
public:
Coordonnee(int x, int y);
Coordonnee();
void setX(int x);
void setY(int y);
double getX();
double getY();
double distance(const Coordonnee &P);
Coordonnee milieu(const Coordonnee &P);
void saisir();
void affiche();
private:
int Cx,Cy;
};
// AppCLR_consol.cpp : fichier projet principal.
#include "stdafx.h"
#include "Coordonnee.h"
using namespace System;
int main(array<System::String ^> ^args)
{
Coordonnee c1(10,10);
c1.affiche();
return 0;
}
eric.a
nq
uetil@
iris
a.f
r
221
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | DLL C++ : Dynamic Link Library
Création d’une DLL C++
Choisir « DLL » comme type d'application
Ajouter les entêtes des fonctions/classes exportées
L'utilisation de « extern "C"» permet d'avoir un nom de
fonction non décoré (cf. utilitaires: dumpbin.exe, dependency walker)
Après compilation et édition de liens, on obtient :
un fichier ModeleCpp.lib et un fichier ModeleCpp.dll
#include <vector>
#include <iostream>
#include "Coordonnee.h"
using namespace std;
class __declspec(dllexport) Tir {
private:
vector<Coordonnee> tabDeCoord;
public:
void add(int x,int y);
void affiche();
};
extern "C" __declspec(dllexport) Tir* Tir_New();
extern "C" __declspec(dllexport) void Tir_Delete(Tir* tdC);
.h
#include "Tir.h"
void Tir::add(int x,int y) { tabDeCoord.push_back(Coordonnee(x,y)); }
void Tir::affiche() {
vector<Coordonnee>::iterator i;
for(i=tabDeCoord.begin(); i!=tabDeCoord.end(); i++) {
((*i).affiche());
cout << "|";
}
cout << endl;
}
extern "C" __declspec(dllexport) Tir* Tir_New(){ return new Tir();}
extern "C" __declspec(dllexport) void Tir_Delete( Tir* tdC){ delete tdC; }
.cpp
eric.a
nq
uetil@
iris
a.f
r
222
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | DLL C++ : Commandes de pré-compilation
Utiliser les commandes de pré-compilation
pour partager les mêmes sources entre 2 projets
1 projet C++ classique #undef WANTDLLEXP
1 projet C++ DLL #define WANTDLLEXP
#ifdef WANTDLLEXP //exportation dll
#define DLL __declspec( dllexport )
#define EXTERNC extern "C"
#else
#define DLL //standard
#define EXTERNC
#endif
class DLL Tir
{
private:
vector<Coordonnee> tabDeCoord;
public:
void add(int x,int y);
void affiche();
};
EXTERNC DLL Tir* Tir_New();
EXTERNC DLL void Tir_Delete(Tir* tdC);
.h
eric.a
nq
uetil@
iris
a.f
r
223
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Wrapper C++/CLI
Objectif
Utiliser des méthodes depuis des dll existantes (C++).
ne pas toucher aux bibliothèques existantes
Créer une assembly en C++/CLI qui englobe la bibliothèque existante
le C++/CLI est le langage idéal pour gérer l'intéropérabilité
Wrapper utilisable dans n'importe quel langage .Net
interface unique en .net d'accès à la bibliothèque
Comment wrapper la classe Tir ?
Créer une interface d'utilisation pour la classe Tir
de notre DLL C++ (ModeleCpp.dll) en C++ managé (CLR)
Créer un projet CLR class library (mWrapper.dll)
L’assembly wrapper = Classe WrapperTir
Inclure le .h et le .lib de la DLL dans la classe wrapper (WrapperTir)
La classe wrapper doit être publique
pour que les autres langages .net puissent l'utiliser
eric.a
nq
uetil@
iris
a.f
r
224
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Création de la classe Wrapper en C++ managé
Classe WrapperTir
Un pointeur (membre privé) vers notre objet natif (Tir* tDCw).
Un constructeur : sert à appeler le constructeur de Tir dans notre dll.
Un destructeur et un finalizer : sert à appeler le destructeur dans notre dll.
C'est le garbage collector qui s'occupera d'appeler le finalizer ou le
destructeur, et permettra ainsi la libération des ressources utilisées.
Méthodes add et affiche qui appellent les méthodes de notre classe.
// mWrapper.h
#include "Tir.h"
#pragma comment (lib,"ModeleCpp.lib")
using namespace System;
namespace mWrapper {
public ref class WrapperTir {
private:
Tir* tDCw;
public:
WrapperTir(){ tDCw=Tir_New(); }
~WrapperTir(){ Tir_Delete(tDCw); }
System::Void add(int x,int y){ tDCw->add(x,y); }
System::Void affiche(){ tDCw->affiche();}
protected:
!WrapperTir(){ Tir_Delete(tDCw);}
};
}
eric.a
nq
uetil@
iris
a.f
r
225
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Utilisation de la classe Wrapper en C++ managé pure
Création d’un projet de test :TestWrapperCLR
De type: Application console CLR
Prise en charge du Common Language Runtime MSIL pure (/clr:pure)
Référencer l’assembly
Propriété propriété commune structure et référence
// TestWrapperCLR.cpp : fichier projet principal.
#include "stdafx.h"
using namespace System;
using namespace mWrapper;
int main(array<System::String ^> ^args)
{
WrapperTir^ mtir = gcnew WrapperTir();
mtir->add(10, 10);
mtir->affiche();
return 0;
}
eric.a
nq
uetil@
iris
a.f
r
226
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Utilisation de la classe Wrapper en C#
Création d’un projet de test : TestWrapperCS
De type Application console c#
Référencer l’assembly
Ajouter une référence à mWrapper
Il faut que la dll soit accessible à l’exécution du programme
// Program.cs.
using System;
using mWrapper;
namespace TestWrapperCS
{
class Program
{
static void Main(string[] args)
{
WrapperTir mtir = new WrapperTir();
mtir.add(10, 10);
mtir.affiche();
}
}
}
eric.a
nq
uetil@
iris
a.f
r
227
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Récapitulatif
DLL C++ ModeleCpp
Exporte:
Classe Tir
Méthode : Tir* Tir_New();
void Tir_Delete(Tir* tdC);
DLL C++/CLI mWrapper
Exporte:
Classe WrapperTir
Attribut Tir* tDCw
Méthode : WrapperTir()
Void add(int x,int y)
Void affiche()
!WrapperTir
~WrapperTir(){
Exe C# TestWrapperCS
eric.a
nq
uetil@
iris
a.f
r
228
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Notion sur le Marshalling (conversion de type)
Gérer la conversion des types entre le monde managé et non managé
Pas besoin de conversion pour certains types
Types blittables
types qui ont une représentation commune à la fois dans le monde
managé et natif. (Byte, Int16, IntPtr, etc ...)
Pour les autres, il faut faire la conversion
Exemple
convertir une String ^ en string de la STL ?
static string convertStringToStlString (String^ chaine)
{
char * chaineChar;
pin_ptr<const wchar_t> wch = PtrToStringChars(chaine);
int taille = (chaine->Length+1) * 2;
chaineChar = new char[taille];
int t = WideCharToMultiByte(CP_ACP, 0, wch, taille, NULL, 0, NULL, NULL);
WideCharToMultiByte(CP_ACP, 0, wch, taille, chaineChar, t, NULL, NULL);
std::string chaineSTL = chaineChar;
delete chaineChar;
return chaineSTL;
}
eric.a
nq
uetil@
iris
a.f
r
229
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Outils pour automatiser la création du Wrapper (SWIG)
SWIG (Simplified Wrapper and Interface Generator)
http://www.swig.org/
SWIG utilise un fichier interface pour définir
les fonctions qui seront wrappées
les différentes informations nécessaires comme les types, les structures, etc.
Gestion du Marshalling/conversion (de la STL …)
NB: le Wrapper sera généré en code C# avec une autre stratégie
DllImport et Pinvoke (Plateform Invoke)
Interface C#
API en C#
Wrapper en C#
DLL SWIG
En C++
DLL à wrapper
En C/C++
Liens créés par SWIG
SWIG
SWIG
SWIG
Créé par l’utilisateur
Créé par SWIG
eric.a
nq
uetil@
iris
a.f
r
230
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Test de la DLL C++ : Classes Coordonnée et Tir
DLL C++ : 2 Classes C++ enrichies (utilisation d’un vector)
#pragma once // Tir.h
#include <vector>
#include <iostream>
#include "Coordonnee.h"
using namespace std;
class __declspec( dllexport ) Tir {
private:
vector<Coordonnee> tabDeCoord;
public:
void add(int x,int y);
void add(vector<Coordonnee>& tabc);
void affiche();
};
#pragma once // Coordonnee.h
class __declspec( dllexport ) Coordonnee {
public:
Coordonnee(int x, int y);
Coordonnee();
void setX(int x);
void setY(int y);
double getX();
double getY();
double distance(const Coordonnee &P);
Coordonnee milieu(const Coordonnee &P);
void saisir();
void affiche();
private:
int Cx,Cy;
};
eric.a
nq
uetil@
iris
a.f
r
231
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Swig : Configuration
Fichier interface de Swig
/* Tir_csharpWrapper.i */
%module m_Tir
%include "std_vector.i"
%include "std_string.i"
%{
#include "Coordonnee.h"
#include "Tir.h"
%}
namespace std {
%template(vector_co) vector<Coordonnee>;
}
%include "Coordonnee.h"
%include "Tir.h"
#pragma once // Tir.h
#include <vector>
#include <iostream>
#include "Coordonnee.h"
using namespace std;
class Tir {
private:
vector<Coordonnee> tabDeCoord;
public:
void add(int x,int y);
void add(vector<Coordonnee>& tabc);
void affiche();
};
#pragma once // Coordonnee.h
class Coordonnee {
public:
Coordonnee(int x, int y);
Coordonnee();
void setX(int x);
void setY(int y);
double getX();
double getY();
double distance(const Coordonnee &P);
Coordonnee milieu(const Coordonnee &P);
void saisir();
void affiche();
private:
int Cx,Cy;
};
Nom du module == nom de la DLL : m_Tir.dll == nom de l’API CS : m_Tir.cs
prévenir SWIG qu’il doit charger les fichiers interface prédéfinis
Fichier à wrapper (sans les entêtes d’exportation)
spécifier que l’on a besoin du type vector<Coordonnee>, cas particulier des définitions apportées par SWIG.
eric.a
nq
uetil@
iris
a.f
r
232
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 21 | Swig: Génération & Tests
On lance la commande
swig.exe -makedefault -csharp -c++ -v Tir_csharpWrapper.i
Pour faire la DLL C++: m_Tir
API et Wrapper C# à inclure dans le
projet C# TestCsSwig
1 / Fichiers générés par SWIG 2/ Projets Visual à créer
2/ DLL C++ Swig
1/ DLL C++
3/ Prog C# de test static void Main(string[] args) {
Tir tir1 = new Tir();
tir1.add(2, 4);
tir1.affiche();
vector_co v = new vector_co();
v.Add(new Coordonnee(5, 8));
v.Add(new Coordonnee(7, 10));
tir1.add(v);
tir1.affiche();
Console.ReadKey();
}
3/ Test du résultat : Utilisation de la DLL en C#
eric.a
nq
uetil@
iris
a.f
r
233
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 22 WPF : Introduction
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Présentation de Wpf (Windows Presentation Foundation)
Technologie de développement d’interface utilisateur
Application riche pour Windows
Orientée Objet et basée sur la plateforme .NET
Cible aussi les navigateurs internet
XBAP (Xaml Browser Application) Windows
Silverlight multiplateforme
Caractéristiques
Unifier les techniques de développement d’interfaces
Affichage vectoriel, mise à l’échelle sans pixellisation…
Composition graphiques vectorielles 2D et 3D
Utilise les processeurs graphiques GPU, basé sur Direct3D (DirectX)
Images, animations, flux multimédia, audio et vidéo, document texte…
Inconvénients : manque encore d’interopérabilité
Dépend du portage de .NET sur les autres systèmes: mono
mono ne supporte actuellement pas le WPF…
Solution émergente Silverlight, WPF pour les applications web .NET
portage réalisé : Moonlight…
eric.a
nq
uetil@
iris
a.f
r
235
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF : code behind / code designer
Principe de WPF
Séparation
du code behind (développeur)
Fonctionnalités codées en .NET (C#...)
Outils : Visual Studio ou …
du code designer (infographiste)
Présentation Visuel décrite en XAML
(eXtensible Application Markup Language)
Outils : Expression Blend, Visual Studio, XamlPad.exe,…
eric.a
nq
uetil@
iris
a.f
r
236
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | XAML (eXtensible Application Markup Language)
Langage déclaratif basé sur la syntaxe du XML
Permet de déclarer et définir des objets dynamiquement grâce à
des balises (équivalent des classes)
et aux attributs (équivalents aux propriétés).
Restitution de graphiques vectoriels, 2D ou 3D…
Respecter la casse
Les balises ouvertes doivent être refermées sans se chevaucher
Chaque attribut doit avoir une valeur inscrite entre " ou ’
Exemple
<Window x:Class="WpfApplicationCours.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ExempleCours" Height="350" Width="525">
<Grid>
<TextBlock Text="Champ texte = Label / WPF" />
<Button Content="Cliquez ici 1!" MaxHeight="50" MaxWidth="100" />
</Grid>
</Window>
eric.a
nq
uetil@
iris
a.f
r
237
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Visual Studio : 1ère application wpf / Xaml
Une 1ère application sous Visual Studio
eric.a
nq
uetil@
iris
a.f
r
238
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Visual Studio : Xaml/c# - Réalisation d'une action
Le gestionnaire d'événements pour l'événement de clic sera ajouté au codebehind de votre classe
l'événement de clic sera connecté à votre balisage XAML
On a un délégué explicitement déclaré connecté à un événement sur un objet et le délégué pointe vers une méthode de gestion. e
ric.a
nq
uetil@
iris
a.f
r
239
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF : Disposition des contrôles WPF dans une fenêtre
Les différents Panels
Le contrôle StackPanel.
Présente les éléments
en les empilant
Le contrôle WrapPanel.
les éléments vont être positionnés les uns après les autres
Le contrôle DockPanel.
permet de « docker » sur ses bordures, les éléments qui le composent.
Les contrôles Grid et GridSplitter.
dispose les éléments
dans une grille
GridSplitter : permet en
plus de choisir la taille
d’une cellule
eric.a
nq
uetil@
iris
a.f
r
240
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF: le contrôle Canvas / un petit exemple
Le contrôle Canvas
Permet de positionner un contrôle grâce à des coordonnées X et Y
en DIP (Device Independent Pixel)
Le code designer Xaml
<Window x:Class="WpfJeu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Canon Noir" Height="650" Width="840">
<Canvas Name="canvas1" MouseLeftButtonDown="MouseDown">
<Image Margin="10,10,10,10" Width="800" Stretch="UniformToFill" Name="plateau"
Source="/WpfJeu;component/Resources/plateau.jpg" />
<Button Canvas.Top="70" Canvas.Left="250" Name="Canon" Click="ClickC">
<StackPanel Orientation="Vertical">
<Image Height="43" Source="/WpfJeu;component/Resources/canon.jpg" Width="47" />
<TextBlock Text="Canon" HorizontalAlignment="Center" FontSize="10" />
</StackPanel>
</Button>
</Canvas>
</Window>
eric.a
nq
uetil@
iris
a.f
r
241
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF: un petit exemple
Le code behind
namespace WpfJeu
{
/// <summary>
/// Logique d'interaction pour MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow() {
InitializeComponent();
}
private void ClickC(object sender, RoutedEventArgs e) {
// Affichage d’une MessageBox avec les coordonnées du bouton Canon
MessageBox.Show("BOUMM ! (" + Canvas.GetLeft(Canon) + "," + Canvas.GetTop(Canon) + ")");
}
private void MouseDown(object sender, MouseButtonEventArgs e) {
// On récupère la position du MouseDown
Point pt = e.GetPosition(canvas1);
// On déplace le Bouton à ces coordonnées
Canvas.SetLeft(Canon, pt.X );
Canvas.SetTop(Canon, pt.Y);
}
}
}
eric.a
nq
uetil@
iris
a.f
r
242
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF: liaison avec une Dll C++
Liaison à la Dll mWrapper using mWrapper;
namespace WpfJeu
{
public partial class MainWindow : Window {
WrapperTir tDC;
public MainWindow() {
InitializeComponent();
// Création de notre Objet Tir via le Wrapper
tDC = new WrapperTir();
}
private void ClickC(object sender, RoutedEventArgs e) {
// Affichage d’une MessageBox avec les coordonnées du bouton Canon
MessageBox.Show("BOUMM ! (" + Canvas.GetLeft(Canon) + "," + Canvas.GetTop(Canon) + ")");
// affichage dans la console des données enregistrées
tDC.affiche();
}
private void MouseDown(object sender, MouseButtonEventArgs e) {
// On récupère la position du MouseDown
Point pt = e.GetPosition(canvas1);
//On ajoute ces coordonnées dans notre structure (DLL C++)
tDC.add((int)pt.X, (int)pt.Y);
// On déplace le Bouton à ces coordonnées
Canvas.SetLeft(Canon, pt.X );
Canvas.SetTop(Canon, pt.Y);
}
}
}
eric.a
nq
uetil@
iris
a.f
r
243
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | WPF: une 1ère idée sur le data binding
But du data binding
permettre de lier un contrôle avec une ou plusieurs sources de données.
le contrôle va définir le binding = la cible
la source de données = la source
Plusieurs configurations possibles pour la mise à jour automatique
méthodes dîtes OneWay, OneTime, TwoWay…
mettre à jour le contrôle et la source dés qu’un des deux est modifié,
ou seulement un seul…
C’est un vaste sujet qu’il faut approfondir …
Cf. http://www.dotnet-france.com/Cours/70-502.html
<Canvas Name="canvas1" MouseLeftButtonDown="MouseDown">
<TextBox Text="{Binding ElementName=Canon, Path=IsMouseOver, Mode=OneWay}" IsReadOnly="True" />
<Image Margin="20,30,10,10" Width="800" Stretch="UniformToFill" Name="plateau"
Source="/WpfJeu;component/Resources/plateau.jpg" />
<Button Canvas.Top="70" Canvas.Left="250" Name="Canon" Click="ClickC">
<StackPanel Orientation="Vertical">
<Image Height="43" Source="/WpfJeu;component/Resources/canon.jpg" Width="47" />
<TextBlock Text="Canon" HorizontalAlignment="Center" FontSize="10" />
</StackPanel>
</Button>
</Canvas>
La source L’évènement sur la source
La cible Le mode
eric.a
nq
uetil@
iris
a.f
r
244
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Aperçu des événements routés
Arborescences d'éléments WPF
Arborescence d'éléments logiques
et visuels (souvent bien plus compliquée)
Routage d'événements
Stratégies de routage à partir de l'arborescence visuelle.
Les événements bulle (Buddling)
Un événement monte le long de l'arborescence visuelle à partir de
l'élément source tant qu'il n'est pas traité ou n'a pas atteint la racine.
Le nom des événements Bubble indique simplement leur action (MouseDown).
Les événements tunnel (Tunneling)
Procèdent dans le sens inverse, depuis l'élément racine jusqu'à ce qu'ils
soient traités ou jusqu'à ce qu'ils atteignent l'élément source.
Permet à des éléments en amont d'intercepter l'événement et de le traiter
avant qu'il n'atteigne l'élément source.
Le nom des événements tunnel comprend le préfixe Preview (PreviewMouseDown).
Les événements directs
Le seul gestionnaire pour l'événement est un délégué connecté à
l'événement.
private void ClickC(object sender, RoutedEventArgs e) {
eric.a
nq
uetil@
iris
a.f
r
245
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Routage d'événements
Illustration du routage d’évènements private void MouseRightDown_canvas(object sender, MouseButtonEventArgs e){
// Affichage du routage provenant du Canvas
routage.Items.Add("MouseRD_canvas");
}
private void MouseRightDown_Button(object sender, MouseButtonEventArgs e){
// Affichage du routage provenant du Button
routage.Items.Add("MouseRD_Button");
}
private void MouseRightDown_Image(object sender, MouseButtonEventArgs e){
// Affichage du routage provenant du Image
routage.Items.Add("MouseRD_Image");
} …
<Canvas Name="canvas1" MouseLeftButtonDown="MouseDown" MouseRightButtonDown="MouseRightDown_canvas" PreviewMouseRightButtonDown="PreviewMouseRightDown_canvas">
<TextBox Text="{Binding ElementName=Canon, Path=IsMouseOver, Mode=OneWay}" IsReadOnly="True" /> <Image Margin="170,30,10,10" Width="800" Stretch="UniformToFill" Name="plateau" Source="/WpfJeu;component/Resources/plateau.jpg" />
<Button Canvas.Top="70" Canvas.Left="250" Name="Canon" Click="ClickC" MouseRightButtonDown="MouseRightDown_Button" PreviewMouseRightButtonDown="PreviewMouseRightDown_Button"> <StackPanel Orientation="Vertical"> <Image Height="43" Source="/WpfJeu;component/Resources/canon.jpg" Width="47" MouseRightButtonDown="MouseRightDown_Image" PreviewMouseRightButtonDown="PreviewMouseRightDown_Image" />
<TextBlock Text="Canon" HorizontalAlignment="Center" FontSize="10" /> </StackPanel> </Button> <ListBox Canvas.Left="10" Canvas.Top="30" Height="293" Name="routage" Width="143" /> </Canvas> e
ric.a
nq
uetil@
iris
a.f
r
246
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 22 | Visual Studio : Solution complète (cf. code)
eric.a
nq
uetil@
iris
a.f
r
247
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 23 Notion de framework : ex. MFC
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Classes de base
Classes dérivées
Chap. 23 | Concept de « framework »
Framework : ensemble de classes de base définissant les fonctionnalités
génériques de différentes applications
Framework :
gestion du séquencement
des fonctionnalités offertes
Protocole (l’interface)
de mise en œuvre
d’une application
Fonctions virtuelles
Fonctions virtuelles pures
Application / Classes dérivées :
doivent réécrire certaines fonctions
et peuvent en surcharger d’autres
eric.a
nq
uetil@
iris
a.f
r
249
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
eric.a
nq
uetil@
iris
a.f
r
Chap. 23 | Concept de « framework »
Dans ce chapitre, on va :
Exploiter un framework en C++ :
l'Architecture Document / Vue des MFC
Concevoir un framework en Java
Conception d’un éditeur
de graphe (gestion Nœuds - Arcs)
250
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 23 | 2 mots sur l'Architecture Document / Vue des MFC
Demo.exe
CloudDoc
_points
add_point() count() get_point() regression()
Un document
… les données ... GraphView
OnDraw() OnLButtonDown()
TextView
OnUpdate()
Des vues
… une représentation
des données ...
• Séparer le code qui gère les données
(Document) de celui qui assure la
restitution (Vues) de ces données
• Maintenir automatiquement une
cohérence entre toutes les vues et le
document
eric.a
nq
uetil@
iris
a.f
r
251
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 23 | Exemple de Modèle Document / Vue
CMainFrame
OnWindowNew()
CloudApp
CloudApp() InitInstance()
CloudDoc
_points
add_point() count() get_point() regression()
GraphView
OnDraw() OnLButtonDown()
TextView
OnUpdate()
CDocument CView
CEditView
CWinApp CMDIFrameWnd CCtrlView
• 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
C++
eric.a
nq
uetil@
iris
a.f
r
252
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 23 | Les interdépendances
Une 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 …
« Cdocument » / le document attaché à la vue ...
Les interdépendances sont spécifiées à travers
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);
pDocTemplate = new CMultiDocTemplate(
IDR_TEXTVIEWTYPE,
RUNTIME_CLASS(CloudDoc),
RUNTIME_CLASS(CMDIChildWnd), // définition par défaut
RUNTIME_CLASS(TextView));
AddDocTemplate(pDocTemplate); ...
C++
eric.a
nq
uetil@
iris
a.f
r
253
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 23 | La notion de document
Un document est une classe simple qui n’est associé à aucune notion
de représentation
Objectif : gestion des données
void CloudDoc::add_point(CPoint p) { _points.push_back(p); } 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 { ... }
C++
eric.a
nq
uetil@
iris
a.f
r
254
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 23 | La notion de vue
Une vue doit gérer :
les notions d’affichage (OnDraw, OnUpDate, …)
La réaction aux événements (OnLButtonDown, …)
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); }
C++
eric.a
nq
uetil@
iris
a.f
r
255
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 24 Java : Conception d'un framework
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Exemple de conception d’un Framework complet
Conception d’un éditeur de graphe (gestion Nœuds - Arcs)
Applications
graphe de circuit logique, graphe de communication réseau, ...
Encapsulation des concepts de base dans un framework
sélection, déplacement, connexion, ...
Conception de l’interface utilisateur
Insérer Supprimer Déplacer
Icônes (exclusives)
gestion du type de
nœuds et
de liaisons
Zone de
représentation :
actions dépendantes
du contexte et des
évènements souris
Choix exclusif du
mode d'édition
Demo.htlm
eric.a
nq
uetil@
iris
a.f
r
257
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Méthodologie : organisation des classes
Séparer les fonctionnalités
communes (framework)
ex : gestion des événements souris, classe de base Nœud et Arc, ...
spécifiques (applications)
ex : type et dessin des formes des nœuds et des arcs, ...
Framework
Nœud Arc
CercleP Cercle Application
Droite
Pointillé
eric.a
nq
uetil@
iris
a.f
r
258
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Abstraction / Utilisation des concepts génériques
La classe du framework : Nœud
abstract class Noeud implements Cloneable
{ public abstract void dessine(Graphics g);
public abstract Rectangle rect_englobant();
public abstract boolean est_dans(Point p);
public Object clone () { ... }
public void deplace (Point p) { _centre = p; }
public Point centre () { return _centre; }
private Point _centre; ... }
La classe utilisateur : Cercle
class Cercle extends Noeud {
public void dessine (Graphics g) {
g.drawOval( centre().get_x() - Rayon,
centre().get_y() - Rayon, 2 * Rayon, 2 * Rayon)
} ...}
Nœud
Cercle
Framework
Application
Java
eric.a
nq
uetil@
iris
a.f
r
259
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Prise en compte des types utilisateurs
La classe du Framework abstract class GraphEditeur extends Applet { …
abstract String[] get_types();
public void enregistrement() {…}
...
}
L'application devra définir :
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; }
GraphEditeur
Framework
MonEditeur
Application
Java
eric.a
nq
uetil@
iris
a.f
r
260
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Initialisation dynamique des nœuds et arcs de l’utilisateur
Le framework va mémoriser les objets correspondants
public void enregistrement() {
String[] typenames = get_types();
for (int i = 0; i < typenames.length; i++)
{ Class cls = Class.forName(typenames[i]);
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 }
}
}
Chap. 24 | Typage dynamique (RTTI)
GraphEditeur
Framework
Java
eric.a
nq
uetil@
iris
a.f
r
261
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Framework : notion d'interface graphique
Applet : Programme Java destiné à fonctionner via un browser WEB
GraphEditeur : Gestion de l’état globale de l’éditeur (mode d’édition) ...
Canvas : Zone de dessin avec gestion des évènements souris, ...
GraphCanvas : Dessin du graphe - gestion des évènements souris
IconCanvas : Gestion et dessin des icônes (types arcs et nœuds)
Framework
Nœud Arc
CercleP Cercle
GraphCanvas
Droite
Pointillé
MonEditeur GraphEditeur
Applet Framework Java
Application
Canvas
IconCanvas
Demo2.htlm
Java
eric.a
nq
uetil@
iris
a.f
r
262
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Diagramme de classe / exemple
Ntriangle()
clone()
dessine()
estDans()
pointFrontiere()
rectEnglobant()
Ntriangle
dessine()
estDans()
pointFrontiere()
rectEnglobant()
NCercle
Nlosange()
clone()
dessine()
estDans()
pointFrontiere()
rectEnglobant()
Nlosange
get_types()
DiagramEditor2
dessine()
estDans()
AFlec...
Adroi tecercle()
dessine()
clone()
estDans()
Adroitecercle
dessine()
estDans()
ALigne
IconCanvas()
ajoutTypeNoeud()
ajoutTypeArc()
mouseReleased()
IconCanvas
centre()
clone()
deplace()
dessine()
estDans()
pointFrontiere()
rectEnglobant()
Noeud_from: Noeud
_to: Noeud
dessine()
estDans()
clone()
dessine()
estDans()
l iasonNoeud()
connect()
Arc
GrapheCanvas()
rechercheNoeud()
supprimeNoeud()
supprimeArc()
paint()
mouseReleased()
mouseDragged()
mouseMoved()
GrapheCanvas
arcCourant()
noeudCourant()
enregistrement()
get_types()
ini t()
mode()
setArcCourant()
setNoeudCourant()
GrapheEditor
+ _from
0..1
+ _to
0..1
- _current_edge
0..1
- _graph
0..1
- _icon
0..1
- _current_node
0..1
eric.a
nq
uetil@
iris
a.f
r
263
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Autonomie du framework et notion de Canvas
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);
_VecNoeuds.addElement(i);
repaint();
} // … public void paint(Graphics g) {
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);
}
for (int j = 0; j < _VecNoeuds.size(); j++) {
Noeud n = (Noeud) _VecNoeuds.elementAt(j);
n.dessine(g);
} }
Canvas
Framework
Java
GraphCanvas
Application
Framework
Java
eric.a
nq
uetil@
iris
a.f
r
264
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 24 | Bilan sur la notion de Framework
Le framework fournit les mécanismes de base
associés aux composants d'un système
Questions de base pour l'utilisation d'un framework
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 ?
Quelles sont les phases d'initialisation exigées ?
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.
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
eric.a
nq
uetil@
iris
a.f
r
265
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 25 Design Pattern Commande : undo
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Rappels des objectifs du modèle « commande »
Principe du modèle « commande »
Encapsuler une commande (requête) dans un objet
Intérêts
Maintien d’une liste de commandes (ou queue de requêtes )
Gestion facilité de l’annulation des commandes (undo/redo)
On peut avoir autant de commandes
Concrètes que l’on veut
client Exécuteur
Receveur
Commande
exécute()
Commande1
exécute()
1
0..*
commandes
action()
Découple l’objet qui sait réaliser la commande
de celui qui l’invoque
eric.a
nq
uetil@
iris
a.f
r
267
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Mise en œuvre du undo/redo
Principe de la mise en œuvre du undo/redo
avec le modèle « commande »
Soit les commandes sont réversibles
Il est possible de coder la commande « inverse »
Soit il faut conserver une mémoire de l’état de l’objet receveur
undo/redo ↔ sauvegarde/restauration des états (Cf. DP Memento)
Besoins
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
eric.a
nq
uetil@
iris
a.f
r
268
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Manipulation de « figures » : undo/redo
Mise en œuvre classique / sans le modèle « commande »
sur un exemple pratique : les « figures »
+ ajouterFig()
+ supprimerFig()
+ faireCmd()
+ undoCmd()
Dessin
# x: int
# y: int
+ translaterX(int)
+ redimensionner(double)
Figure
- CollectionFig 0..*
# r: int
+ redimensionner(double)
Cercle
# l: int
+ redimensionner(double)
Rectangle
# h: int
La difficulté
est ici !!!
eric.a
nq
uetil@
iris
a.f
r
269
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Manipulation de figures : undo/redo
Utilisation du modèle « commande » / gestion du undo
+ ajouterFig()
+ supprimerFig()
+ faireCmd()
+ undoCmd()
Dessin
CommandeAbstraiteFig
# x: int
# y: int
+ translaterX(int)
+ redimensionner(double)
Figure
+ executer()
+ undo()
CommandeInterface
- dx: int
+ executer()
+ undo()
CommandeTranslaterX
- fact: double
+ executer()
+ undo()
CommandeRedimensionner
+ executer()
+ undo()
CommandeSupprimer
- CollectionFig 0..* - CollectionCmdFig
0..*
0..*
0..*
- des
- fig
Interface
minimale à
respecter
Receveur
Exécuteur
actions
eric.a
nq
uetil@
iris
a.f
r
270
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Mise en œuvre du modèle « commande » / undo
Gestion du undo avec le modèles « commande »
Ici les commandes sont réversibles
Nature des associations
+ ajouterFig()
+ supprimerFig()
+ faireCmd()
+ undoCmd()
Dessin
CommandeAbstraiteFig
# x: int
# y: int
+ translaterX(int)
+ redimensionner(double)
Figure
+ executer()
+ undo()
CommandeSupprimer
- CollectionFig 0..* - CollectionCmdFig
0..*
0..*
0..*
- des
- fig
-> 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).
Spécifique à
la commande
supprimer
Générique à
toutes les
commandes
eric.a
nq
uetil@
iris
a.f
r
271
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | 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 !
};
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() ;
};
CommandeAbstraiteFig
+ executer()
+ undo()
CommandeInterface
+ executer()
+ undo()
CommandeSupprimer
+ figure: Figure*
+ des: Dessin*
C++
eric.a
nq
uetil@
iris
a.f
r
272
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Mise en œuvre du modèle « commande » / 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 !
};
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
}
CommandeAbstraiteFig
+ executer()
+ undo()
CommandeInterface
+ executer()
+ undo()
CommandeSupprimer
+ figure: Figure*
+ des: Dessin* - dx: int
+ executer()
+ undo()
CommandeTranslaterX
C++
eric.a
nq
uetil@
iris
a.f
r
273
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | 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() ;
};
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;
}
C++
eric.a
nq
uetil@
iris
a.f
r
274
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | 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();
}
C++
eric.a
nq
uetil@
iris
a.f
r
275
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Retour sur le modèle « commande » / undo
Remarques
Gestion de commandes composites (composées d’autres commandes)
Couplage avec le modèle « composite »
client Exécuteur
Récepteur
Commande
exécute()
Commande1
exécute()
1
0..*
commandes
CommandeSupprimer
Figure
CommandeInterface
CommandeRedimensionner
CommandeDeplacer
Dessin “Main”
CommandeAbstraiteFig
C++
eric.a
nq
uetil@
iris
a.f
r
276
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 25 | Modèle « commande » / gestion de commandes simples
Gestion de commandes simples / non annulables
Exemple avec une classe « Template »
class CommandeInterface {
public:
virtual void executer() =0;
};
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:
Action action;
Receveur* receveur;
};
template <class Receveur>
void CommandeSimple<Receveur>::executer(){
(receveur->*action)();
}
void main() {
Point* p = new Point(10,10);
CommandeInterface* c=new CommandeSimple<Point>(p,&Point::effacer);
c->executer();
}
C++
eric.a
nq
uetil@
iris
a.f
r
277
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 26 Design Pattern Memento : Undo
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | 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
Principe : sauvegarder l’état d’un objet pour pouvoir ensuite le restaurer
Description du Modèle : il est basé sur trois classes
classe « Auteur »
représente les objets dont on souhaite sauvegarder l’état ;
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
C++
eric.a
nq
uetil@
iris
a.f
r
279
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | Exemple : Undo pour la manipulation d’objets de type A
Objectif
gérer la fonctionnalité « undo » pour la manipulation
d’objets de type A
Classe A
état : une valeur entière (_val).
1 constructeur
1 fonction d’accès
2 fonctions de modification : doubler ou tripler la valeur de l’objet.
class A {
public:
A(int val) { _val = val; }
void doubler() { _val = 2 * _val;}
void tripler() { _val = 3 * _val;}
int getVal() { return _val; }
private:
int _val;
};
C++
eric.a
nq
uetil@
iris
a.f
r
280
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | 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.
class MementoA{
public:
MementoA(int etat){
_etat = etat;
}
int getEtat() {
return _etat;
}
private:
int _etat;
};
C++
MementoA
eric.a
nq
uetil@
iris
a.f
r
281
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | La classe Auteur – classe A
Classe A complétée
mémoriser son état : MementoA* creerMementoA()
restaurer son état : void restorerMementoA(MementoA* mem)
. 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;
};
C++
Classe A
eric.a
nq
uetil@
iris
a.f
r
282
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | Le Surveillant - CommandA
Exécution des actions (commandes) sur les objets A
Construction d’une commande avec en paramètre
un pointeur sur un objet A
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
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.
C++
eric.a
nq
uetil@
iris
a.f
r
283
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 26 | Le Surveillant – CommandA / Code
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;
};
C++
eric.a
nq
uetil@
iris
a.f
r
284
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
#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;
cmd2->execute();
cout<<objA1->getVal()<< endl;
CommandA::undo();
cout<<objA1->getVal()<< endl;
CommandA::undo();
cout<<objA1->getVal()<< endl;
}
Chap. 26 | Utilisation /Test
eric.a
nq
uetil@
iris
a.f
r
1
2
6
2
1
Classe A MementoA CommandA
C++
285
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 27 Interfaçage avec la JNI : C++/Java
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : Java Native Interface
Objectif
Interfacer du C/C++ avec du Java dans une même application
Pourquoi faire ?
Codage en C/C++ des parties critiques de code au niveau du temps
d'exécution
Meilleurs performances en terme de temps de calcul
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
Implications
Limitation des possibilités de portage de votre application
Recodage ou recompilation des parties C/C++
C/C++ JAVA
JNI
Java
eric.a
nq
uetil@
iris
a.f
r
287
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : les possibilités d'interfaçage
Le framework de la JNI permet
En Java
On peut appeler des méthodes natives (C/C++)
Les méthodes natives(C/C++) peuvent
Inspecter, modifier ou créer des objets JAVA
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/
Java
eric.a
nq
uetil@
iris
a.f
r
288
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : Les différentes étapes de l'interfaçage
Exemple : appel à une méthode native simple
1ère étape : le programme Java
public class MaClasse {
static {
System.loadLibrary("MaLibrairie");
}
public native void afficheCpp();
public static void main(String[] args) {
MaClasse obj1 = new MaClasse();
obj1.afficheCpp();
}
}
Déclaration de la méthode native
chargement de la librairie (C/C++)
en mémoire (nom sans extension) :
automatique / plate-forme
=> MaLibrairie.dll (Windows)
=> MaLibrairie.so (Unix)
Appel de la méthode native
Java
eric.a
nq
uetil@
iris
a.f
r
289
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : Les différentes étapes de l'interfaçage
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
/* 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
* Method: afficheCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MaClasse_afficheCpp (JNIEnv *, jobject);
#ifdef __cplusplus}
#endif
#endif
Nommage : préfixe + nom de la classe + nom de la méthode
Java _ Maclasse _ afficheCpp
Java
eric.a
nq
uetil@
iris
a.f
r
290
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : Les différentes étapes de l'interfaçage
3ème étape : Codage du fichier C++
Recopier les prototypes des méthodes
Coder le contenu
4ème étape : Génération de la librairie
.dll (Windows) ou .so (Unix)
#include "MaClasse.h"
#include <iostream.h>
/*
* Class: MaClasse
* Method: AfficheCpp
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_MaClasse_afficheCpp (JNIEnv *, jobject) {
cout << "Affichage depuis une methode C++" << endl;
}
Inclure le fichier : MaClasse.h
Les paramètres ne servent pas
dans cet exemple
Java
eric.a
nq
uetil@
iris
a.f
r
291
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : Les différentes étapes de l'interfaçage
5ème étape : Exécution du programme Java
L'emplacement de la librairie doit être connu de la JVM
Pour pouvoir l'utiliser :
Spécifier son emplacement en démarrant la JVM
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
Java
eric.a
nq
uetil@
iris
a.f
r
292
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : envoie de String
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");
}
}
#include "MaClasse.h"
#include <iostream.h>
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++
cout << ch << endl;
// Libération de la chaîne C++
env->ReleaseStringUTFChars(strJava,ch);
}
JNIEnv* env
Pointeur : environnement / accès aux fonction du JNI
Code Java
Code C++
jstring strJava
Paramètre de la fonction envoieString
Java
eric.a
nq
uetil@
iris
a.f
r
293
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : accès aux attributs d'une classe
nb: int
nom: String
afficheCpp()
toString(): String
envoieString(in String)
MaClasse(in String, in int)
MaClasse
JNIEXPORT jstring JNICALL Java_MaClasse_toString(JNIEnv* env, jobject obj) {
char buffer[256];
// Obtention de la Metaclasse de MaClasse
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");
// Récupération de la valeur entière de l'attribut
// à partir de son identificateur
int nb = env -> GetIntField(obj,fid);
// Calcule de l'identificateur de l'attribut nom de type String
fid = env -> GetFieldID(cls,"nom","Ljava/lang/String;");
// 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 return env->NewStringUTF(buffer); }
Code C++
…
public native String toString();
public static void main(String[] args) {
MaClasse obj1 = new MaClasse("obj1", 2);
System.out.println(obj1); }
Code Java
jobject obj
référence sur l'objet qui a invoqué la méthode (this)
GetFieldID(cls,"nb","I") : accès à l'identificateur
Paramètres : classe, chaîne::attribut, chaîne::type
GetIntField(obj,fid); : accès à l'attribut
Paramètres : l'objet, l'identificateur
Java
eric.a
nq
uetil@
iris
a.f
r
294
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : accès aux attributs d'une classe / objet
JNIEXPORT void JNICALL Java_MaClasse_accesAttributJava
(JNIEnv *env, jobject obj){
// 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);
// 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;
}
Code C++ nb: int
nom: String
obj1: Info
accesAttributJava()
MaClasse(in String, in int)
main(in String[])
MaClasse
date: int
Info(in int)
Info
+ obj1
0..1
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();
} }
Code Java
date de obj1 avant modif : 2003
date de obj1 apres modif : 2004
Java
eric.a
nq
uetil@
iris
a.f
r
295
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : invocation d'une méthode Java
JNIEXPORT void JNICALL
Java_MaClasse_appelMethodeJava (JNIEnv *env, jobject obj){
// Récupération d'un objet de Metaclasse
jclass cls = env -> GetObjectClass(obj);
// Récupération de l'identificateur public int getNb()
jmethodID mid = env->GetMethodID(cls,"getNb","()I");
if (mid == 0) {
cout << "Probleme !" << endl;
} else {
int nb =env->CallIntMethod(obj,mid);
cout << "Appel de la methode JAVA getNb : " ;
cout << nb << endl;
} return; }
Code C++
public class MaClasse {
static {
System.loadLibrary("MaLibrairie");
}
public native void appelMethodeJava();
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();
} }
Code Java
Appel de la methode JAVA getNb : 2
nb: int
nom: String
appelMethodeJava()
MaClasse(in String, in int)
getNb(): int
MaClasse
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
CallIntMethod(obj,mid) :
Appel de la méthode qui retourne un entier
Paramètres : obj, identificateur de la méthode
Java
eric.a
nq
uetil@
iris
a.f
r
296
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 27 | JNI : fonctionnalités avancées
Les autres fonctionnalités de la JNI Cf. Doc de Java :
http://java.sun.com/docs/
Les échanges de tableaux
L'appel à des méthodes de classe (static)
La gestion des exceptions
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/
Class1.h
Class2.h
Exemple.i
Exemple_wrap.cpp
ExempleJNI.java
Class1.java
Class2.java
Class1.cpp
Class2.cpp
Exemple.dll
ExempleJNI.class
Class1.class
Class2.class SWIG
Compilation
C++
Compilation
Java
Java
eric.a
nq
uetil@
iris
a.f
r
297
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 28 Annexe Java : Java 5 ...
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Un petit bilan : le modèle objet en JAVA / C++
La notion de variable (discussion)
En C++
une variable sert à stocker les objets
En JAVA
une variable sert à accéder aux objets
les objets sont stockés en mémoire dynamique (Tas)
les identificateurs ne contiennent que les adresses des objets (notion de
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
la copie d’identificateurs ne génère qu’une référence supplémentaire sur un objet
existant / cette notion est peu intuitive ...
*notion de clone
Java
C++
eric.a
nq
uetil@
iris
a.f
r
299
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Introduction : Java5 (Tiger)
Automne 2004
Révision de Java : Java 5 (nom de code Tiger) : J2SE 5.0
Les Principales évolutions
Autoboxing et Auto-Unboxing des types Primitifs
Les itérations sur des collections
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
Java
eric.a
nq
uetil@
iris
a.f
r
300
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Autoboxing et Auto-Unboxing des types primitifs
Simplification du passage (Type Primitifs / objet)
boolean/Boolean, byte/Byte, double/Double, short/Short, int/Interger,
long/Long, float/Float, char/Character
Exemple
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
// 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)
Java
eric.a
nq
uetil@
iris
a.f
r
301
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Itérations sur des collections : nouvelle boucle for
Evolution du for pour l’itération sur des collections
For (paramètre formel : Objet Iterable) { corps }
Notation plus légère et concise
NB: On ne peut pas modifier la collection avec cette notation
List Figures=new ArrayList();
Figures.add(new Rectangle());
//...
// 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);
}
Java
eric.a
nq
uetil@
iris
a.f
r
302
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Type énuméré : enum
Avant Java 5 : utilisation de constante de type int
Avec Java5 : la construction des enum est type-safe
D’autres raffinements sont encore possibles …
public class Etapes {
public static final int ETAPE0=0;
public static final int ETAPE1=1;
public static final int ETAPE2=2;
//...
}
int e=Etapes.ETAPE1;
System.out.println(e); // affichage : 1
e=10; // possible ! Danger !
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
Java
eric.a
nq
uetil@
iris
a.f
r
303
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Nombre d’arguments variable pour une méthode
Notation : « Type … »
Résultat
static void argTest(String ... args) { // nombre variable d’arguments de type String
for (String o : args) {
System.out.println(o);
}
}
// …
argTest("arg1","arg2","arg3"); // 3 paramètres
argTest("bonjour","monsieur"); // 2 Paramètres
arg1
arg2
arg3
bonjour
monsieur
Java
eric.a
nq
uetil@
iris
a.f
r
304
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 28 | Les imports statiques
Objectifs
Rendre visible des méthodes et variables statiques
Attention aux conflits de nommage
// Avant
getContentPane().add(plum, BorderLayout.CENTER);
// Avec Java5 et les imports statiques
Import static java.awt.BorderLayout.*
getContentPane().add(plum, CENTER);
Java
eric.a
nq
uetil@
iris
a.f
r
305
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 29 Annexe Java : Clonage
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Notion de copie en profondeur
En C++
Copie d’objets => recopie (… en profondeur si …)
Attention aux copies de pointeurs (pas de recopie des objets pointés)
En JAVA
Copie d'identificateur : pas de recopie des objets identifiés
Il faut souvent implanter la recopie (… en profondeur si besoin …)
Exemple : code C++ ok / code JAVA erreur Rectangle Carre (Point p, int d) {
Point a= p ;
a.deplacer(-d / 2 , -d / 2);
Point b= p ;
b.deplacer(d / 2 , d / 2);
Rectangle r(a,b); // code C++
Rectangle r=new Rectangle(a,b); // code Java
return r;
}
a
b
p
d
eric.a
nq
uetil@
iris
a.f
r
307
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Notion de copie en profondeur
En JAVA
Copie d'identificateur : pas de recopie des objets identifiés
Il faut souvent implanter la recopie (… en profondeur si besoin …)
Gestion des recopies d’objet avec le constructeur par recopie
Utilisation de la méthode : clone()
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; }
a
b
p
d
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
}
Java
eric.a
nq
uetil@
iris
a.f
r
308
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | La méthode clone( ) de la classe Object
La méthode clone de la classe Object ne fait par défaut que
la réservation mémoire
et
la recopie superficielle (ok pour : types primitifs et les objets invariants)
De 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
Java
eric.a
nq
uetil@
iris
a.f
r
309
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Mise en œuvre de la méthode clone()
Implantation de la méthode clone()
l’interface Cloneable doit être mise en œuvre
le contrôle d’accès à cette fonction nécessite la mise en place du traitement
d’exception
*gestion d’exception
class Point implements Cloneable
{ public Object clone( )
{ try { return super.clone(); } // recopie superficielle
catch (CloneNotSupportedException e) { return null; }
}
…
private int _x; private int _y;
}
Java
eric.a
nq
uetil@
iris
a.f
r
310
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Mise en œuvre de la méthode clone()
Copie en profondeur
Les champs « constants » sont implicitement gérés (nombres, string, ...)
Les champs « identificateurs » doivent être clonés
(toutes les classes référencées doivent être "récursivement" clonées)
class Rectangle implements Cloneable {
public Object clone( ) {
try {
Rectangle r = (Rectangle)super.clone() ;
r._pt_hg = (Point) _pt_hg.clone() ; // fonction clone() à définir
r._pt_bd = (Point) _pt_bd.clone() ; // pour la classe Point
return r;
}
catch (CloneNotSupportedException e) {
return null;
}
}
…
}
Java
eric.a
nq
uetil@
iris
a.f
r
311
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Clonage et héritage
La notion de « cloneable » est transmise aux classes dérivées
La méthode super.clone(), l’héritage et l’attachement dynamique
Quand Niv1.clone() est appelée à travers Niv2.clone() ; Object.clone() est
appelée à travers super.clone() qui travaillera alors avec Niv2
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; // copie automatique
public Niv2(int i) { super(i); } ...
}
Java
eric.a
nq
uetil@
iris
a.f
r
312
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 29 | Remarques sur le clonage en Java
Interface Cloneable
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);
interface Cloneable { }
class Object
{ protected Object clone()
{ if (! (this instanceof Cloneable))
throw new CloneNotSupportedException();
...
}
...
Java
eric.a
nq
uetil@
iris
a.f
r
313
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 30 Annexe Java : Classe Interne
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 30 | Classe interne : inner class
Possibilité de déclarer une classe à l'intérieur d'une autre classe
Association de la visibilité de bloc avec la visibilité de classe
Accès aux membres de la classe englobante
Permet de "cacher" les classes internes liées à une implémentation
spécifique et de rassembler les classes connexes
Trois déclinaisons des classes internes
Classe membre
d'une classe
Classe locale
à une méthode
membre
d'une classe
Classe anonyme
définie à l'intérieur
d'une expression
class Englobe { …
class ClasseMembre { ... } }
class Englobe { …
void methode() {
class ClasseLocale { ... }
} }
class Englobe { …
void methode() {
Ob.addActionListner( new ClasseAnonyme() { ... });
} }
Java
eric.a
nq
uetil@
iris
a.f
r
315
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 30 | Classe interne : membre d'une classe
Une classe membre interne peut être déclarée comme : public, private,
protected.
Elle a accès aux membres (attributs/méthodes), même privés, de la classe
l'englobant
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; // utilisation de la classe interne privée
... } …
Englobe E = new Englobe();
Englobe.LocalePu vpu = E.new LocalePu(); // classe interne publique
Java
eric.a
nq
uetil@
iris
a.f
r
316
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 30 | Classe interne : locale
Classes internes déclarées dans un bloc de code
Uniquement visibles et utilisables dans leur bloc
(idem aux variables locales)
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, …)
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) } } } }
Java
eric.a
nq
uetil@
iris
a.f
r
317
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 30 | 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); } public void test2() {
test( new Point(10,10) {
public int _z;
public void deplacer(int dx, int dy) {
_x += dx; _y += dy; _z=111; }
public String toString() {
return("Point3D : " + x() + " " +y() + " " + _z); } }); } public static void main(String[] args) {
Englobe3 Eng=new Englobe3();
Eng.test2(); } }
Point3D : 10 10 0
Point3D : 11 11 111
Classe anonyme dérivée de la
classe Point
Les arguments sont passés au
constructeur de la classe de
base (Point)
Java
eric.a
nq
uetil@
iris
a.f
r
318
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 30 | 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
import java.awt.*;import javax.swing.*; import java.awt.event.*; public class jboutton { public static void main(String [] args) { JFrame jf = new JFrame(); jf.setSize(400,100); jf.setVisible(true); 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; } ); }}
nombre de clic 1
nombre de clic 2
nombre de clic 3
fermeture de l'application
La méthode addActionListener attend un objet qui implémente l'interface ActionListner :
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
Java
eric.a
nq
uetil@
iris
a.f
r
319
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 31 Windows Forms : Introduction
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Les Windows forms
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é )
Formulaires (fenêtre) : System::Windows::Forms::Form
Fenêtres de dialogue (choix d’un fichier, choix de fontes, conf. impression )
Contrôles (bouton, éditeur, …) : System::Windows::Forms::Control
Composants notion plus globale incluant formulaires, contrôles, etc.
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)
C++
eric.a
nq
uetil@
iris
a.f
r
321
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Deux mots sur .net et 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
Infrastructure) pour exécuter du code CIL (Common Intermediate
Langage) de façon managé (compilation à la volée : « just in time »)
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é : ^
C++
eric.a
nq
uetil@
iris
a.f
r
322
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : présentation
C++
eric.a
nq
uetil@
iris
a.f
r
323
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : le projet
Création d’un projet associé
à une application windows forms
C++
eric.a
nq
uetil@
iris
a.f
r
324
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : EDI et Design
Fenêtre créée
Propriété de la Fenêtre
Code associé à la fenêtre créée
C++
eric.a
nq
uetil@
iris
a.f
r
325
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : Ajout de contrôles
Propriété du bouton Évènements associés
Ajout de contrôles
par « drag and drop »
Nom de la méthode
appelée par réaction
à cet évènement
Nom de l’objet bouton créé
Boîte à outils
C++
eric.a
nq
uetil@
iris
a.f
r
326
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : Le code généré
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;
/// <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:
Form1(void)
{
InitializeComponent();
//
//TODO : ajoutez ici le code du constructeur
//
}
Form1.h
Définition de la classe Form1 (C++ managé)
C++
eric.a
nq
uetil@
iris
a.f
r
327
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Une application WinForms : Le code généré
// ….
private: System::Windows::Forms::Label^ label1;
private: System::Windows::Forms::Button^ buttonPlus1;
private: System::Windows::Forms::Button^ buttonVersion;
public: System::Windows::Forms::NumericUpDown^ numericUpDownCompteur;
private: System::Windows::Forms::Button^ buttonDessin;
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)
{
this->label1 = (gcnew System::Windows::Forms::Label());
this->buttonPlus1 = (gcnew 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());
// …
Form1.h // suite
C++
eric.a
nq
uetil@
iris
a.f
r
328
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Réactions aux évènements
Réactions aux évènements
// ….
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();
}
Form1.h // suite
C++
eric.a
nq
uetil@
iris
a.f
r
329
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Introduction d’une seconde « Form »
Introduction d’une 2nde « Form »
Dessin : 2nd objet Form
private: Dessin^ fentreDessin;
// ….
private: System::Void buttonDessin_Click(System::Object^ sender, System::EventArgs^ e) {
if (this->fentreDessin==nullptr){
this->fentreDessin = gcnew Dessin(numericUpDownCompteur);
}
this->fentreDessin->Show();
}
private: System::Void numericUpDownCompteur_ValueChanged(System::Object^ sender, System::EventArgs^ e) {
if (this->fentreDessin) this->fentreDessin->Invalidate();
}
Form1.h // suite
public:
MesFigures::Carre* unCarre;
System::Windows::Forms::NumericUpDown^ compteur;
Dessin(System::Windows::Forms::NumericUpDown^ c)
{
InitializeComponent();
//
//TODO : ajoutez ici le code du constructeur
//
unCarre = new MesFigures::Carre(10,10);
compteur=c;
} // ….
Dessin.h
C++
eric.a
nq
uetil@
iris
a.f
r
330
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Introduction d’une seconde « Form »
Introduction d’une 2nde « Form »
Evènement Paint
public:
MesFigures::Carre* unCarre; // initialisation dans le constructeur
System::Windows::Forms::NumericUpDown^ compteur;
// ….
private: System::Void dessiner(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
Pen^ pen = gcnew Pen(Color::Black);
pen->Width = 1;
pen->DashStyle = System::Drawing::Drawing2D::DashStyle::Solid;
unCarre->deplacer(this,pen,(int)compteur->Value,(int)compteur->Value);
}
Dessin.h
C++
eric.a
nq
uetil@
iris
a.f
r
331
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 31 | Exemple de classe Rectangle / Carre
Dessin d’un rectangle
#include "rectangle.h"
namespace MesFigures{
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 MonRectangle::dessiner(Form^ f, Pen^ pen) const{
Graphics^ g = f->CreateGraphics();
//dessin du rectangle
g->DrawRectangle(pen, _xpos, _ypos,_pbd.getX()-_phg.getX(),_pbd.getY()-_phg.getY());
}
}//namespace
rectangle.cpp
C++
C++ / managé
C++
namespace MesFigures{
class Carre:public MonRectangle{
public:
//constructeurs
Carre(MonPoint ph, int lg);
Carre(int xh, int yh, int lg);
};//class
}//namespace
C++ carre.h
eric.a
nq
uetil@
iris
a.f
r
332
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 32 MFC : Introduction
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Visual C++
Visual C++ est un EDI :
environnement intégré
de développement
MFC :
Microsoft foundation Class
Bibliothèque/framework encapsulant
la programmation graphique sous Win32
Visual C++ assiste le développement d'application avec les MFC
Worspace
Vues : classes / fichiers / ressources
Sorties
Éditeur : texte / application graphique
C++
eric.a
nq
uetil@
iris
a.f
r
334
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Exemple de types de projets
Projets exploitant les MFC
MFC AppWizard (dll)
création d'une librairie
dynamique
MFC AppWizard (exe) :
création d'une application
graphique
Application C++ / win32
Win32 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
C++
eric.a
nq
uetil@
iris
a.f
r
335
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Exemple : une application graphique simple
Création d'un application graphique
de type dialogue
C++
eric.a
nq
uetil@
iris
a.f
r
336
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | 1ère étape : composants graphiques de l'IHM
Création "graphique"
2 boutons et 1 champ de saisie (Edit Box)
Propriétés
Définition des propriétés de base
(clic droit souris)
Identificateur du bouton
Texte associé au bouton
C++
eric.a
nq
uetil@
iris
a.f
r
337
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | 2ème étape : réaction à un évènement
Action par défaut sur un bouton : clic gauche
Résultat : exécution
void CIntroductionMFCDlg::OnVersion()
{
// TODO: Add your control notification handler code here
AfxMessageBox("Version Aout 2003");
}
Double clic sur le bouton =
définition d'une fonction
de réaction "clic gauche"
Définition de la fonction
Ici : Affichage d'un message
C++
eric.a
nq
uetil@
iris
a.f
r
338
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Utilisation du Class Wizard
Ajout : fonction de réaction à un
clic sur le bouton PlusUn
Association d'une variable
au champ d'édition
définition de ses propriétés
C++
eric.a
nq
uetil@
iris
a.f
r
339
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Écriture du code des méthodes
Réaction au clic sur le bouton PlusUn
Initialisation par défaut de la variable "m_Compteur" / l'Edit box "IDC_Compteur"
void CIntroductionMFCDlg::OnPlusUn() {
// TODO: Add your control notification handler code here
m_Compteur++;
UpdateData(FALSE); // mise à jour de l'affichage
}
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
}
C++
eric.a
nq
uetil@
iris
a.f
r
340
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Initialisation par l'IHM de l'Edit box "IDC_Compteur"
Mise à jour : IHM / Variable
void CIntroductionMFCDlg::OnChangeCompteur() {
// TODO: Add your control notification handler code here
UpdateData(TRUE); // mise à jour de la variable
}
Variable IHM
UpdateData(FALSE)
UpdateData(TRUE)
C++
eric.a
nq
uetil@
iris
a.f
r
341
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Création d'un fenêtre de dessin
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;
}
C++
eric.a
nq
uetil@
iris
a.f
r
342
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Création d'une vue (fenêtre fille du cadre)
Création de la vue
Liaison cadre / 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 }
class CCadreFenetre : public CFrameWnd {
// …
private:
Cvue* maVue; // pointeur de liaison avec la vue
Cvue::Cvue(CWnd* lePere){
CRect leRect;
lePere->GetClientRect(leRect);
Create(NULL, NULL, WS_CHILD, leRect,lePere,NULL);
ShowWindow(SW_SHOWNORMAL);
monPere = ((CCadreFenetre*)lePere)->monPere; };
class Cvue : public CWnd { // Construction
public: Cvue(); Cvue(CWnd* lePere); private: CWnd* monPere;
C++
eric.a
nq
uetil@
iris
a.f
r
343
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Affichage fenêtre depuis la boîte de dialogue
eric.a
nq
uetil@
iris
a.f
r
344
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; // …
class CIntroductionMFCDlg : public CDialog
{
public:
CIntroductionMFCDlg(CWnd* pParent = NULL); // standard constructor
CCadreFenetre* maFenetre; // …
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
C++
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 32 | Échange de données Fenêtre / Boîte de dialogue
eric.a
nq
uetil@
iris
a.f
r
345
Rafraîchissement de la vue
void Cvue::OnPaint() {
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
}
void CIntroductionMFCDlg::OnPlusUn() {
// TODO: Add your control notification handler code here
m_Compteur++;
if (maFenetre!=NULL) { maFenetre->Invalidate();}
UpdateData(FALSE);
}
Dessin d'un rectangle
dans la vue
C++
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Eric Anquetil ([email protected]) Dépt. Informatique Insa Rennes Version 5.0
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chapitre 33 Remarques
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 33 | Quelques Remarques ....
Passer par une bonne analyse des concepts associés au problème avant toute
implémentation
analyse et conception objet, gestion de projet de type spirale,...
Chaque classe doit représenter un concept compact et bien défini
éviter les objets trop gros, avec trop de méthodes,...
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++
eric.a
nq
uetil@
iris
a.f
r
347
Institu
t n
atio
nal d
es s
cie
nces a
pp
liqu
ées
Chap. 33 | Quelques Remarques ....
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 !
Exploiter les espaces de nommage pour éviter les conflits
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,...
eric.a
nq
uetil@
iris
a.f
r
348