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