Introduction À La Programmation Orientée Objet
Introduction À La Programmation Orientée Objet
Introduction À La Programmation Orientée Objet
http://hdd34.developpez.com/cours/artpoo/
Forums Tutoriels Magazine FAQs Blogs Projets Chat Newsletter tudes Emploi Club Contacts
Accueil Conception Java .NET Dv. Web EDI Langages SGBD Office Solutions d'entreprise Applications Systmes
Langages
ACCUEIL PASCAL
Assembleur
C++
C#
Pascal
Perl
Python
EXERCICES
Visual Basic 6
SOURCES
Visual Basic.NET
XML
Autres
FORUM PASCAL
F.A.Q PASCAL
TUTORIELS
COMPILATEURS
OUTILS
LIVRES
Dans ce tutoriel vous apprendrez manier la Programmation Oriente Objet, ou POO pour les intimes, dans le cadre du langage Pascal Orient Objet. Loin d'tre aussi complexe qu'elle peut le laisser transparatre, la POO peut se matriser rapidement au point de ne plus pouvoir s'en passer. Version PDF (Miroir) Version hors-ligne (Miroir)
Avant-Propos 1. Vue d'ensemble de la POO 1.1. L'objet 1.2. Objet et classe 1.3. Les trois fondamentaux de la POO 1.3.1. Encapsulation 1.3.2. Hritage 1.3.3. Polymorphisme 2. Diffrents types de mthodes 2.1. Constructeurs et destructeurs 2.1.1. Constructeurs 2.1.2. Destructeurs 2.2. Pointeur interne 2.3. Mthodes virtuelles et mthodes dynamiques 2.3.1. Mthodes virtuelles 2.3.1.1. Principe 2.3.1.2. Constructeurs et Table des Mthodes Virtuelles 2.3.2. Mthodes dynamiques 2.4. Mthodes abstraites 3. Visibilit 3.1. Champs et mthodes publics 3.2. Champs et mthodes privs 3.3. Champs et mthodes protgs 4. Le Pascal Objet 4.1. Dclaration d'un objet 4.1.1. Dclaration simple 4.1.2. Dclarations imbriques 4.2. Champs et mthodes 4.2.1. Procdures et fonctions 4.2.2. Constructeurs 4.2.3. Destructeurs 4.2.4. Mthodes virtuelle et dynamique 4.2.5. Mthodes abstraites 4.2.6. Paramtre implicite Self 4.3. Visibilit 4.4. Hritage 4.4.1. Dclaration 4.4.2. Surcharge et appel de l'anctre 4.4.2.1. Anctre direct 4.4.2.2. Anctre indirect 4.4.3. Valeur de retour d'un constructeur 4.4.4. Ordre d'appel de l'anctre dans les constructeurs et destructeurs 4.5. Instanciation d'un objet 4.5.1. Instanciation statique 4.5.2. Instanciation dynamique 4.5.2.1. Allocation 4.5.2.2. Dsallocation 4.6. L'objet gnrique TObject Conclusion Remerciements
Avant-Propos
1 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Si la programmation dite procdurale est constitue de procdures et fonctions sans liens particuliers agissant sur des donnes dissocies pouvant mener rapidement des difficults en cas de modification de la structure des donnes, la programmation objet, pour sa part, tourne autour d'une unique entit : l'objet, offrant de nouvelles perspectives, et que je vous invite dcouvrir de suite... Attention ! Borland a longtemps employ le nom de Pascal Objet pour Delphi. Celui-ci a t rcemment renomm langage Delphi. Nous n'aborderons pas dans ce tutoriel une approche spcifique Delphi. Nous nous orienterons plus vers une approche gnrale du Pascal, tous compilateurs Pascal confondus sitt que ceux-ci supportent la Programmation Oriente Objet, comme c'est le cas pour Turbo Pascal, Free Pascal, GNU Pascal... et bien sr Delphi.
1.1. L'objet
Il est impossible de parler de Programmation Oriente Objet sans parler d'objet, bien entendu. Tchons donc de donner une dfinition aussi complte que possible d'un objet. Un objet est avant tout une structure de donnes. Autrement, il s'agit d'une entit charge de grer des donnes, de les classer, et de les stocker sous une certaine forme. En cela, rien ne distingue un objet d'une quelconque autre structure de donnes. La principale diffrence vient du fait que l'objet regroupe les donnes et les moyens de traitement de ces donnes. Un objet rassemble de fait deux lments de la programmation procdurale.
Les champs : Les champs sont l'objet ce que les variables sont un programme : ce sont eux qui ont en charge les donnes grer. Tout comme n'importe quelle autre variable, un champ peut possder un type quelconque dfini au pralable : nombre, caractre... ou mme un type objet. Les mthodes : Les mthodes sont les lments d'un objet qui servent d'interface entre les donnes et le programme. Sous ce nom obscur se cachent simplement des procdures ou fonctions destines traiter les donnes. Les champs et les mthodes d'un objet sont ses membres. Si nous rsumons, un objet est donc un type servant stocker des donnes dans des champs et les grer au travers des mthodes. Si on se rapproche du Pascal, un objet n'est donc qu'une extension volue des enregistrements (type record) disposant de procdures et fonctions pour grer les champs qu'il contient. On notera souvent les membres d'un objet Objet.Membre de faon lever toute ambigut quant au propritaire du membre considr.
2 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
1.3.1. Encapsulation
Derrire ce terme se cache le concept mme de l'objet : runir sous la mme entit les donnes et les moyens de les grer, savoir les champs et les mthodes. L'encapsulation introduit donc une nouvelle manire de grer des donnes. Il ne s'agit plus de dclarer des donnes gnrales puis un ensemble de procdures et fonctions destines les grer de manire spare, mais bien de runir le tout sous le couvert d'une seule et mme entit. Si l'encapsulation est dj une ralit dans les langages procduraux (comme le Pascal non objet par exemple) au travers des units et autres librairies, il prend une toute nouvelle dimension avec l'objet. En effet, sous ce nouveau concept se cache galement un autre lment prendre en compte : pouvoir masquer aux yeux d'un programmeur extrieur tous les rouages d'un objet et donc l'ensemble des procdures et fonctions destines la gestion interne de l'objet, auxquelles le programmeur final n'aura pas avoir accs. L'encapsulation permet donc de masquer un certain nombre de champs et mthodes tout en laissant visibles d'autres champs et mthodes. Nous verrons ceci un peu plus loin. Pour conclure, l'encapsulation permet de garder une cohrence dans la gestion de l'objet, tout en assurant l'intgrit des donnes qui ne pourront tre accdes qu'au travers des mthodes visibles.
1.3.2. Hritage
Si l'encapsulation pouvait se faire manuellement (grce la dfinition d'une unit par exemple), il en va tout autrement de l'hritage. Cette notion est celle qui s'explique le mieux au travers d'un exemple. Considrons un objet Btiment. Cet objet est pour le moins gnrique, et sa dfinition reste assez vague. On peut toutefois lui associer divers champs, dont par exemple :
les murs ; le toit ; une porte ; l'adresse ; la superficie. On peut supposer que cet objet Btiment dispose d'un ensemble de mthodes destines sa gestion. On pourrait ainsi dfinir entre autres des mthodes pour :
ouvrir le Btiment ; fermer le Btiment ; agrandir le Btiment. Grce au concept d'hritage, cet objet Btiment va pouvoir donner naissance un ou des descendants. Ces descendants vont tous bnficier des caractristiques propres de leur anctre, savoir ses champs et mthodes. Cependant, les descendants conservent la possibilit de possder leurs propres champs et mthodes. Tout comme un enfant hrite des caractristiques de ses parents et dveloppe les siennes, un objet peut hriter des caractristiques de son anctre, mais aussi en dvelopper de nouvelles, ou bien encore se spcialiser. Ainsi, si l'on poursuit notre exemple, nous allons pouvoir crer un objet Maison. Ce nouvel objet est toujours considr comme un Btiment, il possde donc toujours des murs, un toit, une porte, les champs Adresse ou Superficie et les mthodes destines par exemple Ouvrir le Btiment. Toutefois, si notre nouvel objet est toujours un Btiment, il n'en reste pas moins qu'il s'agit d'une Maison. On peut donc lui adjoindre d'autres champs et mthodes, et par exemple :
nombre de fentres ; nombre d'tages ; nombre de pices ; possde ou non un jardin ; possde une cave. Notre Btiment a ici bien volu. Il s'est spcialis. Avec notre Maison, nous sommes alls plus avant dans les dtails, et elle est mme de nous offrir des services plus volus. Nous avons complt ce qui n'tait qu'un squelette. Ce processus d'hritage peut bien sr tre rpt. Autrement dit, il est tout fait possible de dclarer prsent un descendant de Maison, dveloppant sa spcialisation : un Chalet ou encore une Villa. Mais de la mme manire, il n'y a pas de restrictions thoriques concernant le nombre de descendants pour un objet. Ainsi, pourquoi ne pas dclarer des objets Immeuble ou encore Usine dont l'anctre commun serait toujours Btiment.
3 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Ce concept d'hritage ouvre donc la porte un nouveau genre de programmation. On notera qu'une fois qu'un champ ou une mthode sont dfinis, il ou elle le reste pour tous les descendants, quel que soit leur degr d'loignement.
1.3.3. Polymorphisme
Le terme polymorphisme est certainement celui que l'on apprhende le plus. Mais il ne faut pas s'arrter cela. Afin de mieux le cerner, il suffit d'analyser la structure du mot : poly comme plusieurs et morphisme comme forme. Le polymorphisme traite de la capacit de l'objet possder plusieurs formes. Cette capacit drive directement du principe d'hritage vu prcdemment. En effet, comme on le sait dj, un objet va hriter des champs et mthodes de ses anctres. Mais un objet garde toujours la capacit de pouvoir redfinir une mthode afin de la rcrire, ou de la complter. On voit donc apparatre ici ce concept de polymorphisme : choisir en fonction des besoins quelle mthode anctre appeler, et ce au cours mme de l'excution. Le comportement de l'objet devient donc modifiable volont. Le polymorphisme, en d'autres termes, est donc la capacit du systme choisir dynamiquement la mthode qui correspond au type rel de l'objet en cours. Ainsi, si l'on considre un objet Vhicule et ses descendants Bateau, Avion, Voiture possdant tous une mthode Avancer, le systme appellera la fonction Avancer spcifique suivant que le vhicule est un Bateau, un Avion ou bien une Voiture. Attention ! Le concept de polymorphisme ne doit pas tre confondu avec celui d'hritage multiple. En effet, l'hritage multiple - non support par le Pascal standard - permet un objet d'hriter des membres (champs et mthodes) de plusieurs objets la fois, alors que le polymorphisme rside dans la capacit d'un objet modifier son comportement propre et celui de ses descendants au cours de l'excution.
2.1.1. Constructeurs
Comme leur nom l'indique, les constructeurs servent construire l'objet en mmoire. Un constructeur va donc se charger de mettre en place les donnes, d'associer les mthodes avec les champs et de crer le diagramme d'hritage de l'objet, autrement dit de mettre en place toutes les liaisons entre les anctres et les descendants. Il faut savoir que s'il peut exister en mmoire plusieurs instances d'un mme type objet, autrement dit plusieurs variables du mme type, seule une copie des mthodes est conserve en mmoire, de sorte que chaque instance se rfre la mme zone mmoire en ce qui concerne les mthodes. Bien entendu, les champs sont distincts d'un objet un autre. De fait, seules les donnes diffrent d'une instance une autre, la "machinerie" reste la mme, ce qui permet de ne pas occuper inutilement la mmoire. Certaines remarques sont prendre en considration concernant les constructeurs.
4 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Un objet peut ne pas avoir de constructeur explicite. Dans ce cas, c'est le compilateur qui se charge de crer de manire statique les liens entre champs et mthodes. Un objet peut avoir plusieurs constructeurs : c'est l'utilisateur qui dcidera du constructeur appeler. La prsence de constructeurs multiples peut sembler saugrenue de prime abord, leur rle tant identique. Cependant, comme pour toute mthode, un constructeur peut tre surcharg, et donc effectuer diverses actions en plus de la construction mme de l'objet. On utilise ainsi gnralement les constructeurs pour initialiser les champs de l'objet. diffrentes initialisations peuvent donc correspondre diffrents constructeurs. S'il n'est pas ncessaire de fournir un constructeur pour un objet statique, il devient obligatoire en cas de gestion dynamique, car le diagramme d'hritage ne peut tre construit de manire correcte que lors de l'excution, et non lors de la compilation.
2.1.2. Destructeurs
Le destructeur est le pendant du constructeur : il se charge de dtruire l'instance de l'objet. La mmoire alloue pour le diagramme d'hritage est libre. Certains compilateurs peuvent galement se servir des destructeurs pour liminer de la mmoire le code correspondant aux mthodes d'un type d'objet si plus aucune instance de cet objet ne rside en mmoire. L encore, diffrentes remarques doivent tre gardes l'esprit.
Tout comme pour les constructeurs, un objet peut ne pas avoir de destructeur. Une fois encore, c'est le compilateur qui se chargera de la destruction statique de l'objet. Un objet peut possder plusieurs destructeurs. Leur rle commun reste identique, mais peut s'y ajouter la destruction de certaines variables internes pouvant diffrer d'un destructeur l'autre. La plupart du temps, un constructeur distinct est associ un destructeur distinct. En cas d'utilisation dynamique, un destructeur s'impose pour dtruire le diagramme cr par le constructeur.
2.3.1.1. Principe Une mthode dite virtuelle n'a rien de fictif ! Il s'agit d'une mthode dont la rsolution des liens est effectue dynamiquement. Voyons ce que cela signifie. Comme nous le savons dj, toute mthode est susceptible d'tre surcharge dans un descendant, de manire tre crase ou complte. Par consquent, toute mthode surcharge donne lieu cration d'une nouvelle section de code, et donc une nouvelle adresse en mmoire. De plus, tout objet possde un lien vers la table des mthodes de ses anctres : le diagramme d'hritage. De fait, tout type objet est directement li ses types anctres. Autrement dit, si nous reprenons l'exemple du dbut, l'objet Maison peut tre assimil un Btiment. Considrons prsent la mthode Ouvrir d'un Btiment. Celle-ci consiste ouvrir la porte principale. prsent, surchargeons cette mthode pour l'objet Maison, de sorte que la mthode Ouvrir non seulement ouvre la porte principale, mais galement les volets de notre Maison. Dclarons maintenant une instance statique de Btiment, et appelons cette mthode Ouvrir. Lors de la cration de l'excutable, le compilateur va vrifier le type d'instance cr. Le compilateur lie alors notre appel celui de Btiment.Ouvrir (la mthode Ouvrir de l'objet Btiment), en toute logique. Il ne se pose aucun problme. Considrons prsent un autre exemple : dclarons une variable dynamique destine, en principe, recevoir un objet Btiment. Comme nous l'avons vu juste avant, l'objet Maison est compatible avec l'objet Btiment. Comme nous travaillons en dynamique, nous nous servons de pointeurs. De fait, je peux trs bien dcider, avec cette variable pointant vers un objet Btiment, de dclarer une instance de type Maison : le compilateur ne montrera aucune rticence.
5 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Si nous rsumons, nous avons donc une variable de type officiel pointeur vers Btiment et contenant en ralit une Maison. Appelons alors notre mthode Ouvrir. Comme nous avons une Maison, il faut que l'on ouvre les volets. Or, si nous excutons notre programme, les volets resteront clos. Que s'est-il pass ? Lors de la cration du programme, le compilateur s'est arrt sur notre appel Ouvrir. Ayant dclar un objet Btiment, le compilateur ignore tout du comportement du programme lors de son excution, et par consquent ignore que la variable de type pointeur vers Btiment contiendra l'excution un objet Maison. De fait, il effectue une liaison vers Btiment.Ouvrir alors que nous utilisons une Maison ! La solution, vous l'aurez compris, rside dans l'utilisation des mthodes virtuelles. Grce celles-ci, la rsolution des liens est effectue dynamiquement, autrement dit lors de l'excution. Ainsi, si nous dclarons notre mthode Ouvrir comme virtuelle, lors de la cration du programme, le compilateur n'effectuera aucune liaison statique avant notre appel. Ce n'est que lors de l'excution, au moment de l'appel, que la liaison va s'effectuer. Ainsi, au moment o l'on dsirera appeler Ouvrir, notre programme va interroger son pointeur interne pour dterminer son type. Bien videmment, cette fois-ci, il va dtecter une instance de Maison, et l'appel se fera donc en direction de Maison.Ouvrir. Les volets s'ouvrent... Vous aurez not toute l'importance des mthodes virtuelles. D'une manire gnrale, sitt qu'une mthode est susceptible d'tre surcharge, il faut la dclarer comme virtuelle . Attention ! Les constructeurs des objets ne seront jamais dclars comme virtuels, car c'est toujours le bon constructeur qui est appel. Le caractre virtuel est donc inutile et sera mme signal comme une erreur par le compilateur. Par contre, les destructeurs seront toujours dclars comme virtuels car souvent surchargs. Il n'en est pas de mme pour les classes qui elles peuvent s'appuyer sur le principe de constructeur virtuel. C'est notamment le cas de Delphi avec les rfrences de classes propos desquelles la documentation donne plus de prcisions. Vous pouvez aussi consulter les tutoriels suivants : * Cours sur la POO de Frdric Beaulieu ; * Cours sur les mtaclasses de Laurent Dardenne.
2.3.1.2. Constructeurs et Table des Mthodes Virtuelles Afin de pouvoir appeler la mthode approprie au moment souhait, un objet doit s'appuyer sur une liste de ses mthodes virtuelles : la VMT ou Virtual Methods Table, la Table des Mthodes Virtuelles. Cette table est mise en place par les constructeurs d'un objet. Tout objet possde sa propre VMT, conservant toujours un lien avec la VMT de son anctre. Lorsqu'un appel une mthode virtuelle est effectu, l'objet recherche dans sa VMT s'il trouve la mthode recherche. Si c'est le cas, alors il utilise l'adresse enregistre et excute la mthode. Sinon, il parcourt la VMT de son anctre direct et ainsi de suite jusqu' l'anctre le plus loign dans la hirarchie. De mme, lorsque qu'une mthode surcharge fait appel la mthode anctre, alors une recherche est effectue en partant cette fois-ci de la VMT du premier anctre. La VMT est dtruite par un destructeur lorsque celle-ci n'a plus lieu d'exister. Si jamais on utilise une mthode virtuelle sans avoir appel au pralable un constructeur, le caractre virtuel ne sera pas pris en compte et les rsultats seront imprvisibles .
Avantage : les mthodes dynamiques consomment moins de mmoire ; Inconvnient : la gestion interne des mthodes dynamiques est plus complexe, et donc plus lente. Par consquent, on prfrera toujours les mthodes virtuelles, sauf si de nombreuses mthodes virtuelles doivent tre dclares, auquel cas on se reportera aux mthodes dynamiques .
3. Visibilit
De par le principe de l'encapsulation, afin de pouvoir garantir la protection des donnes, il convient de pouvoir masquer certaines donnes et mthodes internes les grant, et de pouvoir laisser visibles certaines autres devant servir la gestion publique de l'objet. C'est le
6 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
principe de la visibilit.
4. Le Pascal Objet
Tous les lments de la Programmation Oriente Objet noncs jusqu'ici sont bien entendu supports par le Pascal Objet. Nous allons voir prsent comment les implmenter.
On remarquera que la dclaration d'un objet se terminera toujours par un end;. De plus, on adopte trs souvent en Pascal une convention de notation pour les objets : leur nom commence toujours par T, comme type. Nous respecterons toujours cette convention dans ce tutoriel, et nous parlerons donc des objets TMaison ou encore TChose. Attention ! Sur les compilateurs de nouvelle gnration, le mot rserv object sera remplac par le mot rserv class.
7 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Dans la suite de ce tutoriel, nous adopterons l'utilisation de mot rserv object. Celui-ci sera remplacer en fonction du compilateur utilis (Delphi par exemple).
type TParent = object Enfant: TEnfant; end; TEnfant = object Parent: TParent; end;
Le compilateur va dclencher une erreur indiquant qu'il connat pas encore TEnfant lorsqu'il tente d'analyser la structure de TParent. La solution au problme passe ncessairement par l'instanciation dynamique des deux objets (voir le paragraphe concern). On va donc dclarer deux pointeurs vers les deux types considrs et seulement ensuite, on dclarera les objets eux-mmes, ceci dans le mme bloc type :
type { Dclaration des pointeurs } PParent = ^TParent; PEnfant = ^TEnfant; { Dclaration des objets utilisant les pointeurs } TParent = object Enfant: PEnfant; end; TEnfant = object Parent: PParent; end;
Grce cette mthode, plus aucune erreur n'est dclenche, car lorsque le compilateur va analyser TParent, il aura dj eu connaissance de l'existanceexistence de PEnfant. Ceci n'est bien videmment possible que parce que le compilateur accepte la dclaration prmature de pointeurs avant le type vers lequel ils pointent. Sous Delphi, l'instanciation tant automatiquement dynamique, ce problme ne se pose pas, et pour rsoudre le problme, on se contente d'annoncer la classe avec une dclaration partielle :
type { Dclarations partielles } TParent = class; TEnfant = class; { Dclaration des objets utilisant les classes } TParent = class Enfant: TEnfant; end; TEnfant = class Parent: TParent; end;
type TChose = object Entier: Integer; Chaine: string; Fichier: file; end;
8 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
type TTruc = object Obj1: TChose; Obj2: object Champ: Char; end; end;
var Bidule: TBidule; Truc: TTruc; begin ... Bidule.Enr.A := ...; ... Truc.Obj1.Entier := 0; Truc.Obj2.Champ := 'X'; ... end.
Les mthodes se dclarent la suite des champs. Le schma thorique actuel de description d'un objet serait ainsi :
type TObjet = object Champ; ... Champ; Methode; ... Methode; end;
type TObjet = object Champs; .... procedure Methode1(Params: ParamType); function Methode2(Params: ParamType): RetType; end;
Une fois ces mthodes dclares, il faut crire le code source associ. On complte leur dclaration en dehors de la dclaration de l'objet. Le nom de la mthode est alors prcd du nom de l'objet suivi d'un point. Un exemple expliquant aussi bien, voici donc ce que donnerait l'ajout d'une mthode Methode1 :
Comme il s'agit d'une dclaration de type forward, on peut ventuellement omettre les paramtres lorsque l'on complte la dclaration d'une mthode :
Ce code et le code prcdent sont tous deux parfaitement identiques. On choisira donc de privilgier soit la facilit de lecture, soit la simplicit d'criture.
4.2.2. Constructeurs
9 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Un constructeur se dclare exactement comme une autre mthode. Il n'y a pas d'ordre particulier, et on peut trs bien intercaler des constructeurs au milieu des autres mthodes. Le mot rserv procedure (ou function) sera ici remplac par le mot rserv constructor :
L'usage veut que le constructeur principal d'un objet soit appel Init ou Create. Il n'y a aucune obligation dans ce domaine, mais on essaie la plupart du temps de suivre cette convention.
Turbo Pascal utilise pour tous les objets standard la "convention Init", et Delphi pour sa part utilise la "convention Create". Il est possible de faire chouer un constructeur, par exemple si une opration ncessaire l'initialisation de l'objet s'est mal droule. En fonction du compilateur, soit on dclenchera une exception (Delphi), soit on fera appel la procdure Fail :
type TObjet = object constructor Init; end; constructor TObjet.Init; begin ... { Fait chouer le constructeur } if ... then Fail; end;
4.2.3. Destructeurs
De mme que pour les constructeurs, on se servira ici du mot rserv destructor :
Ici encore, l'usage veut que l'on appelle les destructeurs Done ou Destroy. De plus, la plupart du temps, un destructeur n'aura pas de paramtre. Toutefois, le contraire est tout fait autoris par le compilateur. Turbo Pascal utilise pour tous les objets standard la "convention Done", et Delphi pour sa part utilise la "convention Destroy".
type TObjet = object procedure Methode(Param: ParamType); virtual; end; procedure Methode(Param: ParamType); begin ... end;
Les mthodes dynamiques sont galement appeles mthodes virtuelles indexes. En effet, rien ne les distingue des mthodes virtuelles si ce n'est qu'elles possdent un index, un numro pour les identifier. La dclaration d'une mthode dynamique varie d'un compilateur un autre. Sur les compilateurs plus anciens, elles seront dclares comme ceci :
type TObjet = object procedure Methode(Param: ParamType); virtual IndexUnique; end; procedure Methode(Param: ParamType); begin
10 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
... end;
O IndexUnique reprsente un entier unique permettant d'identifier la mthode virtuelle. Sur les compilateurs plus rcents, l'index est gr automatiquement, et il suffit pour dclarer une mthode dynamique de remplacer le mot rserv virtual par le mot rserv dynamic :
type TObjet = class procedure Methode(Param: ParamType); dynamic; end; procedure TObjet.Methode(Param: ParamType); begin ... end;
Attention ! Si votre compilateur utilise le mot rserv object (comme Turbo Pascal), et si une mthode est dclare avec le mot rserv virtual alors toutes les mthodes surcharges devront aussi tre dclares avec virtual. Il en sera de mme avec les mthodes dynamiques. Si par contre votre compilateur utilise le mot rserv class, les mthodes surcharges devront tre dclares avec le mot rserv override. Consultez la documentation de votre compilateur pour plus de dtails.
type TObjet = object procedure MethodeAbs; end; procedure TObjet.MethodeAbs; begin { C'est une mthode abstraite } Abstract; end;
Les nouveaux compilateurs utilisent le mot rserv abstract, et suppriment logiquement le corps de la mthode :
type TObjet = class { C'est une mthode abstraite } procedure MethodeAbs; abstract; end;
Le paramtre Self sert de manire interne l'objet pour garantir un appel correct des mthodes virtuelles. Pour le programmeur, Self peut aussi servir vrifier qu'une instance d'un mme type d'objet est dj en mmoire et, par exemple, interdire la cration d'une nouvelle instance :
11 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
var Instance: TObjet; constructor TObjet.Init; begin if Instance <> Self then Fail; ... end; begin Instance.Init; ... end.
Le paramtre Self est toujours transmis en premier la mthode. Ceci peut avoir son importance lors de l'utilisation de l'assembleur.
4.3. Visibilit
La visibilit de champs et mthodes s'indique grce divers mots rservs :
visibilit publique : public ; visibilit prive : private ; visibilit protge : protected. Le spcificateur de visibilit doit tre plac avant l'ensemble des champs et mthodes devant bnficier de cette visibilit :
type TObjet = object private ChampPriv; ... MethodePriv; ... public ChampPub; ... MethodePub; ... end;
Les spcificateurs peuvent tre placs dans un ordre quelconque, et apparatre plusieurs fois si ncessaire, bien que cette possibilit soit rarement utilise. Rappel La visibilit protge n'est pas disponible sous Turbo Pascal.
4.4. Hritage
4.4.1. Dclaration
Un objet en Pascal ne peut hriter que d'un seul anctre. Afin de spcifier celui-ci, on spcifie son nom entre parenthses aprs le mot rserv object :
Sitt qu'un anctre est dclar pour un objet, ce dernier peut accder tous les champs et mthodes de son anctre sans avoir les redclarer (en fonction de la visibilit). Attention ! Si vous dsirez surcharger une mthode virtuelle, alors vous devez la redclarer exactement comme elle tait dclare dans l'anctre. Notamment, vous ne pourrez pas ajouter ou supprimer de paramtres sa dclaration. Par contre, si vous redfinissez une mthode, alors vous pourrez trs bien modifier ses paramtres comme vous le dsirez si celle-ci n'est pas virtuelle.
type TAncetre = object Champ: Integer; procedure ModifChamp(Valeur: Integer); virtual; procedure ARedefinir; end; procedure TAncetre.ModifChamp(Valeur: Integer); begin Champ := Valeur; end; procedure TAncetre.ARedefinir;
12 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
type TDescendant = object(TAncetre) procedure ModifChamp(Valeur: Integer); virtual; procedure ARedefinir(ParamSup: Integer); end; { On surcharge la mthode virtuelle ModifChamp en la remplaant par une autre } procedure TDescendant.ModifChamp(Valeur: Integer); begin { On accde au champ sans le redclarer dans TDescendant } Champ := Valeur + 1; end; { La mthode a t redfinie avec de nouveaux paramtres } procedure TDescendant.ARedefinir(ParamSup: Integer); begin ... end;
4.4.2.1. Anctre direct Gnralement, on appelle l'anctre direct, celui dont on hrite en premire main. Pour appeler la mthode anctre, on utilise alors le mot rserv inherited devant le nom de la mthode, l'endroit on l'on dsire effectuer l'appel :
type TAncetre = object Champ: Integer; procedure ModifChamp(Valeur: Integer); virtual; end; procedure TAncetre.ModifChamp(Valeur: Integer); begin Champ := Valeur; end;
type TDescendant = object(TAncetre) Temp: Integer; procedure ModifChamp(Valeur: Integer); virtual; end; procedure TDescendant.ModifChamp(Valeur: Integer); begin { On effectue diverses actions } Inc(Valeur); { On appelle l'anctre } inherited ModifChamp(Valeur); { On peut effectuer d'autres actions } Temp := Champ; end;
La mthode anctre peut tre appele autant de fois que dsir, et on peut effectuer un nombre quelconque d'oprations avant et/ou aprs ce ou ces appel(s).
4.4.2.2. Anctre indirect Dans certains cas particuliers, il peut tre ncessaire d'appeler un anctre plus loign dans la hirarchie : par exemple l'anctre de l'anctre direct. Dans ce cas, il faut faire explicitement appel la mthode en faisant prcder son nom par le nom de l'anctre suivi d'un point. Dans ce cas, les mthodes surcharges apparaissant entre l'objet et l'anctre appel seront ignores.
type TPremier = object ... procedure Methode; virtual; end; procedure TPremier.Methode; begin ... end;
type
13 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
TSecond = object(TPremier) ... procedure Methode; virtual; end; procedure TSecond.Methode; begin ... end;
type TDernier = object(TSecond) ... procedure Methode; virtual; end; procedure TDernier.Methode; begin ... { On appelle TPremier.Methode : TSecond.Methode est ignore } TPremier.Methode; end;
constructor TDescendant.Init(...); begin if not inherited Init(...) then Fail; ... end;
Constructeurs : D'une manire gnrale, le constructeur anctre devra tre appel en premier lieu, aucune autre instruction ne devant prcder cet appel. Cependant, il est possible d'effectuer diverses oprations en vue, par exemple, de transmettre une valeur en paramtre au constructeur anctre. Nanmoins, on s'abstiendra de toute modification de la valeur d'un champ avant l'appel l'anctre, car cette valeur serait sujette modification.
constructor TDescendant.Init(...); begin { Premire opration du constructeur : l'appel de l'anctre } if not inherited Init(...) then Fail; ... end;
Destructeur : De faon logique, l'appel au destructeur anctre devra se faire en dernier, une fois tous les champs du descendant ncessitant un traitement particulier dsallous proprement. En effet, une fois un destructeur appel, il est impossible de prvoir la valeur d'un champ.
destructor TDescendant.Done; begin ... { Dernire opration du destructeur : l'appel de l'anctre } inherited Done; end;
14 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
L'instanciation statique est certainement la plus simple mettre en oeuvre, mais aussi celle viter le plus possible. Elle consiste simplement dclarer une variable du type objet comme on dclarerait n'importe quelle variable :
Si l'objet possde un constructeur, celui-ci devra tre appel avant toute autre mthode, et de mme, si l'objet possde un destructeur, il devra tre appel en dernier.
type TObjet = object ... constructor Init(...); destructor Done; end; constructor TObjet.Init(...); begin ... end; destructor TObjet.Done; begin ... end;
var MonObjet: TObjet; begin ... MonObjet.Init(...); ... MonObjet.Methode; ... MonObjet.Done; ... end.
L'instanciation statique prsente plusieurs inconvnients, le principal concernant la mmoire. En effet, en mode rel sous DOS, seuls 64 Ko de mmoire sont disponibles pour les variables statiques. Il en rsulte donc une limitation drastique concernant le nombre d'objets en mmoire et leur taille. L'instanciation statique a t supprime sur les compilateurs rcents comme Delphi, o la gestion est obligatoirement dynamique, mais en gardant une syntaxe quivalente la syntaxe statique (suppression notamment de l'utilisation explicite des pointeurs).
4.5.2.1. Allocation L'allocation mmoire de l'objet et son initialisation se font gnralement en mme temps l'aide de la fonction standard New. Deux formes peuvent tre utilises :
New(VarObjet, Constructeur); Avec cette syntaxe, on utilise New en tant que procdure en faisant apparatre en tant que deuxime paramtre le constructeur avec ses ventuels paramtres.
var VarObjet := New(PointeurTypeObjet, Constructeur); Objet: PObjet; Cette syntaxe utilise la syntaxe tendue de New en l'utilisant en tant que fonction. On fait toujours apparatre en deuxime le constructeur affect de ses divers paramtres. begin La diffrence vient du fait que l'on spcifie clairement de quel type l'objet doit tre. New(Objet, Init(...)); ... Cette syntaxe permet plus de libert en ce que l'on peut trs bien affecter un pointeur quelconque (un type descendant par end. exemple) un autre type objet.
15 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
De plus, cette syntaxe se rapproche beaucoup de celle adopte par les compilateurs plus rcents comme Delphi. On pourra donc lgitimement la prfrer.
Il est tout fait possible d'allouer dans un premier temps l'objet comme n'importe quel pointeur avec New(Objet); et ensuite d'appeler le constructeur. Nanmoins, cette pratique est obsolte et on l'vitera autant que possible. On n'oubliera pas lors de l'appel aux mthodes que l'on utilise dornavant un pointeur. Le symbole ^ est donc de mise :
Attention ! Comme on travaille prsent avec des pointeurs, il faut vrifier que l'objet est bien allou . On peut ainsi tester l'galit avec nil ou bien utiliser la fonction interne Assigned :
var Objet: PObjet; begin Objet := New(PObjet, Init(...)); if Objet <> nil then begin ... Dispose(Objet, Done); end; end.
Ou :
var Objet: PObjet; begin Objet := New(PObjet, Init(...)); if Assigned(Objet) then begin ... Dispose(Objet, Done); end; end.
Les compilateurs rcents comme Delphi utilisent la syntaxe VarObjet := TypeObjet.Constructeur;, les pointeurs tant intgrs directement la dclaration de la classe. Ils sont donc implicites. De plus, on se servira de blocs try...finally pour protger son code :
var Objet: TObjet; begin Objet := TObjet.Create(...); try ... finally ... end; end;
4.5.2.2. Dsallocation Tout comme pour l'allocation, la dsallocation d'effectue s'effectue gnralement en mme temps que l'appel du destructeur de l'objet l'aide de la procdure Dispose. Le destructeur est alors pass avec ses ventuels paramtres comme deuxime paramtre de la procdure.
16 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Tout comme pour les constructeurs, il est possible d'appeler le destructeur pour n'appeler que par la suite Dispose sparment. Cette pratique devra toutefois tre vite car obsolte et parfois source d'erreurs. Delphi n'appelle pas directement le destructeur mais fait appel la procdure Free :
var Objet: TObjet; begin Objet := TObjet.Create(...); try ... finally TObjet.Free; end; end.
type PObject = ^TObject; TObject = object constructor Init; destructor Done; virtual; procedure Free; end;
Init : Le constructeur de TObject, en plus d'effectuer son rle habituel (mise en place du diagramme d'hritage, VMT...), met zro tous les champs. Cette opration n'est en effet pas automatique pour un objet quelconque, et, par consquent, tous les objets ne drivant pas de TObject voient le contenu de leurs champs indfini au moment de l'initialisation. Done : Le destructeur Done n'effectue rien ! Son seul intrt rside dans le fait qu'il est dclar comme virtuel. Par consquent, tous les descendants devront implmenter un destructeur virtuel, ce qui permet d'viter toute erreur due l'oubli de la sorte. Free : La mthode Free permet de se dispenser de l'appel Dispose. En effet, en appelant Free, l'objet se libre tout seul. On pourra donc prendre pour habitude de driver tous ses objets de base de TObject, car il fournit une architecture de base pratique et importante pour la compatibilit avec les objets de la bibliothque standard. L'allocation et la dsallocation d'un tel objet deviendront alors :
uses Objects; type PChose = ^TChose; TChose = object(TObject) private ... public ... constructor Init(...); destructor Done; virtual; end; constructor TChose.Init(...); begin if not inherited Init then Fail; ... end; destructor TChose.Done; begin ... inherited Done; end; ...
var Chose: PChose; begin Chose := New(PChose, Init(...)); if Assigned(Chose) then begin ...
17 sur 18
05/11/2011 15:38
http://hdd34.developpez.com/cours/artpoo/
Delphi impose par dfaut TObject comme anctre si aucun anctre n'est spcifi lors de la dclaration d'une classe. Ainsi, les deux exemples suivants sont quivalents :
Conclusion
Vous avez appris ici les bases de la Programmation Oriente Objet et vous tes prsent mme de construire vous-mme vos propres programmes objets. Seule la pratique permettant de faire des progrs, vos claviers ! Liens consulter en complment : * Cours sur la POO de Frdric Beaulieu ; * Cours sur les mtaclasses de Laurent Dardenne ; * Les exemples de code illustrant le livre de John Colibri.
Remerciements
Remerciements particuliers Laurent Dardenne et Richard Gaillard, ainsi qu' Claude Leloup pour sa relecture.
Les sources prsentes sur cette page sont libres de droits et vous pouvez les utiliser votre convenance. Par contre, la page de prsentation constitue une uvre intellectuelle protge par les droits d'auteurs. Copyright 2004-2011 Eric Sigoillot. Aucune reproduction, mme partielle, ne peut tre faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu' trois ans de prison et jusqu' 300 000 de dommages et intrts. Cette page est dpose.
Developpez.com
Nous contacter Participez Informations lgales
Services
Forum Pascal Blogs Hbergement
Partenaires
Hbergement Web
18 sur 18
05/11/2011 15:38