Вы находитесь на странице: 1из 11

ESIEE Paris L. Buzer et B.

Perret

Oct 2011 v1.11

PROGRAMMATION OBJET AVANCEE & LANGAGE C# Rsum de cours


Hritage & Polymorphisme

0. Objectifs
Comprendre les principes de lhritage Comprendre le polymorphisme dhritage Comprendre le chainage des constructeurs Comprendre les interfaces Savoir mette en uvre ces notions en C#

1. Rappel sur les classes & instances


Une classe est une description, un modle, un plan, un moule ou encore un schma de construction pour les objets crer. Une classe nexiste pas physiquement en mmoire (exception faite des statics). Seuls les objets allouent des ressources chacune de leur cration. Une classe dcrit lensemble des paramtres et des mthodes dtenus par chaque instance.

1.1 Encapsulation
Un objet est vu de l'extrieur comme une bote noire fournissant des proprits et des mthodes. Pour faciliter la mise en uvre dun programme, il est utile de savoir comment on utilise un objet sans connatre toute sa mcanique interne. Par analogie avec la vie courante, vous savez comment vous servir dun tlphone portable et il vous semblerait trange davoir matriser toutes les technologies utilises lintrieur du tlphone pour passer un simple coup de fil. On parle dencapsulation au sens o les objets que vous concevez doivent masquer leur mcanique interne la fois pour tre facile utiliser ou pour se protger dutilisation maladroite. Dans une librairie, par exemple .net, Microsoft fournit laccs aux membres externes (public et protected) de ses classes. Les membres internes des diffrentes classes restent masqus et leur code peut voluer sans que cela change le comportement de la classe. Chaque membre de la classe (champs, mthodes, proprits) peut tre qualifi par un des modificateurs suivant : public : accessible par tout le monde : parents, enfants, autres private : accessible uniquement depuis la classe. Les classes drives ny ont pas accs. protected : accessible uniquement depuis la classe et ses classes drives. Remarque : si aucun qualificatif nest donn, cest implicitement un private. Il nest pas toujours vident de choisir le bon niveau de visibilit. La prudence suggre de toujours utiliser le niveau de visibilit le plus bas possible. Pour le prototypage o lon privilgie la rapidit de dveloppement la scurit du code, on prfrera le niveau public. Lors de vos travaux pratiques et exercices en classe, sauf avis contraire, vous pouvez rendre tous les membres publics.

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

2. Hritage
Lhritage est une approche puissante pour la rutilisation du code. Comme toute technique de rutilisation, elle facilite la maintenance, amliore la productivit et permet de mieux structurer votre programme. Lhritage permet de construire une classe B partir dune classe existante A. Il sagit dune sorte dhritage biologique. La classe B va ainsi hriter des variables, des mthodes, bref de tous les membres de A puis, on va ajouter des lments supplmentaires propres la classe B. Un hritage entre plusieurs classes fait natre une notion de hirarchie. Si B hrite de A, on dit que B est une classe fille, une sous-classe, une classe enfant ou encore une classe drive de A. Dune autre manire, A se nomme la classe mre, la classe de base, la classe parent ou encore la super classe de B. On peut examiner une hirarchie de classes de deux faons diffrentes. On peut choisir une vision par spcialisation/redfinition. Dans ce cas, la classe B est vue comme un cas particulier de la classe A. Par exemple, un 4x4 est un cas particulier dune Voiture. Dans cette vision, lensemble des Voitures est lensemble englobant et les 4x4 reprsentent un sous-ensemble des Voitures. Un autre point de vue est celui de lextension. La classe B est vue comme une version tendue de la classe A. Par exemple, un 4x4 est une voiture disposant de 2 roues motrices supplmentaires. Du point de vue des fonctionnalits, la classe 4x4 englobe les fonctionnalits de la classe Voiture, la classe Voiture a moins de paramtres internes que la classe 4x4.
Vhicule

Avion

Voiture

Vlo

4x4

Vlo de Course

Vlo de montagne

Rgles : Syntaxe :

Il ne peut y avoir quune seule classe parent. Lhritage multiple est interdit. Les cycles sont interdits : A ne peut hriter de B si B hrite dj de A.

class Vehicule { public string public void }

nom; AfficheNom() { WriteLine(nom); }

class Voiture : Vehicule { public int puissance; public void Info() { WriteLine(nom); WriteLine(puissance); } }

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

Vehicule V = new Vehicule(); V.nom = Proto; => OK V.AfficheNom(); => Proto V.puissance = 4; => ERREUR V.Info(); => ERREUR

Voiture K = new Voiture(); K.nom = Buggy; K.puissance = 4 ; K.Info() ; K.AfficheNom() ;

=> OK => OK => Buggy 4 => Buggy

La MSDN permet de voir la hirarchie de classe pour chaque classe du framework .net : Par exemple pour la classe System.Windows.Shapes.Rectangle on obtient :

Ce qui signifie que la classe Rectangle hrite de Shape, qui elle-mme hrite de FrameworkElement et ainsi de suite. Vous constaterez que les librairies modernes utilisent abondamment lhritage et que les hirarchies de classe peuvent tre relativement complexes. Remarque : le mot clef sealed prcdant le mot clef class permet dempcher lextension dune classe. Remarque : en C#, les hirarchies des classes tant fixes durant lexcution du programme, il faut que la relation entre les classes restent valide dans le temps. Par exemple, la Kangoo ne pas tre fille de la classe Voiture Essence, bien qu'il existe essentiellement des Kangoo dotes d'un moteur essence. En effet, il suffit quil existe galement des motorisations lectriques (ou diesel) pour que Kangoo ne puisse plus hriter de Voiture Essence. HP : public class et internal.

3. Constructeurs et chanage
Prenons une classe B enfant dune classe A. Lors de lcriture de ses constructeurs paramtriques ou sans arguments de la classe B, on doit se poser la question de comment va-t-on grer la construction des lments provenant de A. Le choix maladroit : Constructeur de Vehicule : Constructeur de Voiture : Vehicule(string _nom) Voiture(string _nom, int p) { nom = _nom ; } { nom = _nom ; puissance = p ; }

Cette solution est correcte et fonctionnelle. Cependant elle constitue une source de futurs problmes. Dans le cas dune classe plus complexe, pour certains paramtres vous allez effectuer des tests pour vrifier lexactitude des valeurs passes. Par exemple, pour un

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

objet Rectangle, vous vrifiez que sa longueur est positive. Si vous crez une classe drive Carr, il faudra soit dupliquer ces tests dans le nouveau constructeur et il est absolument interdit de copier coller du code lidentique soit oublier de faire ces vrifications, ce qui est fcheux. Pour viter ces problmes, il faut utiliser le chanage de constructeurs. Le choix correct : class Voiture { public Voiture(string _nom, int p) : base(_nom) { puissance = p ; } } Le mot clef base sert appeler explicitement le constructeur de la classe mre de Voiture. Le constructeur de la classe parent fait ce quil doit faire : vrification / affectation / initialisation et nous faisons dans le constructeur de Voiture uniquement ce qui concerne la classe Voiture. Question : dans quel ordre sont lancs les constructeurs ? class A { public A() } class B : A { public B() : base() } B toto = new B() ;

{ WriteLine(construction de A); }

{ WriteLine(construction de B); } => construction de A => construction de B

Le constructeur de la classe parent est lanc AVANT les instructions du constructeur de la classe B. Si la classe A possde un parent, son constructeur sera appel avant que celui de A soit excut. Au final, cest le constructeur du parent initial dans la hirarchie qui sera le premier lanc, puis ceux de ses enfants successivement. Ce comportement logique provient du fait que pour fonctionner, la classe B peut ncessiter des ressources venant de sa classe mre, le parent doit donc tre cr avant. Remarque 1 : lcriture de : base() est optionnel. Dans tous les cas, cela veut dire que si vous ne chanez pas explicitement le constructeur parent, PAR DEFAUT LE CONSTRUCTEUR SANS ARGUMENT DU PARENT SERA APPELE. Les raisons sont identiques aux prcdentes, pour fonctionner B peut avoir besoin des ressources provenant de A, il faut donc quelles soient initialises correctement. Remarque 2 : si vous fates un hritage en laissant lappel par dfaut au constructeur sans arguments, le systme exigera que le constructeur sans arguments soit cod, il nen fournira plus un par dfaut. Inutile de retenir ce dtail, les messages du compilateur vous le rappelleront. Remarque 3 : Lors de la construction de B, le fait que le constructeur de A soit appel ne veut pas dire quun objet de type A est cr mais que les membres hrits de A dans B sont initialiss. Au final, il ny a bien quun seul objet de type B de cr.

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

4 Polymorphisme
4.1 Principe
Le terme polymorphisme dsigne la capacit dune mthode pouvoir prendre un comportement diffrent suivant le contexte (les types utiliss). Ainsi nous pouvons obtenir des implmentations plus gnrales, mieux structures et plus simples comprendre. Par exemple, si lon veut crer une fonction calculant le maximum de deux nombres, il serait pratique quelle puisse porter le mme nom quels que soient les paramtres utiliss. On voudrait crer ces fonctions de la manire suivante : int max(int a, int b) float max(float a, float b) double max(double a,double b) k = max(u,v) ; {} {} {}

Le compilateur connat les types des variables u et v, il va donc chercher la fonction max prenant ces types l en arguments. Les diffrentes fonctions max ne traitent pas les mmes lments, pourtant conceptuellement, elles effectuent le mme calcul. Cest un des aspects du polymorphisme. Remarque : en C strict, un identificateur de fonction ne peut tre associ qu une liste unique de paramtres. Le langage dorigine nimplmentait pas le polymorphisme et il fallait alors crer des fonctions diffrentes : max_int max_float et max_double. Ce concept de polymorphisme stend lhritage. Par exemple si vous fates un jeu de simulation affichant plusieurs types de vhicules lcran, il serait agrable davoir une unique fonction AfficheToi(). Ainsi pour dessiner lcran du jeu, je demande chaque objet de safficher en utilisant le mme nom de fonction. Cette action est similaire pour une voiture, un avion, un vlo, chacun va safficher lcran, mais avec un comportement diffrent. Un objet A320 dessinera spcifiquement un Airbus A320, chaque voiture Peugeot 205 dessinera une Peugeot 205 Il est possible, mais plus lourd grer, de crer des fonctions diffrentes comme AfficheA320(), AfficheC3(), AffichePeugeot205() Ainsi une fonction peut exister sous le mme nom dans une hirarchie mais avoir un comportement diffrent suivant le type de lobjet instanci. On parle alors de polymorphisme dhritage.

4.2 Mise en place


Lapproche viter : A premire vue, il ny a pas de syntaxe particulire mettre en place. La rgle qui sapplique est la suivante : la redclaration dune mthode dinstance dans une hirarchie a pour effet de masquer la mthode du parent et de propager cette nouvelle mthode lensemble de ses enfants. class A class B : A class C : B { public void Aff() {} { public void Aff() { WriteLine(Bonjour); } } { WriteLine(Coucou); } }

ESIEE Paris L. Buzer et B. Perret


class D : C {}

Oct 2011 v1.11

Pour crer une collection dobjets, on stocke leurs rfrences dans une structure de donnes. Prenons un tableau par exemple. En crant ce tableau, la syntaxe nous impose de choisir un type unique pour toutes les rfrences quil va stocker. Par bon sens, nous choisissons comme type une rfrence vers lanctre de la hirarchie qui nous intresse : A[] Liste = new A[4] ; Liste[0] = new A(); Liste[1] = new B() ; Liste[2] = new C() ; Liste[3] = new D() ; foreach(A m in Liste) m.Aff(); // rsultats : Bonjour Bonjour Bonjour Bonjour Cette approche pose problme. Les objets sont grs comme sils taient TOUS de type A alors que ce nest pas le cas. En labsence de toute syntaxe particulire, le langage considre que le type de lobjet rfrenc est donn par le type de la rfrence. Cette rgle est la source de ce comportement pathogne. Lapproche correcte : Le polymorphisme dhritage est garanti si lon utilise une syntaxe particulire. La premire classe o la mthode est dclare pour la premire fois doit porter le qualificatif virtual et toutes les classes enfants modifiant son comportement doivent prcder sa dclaration par le qualificatif override. class A class B : A class C : B class D : C { public virtual {} { public override {} void Aff() void Aff() { WriteLine(Bonjour); } } { WriteLine(Coucou); } }

A[] Liste = new A[4] ; Liste[0] = new A(); Liste[1] = new B() ; Liste[2] = new C() ; Liste[3] = new D() ; foreach(A m in Liste) m.Aff(); // Rsultats : Bonjour Bonjour Coucou Coucou Rem 1 : le mot clef override est obligatoire pour redfinir une fonction virtuelle. Rem 2 : on peut utiliser le mot clef final pour empcher toute redfinition. Le polymorphisme dhritage est une facilit pour le programmeur mais elle a un cot pour le programme. En effet, le type de lobjet nest pas connu la compilation mais dtermin lexcution. En effet, suivant les actions de votre joueur, la liste dobjets peut contenir uniquement des voitures ou seulement des avions Le langage doit donc effectuer un test pendant lexcution pour connatre le type exact de lobjet rfrenc. Pour des fonctions effectuant beaucoup de calculs, comme un affichage graphique, ce cot est insignifiant. Par contre, faire du polymorphisme dhritage sur des fonctions effectuant trs peu de calculs peut engendrer un surcot doprations.

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

4.3

Chainage des redfinitions

Il est toujours possible dappeler la fonction qui a t redfinie partir de la redfinition avec le mot cl base. Cela permet de construire des chaines de fonctions dans le mme principe que le chainage des constructeurs. Par exemple, supposons que la classe Voiture dispose dune fonction TestAllumage() qui vrifie que tous les composants lectriques (ordinateur de bord, ABS, ESP, air bag, ...) de la voiture fonctionnent bien. Dans le cas dun Cabriolet qui ajoute un toit amovible, il faudra contrler lensemble des systmes dune voiture simple et le systme qui rentre/sort le toit amovible. class Cabriolet : Voiture { public override void TestAllumage() { base() ; // test des lments de la classe Voiture // par appel a TestAllumage() de Voiture testToitAmovible() ; // test des lments spcifiques au Cabriolet ... } }

5 Mthodes de modlisation objet


Lagrgation consiste dire quun objet intgre dans ses paramtres dautres objets. Par exemple, une voiture a 4 roues, nous pouvons donc modliser cette situation en mettant un tableau de 4 objets de type Roue dans un objet Voiture. Lhritage, lui permet de dire quune classe est un cas particulier ou une extension dune autre classe. La classe enfant possde alors tous les attributs de la classe mre. La question de savoir comment utiliser l'hritage et l'agrgation est dlicate et mrite un cours elle seule. Il sagit dune problmatique centrale des cours de POO et de Gnie Logiciel. Nanmoins, on peut tirer quelques principes gnraux : l'agrgation correspond la relation "... a ...". Par exemple "Une voiture a 4 roues". l'hritage correspond la relation "... est ...". Par exemple "Une voiture est un vhicule".

Nanmoins cette approche ne permet pas rigide car une relation "... est ..." peut facilement tre transforme en une relation "... a ...". Par exemple "La Renault Fluence est une voiture lectrique" devient "La Renault Fluence a un moteur lectrique". Par ailleurs, comment faire lorsqu'une classe semble hriter de plusieurs autres classes. Par exemple : un smartphone est la fois un tlphone, un lecteur mp3 et un microordinateur. Une premire solution serait de crer une fusion des deux classes Tlphone et Lecteur MP3. On parle alors dhritage multiple. Ce choix fut longtemps plbiscit par le langage C++. Ainsi, la nouvelle classe rassemble tous les membres des classes parentes. Une contrainte apparat au niveau des conflits entre les membres de mme nom. Il faudra alors les discerner explicitement. Tous les membres des classes parents sont conservs. Un problme apparat rellement si des membres ont le mme rle. Ils deviennent alors redondants ce qui peut tre source de confusion : par exemple, un tlphone et un lecteur

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

MP3 possdent respectivement une batterie, un objet SmartPhone possde-t-il deux batteries ? Si lon veut conserver une seule batterie, laquelle faut-il conserver ? L'hritage multiple peut poser des problmes dlicats, il y a donc controverse sur le fait de savoir si ses avantages surpassent ses inconvnients. Pour cette raison, il a t retir des langages modernes (Java, C#). Face cette situation, il faut essayer dutiliser une agrgation ou ventuellement si cela est possible des interfaces.

5.1 Interface
Dans certains cas, on cherche seulement hriter dun ensemble de fonctionnalits, dun type de service ou dun comportement. Par exemple, la climatisation de votre voiture SKUDA peut tre vue comme un service fournissant obligatoirement lensemble des fonctions suivantes : int Temperature_actuelle() ; void Activer() ; void Arreter() ; void Vitesse(int v) ; En fait, nous remarquons que le service climatisation est indpendant de la SKUDA. Il peut exister dans toute voiture, voir dans une chambre ou dans un avion. Dans cet exemple, la climatisation na pas de variables propres et dans ce cas prcis, elle peut tre dcrite partir dune interface en C#. Si vous voulez rajouter un paramtre interne la climatisation comme ltat de son filtre, sa puissance de refroidissement il faudra alors crer une classe et passer par une agrgation. Une interface dfinit un comportement devant tre implment par les classes dclarant cette interface. On peut voir une interface comme une norme servant dcrire tous les services devant tre proposs par une classe pour adhrer cette norme. Un des exemples les plus courants dans .net est le comportement numrable , cest--dire la capacit accder aux lments dun objet lun aprs lautre. On peut considrer quun Triangle est numrable en fournissant chacun de ses trois sommets lun aprs lautre. Le C# dfinit justement linstruction foreach pour parcourir ce type dobjet. Cette interface est dfinie dans System.Collections.IEnumerable. Une interface est dfinie de manire similaire une classe mais elle ne contient que des prototypes de fonctions sans qualificateur de visibilit. Cest la classe implmentant linterface qui choisit leurs visibilits. Une classe peut hriter de plusieurs interfaces. Elle doit pour cela implmenter le code de chacune des fonctions proposes par les diffrentes interfaces. Quelques repres : - Interface et classe abstraite ne sont pas quivalentes. Une interface nimplmente aucune mthode. Une classe abstraite peut ne pas implmenter certaines de ces mthodes. - Une classe peut implmenter plusieurs interfaces. - Une classe a au plus une super-classe. - Des classes non lies hirarchiquement peuvent implmenter une mme interface. Les interfaces en C# disposent aussi des facilits de lhritage et comme une interface na pas de champs interne, lhritage multiples est cette fois autoris. Linterface fille nimplmente pas ces interfaces car ce serait contraire au principe des interfaces. La classe qui implmente linterface fille devra par contre implmenter toutes les fonctions dcrite par la hirarchie des interfaces. class Enfant { ... }

ESIEE Paris L. Buzer et B. Perret

Oct 2011 v1.11

interface interface interface

IBonjour { void DireBonjour() ; } IAurevoir { void DireAurevoir() ; } IPolitesse : IBonjour, IAurevoir {}

class EnfantPoli : IPolitesse { public void DireBonjour() {...} public void DireAurevoir() {...} } Remarque : comme les interfaces sont proches des classes, on peut aussi par le mme mcanisme dclarer une rfrence sur une interface : EnfantPoli Paul = new EnfantPoli() ; IPolitesse iP = Paul ; iP.DitBonjour() ; // correct Paul implmente IPolitesse

6. Cas particuliers
6.1 Classe abstraite
Considrons un logiciel de dessin vectoriel. Ce logiciel de dessin doit tre capable de manipuler diffrentes objets : des ellipses, des rectangles... Il va donc tre utile de les regrouper dans une mme hirarchie avec un parent commun : ObjetVectoriel. Il sera naturel dutiliser une mthode polymorphe Draw() pour ces objets. Cependant la classe ObjetVectoriel ne contient pas dinformation gomtrique et elle ne sait pas se dessiner. Deux options soffrent vous, lorsque vous crez la mthode virtuelle Draw de ObjetVectoriel : Vous dclarez la fonction et vous lui associez un corps vide : {}. Cette solution fonctionne mais amne quelques risques. En effet, lutilisateur (un autre programmeur que vous), peut alors instancier tort un ObjetVectoriel alors que cet objet est une coquille vide. Cela napportera pas vraiment de bugs, par contre, lutilisateur va snerver pour faire marcher cet objet et il ny arrivera pas. Pensez au temps perdu lorsque vous avez essay dinstancier la classe stream. Vous tre un programmeur sympathique et pensez au bien tre de vos collaborateurs. Vous ajoutez un qualificatif indiquant que cette classe nest pas utilisable et vous empchez toute tentative dinstanciation. En bonus, vous ntes pas oblig de programmer des mthodes vides. Une telle classe est qualifie dabstraite.

Lorsque vous tes surs que le parent commun ne doit pas tre instanci, il est fortement recommand de construire une classe abstraite et voici la syntaxe : abstract class Shape { protected string nom ; public abstract void Draw() ; } class Triangle : Shape {

// mthode abstraite : pas de block {}

ESIEE Paris L. Buzer et B. Perret


protected Point p1, p2, p3 ; public override void Draw() { ... } }

Oct 2011 v1.11

Remarque : une mthode abstraite est automatiquement virtuelle. Par contre, il faut utiliser le qualificatif override lors de sa dfinition dans les sous-classes. Remarque 2 : une classe abstraite ne peut pas tre instancie, ce qui ne lempche pas de possder un ou plusieurs constructeurs appels par le mcanisme de chanage des constructeurs. Remarque 3 : une classe non abstraite fille dune classe abstraite doit implmenter toutes les mthodes abstraites de sa classe mre. Remarque 4 : vous pouvez crer une sous-classe abstraite dune classe abstraite. Il faudra alors qualifier explicitement cette sous classe dabstraite.

6.2 Une classe mre commune


En C#, toute classe sans parent explicite hrite implicitement de la classe mre Object. La class Object est ainsi la racine de la hirarchie de toutes les classes, les vtres comme celles de .net. La classe Object dclare cinq mthodes de base accessibles partir de toutes les instances. Nous dtaillerons leurs rles dans une autre partie du cours.
Mthode public bool Equals(Object) public void Finalize() public int GetHashCode() public Type GetType() public Object MemberWiseClone() public string ToString() Action Dtermine si lobjet spcifi est gal lobjet en cours Libre les ressources avant que lobjet soit dtruit par le ramasse miettes Retourne le code de hashage de lobjet Retourne le type de lobjet Cr une copie superficielle de lobjet Retourne une chane qui reprsente l'objet

6.3 Identification dynamique des types de classes


On peut trouver des collections dans lesquelles sont stocks toutes sortes dobjets : des vhicules, des tlviseurs, des personnes Cela est techniquement possible puisque nous venons de voir que tout objet en C# appartient implicitement la mme famille dont la racine est Object. Si certains objets appartiennent une mme hirarchie (Voiture), dautres sont sans rapport entre eux. Dans cette situation, il peut tre utile de dterminer le type dun objet la vole, en C# le mot clef is fournit cette facilit. class A { ... } class B : A { ... } class C { ... } A a = new B(); if ( a is A ) WriteLine(Je suis de type A); if ( a is B ) WriteLine(Je suis de type B); if ( a is C ) WriteLine(Je suis de type C); // => Je suis de type A // => Je suis de type B // - rien

Une instance de la classe B est considre comme tant de type A car elle est une descendante de A. Si nous prenons un exemple dutilisation, nous obtenons : foreach (Object o in Liste)

ESIEE Paris L. Buzer et B. Perret


{ if ( o is Voiture ) { Voiture v = (Voiture) o ; v. Demarre() ; } }

Oct 2011 v1.11

Quelle que soit le modle de voiture (C3, Corsa, SCUDA), nous dterminons si o est un objet hritant de la classe Voiture. Nous effectuons une conversion explicite et nous avons ainsi accs toutes les mthodes polymorphes des Voitures. On peut utiliser une syntaxe quivalente avec le mot clef as. Ce mot clef effectue une tentative de transtypage et si celle-ci choue le rsultat est null. Voiture v = o as B ; if ( v != null ) v.Demarre() ;

Вам также может понравиться