Relations entre classes Relations fondamentales * Héritage: généralisation / spécialisation * Symbolisée par "est une version spécialisée de" * Exemple: les cercles sont une catégorie de formes * Agrégation / composition * Symbolisée par "contient", "possède", "regroupe"... * Exemple: un dessin est constitué de formes * Association: communication * Symbolisée par "communique avec", "utilise"... * Exemple: une fenêtre affiche un dessin Représentation en UML * Relation d'héritage * Une classe B hérite des caractéristiques d'une classe A * Relation d'agrégation / composition * Une classe B possède des objets d'une classe A * Relation d'association * Une classe B est associée à une classe A Exemples UML (1/2) Exemples UML (2/2) Agrégation et composition * Modélisation du groupage, de l'appartenance * Modèle naturel des conteneurs * Souvent, cardinalité 1-N * 1 agrégeant contient N agrégés * Agrégation vs. composition * Agrégation: agrégé indépendant de l'agrégeant * Composition: vie de l'agrégé dépendante de l'agrégeant * Symboles UML * Agrégation: * Composition: Association * Modélise des relations plus "floues" * "utilise", "est associé à", "communique avec" * Pas de dominance d'une classe sur l'autre * Contrairement à l'agrégation / composition * Caractéristiques * Habituellement nommée * Cardinalité M-N * Association vs. agrégation * L'agrégation est une forme d'association * Pas toujours évident de les différencier * Agrégation: notion de parties / décomposition * Agrégation, composition et association ==> attributs * Implémentation sous forme d'attributs * Attributs objets, références ou pointeurs 2ème principe fondateur: l'héritage * Permet de définir une hiérarchie entre classes * Description générale ? description plus spécifique * Vocabulaire * Classe spécialisée = sous-classe, classe fille / dérivée * Classe générale = super-classe, classe mère * La classe spécialisée dérive de sa classe mère * Permet de définir une hiérarchie entre classes * Une classe fille hérite des attributs et méthodes de sa mère * Une classe fille possède ses propres attributs et méthodes * Certains langages autorisent l'héritage multiple * Intérêts * Rend les classes extensibles * Manipulation homogène d'objets hétérogènes * Grâce au "polymorphisme" Classe dérivée * Reprend / hérite des caractéristiques de la classe mère * Uniquement les membres publics ou protégés * Les membres privés ne sont pas hérités * Les constructeurs ne sont pas hérités * Souvent, le destructeur n'est pas hérité (exception: Java) * Peut ajouter ses propres caractéristiques * Attributs et méthodes d'instance ou de classe * Constructeurs et destructeur ==> Peut donc répondre à de nouveaux messages * Peut modifier les caractéristiques héritées * Remplacement ou complément de méthodes d'instance * Appelées méthodes "virtuelles" ==> Peut donc répondre différemment aux messages hérités * Mécanisme appelé "polymorphisme" Exemple d'héritage 3ème principe fondateur: le polymorphisme * Polymorphisme = une méthode peut avoir plusieurs formes * Définir une nouvelle forme ==> "surcharge" ou "redéfinition" * Deux types de polymorphismes * Polymorphisme statique * "Overloading" / "surcharge" * Méthodes avec même nom mais signatures différentes * Détection de la bonne méthode à la compilation * Polymorphisme dynamique * "Overriding" / "redéfinition" * Une sous-classe redéfinit une méthode d'une classe mère * Détection de la bonne méthode à l'exécution Polymorphisme dynamique * Exemple Forme f1 = new Cercle(10,20,5); Forme f2 = new Rectangle(30,40,10,15); f1.tracer(); f2.tracer(); * "f1" et "f2" sont des objets de la classe "Forme" * Pourtant leur méthode "tracer" est différente * La méthode "tracer" prend donc des formes différentes * C'est ça le polymorphisme * Intérêt: manipulation homogène d'objets hétérogènes Forme tab[] = new Forme[2]; tab[0] = new Cercle(10,20,5); tab[1] = new Rectangle(30,40,10,15); for (int i = 0; i < 2; ++i) tab[i].tracer(); Méthodes virtuelles (1/3) * Pas de polymorphisme dynamique sans méthode "virtuelle" * Méthode virtuelle = on peut obtenir une version plus spécifique * Virtualité ==> surcoût à l'appel de méthode * Un mécanisme est nécessaire pour trouver la version la plus spécifique * Surcoût présent même si on n'utilise pas le polymorphisme * Il est donc important de décider si une méthode est virtuelle ou non * Attention: tous les langages n'ont pas la même politique * Java: méthode virtuelle par défaut * Utiliser "final" pour rendre une méthode "concrète" * C++ / C#: méthode concrète par défaut * Utiliser "virtual" pour rendre une méthode virtuelle Méthodes virtuelles (2/3) * Exemple Java * class A { public void m() { System.out.println("A"); } } class B extends A { public void m() { System.out.println("B"); } } * A x = new B(); x.m(); * Résultat: "B" * Méthode "m" virtuelle ==> polymorphisme Méthodes virtuelles (3/3) * Exemple C++ * class A { public: void m() { cout << "A" << endl; } }; class B : public A { public: void m() { cout << "B" << endl; } }; * A * x = new B(); x->m(); * Résultat: "A" * Méthode "m" concrète ==> pas de polymorphisme * virtual void m() ==> polymorphisme Constructeurs et héritage * Les constructeurs ne sont pas hérités * new Cercle(10,20) ==> incorrect * Mais il est possible d'utiliser le constructeur de la super-classe * En Java Cercle(int x,int y,int r) { super(x,y); rayon = r; } * En C++ Cercle(int x,int y,int r) : Forme(x,y) { rayon = r; } * new Cercle(...) ==> construction de "Forme", puis "Cercle" Destructeur et héritage * Souvent, le destructeur n'est pas hérité (C++ / C#) * Mais l'appel au destructeur de la super-classe est automatique * Destruction d'un objet ==> appel en cascade dans toute la hiérarchie d'héritage * Exemple * B hérite de A * Destruction d'un objet B ==> appel destructeur B puis destructeur A * Cas où le destructeur est hérité (Java) * Il s'agit d'une méthode virtuelle * La destruction en cascade n'est pas automatique ==> prise en charge par le développeur * Exemple class B extends A { ... void finalize() { /* Destruction B */ super.finalize(); } } |